访问排行榜
谷歌广告
谷歌广告
使用远程下载的.9图片(进阶)可传参数与适应各种分辨率
Author zero | Posted 2016-11-28 18:42:00

Android 使用远程下载的.9图片(进阶)可传参数与适应各种分辨率

上一章解决了远程图片作为.9图片使用的问题,这一章实现了任意远程图片+left,top,right,bottom参数构造实现.9图片的问题,独此一家别无分店。 先说明原理:和点9图片差不多,不一样的是少了右边和底边的显示区域的界定,默认显示在所有区域,相信用习惯点9图片的人,制作图片应该都是这样,否则更换图片太累。 其次,也是最重要的,本章实现的功能横向与竖向拉伸均不能在图片的边缘区域,要实现边缘区域需要图片图片像素点进行判断,效率比较低下,正常情况也不会在意这个一两像素,如果有需要可以留言作者, 作者可以帮你补全代码。 OK,下面开始水代码:

/**
  * 根据left,top,right,bottom创造nine patch参数,注意:未处理黑点从边缘开始绘制的情况,从边缘开始拉伸需要读取图片资源,效率较低,所以不做处理
  * @param bitmap
  * @param left
  * @param top
  * @param right
  * @param bottom
  * @return
  * @throws IOException
  */
public static byte[] readChunkByNum(Bitmap bitmap,int left,int top,int right,int bottom) throws IOException{
    Bitmap realBitmap = bitmap;

    final int BM_W = realBitmap.getWidth();
    final int BM_H = realBitmap.getHeight();

    int xPointCount = 0;
    int yPointCount = 0;
    int xBlockCount = 0;
    int yBlockCount = 0;

    ByteArrayOutputStream bao = new ByteArrayOutputStream();
    for (int i = 0; i < 32; i++) {
        bao.write(0);
    }

    //横向处理
    xPointCount++;
    writeInt(bao, left);
    xPointCount++;
    writeInt(bao, BM_W - right);
    xBlockCount = xPointCount + 1;

    //纵向处理
    yPointCount++;
    writeInt(bao, top);
    yPointCount++;
    writeInt(bao, BM_H - bottom);
    yBlockCount = yPointCount + 1;

    {
        for (int i = 0; i < xBlockCount * yBlockCount; i++) {
            writeInt(bao, NO_COLOR);
        }
    }

    byte[] data = bao.toByteArray();
    data[0] = 1;
    data[1] = (byte) xPointCount;
    data[2] = (byte) yPointCount;
    data[3] = (byte) (xBlockCount * yBlockCount);
    dealPaddingInfo(realBitmap, data);
    return data;
}

private static void dealPaddingInfo(Bitmap bm, byte[] data) {
   { // padding left & padding right
      int[] bottomPixels = new int[bm.getWidth() - 2];
      bm.getPixels(bottomPixels, 0, bottomPixels.length, 1,
            bm.getHeight() - 1, bottomPixels.length, 1);
      for (int i = 0; i < bottomPixels.length; i++) {
         if (Color.BLACK == bottomPixels[i]) { // padding left
            writeInt(data, 12, i);
            break;
         }
      }
      for (int i = bottomPixels.length - 1; i >= 0; i--) {
         if (Color.BLACK == bottomPixels[i]) { // padding right
            writeInt(data, 16, bottomPixels.length - i - 2);
            break;
         }
      }
   }
   { // padding top & padding bottom
      int[] rightPixels = new int[bm.getHeight() - 2];
      bm.getPixels(rightPixels, 0, 1, bm.getWidth() - 1, 0, 1,
            rightPixels.length);
      for (int i = 0; i < rightPixels.length; i++) {
         if (Color.BLACK == rightPixels[i]) { // padding top
            writeInt(data, 20, i);
            break;
         }
      }
      for (int i = rightPixels.length - 1; i >= 0; i--) {
         if (Color.BLACK == rightPixels[i]) { // padding bottom
            writeInt(data, 24, rightPixels.length - i - 2);
            break;
         }
      }
   }
}

private static void writeInt(OutputStream out, int v) throws IOException {
   out.write((v >> 0) & 0xFF);
   out.write((v >> 8) & 0xFF);
   out.write((v >> 16) & 0xFF);
   out.write((v >> 24) & 0xFF);
}

private static void writeInt(byte[] b, int offset, int v) {
   b[offset + 0] = (byte) (v >> 0);
   b[offset + 1] = (byte) (v >> 8);
   b[offset + 2] = (byte) (v >> 16);
   b[offset + 3] = (byte) (v >> 24);
}

private static int getInt(byte[] bs, int from) {
   int b1 = bs[from + 0];
   int b2 = bs[from + 1];
   int b3 = bs[from + 2];
   int b4 = bs[from + 3];
   int i = b1 | (b2 << 8)  | (b3 << 16) | b4 << 24;
   return i;
}

调用的方法也很简单:我可是实现了多分辨率适配的哦,基数是2.0的bitmap和数据,毕竟2.0的手机现在是大头。使用zoomBitmap可以很好地放缩图片

/**
 * 获取ImageView的src图片,生成nine patch图片设置成背景
 //160DPI:ppi = 1,320DPI:ppi = 2;480DPI:ppi = 3
 //bitmap需要根据PPI进行放大缩小处理
 //数据、图片是根据2.0给的,注意。。。。。
 * @param imageView
 * @param context
 * @param left
 * @param top
 * @param right
 * @param bottom
 */
public static void changeBitmapToNinePatch(ImageView imageView,Context context,int left,int top,int right,int bottom){
    BitmapDrawable drawable = (BitmapDrawable)imageView.getDrawable();
    imageView.setImageDrawable(null);
    Bitmap realBitmap = drawable.getBitmap();
    if(realBitmap.isRecycled()){
        return;
    }
    float ppi = ViewUtil.getPPI(context);
    if(ppi != 2.0){
        realBitmap = BaseUtil.zoomImg(realBitmap,(int)(realBitmap.getWidth() * (ppi / 2)),(int)(realBitmap.getHeight() * (ppi / 2)),true);
    }
    //drawable用在两个地方,所以需要创建一个镜像
    NinePatch ninePatch = null;
    try {
        byte[] chunk = NinePatchUtils.readChunkByNum(realBitmap,(int)(left * (ppi / 2)),(int)(top * (ppi / 2)),(int)(right * (ppi / 2)),(int)(bottom * (ppi / 2)));
        ninePatch = new NinePatch(realBitmap, chunk);
    } catch (IOException e) {
        e.printStackTrace();
    }
    NinePatchDrawable ninePatchDrawable = new NinePatchDrawable(context.getResources(),ninePatch);
    imageView.setBackgroundDrawable(ninePatchDrawable);
}
/**
 *  处理图片
 * @param bm 所要转换的bitmap
 * @param newWidth 新的宽
 * @param newHeight 新的高
 * @return 指定宽高的bitmap
 */
public static Bitmap zoomImg(
        Bitmap bm ,
        int newWidth ,
        int newHeight ,
        boolean needRecycle )
{
    if( null == bm ){
        return null;
    }
    // 获得图片的宽高
    int width = bm.getWidth();
    int height = bm.getHeight();
    // 计算缩放比例
    float scaleWidth = ( (float)newWidth ) / width;
    float scaleHeight = ( (float)newHeight ) / height;
    // 取得想要缩放的matrix参数
    Matrix matrix = new Matrix();
    matrix.postScale( scaleWidth , scaleHeight );
    // 得到新的图片
    Bitmap newbm = Bitmap.createBitmap( bm , 0 , 0 , width , height , matrix , true );
    if( needRecycle && newbm != bm )
    {
        bm.recycle();
    }
    return newbm;
}

如此,又一件伟大的作品完成了。

Android+GoLang+SprintBoot探讨群:186305789(疯狂的程序员),绝影大神在等你

个人兴趣网站:zero接码平台

个人兴趣网站:猿指


Comments

comments powered by zero