• (转)Android中实现区域平均算法在图片缩放里的应用(缩放图片抗锯齿)


    摘要:
    Android图片缩放效果较差,尤其是将大尺寸的图片缩放成小尺寸的图片时,即便是加了抗锯齿,锯齿现象也比较严重;而java sdk里的区域平均算法缩放图片,效果就比较完美了,因为jdk不能直接用于安卓项目中(类冲突),也没找到可以使用的替代的library,最终只好自己写,在此分享!

    正文:

    目前我知道的Android API中的传统的图片抗锯齿优化处理无非就是以下相关的设置:

    //缩放抗锯齿
    Bitmap.createScaledBitmap(bitmap, width, height, true);
    Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

    //画布抗锯齿
    PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); //画图片时设置画布抗锯齿
    canvas.setDrawFilter(pfd);

    //画笔抗锯齿
    Paint p = new Paint(Paint.FILTER_BITMAP_FLAG);
    p.setAntiAlias(true);

    另外也无意发现了竟然还有这种缩放的api:ThumbnailUtils.extractThumbnail(bitmap, width, height);

    以上都试过了,将图片缩放后效果都一样差!opengl、


    经过测试,使用java sdk有较好的效果:
    1、使用此方法,效果与安卓的缩放一样:
    Image.getScaledInstance(width, height, java.awt.Image.SCALE_DEFAULT);//或java.awt.Image.SCALE_FAST等

    2、使用此方法,效果很好:
    Image.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH);//或java.awt.Image.SCALE_AREA_AVERAGING


    Android偏偏丢弃了java.awt.image,
    因为jdk不能直接用于安卓项目中(类冲突),所以我进行了如下解决办法:

    1、在stackoverflow上找到一个可以用于安卓的替代项目:https://code.google.com/p/awt-android-compat/
    翻墙下载下来后,该项目报错太多,仍有一些java类没有整合进来,不能使用;
    2、尝试从java sdk源码中抽取,但类的继承、嵌套层级太深,试过几次都不行。

    3、最后只好阅读java sdk缩放图片的相关源码,缩放时用了区域平均算法,大体就是取某个区域里像素点a g的平均颜色值,作为缩放后的图片相应区域的颜色值,目前看来此算法缩放效果最优。
    可参考java代码:
    java.awt.Image#getScaledInstance()
    java.awt.image.AreaAveragingScaleFilter

    了解该算法之后,新写了一个图片缩放工具类,在Android中缩放效果已经比较好了,


    至此已经解决。


    区域平均算法缩放具体怎么好,请见图片:
    原图是两张500x500像素的图片,缩放到40x40像素后的效果对比:

     

    上面两张是安卓里的抗锯齿缩放,下面两张是使用区域平均算法缩放出的图片。


    对于缩放质量要求高的可以使用,下面共享代码:

    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    
    /**
     * 区域平均算法缩放图片,500x500的图,缩放成小图时;若使用安卓提供的api,无论怎么抗锯齿,缩放出的图片也是带有较明显锯齿的。此缩放效果提升
     * 
     * @Author zhuanggy  欢迎加入安卓开发交流qq群 88130145
     * @Date:2014-12-5
     * @Copyright 原创:http://www.eoeandroid.com/thread-556407-1-1.html
     */
    public class AreaAveragingScale {
            protected int[] colorArray;
            private int srcWidth;
            private int srcHeight;
    
            private int destWidth;
            private int destHeight;
    
            float[] reds;
            float[] greens;
            float[] blues;
            float[] alphas;
    
            public AreaAveragingScale(Bitmap src) {
                    srcWidth = src.getWidth();
                    srcHeight = src.getHeight();
    
                    colorArray = new int[srcWidth * srcHeight];
                    src.getPixels(colorArray, 0, srcWidth, 0, 0, srcWidth, srcHeight);
                    int a, r, g, b;
                    for (int y = 0; y < srcHeight; y++) {
                            for (int x = 0; x < srcWidth; x++) {
                                    int index = y * srcWidth + x;
                                    a = (colorArray[index] >> 24) & 0xff;
                                    r = (colorArray[index] >> 16) & 0xff;
                                    g = (colorArray[index] >> 8) & 0xff;
                                    b = colorArray[index] & 0xff;
                                    colorArray[index] = (a << 24) | (r << 16) | (g << 8) | b;
                            }
                    }
            }
    
            public Bitmap getScaledBitmap(int width, int height) {
                    destWidth = width;
                    destHeight = height;
                    reds = new float[srcWidth];
                    greens = new float[srcWidth];
                    blues = new float[srcWidth];
                    alphas = new float[srcWidth];
    
                    Bitmap bitmap = Bitmap.createBitmap(destWidth, destHeight, Config.ARGB_8888);
                    accumPixels(0, 0, srcWidth, srcHeight, bitmap);
    
                    return bitmap;
            }
    
            private void accumPixels(int x, int y, int w, int h, Bitmap bitmap) {
                    int sy = y;
                    int syrem = destHeight;
                    int dy, dyrem;
                    dy = 0;
                    dyrem = 0;
                    while (sy < y + h) {
                            int amty;
                            if (dyrem == 0) {
                                    for (int i = 0; i < destWidth; i++) {
                                            alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
                                    }
                                    dyrem = srcHeight;
                            }
                            if (syrem < dyrem) {
                                    amty = syrem;
                            } else {
                                    amty = dyrem;
                            }
                            int sx = 0;
                            int dx = 0;
                            int sxrem = 0;
                            int dxrem = srcWidth;
                            float a = 0f, r = 0f, g = 0f, b = 0f;
                            while (sx < w) {
                                    if (sxrem == 0) {
                                            sxrem = destWidth;
    
                                            a = getAComponent(sx, sy);
                                            r = getRComponent(sx, sy);
                                            g = getGComponent(sx, sy);
                                            b = getBComponent(sx, sy);
    
                                            if (a != 255.0f) {
                                                    float ascale = a / 255.0f;
                                                    r *= ascale;
                                                    g *= ascale;
                                                    b *= ascale;
                                            }
                                    }
                                    int amtx;
                                    if (sxrem < dxrem) {
                                            amtx = sxrem;
                                    } else {
                                            amtx = dxrem;
                                    }
                                    float mult = ((float) amtx) * amty;
                                    alphas[dx] += mult * a;
                                    reds[dx] += mult * r;
                                    greens[dx] += mult * g;
                                    blues[dx] += mult * b;
                                    if ((sxrem -= amtx) == 0) {
                                            sx++;
                                    }
                                    if ((dxrem -= amtx) == 0) {
                                            dx++;
                                            dxrem = srcWidth;
                                    }
                            }
                            if ((dyrem -= amty) == 0) {
                                    do {
                                            calcRow(dy, bitmap);
                                            dy++;
                                    } while ((syrem -= amty) >= amty && amty == srcHeight);
                            } else {
                                    syrem -= amty;
                            }
                            if (syrem == 0) {
                                    syrem = destHeight;
                                    sy++;
                            }
                    }
            }
    
            private void calcRow(int dy, Bitmap bitmap) {
    
                    // Log.e("", "calcRow" + dy);
    
                    float origmult = ((float) srcWidth) * srcHeight;
                    for (int x = 0; x < srcWidth; x++) {
                            float mult = origmult;
                            int a = Math.round(alphas[x] / mult);
                            if (a <= 0) {
                                    a = 0;
                            } else if (a >= 255) {
                                    a = 255;
                            } else {
                                    mult = alphas[x] / 255;
                            }
                            int r = Math.round(reds[x] / mult);
                            int g = Math.round(greens[x] / mult);
                            int b = Math.round(blues[x] / mult);
    
                            if (r < 0) {
                                    r = 0;
                            } else if (r > 255) {
                                    r = 255;
                            }
                            if (g < 0) {
                                    g = 0;
                            } else if (g > 255) {
                                    g = 255;
                            }
                            if (b < 0) {
                                    b = 0;
                            } else if (b > 255) {
                                    b = 255;
                            }
                            setPixelColor(bitmap, x, dy, r, g, b, a);
                    }
            }
    
            private void setPixelColor(Bitmap bitmap, int x, int y, int c0, int c1, int c2, int a) {
                    int rgbcolor = (a << 24) + (c0 << 16) + (c1 << 8) + c2;
                    colorArray[((y * srcWidth + x))] = rgbcolor;
                    if (x >= destWidth || y >= destHeight) {
    
                    } else {
                            bitmap.setPixel(x, y, colorArray[((y * srcWidth + x))]);
                    }
    
            }
    
            // 获得像素点的透明度 A
            private int getAComponent(int x, int y) {
                    return (colorArray[((y * srcWidth + x))] & 0xFF000000) >>> 24;
            }
    
            // 获得像素点的红色值 R
            private int getRComponent(int x, int y) {
                    return (colorArray[((y * srcWidth + x))] & 0x00FF0000) >>> 16;
            }
    
            // 获得像素点的绿色值 G
            private int getGComponent(int x, int y) {
                    return (colorArray[((y * srcWidth + x))] & 0x0000FF00) >>> 8;
            }
    
            // 获得像素点的蓝色值 B
            private int getBComponent(int x, int y) {
                    return (colorArray[((y * srcWidth + x))] & 0x000000FF);
            }
    }

    原文地址:http://www.eoeandroid.com/thread-556407-1-1.html

  • 相关阅读:
    每日总结
    每日总结
    团队冲刺阶段二(10)
    团队冲刺阶段二(9)
    团队冲刺阶段二(8)
    团队冲刺阶段二(7)
    团队冲刺阶段二(6)
    团队冲刺阶段二(5)
    团队冲刺阶段二(4)
    根据Panda Global了解,中央政治局第十八次集体学习中指出“区块链技术的集成应用在新的技术革新和产业变革中起着重要作用”
  • 原文地址:https://www.cnblogs.com/ywtk/p/4151096.html
Copyright © 2020-2023  润新知