摘要:
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测试数据/p/awt-android-compat/
FQ下载下来后,该项目报错太多,仍有一些java类没有整合进来,不能使用;
2、尝试从java sdk源码中抽取,但类的继承、嵌套层级太深,试过几次都不行。
3、最后只好阅读java sdk缩放图片的相关源码,缩放时用了区域平均算法,大体就是取某个区域里像素点a\r\g\b的平均颜色值,作为缩放后的图片相应区域的颜色值,目前看来此算法缩放效果最优。
可参考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://HdhCmsTesteoeandroid测试数据/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://HdhCmsTesteoeandroid测试数据/thread-556407-1-1.html
?
查看更多关于(转)Android中实现区域平均算法在图片缩放里的应用(缩放图片抗锯齿)的详细内容...