launcher矩形图标

Posted dido222

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了launcher矩形图标相关的知识,希望对你有一定的参考价值。

一、需求:launcher上的图标统一改成矩形,如下图所示;
这里写图片描述

二、实现方案
主要采用openCV来实现图片的一些识别和判断,本人在做这个需求之前从来没有接触过openCV,一切都是现学现用,对图像处理的一些技术和算法也了解的不多,磕磕绊绊总算做出来的效果可以看看。自知代码写的很低级,但是对图像处理这方面的东西还是挺有兴趣的。希望读者偶然看到可以就文中的一些不足之处指点一二,不才在此先谢过了!

  1. 内部应用和MIE应用,以及中国区市场上的top100的应用的图标由UE提供预置在launcher中替换。

  2. 其他未预制图标的应用图标,按照其图标的特征,由代码进行处理,处理方式分如下三种:

    2.1 原图标大小为正方形且基本接近正常图标大小的,查看新图标是否为中心截圆并加白色背板。效果如下图所示:
    这里写图片描述
    原图1
    这里写图片描述
    截圆加白背板图1

原本这类图标会再细分为两类分别做处理。
一类为背板颜色较单一的,如google, BBC News,因为把图标放在矩形区域中时,可能会露出空白的部分,比如如果原图标圆角弧度较大的,所以当时有两种方案,一种是抠图,即抠出图片中心的特征点,比如google图标中心的”g”, BBC News中间的“BBC NEWS“字样,并画出一个矩形圆角形状,取出背板的颜色作为矩形的填充色,两者组合在一起形成新的图标。另一种技术方案是将背板颜色做延伸,填充矩形区域去截取原图标后可能露出的空白处。抠图的方案可以由openCV的Imgproc.grabCut(mat, mask, rect, bgdModel, fgdModel, 1, Imgproc.GC_INIT_WITH_RECT)方法来实现,但是准确度欠缺,不知道是否我用的不对。背板颜色延伸的方案有难度,后来项目就进度考虑未深度研究下去。总之这类图标的处理没有实现。
另一类图标是背板颜色五颜六色,也可以说没有主要的图标特征。比如Angry Birds, European War。因为不管抠图还是背板颜色延伸的方案都不可能,所以这类图标截取中心圆加白色白板。最终UE提供的图片是中心透明的,所以在处理上只需要将原图标按图标可见区域的实际大小缩小至一定比例然后再画上背板图片即可。

2.2 原图标大小为不规则形状(不是正方形,或者大小比正常图标大小要小(小的程度在代码中自定义了一个阈值,这个阈值不应该是关注的重点),应该加上取原图标的主色调做背板颜色并加渐变色效果的一个背板。如下图所示:
这里写图片描述
原图2
这里写图片描述
截圆加白背板图2

2.3 原图标为矩形,且长宽比和要求的图标长宽比相近,应该只对图标进行适当缩放并加圆角处理。该效果基本保持和原图一致,除大小稍做调整并且明显的直角会稍做圆角处理。效果如下图所示:
这里写图片描述
原图3
这里写图片描述
截圆加白背板图3

三、技术要点
1. 判断是否有预制图标并替换。
在原调用Utilities.createIconBitmap的地方,先做预置图标的判断,如IconChache的

CacheLocked((ComponentName componentName,....)方法:
if (!getEntryFromDB(componentName, user, entry, useLowResIcon)) {
                if (info != null) {                 
                    // entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
                    if(CustomUtil.sWhetherUseRectangleIcon) {
                        // {@ icon replace start@}
                        Drawable icon = Utilities.findPrePlacedIconResource(componentName, mContext);
                        if (icon != null) {
                            entry.icon = Utilities.createIconBitmap(icon, mContext);
                        } else {
                            if(Utilities.sRectangleIconDEBUG){
                                Log.d(Utilities.sRectangleIcon,"packageName: "+info.getLabel() + " START<<<<<<<<<<<<<<<<<<<<<");
                            }
                            entry.icon = Utilities.createRectangleIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
                            if(Utilities.sRectangleIconDEBUG){
                                Log.d(Utilities.sRectangleIcon,"packageName: "+info.getLabel() + " END>>>>>>>>>>>>>>>>>>>>>>>");
                            }
                        }
                        // {@ icon replace end@}
                    } else {
                        entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
                    }
                } else {
    public static Drawable findPrePlacedIconResource(ComponentName componentName, Context context){
        Drawable icon = null;
        if (componentName != null && !TextUtils.isEmpty(componentName.getPackageName())
                && !TextUtils.isEmpty(componentName.getClassName())) {
            String filename = componentName.toString().replace("ComponentInfo{", "");
            filename = filename.replace("}", "");
            filename = filename.replace("/", "_");

            return findPrePlacedIconResource(filename, context);
        }

        return icon;
    }

//    public static Drawable findPrePlacedIconResource(String packageName, Context context){
    public static Drawable findPrePlacedIconResource(String fileName, Context context) {
        Drawable icon = null;
        if (!TextUtils.isEmpty(fileName)) {
            InputStream is = null;
            try {
//                String path = "icons";
//                String unit = ".png";
//                is = getIconsInputStream(is, fileName, path, unit, context);
                StringBuilder sb=new StringBuilder();
                is = context.getAssets().open(sb.append(REPLACE_ICON_PATH).append(fileName).append(REPLACE_ICON_FORMAT).toString());
                if (is != null) {
                    icon = Drawable.createFromStream(is, null);
                    TLog.d(TAG,"replace icon by launcher default for APP "+fileName);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return icon;
    }
  1. 判断图标是否为矩形且长宽比是否和要求的长宽比
//找到图标的最外层轮廓
    public static MatOfPoint findFirstContour(Bitmap b){
        Mat RGBMat = new Mat();
        Mat oriMatCompare = new Mat();
        Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), oriMatCompare);
        Imgproc.cvtColor(oriMatCompare, RGBMat, Imgproc.COLOR_RGBA2RGB);
        Mat grayMatForCompare = new Mat();
        Mat mHierarchy = new Mat();
        Imgproc.cvtColor(RGBMat, grayMatForCompare, Imgproc.COLOR_RGBA2GRAY);
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(grayMatForCompare, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);

        Iterator it = contours.iterator();
        MatOfPoint contour = (MatOfPoint) it.next();
        org.opencv.core.Point[] contourArray = contour.toArray();
        return contour;
    }
![图标的最外层轮廓,其中百度地图为预置图标](http://img.blog.csdn.net/20160517165017209)

    public static boolean isBitmapNeedtoChange(MatOfPoint contour, MatOfPoint compareContour){
        MatOfPoint2f approxContour = new MatOfPoint2f();
        MatOfPoint2f mMOP2f1=new MatOfPoint2f();
        contour.convertTo(mMOP2f1, CvType.CV_32FC2);
        //获取图标的近似轮廓
        Imgproc.approxPolyDP(mMOP2f1, approxContour, Imgproc.CV_POLY_APPROX_DP, true);
        MatOfPoint mMOP2f2 = new MatOfPoint();
//获取图标最外层轮廓的最小外界矩形
        org.opencv.core.Rect boundingRect = Imgproc.boundingRect(mMOP2f2);
        //获取对比图标的最外层轮廓的最小外界矩形
        //此对比图标为符合要求的矩形图标,如图所示:
   org.opencv.core.Rect boundingRectOfCompare = Imgproc.boundingRect(compareContour);
        DecimalFormat df   = new DecimalFormat("######0.00");
        double areaD =  (boundingRect.area() - Imgproc.contourArea(approxContour)) / boundingRect.area();
        double rate1 = (double)boundingRect.width/(double)boundingRect.height;
        double rate2 = (double)boundingRectOfCompare.width/(double)boundingRectOfCompare.height;
        if(sRectangleIconDEBUG) {
            Log.d(sRectangleIcon, "areaD: " + areaD + ",bound rate:" + rate1 + "== " + df.format(rate1) + ",conpare bounding rate:" + rate2 + "==" + df.format(rate2)+", rate rio:"+Math.abs(rate1 - rate2)/rate2);
        }
//比较轮廓的最小外接矩形面积和轮廓内的面积的差值比是否在一定阈值内
//且图标和其对比图标的最小外接矩形的宽高比的差值比是否在一定阈值内
//两个阈值的设定都是通过安装大量的apk根据视觉效果来定出
        if (areaD < 0.1 && Math.abs(rate1 - rate2) / rate2 < 0.05) {
            return true;
        }
        return false;
    }

对比图标这里写图片描述

  1. 判断图标是否应该需要加主色调背板–原图标为不规则形状,或者大小比正常大小图标要小。
    该方法是取图标边界到外轮廓中心线上的四个点的距离判断相等,或者轮廓到图标边界的距离是否在一定阈值内来判断,方法有点低级,但是实在想不到还有什么好办法。后面在研究研究。
  public static boolean shouldBitmapAddMainColorBg(Bitmap b, MatOfPoint contour, Context context){
        org.opencv.core.Point[] contourArray = contour.toArray();
        Mat mat = new Mat();
        Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), mat);
        int point2Didsance = mat.rows()/4;
        org.opencv.core.Point tempPtXMiddle = new org.opencv.core.Point((double) (mat.rows() / 2), (double) 0);
        org.opencv.core.Point tempPtYMiddle = new org.opencv.core.Point((double) 0, (double) (mat.cols() / 2));
        org.opencv.core.Point tempPtX2 = new org.opencv.core.Point((double) (mat.rows() / 2 + point2Didsance), (double) 0);
        org.opencv.core.Point tempPtY2 = new org.opencv.core.Point((double) 0, (double) (mat.cols() / 2 + point2Didsance));

        double positionCheckXMiddle = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtXMiddle, true);
        double positionCheckYMiddle = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtYMiddle, true);
        double positionCheckX2 = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtX2, true);
        double positionCheckY2 = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtY2, true);
        double distance = context.getResources().getDimensionPixelSize(R.dimen.visible_contour_distance);
        if(sRectangleIconDEBUG){
            Log.d(sRectangleIcon, "distance:" + distance + ", positionCheckXMiddle:" + positionCheckXMiddle + ",positionCheckYMiddle:" + positionCheckYMiddle + ",positionCheckX5:" + positionCheckX2 + ",positionCheckY5:" + positionCheckY2);
        }

        //check if the contour is a line
        if(((Math.abs(positionCheckX2) != Math.abs(positionCheckXMiddle)) || Math.abs(positionCheckY2) != Math.abs(positionCheckYMiddle)) ? true:
            (Math.abs(positionCheckXMiddle) > distance || Math.abs(positionCheckYMiddle) > distance)) {
                return true;
        }
        else
            return  false;
    }
  1. 如果满足条件2,图标进行适当缩放,并对可见矩形部分做圆角处理。
    public static Bitmap bitmapAddRoundCorner(Context context, Bitmap bitmap, MatOfPoint contour, MatOfPoint compareContour, int iconSize){
        org.opencv.core.Rect rect = getBitmapBoundingRect(contour);
        org.opencv.core.Rect compareRect = Imgproc.boundingRect(compareContour);
        float resizeRate = Math.abs((float) rect.height / (float) compareRect.height);
        float bitmatZoomedSize = resizeRate * iconSize;
        int resizeRectW = (int)(Math.abs(rect.width) * resizeRate);
        int resizeRectH = Math.abs(compareRect.height) ;

        Bitmap resizeBitmap = zoomBitmap(bitmap, bitmatZoomedSize, bitmatZoomedSize);
//        return resizeBitmap;
        //Log.d(sRectangleIcon, "bitmatZoomedSize:"+bitmatZoomedSize+",compareRect:"+compareRect+",rect:"+rect);

        Bitmap bg = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
        Canvas canvas1 = new Canvas(bg);
        int srcLeft = ((int) bitmatZoomedSize - resizeRectW) / 2;
        int srcTop = ((int) bitmatZoomedSize - resizeRectH) / 2;
        int dstLeft = (iconSize - resizeRectW) / 2;
        int dstTop = (iconSize - resizeRectH) / 2;
        Rect src = new Rect(srcLeft, srcTop, resizeRectW + srcLeft, resizeRectH + srcTop);
        Rect dst = new Rect(srcLeft, srcTop, resizeRectW + srcLeft, resizeRectH + srcTop);
        RectF rectf = new RectF(dst);
        Paint photoPaint = new Paint();
        photoPaint.setAntiAlias(true);
        photoPaint.setDither(true);
        //photoPaint.setARGB(100, 255, 0, 0);
        int roundPx = context.getResources().getDimensionPixelSize(R.dimen.round_size);
        canvas1.drawRoundRect(rectf, roundPx, roundPx, photoPaint);
        photoPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas1.drawBitmap(resizeBitmap, src, dst, photoPaint);
        canvas1.setBitmap(null);
        return bg;
    }
  1. 如果满足条件3,则取图标的主色调作为背板颜色并加渐变色,加圆角矩形背板,并缩小原图标至一定尺寸组合再一起作为新图标。
  static Bitmap bitmapAddBgUseMainColor(Context context, Bitmap b) {

        final float FLAT_ASPECT_RATIO = 0.792f; //According to GD
        int iconSize = getIconBitmapSize();
        int height = (int) (iconSize * FLAT_ASPECT_RATIO);
        //取图标的六种调色板的颜色
        Bitmap bg = FallbackAlgorithm.getProcessedIcon(context, b, new Point(iconSize, height));

        //draw blank bg
        Drawable bg2 = context.getResources().getDrawable(R.drawable.carving);
        Bitmap blankbg = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
        Canvas canvas2 = new Canvas(blankbg);
        bg2.setBounds(0, 0, iconSize, iconSize);
        bg2.draw(canvas2);
        Paint p2 = new Paint();
        p2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
        canvas2.drawBitmap(bg, 0, (iconSize - bg.getHeight()) / 2, null);
        canvas2.setBitmap(null);

        return blankbg;
    }

其中取背板颜色的类如下:

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.graphics.Palette;
import android.util.Log;

import com.tct.launcher.R;

public class FallbackAlgorithm {
    private static class RGB {
        float r, g, b; // Red, Green and Blue in [0, 1]

        RGB() { }

        RGB(float r, float g, float b){
            this.r = r;
            this.g = g;
            this.b = b;
        }

        int getColor(){
            return Color.rgb((int) (r * 255), (int) (g * 255), (int) (b * 255));
        }

        @Override
        public String toString(){
            return "{ r: " + r + ", g: " + g + ", b: " + b + " }";
        }
    }

    private static class HSL {
        float h, s, l; // Hue in [0, 360], Saturation and Lightness in [0, 1]

        //HSL() { }

        HSL(float h, float s, float l){
            this.h = h;
            this.s = s;
            this.l = l;
        }

        HSL(float[] hsl){
            this.h = hsl[0];
            this.s = hsl[1];
            this.l = hsl[2];
        }

        @Override
        public String toString(){
            return "{ h: " + h + ", s: " + s + ", l: " + l + " }";
        }
    }

    private static float hue2rgb(float p, float q, float t){
        if (t < 0f) t += 1f;
        if (t > 1f) t -= 1f;
        if (t < 1f/6f) return p + (q - p) * 6f * t;
        if (t < 1f/2f) return q;
        if (t < 2f/3f) return p + (q - p) * (2f/3f - t) * 6f;
        return p;
    }

    private static void hsl2rgb(HSL hsl, RGB rgb){

        if (hsl.s == 0){
            rgb.r = rgb.g = rgb.b = hsl.l; // achromatic
        }
        else {
            float q = hsl.l < 0.5f ? hsl.l * (1f + hsl.s) : hsl.l + hsl.s - hsl.l * hsl.s;
            float p = 2 * hsl.l - q;
            rgb.r = hue2rgb(p, q, hsl.h / 360f + 1f / 3f);
            rgb.g = hue2rgb(p, q, hsl.h / 360f);
            rgb.b = hue2rgb(p, q, hsl.h / 360f - 1f / 3f);
        }
    }

    private static RGB hsl2rgb(HSL hsl){
        RGB rgb = new RGB();
        hsl2rgb(hsl, rgb);
        return rgb;
    }


    private static float softlight(float in, float softlightCoef){
        return ((float) Math.pow(in, Math.pow(2f, 2f * (0.5f - softlightCoef))));
    }

    private static RGB softlight(RGB rgbIn, float softlightCoef){
        return new RGB(softlight(rgbIn.r, softlightCoef),
                       softlight(rgbIn.g, softlightCoef),
                       softlight(rgbIn.b, softlightCoef));
    }

    private static class ChosenSwatch {
        Palette.Swatch mSwatch;
        int mPopulation;

        final int POPULATION_STEP_COEF = 10; // Empirical value

        void updateChoice(Palette.Swatch swatch){
            mPopulation *= POPULATION_STEP_COEF;

            if (swatch == null) return;

            if (mSwatch == null || mPopulation < swatch.getPopulation()){
                mSwatch = swatch;
                mPopulation = mSwatch.getPopulation();
            }
        }
    }

    public static Bitmap getProcessedIcon(Context context, Bitmap originalIcon, Point targetResolution){
        Bitmap finalIcon = Bitmap.createBitmap(targetResolution.x, targetResolution.y, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(finalIcon);
        canvas.drawColor(Color.TRANSPARENT);

        try {
            Palette palette = Palette.from(originalIcon).generate();
            ChosenSwatch chosenSwatch = new ChosenSwatch();
            chosenSwatch.updateChoice(palette.getVibrantSwatch());
            chosenSwatch.updateChoice(palette.getDarkVibrantSwatch());
            chosenSwatch.updateChoice(palette.getDarkMutedSwatch());
            chosenSwatch.updateChoice(palette.getMutedSwatch());
            chosenSwatch.updateChoice(palette.getLightMutedSwatch());
            chosenSwatch.updateChoice(palette.getLightVibrantSwatch());
            Palette.Swatch swatch = chosenSwatch.mSwatch;

            RGB rgb;
            if (swatch == null){
                rgb = hsl2rgb(new HSL(50, 0.2f, 0.8f));
            }
            else {
                HSL hsl = new HSL(swatch.getHsl());
                if (hsl.h >= 35 && hsl.h < 70){
                    hsl.s = 0.2f;
                    hsl.l = 0.8f;
                }
                else {
                    hsl.l = Math.min(0.30f, 0.75f * hsl.l);
                }
                rgb = hsl2rgb(hsl);
            }

            RGB gradientLight = softlight(rgb, 0.75f);
            RGB gradientDark = softlight(rgb, 0.25f);

            // FIXME: Scale-down and blur coefs shall depend on display density !!!
            final int SHADOW_SCALE_DOWN = 4;
            Bitmap smallerOriginal = Bitmap.createScaledBitmap(originalIcon, originalIcon.getWidth() / SHADOW_SCALE_DOWN, originalIcon.getHeight() / SHADOW_SCALE_DOWN, true);
            BlurMaskFilter blurMaskFilter = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);

            Paint blurPaint = new Paint();
            blurPaint.setMaskFilter(blurMaskFilter);
            blurPaint.setColor(Color.BLACK);
            int[] offsetXY = new int[2];
            Bitmap shadow = smallerOriginal.extractAlpha(blurPaint, offsetXY);

            Shader shader = new LinearGradient(0, 0, 0, finalIcon.getHeight(), gradientLight.getColor(), gradientDark.getColor(), Shader.TileMode.CLAMP);
            Paint paint = new Paint();
            paint.setShader(shader);
            //canvas.drawRect(new RectF(0, 0, finalIcon.getWidth(), finalIcon.getHeight()), paint);
            int roundPx = context.getResources().getDimensionPixelSize(R.dimen.round_size);
            canvas.drawRoundRect(new RectF(0, 0, finalIcon.getWidth(), finalIcon.getHeight()), roundPx, roundPx, paint);

            final float BORDER_MARGIN = 1.25f; //Empirical value
            float maxWidthRatio  = 1f * finalIcon.getWidth()  / BORDER_MARGIN / originalIcon.getWidth();
            float maxHeightRatio = 1f * finalIcon.getHeight() / BORDER_MARGIN / originalIcon.getHeight();
            float maxRatio = Math.min(1f, Math.min(maxWidthRatio, maxHeightRatio));
            //Log.i(_.TAG, "maxWidthRatio: " + maxWidthRatio + ", maxHeightRatio: " + maxHeightRatio + " => maxRatio: " + maxRatio);

            final float MIN_CONTENT_SIZE = 1.618f; // Empirical value
            float minWidthRatio  = 1f * finalIcon.getWidth()  / MIN_CONTENT_SIZE / originalIcon.getWidth();
            float minHeightRatio = 1f * finalIcon.getHeight() / MIN_CONTENT_SIZE / originalIcon.getHeight();
            float minRatio = Math.max(minWidthRatio, minHeightRatio);
            //Log.i(_.TAG, "minWidthRatio: " + minWidthRatio + ", minHeightRatio: " + minHeightRatio + " => minRatio: " + minRatio);

            float ratio = Math.max(maxRatio, minRatio);
            //Log.i(_.TAG, "ratio: " + ratio);

            final float SHADOW_RATIO = 0.9f; // Empirical value. Make sure it's not too big...
            float finalShadowWidth  = SHADOW_RATIO * ratio * (originalIcon.getWidth()  - 2 * SHADOW_SCALE_DOWN * offsetXY[0]);
            float finalShadowHeight = SHADOW_RATIO * ratio * (originalIcon.getHeight() - 2 * SHADOW_SCALE_DOWN * offsetXY[1]);
            float finalShadowLeft = (finalIcon.getWidth()  - finalShadowWidth)  / 2;
            float finalShadowTop  = (finalIcon.getHeight() - finalShadowHeight) / 2 - SHADOW_RATIO * SHADOW_SCALE_DOWN * offsetXY[1];

            RectF shadowDstRect = new RectF(finalShadowLeft,
                    finalShadowTop,
                    finalShadowLeft + finalShadowWidth,
                    finalShadowTop + finalShadowHeight);
            Paint shadowPaint = new Paint();
            shadowPaint.setAlpha(0x40); // Empirical value
            shadowPaint.setFilterBitmap(true);
            canvas.drawBitmap(shadow, null, shadowDstRect, shadowPaint);

            float finalWidth  = ratio * originalIcon.getWidth();
            float finalHeight = ratio * originalIcon.getHeight();
            float finalLeft = (finalIcon.getWidth() - finalWidth) / 2;
            float finalTop = (finalIcon.getHeight() - finalHeight) / 2;

            RectF dstRect = new RectF(finalLeft, finalTop, finalLeft + finalWidth, finalTop + finalHeight);
            Paint iconPaint = new Paint();
            iconPaint.setFilterBitmap(true);
            canvas.drawBitmap(originalIcon, null, dstRect, iconPaint);
            //_.saveBitmap(sApplicationContext, finalIcon, "finalIcon-" + Math.random());
        }
        catch (Exception e){
            e.printStackTrace();
        }

        return finalIcon;
    }

    public static Bitmap getDrawableBitmap(Drawable drawable) {
        Bitmap originalIcon;
        if (BitmapDrawable.class.isInstance(drawable)){
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            originalIcon = bitmapDrawable.getBitmap();
        }
        else {
            int width  = drawable.getIntrinsicWidth();
            int height = drawable.getIntrinsicHeight();
            if (width != 0 || height != 0){
                if (width != 0 && height == 0){
                    height = width;
                }
                else if (height != 0 && width == 0){
                    width = height;
                }
            }

            originalIcon = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(originalIcon);
            canvas.drawColor(Color.TRANSPARENT);
            drawable.setBounds(0, 0, width, height);
            drawable.draw(canvas);
        }
        return originalIcon;
    }
}
  1. 调节2,3筛选后的图标都做中心截圆加白背板处理。
public static Bitmap bitmapAddWhiteBg(Context context, int iconSize, Bitmap b, MatOfPoint contour){
        //find the visible area, ajust the resize ratio according visible area
        org.opencv.core.Point[] contourArray = contour.toArray();
        Mat mat = new Mat();
        Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), mat);
        org.opencv.core.Point tempPtXMiddle = new org.opencv.core.Point((double) (mat.cols() / 2), (double) 0);
        org.opencv.core.Point tempPtYMiddle = new org.opencv.core.Point((double) 0, (double) (mat.rows() / 2));
        org.opencv.core.Point tempPtX2 = new org.opencv.core.Point((double) (mat.cols() / 2 ), (double) mat.rows());
        org.opencv.core.Point tempPtY2 = new org.opencv.core.Point((double) mat.cols(), (double) (mat.rows() / 2 ));

        double positionCheckXMiddle = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtXMiddle, true));
        double positionCheckYMiddle = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtYMiddle, true));
        double positionCheckX2 = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtX2, true));
        double positionCheckY2 = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtY2, true));

        Drawable iconbgDrawable = context.getResources().getDrawable(R.drawable.baseboard);
        Bitmap addbg = Bitmap.createBitmap(iconSize, iconSize,
                iconbgDrawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        Canvas canvasBg = new Canvas(addbg);
        iconbgDrawable.setBounds(0, 0, iconSize, iconSize);
        iconbgDrawable.draw(canvasBg);
        Paint p2 = new Paint();
        p2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
        //zoom bitmap according the visible area
        double resizeIconsizeX ;
        double resizeIconsizeY ;
        //取原图标外轮廓的内接垂直和水平的中心线的长度的最小值(Math.min(visibleW, visibleH))和白背板图标的中心圆的直径做比,乘以项目所对应的要求的正方形图标的大小(其实所有的图标都是正方形的),即为缩小后的图标大小。如果缩小后的图标可见区域的较大值(Math.max(visibleW, visibleH)*resizeRate)比标准图标的可见高度要大,则以大的那个值和中心圆的直径做对比求出缩小的比例。
        double visibleH = iconSize - positionCheckXMiddle - positionCheckX2;
        double visibleW = iconSize - positionCheckYMiddle - positionCheckY2;
        float innerCirleDiameter = context.getResources().getDimension(R.dimen.visible_inner_circle_d);
        float visibleWhiteBgH = context.getResources().getDimension(R.dimen.visible_whitle_bg_h);

        double resizeRate = innerCirleDiameter / Math.min(visibleW, visibleH);

        resizeIconsizeX = resizeIconsizeY =  resizeRate * iconSize;
        double cutRateH = 1;
        if(visibleH * resizeRate > visibleWhiteBgH){
//            resizeIconsize = innerCirleDiameter / Math.max(visibleW, visibleH) * iconSize;
            cutRateH = visibleWhiteBgH/visibleH;
            b = Bitmap.createBitmap(b, 0, Math.max(0,(int)((b.getHeight()-b.getHeight()* cutRateH)/2)), b.getWidth(), Math.min((int)(b.getHeight()* cutRateH),b.getHeight()), new Matrix(), true);
        }
        if (sRectangleIconDEBUG) {
            Log.d(sRectangleIcon, "resizeIconsizeX: " + resizeIconsizeX + "resizeIconsizY: " + resizeIconsizeY + ",visibleW:" + ",visibleH:" + visibleH + ",positionCheckXMiddle:" + positionCheckXMiddle + ",positionCheckX2:" +
                    positionCheckX2 + ",positionCheckYMiddle:" + positionCheckYMiddle + ",positionCheckY2:" + positionCheckY2);
        }
        Bitmap resizeCircleBitmap = zoomBitmap(b, (float)resizeIconsizeX, (float)resizeIconsizeY*(float)cutRateH);
        double adX = (iconSize - resizeIconsizeX)/2;
        double adY = (iconSize - resizeIconsizeY*cutRateH)/2;
        canvasBg.drawBitmap(resizeCircleBitmap, (float)adX ,(float) adY , p2);
        canvasBg.setBitmap(null);
        return addbg;
    }

最后附上效果图:
这里写图片描述
这里写图片描述
参考文档会陆续整理在这个链接中: http://blog.csdn.net/dido222/article/details/51098700

以上是关于launcher矩形图标的主要内容,如果未能解决你的问题,请参考以下文章

关于Android app的launcher图标更换后,仍然显示默认的ic_launcher图标的解决方法

创建具有多个图标的 iPhone 视图(例如 Yelp、Old Facebook Launcher)

android开发者:修改android图标ic_launcher,为自定义的.

android 怎么修改launcher3,使桌面图标变大?

android framework项目开发案例-动态隐藏Launcher上图标2

android framework项目开发案例-动态隐藏Launcher上图标2