NDK处理图片——添加文字和图片水印

来源:互联网 发布:淘宝达人登录网址 编辑:程序博客网 时间:2024/05/22 06:42

        马化腾说过腾讯的服务器一天存储几个亿的图片,可见图片已经成为移动社交必不可少的元素。而用户往往喜欢在原图基础上编辑文字或者添加配图,达到图文并茂、生动形象的目的,以表达此时此地此景此物。添加水印已成为美图秀秀、QQ天天P图、各大直播平台的必备技能。接下来给大家介绍下,这是基于android移动端的NDK处理图片,添加文字或者图片水印。

        先看下添加水印后的效果:


        一张图片是由宽x高的二维矩阵像素点构成的,添加水印就是将覆盖层的矩阵像素与原图矩阵像素叠加。而一个像素是由ARGB(Alpha、Red、Green、Blue)组成,像素叠加需要拆分成ARGB分量进行叠加。native层处理代码如下:

jintArrayJava_com_frank_image_ImageUtil_textWaterMark(JNIEnv *env, jobject, jintArray pixels, jint width, jint height,                                         jintArray textPixels, jint textWidth, jint textHeight){    //像素数组拷贝到native层    jint *pixel = env->GetIntArrayElements(pixels, false);    jint *textPixel = env->GetIntArrayElements(textPixels, false);    int size = width * height;    int alpha, red, green, blue;    int text_alpha, text_red, text_green, text_blue;    int x, y;    for(x=0; x<width; x++){        for(y=0; y< height; y++){            //获取每一个像素点            int color = pixel[y*width + x];            alpha = (color >> 24) & 0xFF;            red = (color >> 16) & 0xFF;            green = (color >> 8) & 0xFF;            blue = color & 0xFF;            //获取text的像素点,与原图像素相加            if(x < textWidth && y < textHeight){                int textColor = textPixel[y*textWidth + x];                text_alpha = (textColor >> 24) & 0xFF;                text_red = (textColor >> 16) & 0xFF;                text_green = (textColor >> 8) & 0xFF;                text_blue = textColor & 0xFF;                //新的RGB分量=图片分量(R/G/B) + 文本分量(R/G/B)                red   = (1-text_alpha)*red  + text_alpha*text_red;                green = (1-text_alpha)*green + text_alpha*text_green;                blue  = (1-text_alpha)*blue + text_alpha*text_blue;                //边界检测:0<rgb<255                red = red > 255 ? 255 : (red < 0 ? 0 : red);                green = green > 255 ? 255 : (green < 0 ? 0 : green);                blue = blue > 255 ? 255 : (blue < 0 ? 0 : blue);            }            //重新赋值给每个像素点            pixel[y*width + x] = (alpha << 24) | (red << 16) | (green << 8) | blue;        }    }    jintArray newPixel = env->NewIntArray(size);    env->SetIntArrayRegion(newPixel, 0, size, pixel);    env->ReleaseIntArrayElements(pixels, pixel, 0);    env->ReleaseIntArrayElements(textPixels, textPixel, 0);    return newPixel;}
        java层调用native层的文字水印处理方法,传入原图像素数组、原图宽度、原图高度、水印的像素数组、水印宽度、水印高度等参数。等待native层处理完成返回新数组,然后根据新数组创建新的Bitmap:

    /**     * 使用NDK向图片添加文字水印     * @param drawable drawable     * @param imageView imageView     * @param text 文本内容     */    private void textWaterMark(Drawable drawable, ImageView imageView, String text){        if (drawable != null && drawable instanceof BitmapDrawable) {            Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();            int width = bitmap.getWidth();            int height = bitmap.getHeight();            int[] pixels = new int[width * height];            //获取bitmap的所有pixel像素点            bitmap.getPixels(pixels, 0, width, 0, 0, width, height);            //文本转成bitmap,再获取像素数组            Bitmap textBitmap = BitmapUtil.textToBitmap(text, Color.BLUE, 16, this);            int textWidth = textBitmap.getWidth();            int textHeight = textBitmap.getHeight();            int[] textPixel = new int[textWidth * textHeight];            textBitmap.getPixels(textPixel, 0, textWidth, 0, 0, textWidth, textHeight);            //ndk处理像素点数组            int[] newPixels = ImageUtil.textWaterMark(pixels, width, height, textPixel, textWidth, textHeight);            Bitmap ndkBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);            //重新设置bitmap的所有pixel像素点            ndkBitmap.setPixels(newPixels, 0, width, 0, 0, width, height);            imageView.setImageBitmap(ndkBitmap);        }    }
        除此之外,需要加载so库,声明native方法供java调用:

    static {        System.loadLibrary("image");    }    public static native int[] textWaterMark(int[] pixels, int width, int height,                                         int[] textPixels, int textWidth, int textHeight);
        这样看起来,只是在原图左上角添加水印,不够灵活。那么问题来了,有没办法去灵活控制水印在原图的位置呢?答案是肯定的,只需要传入x、y坐标的偏移量,native层加上偏移量处理就可以了。代码如下:

jintArrayJava_com_frank_image_ImageUtil_textWaterMark(JNIEnv *env, jobject, jintArray pixels, jint width, jint height,                                         jintArray textPixels, jint textWidth, jint textHeight,                                         jint offsetX, jint offsetY){    //像素数组拷贝到native层    jint *pixel = env->GetIntArrayElements(pixels, false);    jint *textPixel = env->GetIntArrayElements(textPixels, false);    int size = width * height;    int alpha, red, green, blue;    int text_alpha, text_red, text_green, text_blue;    int x, y;    for(x=0; x<width; x++){        for(y=0; y< height; y++){            //获取每一个像素点            int color = pixel[y*width + x];            alpha = (color >> 24) & 0xFF;            red = (color >> 16) & 0xFF;            green = (color >> 8) & 0xFF;            blue = color & 0xFF;            //获取text的像素点,与原图像素相加(加上偏移量判断,控制水印显示位置)            if(x > offsetX && x < (textWidth+offsetX) && y > offsetY && y < (textHeight+offsetY)){                int textColor = textPixel[(y-offsetY)*textWidth + (x-offsetX)];                text_alpha = (textColor >> 24) & 0xFF;                text_red = (textColor >> 16) & 0xFF;                text_green = (textColor >> 8) & 0xFF;                text_blue = textColor & 0xFF;                //新的RGB分量=图片分量(R/G/B) + 文本分量(R/G/B)                red   = (1-text_alpha)*red  + text_alpha*text_red;                green = (1-text_alpha)*green + text_alpha*text_green;                blue  = (1-text_alpha)*blue + text_alpha*text_blue;                //边界检测:0<rgb<255                red = red > 255 ? 255 : (red < 0 ? 0 : red);                green = green > 255 ? 255 : (green < 0 ? 0 : green);                blue = blue > 255 ? 255 : (blue < 0 ? 0 : blue);            }            //重新赋值给每个像素点            pixel[y*width + x] = (alpha << 24) | (red << 16) | (green << 8) | blue;        }    }    jintArray newPixel = env->NewIntArray(size);    env->SetIntArrayRegion(newPixel, 0, size, pixel);    env->ReleaseIntArrayElements(pixels, pixel, 0);    env->ReleaseIntArrayElements(textPixels, textPixel, 0);    return newPixel;}

        同样地,添加图片水印的native方法如下:

jintArrayJava_com_frank_image_ImageUtil_picWaterMark(JNIEnv *env, jobject, jintArray pixels, jint width, jint height,                                            jintArray overlayPixels, jint overlayWidth, jint overlayHeight,                                             jint offsetX, jint offsetY){    //像素数组拷贝到native层    jint *pixel = env->GetIntArrayElements(pixels, false);    jint *overlayPixel = env->GetIntArrayElements(overlayPixels, false);    int size = width * height;    int alpha, red, green, blue;    int x, y;    for(x=0; x<width; x++){        for(y=0; y< height; y++){            //获取每一个像素点            int color = pixel[y*width + x];            alpha = (color >> 24) & 0xFF;            red = (color >> 16) & 0xFF;            green = (color >> 8) & 0xFF;            blue = color & 0xFF;            //获取覆盖层图片的像素点            if(x > offsetX && x < (overlayWidth+offsetX) && y > offsetY && y < (overlayHeight+offsetY)){                int addColor = overlayPixel[(y-offsetY)*overlayWidth + (x-offsetX)];                //替换原图像素的RGBA                alpha = (addColor >> 24) & 0xFF;                red = (addColor >> 16) & 0xFF;                green = (addColor >> 8) & 0xFF;                blue = addColor & 0xFF;            }            //重新赋值给每个像素点            pixel[y*width + x] = (alpha << 24) | (red << 16) | (green << 8) | blue;        }    }    jintArray newPixel = env->NewIntArray(size);    env->SetIntArrayRegion(newPixel, 0, size, pixel);    env->ReleaseIntArrayElements(pixels, pixel, 0);    env->ReleaseIntArrayElements(overlayPixels, overlayPixel, 0);    return newPixel;}

        加上x、y坐标偏移量的添加水印效果如下:




        欢迎各位图片处理、多媒体开发爱好者相互交流,相互学习。。。

阅读全文
'); })();
1 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 川菜经典 川菜的做法 川菜有哪些 川菜的特点 川菜食谱 川菜做法 特色川菜 川菜特色 川菜家常菜 川菜排行榜 川菜水煮鱼 川菜速成班 川菜餐厅 菜谱川菜 新式川菜 川菜素菜 川菜的品格 川菜快餐 有名的川菜 川菜菜名 川菜的名菜 老屋川菜 川菜菜谱大全 经典川菜100款 川菜菜谱大全图片热菜 正宗川菜160例大全 川菜大全130道菜图作法 川菜东坡肘子 川菜干煸四季豆 十个必点川菜 川菜家常菜100道菜名大全 正宗川菜魔芋烧鸭做法 正宗川菜160种 川菜酸菜鱼做法 川菜蒜泥白肉 舌尖上的川菜 成都川菜馆排名 十道经典老川菜 正宗川菜菜谱大全 正宗川菜水煮鱼做法 新派川菜菜谱大全做法