探索生成有数字的图片以及在图片的右上角画小圆形状态标志等

在Android开发中经常需要图标上以及甚至在应用图标的快捷方式上显示数字,表示未读消息数以及在以及在某条信息右上角标志小圆形,表示这条消息是未读的状态等等,之前对此内容不熟悉的时候也表示困扰,现在对图片一些操作也写在一个工具类中,以方便调用。
按照惯例先来看一下最终效果图:



BitmapUtil.class

package com.xiaolijuan.bitmapdome.utils;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.TypedValue;

/**
 * @author: xiaolijuan
 * @description: 图片工具类
 * @projectName: BitmapDome
 * @date: 2016-01-19
 * @time: 21:48
 */
public class BitmapUtil {
    // 默认圆角半径
    private static final int DEFAULT_CORNER_RADIUS_DIP = 8;
    // 默认边框宽度
    private static final int DEFAULT_STROKE_WIDTH_DIP = 2;
    // 边框的颜色
    private static final int DEFAULT_STROKE_COLOR = Color.WHITE;
    // 中间数字的颜色
    private static final int DEFAULT_NUM_COLOR = Color.parseColor("#CCFF0000");

    /**
     * 生成有数字的图片(没有边框)
     *
     * @param context   上下文
     * @param icon      图片
     * @param isShowNum 是否要绘制数字
     * @param num       数字字符串:整型数字 超过99,显示为"99+"
     * @return 重新生成带数字的图片
     */
    public static Bitmap generatorNumIcon2(Context context, Bitmap icon,
                                           boolean isShowNum, String num) {

        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        // 基准屏幕密度
        float baseDensity = 2.3f;
        float factor = dm.density / baseDensity;

        // 初始化画布
        int iconSize = (int) context.getResources().getDimension(
                android.R.dimen.app_icon_size);
        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(numIcon);

        // 拷贝图片
        Paint iconPaint = new Paint();
        iconPaint.setDither(true);// 防抖动
        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
        Rect dst = new Rect(0, 0, iconSize, iconSize);
        canvas.drawBitmap(icon, src, dst, iconPaint);

        if (isShowNum) {

            if (TextUtils.isEmpty(num)) {
                num = "0";
            }

            if (!TextUtils.isDigitsOnly(num)) {
                // 非数字
                num = "0";
            }

            int numInt = Integer.valueOf(num);

            if (numInt > 99) {// 超过99
                num = "99+";
            }

            // 启用抗锯齿和使用设备的文本字体大小
            // 测量文本占用的宽度
            Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG
                    | Paint.DEV_KERN_TEXT_FLAG);
            numPaint.setColor(Color.WHITE);
            numPaint.setTextSize(20f * factor);
            numPaint.setTypeface(Typeface.DEFAULT_BOLD);
            int textWidth = (int) numPaint.measureText(num, 0, num.length());

            /**
             * 绘制圆角矩形背景
             */
            int backgroundHeight = (int) (2 * 15 * factor);
            int backgroundWidth = textWidth > backgroundHeight ? (int) (textWidth + 10 * factor)
                    : backgroundHeight;//圆角矩形背景的宽度

            canvas.save();// 保存状态

            ShapeDrawable drawable = getDefaultBackground(context);
            drawable.setIntrinsicHeight(backgroundHeight);
            drawable.setIntrinsicWidth(backgroundWidth);
            drawable.setBounds(0, 0, backgroundWidth, backgroundHeight);
            canvas.translate(iconSize - backgroundWidth, 0);
            drawable.draw(canvas);

            canvas.restore();// 重置为之前保存的状态

            // 绘制数字
            canvas.drawText(num,
                    (float) (iconSize - (backgroundWidth + textWidth) / 2),
                    22 * factor, numPaint);
        }
        return numIcon;
    }

    /**
     * 生成有数字的图片(有边框的)
     *
     * @param context   上下文
     * @param icon      图片
     * @param isShowNum 是否要绘制数字
     * @param num       数字字符串:整型数字 超过99,显示为"99+"
     * @return 重新生成带数字的图片
     */
    public static Bitmap generatorNumIcon3(Context context, Bitmap icon,
                                           boolean isShowNum, String num) {

        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        // 基准屏幕密度
        float baseDensity = 2.2f;
        float factor = dm.density / baseDensity;

        // 初始化画布
        int iconSize = (int) context.getResources().getDimension(
                android.R.dimen.app_icon_size);

        Bitmap numIcon = Bitmap.createBitmap(iconSize, iconSize,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(numIcon);

        // 拷贝图片
        Paint iconPaint = new Paint();
        iconPaint.setDither(true);// 防抖动
        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
        Rect dst = new Rect(0, 0, iconSize, iconSize);
        canvas.drawBitmap(icon, src, dst, iconPaint);

        if (isShowNum) {

            if (TextUtils.isEmpty(num)) {
                num = "0";
            }

            if (!TextUtils.isDigitsOnly(num)) {
                // 非数字
                num = "0";
            }

            int numInt = Integer.valueOf(num);

            if (numInt > 99) {// 超过99
                num = "99+";
            }

            // 启用抗锯齿和使用设备的文本字体大小
            // 测量文本占用的宽度
            Paint numPaint = new Paint(Paint.ANTI_ALIAS_FLAG
                    | Paint.DEV_KERN_TEXT_FLAG);
            numPaint.setColor(Color.WHITE);
            numPaint.setTextSize(20f * factor);
            numPaint.setTypeface(Typeface.DEFAULT_BOLD);
            int textWidth = (int) numPaint.measureText(num, 0, num.length());

            /**
             * 绘制圆角矩形背景:先画边框,再画内部的圆角矩形
             */
            // 圆角矩形背景的宽度
            int backgroundHeight = (int) (2 * 15 * factor);
            int backgroundWidth = textWidth > backgroundHeight ? (int) (textWidth + 10 * factor)
                    : backgroundHeight;
            // 边框的宽度
            int strokeThickness = (int) (2 * factor);

            canvas.save();// 保存状态

            int strokeHeight = backgroundHeight + strokeThickness * 2;
            int strokeWidth = textWidth > strokeHeight ? (int) (textWidth + 10
                    * factor + 2 * strokeThickness) : strokeHeight;
            ShapeDrawable outStroke = getDefaultStrokeDrawable(context);
            outStroke.setIntrinsicHeight(strokeHeight);
            outStroke.setIntrinsicWidth(strokeWidth);
            outStroke.setBounds(0, 0, strokeWidth, strokeHeight);
            canvas.translate(iconSize - strokeWidth - strokeThickness,
                    strokeThickness);
            outStroke.draw(canvas);

            canvas.restore();// 重置为之前保存的状态

            canvas.save();// 保存状态

            ShapeDrawable drawable = getDefaultBackground(context);
            drawable.setIntrinsicHeight((int) (backgroundHeight + 2 * factor));
            drawable.setIntrinsicWidth((int) (backgroundWidth + 2 * factor));
            drawable.setBounds(0, 0, backgroundWidth, backgroundHeight);
            canvas.translate(iconSize - backgroundWidth - 2 * strokeThickness,
                    2 * strokeThickness);
            drawable.draw(canvas);

            canvas.restore();// 重置为之前保存的状态

            // 绘制数字
            canvas.drawText(
                    num,
                    (float) (iconSize
                            - (backgroundWidth + textWidth + 4 * strokeThickness)
                            / 2 - 1), (22) * factor + 2 * strokeThickness,
                    numPaint);
        }
        return numIcon;
    }


    /**
     * 圆角矩形,相当于用<shape>的xml的背景
     *
     * @param context 上下文
     * @return
     */
    private static ShapeDrawable getDefaultBackground(Context context) {

        // 这个是为了应对不同分辨率的手机,屏幕兼容性
        int r = dipToPixels(context, DEFAULT_CORNER_RADIUS_DIP);
        float[] outerR = new float[]{r, r, r, r, r, r, r, r};

        // 圆角矩形
        RoundRectShape rr = new RoundRectShape(outerR, null, null);
        ShapeDrawable drawable = new ShapeDrawable(rr);
        drawable.getPaint().setColor(DEFAULT_NUM_COLOR);// 设置颜色
        return drawable;

    }

    /**
     * 圆角矩形,相当于用<shape>的xml的背景
     *
     * @param context 上下文
     * @return
     */
    private static ShapeDrawable getDefaultStrokeDrawable(Context context) {
        // 这个是为了应对不同分辨率的手机,屏幕兼容性
        int r = dipToPixels(context, DEFAULT_CORNER_RADIUS_DIP);
        int distance = dipToPixels(context, DEFAULT_STROKE_WIDTH_DIP);
        float[] outerR = new float[]{r, r, r, r, r, r, r, r};

        // 圆角矩形
        RoundRectShape rr = new RoundRectShape(outerR, null, null);
        ShapeDrawable drawable = new ShapeDrawable(rr);
        drawable.getPaint().setStrokeWidth(distance);
        drawable.getPaint().setStyle(Paint.Style.FILL);
        drawable.getPaint().setColor(DEFAULT_STROKE_COLOR);// 设置颜色
        return drawable;
    }

    /**
     * dp to px
     *
     * @param context 上下文
     * @param dip
     * @return
     */
    public static int dipToPixels(Context context, int dip) {
        Resources r = context.getResources();
        float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
                r.getDisplayMetrics());
        return (int) px;
    }

    /**
     * 在原图右上角画圆形状态标志,其中icon为原图,color为所需状态标示的颜色,一般取值为"Color.**",r为所画圆的半径
     *
     * @param icon  原图
     * @param res   获取Resources
     * @param color 所需状态标示的颜色,一般取值为"Color.**"
     * @param r     所画圆的半径
     * @return
     */
    public static Bitmap generatorStatusIcon(Bitmap icon, Resources res,
                                             int color, int r) {
        // 初始化画布
        int iconSize = (int) res.getDimension(android.R.dimen.app_icon_size);
        Bitmap contactIcon = Bitmap.createBitmap(iconSize, iconSize,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(contactIcon);

        // 拷贝图片
        Paint iconPaint = new Paint();
        iconPaint.setDither(true);// 防抖动
        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
        Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
        Rect dst = new Rect(0, 0, iconSize, iconSize);
        canvas.drawBitmap(icon, src, dst, iconPaint);

        Paint countPaint = new Paint(Paint.ANTI_ALIAS_FLAG
                | Paint.DEV_KERN_TEXT_FLAG);
        countPaint.setColor(color);

        canvas.drawCircle(iconSize - r, r, r, countPaint);
        return contactIcon;
    }

    /**
     * 传入一张Bitmap型的方形图片使之变成圆形
     *
     * @param bitmap 图片
     * @return
     */
    public static Bitmap makeRoundCorner(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int left = 0, top = 0, right = width, bottom = height;
        float roundPx = height / 2;
        if (width > height) {
            left = (width - height) / 2;
            top = 0;
            right = left + height;
            bottom = height;
        } else if (height > width) {
            left = 0;
            top = (height - width) / 2;
            right = width;
            bottom = top + width;
            roundPx = width / 2;
        }

        Bitmap output = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        int color = 0xff424242;
        Paint paint = new Paint();
        Rect rect = new Rect(left, top, right, bottom);
        RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    /**
     * 传入一张Bitmap型的方形图片使之变成圆角矩形,ratio值在1以上就很明显
     *
     * @param bitmap 图片
     * @param ratio  比例,这里是宽高与半径的比例
     * @return
     */
    public static Bitmap toRoundCorner(Bitmap bitmap, float ratio) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(rectF, bitmap.getWidth() / ratio,
                bitmap.getHeight() / ratio, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    /**
     * 使bitmap图标边角圆弧化,pixels值在10以上才比较明显,变化慢
     *
     * @param bitmap 图片
     * @param pixels 圆角的半径
     * @return
     */
    public static Bitmap toRoundCorner_1(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    /**
     * 在一张背景图片上合成四个头像
     *
     * @param backGroundIcon 背景图片
     * @param res            获取Resources
     * @param first          图片1
     * @param second         图片2
     * @param third          图片3
     * @param four           图片4
     * @return
     */
    public static Bitmap add4Bitmap(Bitmap backGroundIcon, Resources res,
                                    Bitmap first, Bitmap second, Bitmap third, Bitmap four) {
        int iconSize = (int) res.getDimension(android.R.dimen.app_icon_size);
        Bitmap contactIcon = Bitmap.createBitmap(iconSize, iconSize,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(contactIcon);

        Paint iconPaint = new Paint();
        iconPaint.setDither(true);// 防抖动
        iconPaint.setFilterBitmap(true);// 用来对Bitmap进行滤波处理,这样,当你选择Drawable时,会有抗锯齿的效果
        Rect src = new Rect(0, 0, backGroundIcon.getWidth(),
                backGroundIcon.getHeight());
        Rect dst = new Rect(0, 0, iconSize, iconSize);
        canvas.drawBitmap(backGroundIcon, src, dst, iconPaint);

        int width = iconSize / 2;
        int height = iconSize / 2;
        canvas.drawBitmap(pictureZoom(first, iconSize / 2, iconSize / 2), 0, 0,
                iconPaint);
        canvas.drawBitmap(pictureZoom(second, iconSize / 2, iconSize / 2),
                width, 0, iconPaint);
        canvas.drawBitmap(pictureZoom(third, iconSize / 2, iconSize / 2), 0,
                height, iconPaint);
        canvas.drawBitmap(pictureZoom(four, iconSize / 2, iconSize / 2), width,
                height, iconPaint);
        return contactIcon;
    }

    /**
     * 图片缩放
     *
     * @param bitMap    原图片
     * @param newWidth  新的宽
     * @param newHeight 新的高
     * @return
     */
    public static Bitmap pictureZoom(Bitmap bitMap, int newWidth, int newHeight) {

        int width = bitMap.getWidth();
        int height = bitMap.getHeight();

        // 计算缩放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        // 取得想要缩放的matrix参数
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);

        // 得到新的图片
        bitMap = Bitmap.createBitmap(bitMap, 0, 0, width, height, matrix, true);

        return bitMap;
    }

    /**
     * 渲染成灰色图片
     *
     * @param bitmap 图片
     * @return
     */
    public static final Bitmap grey(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        Bitmap faceIconGreyBitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(faceIconGreyBitmap);
        Paint paint = new Paint();
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.setSaturation(0);
        ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(
                colorMatrix);
        paint.setColorFilter(colorMatrixFilter);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        return faceIconGreyBitmap;
    }
}

项目源码,点击下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容