关于Android的图片压缩
最近有项目需要压缩图片(300 x 300)传入服务器展示
但是效果却不近人情,到这个size 图片就糊掉了 ,但是IOS却没问题经过反复查证IOS和android 在底层的OnDraw方法用的是同一个包,但是IOS在底层绘制的时候把一些属性都加上(smooth化、锐化操作)了所以大小和质量都比android 质量高一些。
对于这样的问题下android本身目前是没有办法去修改的。
但是目前有三种方法去提高一些质量
1.android方面
根据相关的方法等比压缩对图片resize 操作
public static Bitmap getResizedBitmap(Bitmap bitmap,float newWidth, float newHeight) { if (bitmap.getHeight()>bitmap.getWidth()){ newHeight=300f; newWidth= (int) (bitmap.getWidth()*(newHeight/(float) bitmap.getHeight())); }else{ newWidth=300f; newHeight= (int) (bitmap.getHeight()*(newWidth/(float) bitmap.getWidth())); } Bitmap resizedBitmap = Bitmap.createBitmap((int)newWidth,(int) newHeight, Bitmap.Config.ARGB_8888); float scaleX = newWidth / (float) bitmap.getWidth(); float scaleY = newHeight / (float) bitmap.getHeight(); float pivotX = 0; float pivotY = 0; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY); Canvas canvas = new Canvas(resizedBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG)); return resizedBitmap; }
结论:压缩500X500以下的图片 会模糊
2. jni方面
加载bither库
微信处理压缩方法
有压缩以及resize的方法
压缩首先
int generateJPEG(BYTE* data, int w, int h, int quality,
const char* outfilename, jboolean optimize) {
int nComponent = 3;
struct jpeg_compress_struct jcs;
struct my_error_mgr jem;
jcs.err = jpeg_std_error(&jem.pub);
jem.pub.error_exit = my_error_exit;
if (setjmp(jem.setjmp_buffer)) {
return 0;
}
jpeg_create_compress(&jcs);
FILE* f = fopen(outfilename, "wb");
if (f == NULL) {
return 0;
}
jpeg_stdio_dest(&jcs, f);
// if(w>h){
// jcs.image_width = 396;
// jcs.image_height = (int)(h*(396/w));
// }else{
// jcs.image_height = 396;
// jcs.image_width = (int)(w*(396/h));
// }
jcs.image_height = h;
jcs.image_width = w;
if (optimize) {
LOGI("optimize==ture");
} else {
LOGI("optimize==false");
}
jcs.arith_code = false;
jcs.input_components = nComponent;
if (nComponent == 1)
jcs.in_color_space = JCS_GRAYSCALE;
else
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);
jcs.optimize_coding = optimize;
jpeg_set_quality(&jcs, quality, true);
jpeg_start_compress(&jcs, TRUE);
JSAMPROW row_pointer[1];
int row_stride;
row_stride = jcs.image_width * nComponent;
while (jcs.next_scanline < jcs.image_height) {
row_pointer[0] = &data[jcs.next_scanline * row_stride];
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
if (jcs.optimize_coding) {
LOGI("optimize==ture");
} else {
LOGI("optimize==false");
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
fclose(f);
return 1;
}
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} rgb;
char* jstrinTostring(JNIEnv* env, jbyteArray barr) {
char* rtn = NULL;
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, 0);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba, 0);
return rtn;
}
jbyteArray stoJstring(JNIEnv* env, const char* pat,int len) {
jbyteArray bytes = (*env)->NewByteArray(env, len);
(*env)->SetByteArrayRegion(env, bytes, 0, len, pat);
jsize alen = (*env)->GetArrayLength(env, bytes);
return bytes;
}
jstring Java_包名_compressBitmap(JNIEnv* env,
jobject thiz, jobject bitmapcolor, int w, int h, int quality,
jbyteArray fileNameStr, jboolean optimize) {
AndroidBitmapInfo infocolor;
BYTE* pixelscolor;
int ret;
BYTE * data;
BYTE *tmpdata;
char * fileName = jstrinTostring(env, fileNameStr);
if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return (*env)->NewStringUTF(env, "0");;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
BYTE r, g, b;
data = NULL;
data = malloc(w * h * 3);
tmpdata = data;
int j = 0, i = 0;
int color;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
color = *((int *) pixelscolor);
r = ((color & 0x00FF0000) >> 16);
g = ((color & 0x0000FF00) >> 8);
b = color & 0x000000FF;
*data = b;
*(data + 1) = g;
*(data + 2) = r;
data = data + 3;
pixelscolor += 4;
}
}
AndroidBitmap_unlockPixels(env, bitmapcolor);
int resultCode= generateJPEG(tmpdata, w, h, quality, fileName, optimize);
free(tmpdata);
if(resultCode==0){
jstring result=(*env)->NewStringUTF(env, error);
error=NULL;
return result;
}
return (*env)->NewStringUTF(env, "1"); //success
}
resize方法
jboolean Java_包名_resizePicture(JNIEnv* env,
jobject thiz,jstring strSource, jstring strTarget,int w, int h)
{
int WIDTH = 396;
int HEIGHT = 396;
CImage oldimg;
CImage newimg;
oldimg.Load(strSource);
if (oldimg.IsNull())
return false;
int nWidth = 0;
int nHeight = 0;
nWidth = oldimg.GetWidth();
nHeight = oldimg.GetHeight();
if (nWidth > WIDTH || nHeight > HEIGHT)
{
double dRatio = nWidth * 1.0 / nHeight;
if (nWidth > nHeight)
{
nWidth = WIDTH;
nHeight = (int)(nWidth / dRatio);
}
else
{
nHeight = HEIGHT;
nWidth = (int)(nHeight * dRatio);
}
}
if (!newimg.CreateEx(nWidth, nHeight, 24, BI_RGB))
{
oldimg.Destroy();
return false;
}
int nPreMode = ::SetStretchBltMode(newimg.GetDC(), HALFTONE);
newimg.ReleaseDC();
oldimg.Draw(newimg.GetDC(), 0, 0, nWidth, nHeight, 0, 0, oldimg.GetWidth(), oldimg.GetHeight());
newimg.ReleaseDC();
::SetBrushOrgEx(newimg.GetDC(), 0, 0, NULL);
newimg.ReleaseDC();
::SetStretchBltMode(newimg.GetDC(), nPreMode);
newimg.ReleaseDC();
newimg.Save(strTarget);
newimg.Destroy();
oldimg.Destroy();
return true;
}
结论:压缩500X500以下的图片 会模糊 想测试的同学可以通过上面方式的查看相关GitHub库或者文章
3.Opencv
加载openCV3.0 库
注:最好加载3.0库以上
@Override // public void onResume() { // super.onResume(); // if (!OpenCVLoader.initDebug()) { // OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback); // } else { // mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); // } // } // //openCV4Android 需要加载用到 // private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { // @Override // public void onManagerConnected(int status) { // switch (status) { // case LoaderCallbackInterface.SUCCESS: { //
// mOpenCvCameraView.enableView(); //// mOpenCvCameraView.setOnTouchListener(ColorBlobDetectionActivity.this); // } // break; // default: { // super.onManagerConnected(status); // } // break; // } // } // }; // // static { // if (!OpenCVLoader.initDebug()) { // } // }
如果3.0以下 启动时会下载opencv库 在手机里 所以避免这一步最好加载3.0库
File dirFile = getExternalCacheDir(); // // File tempFile =new File(dirFile,"temp.jpg"); // NativeUtil.compressBitmap(BitmapFactory.decodeFile(photo_path),tempFile.getAbsolutePath(), false); // BufferedImage image = new BufferedImage(182, 396, BufferedImage.TYPE_INT_RGB); // image.getGraphics().drawImage(targetImage.getScaledInstance(182, 396, image.SCALE_SMOOTH), 0, 0, 182, // 396, null); // double scale = 0.2; // 缩放比例 // Mat img = imread(photo_path);// 读入图片,将其转换为Mat // Size dsize = new Size(182, 396); // 设置新图片的大小 // Mat img2 = new Mat(dsize, CvType.CV_64F); // Mat img3= new Mat(dsize, CvType.CV_32F); // // 创建一个新的Mat(opencv的矩阵数据类型) // Imgproc.resize(img, img2,dsize,0,0,INTER_NEAREST);//调用Imgproc的Resize方法,进行图片缩放 // double ksize = 3.0f; // Imgproc.blur(img2,img3,new Size(ksize,ksize));//调用Imgproc的Resize方法,进行图片缩放 // String base64Img = null; // if(imwrite("/sdcard/temp.jpg", img2)){//将图形保存到new.jpg中 // File f = new File("/sdcard/temp.jpg"); // if(f.exists()) { // base64Img = ImgUtil.bitmapToBase64(BitmapFactory.decodeFile(f.getAbsolutePath())); // } // }
通过这种方法来resize 图片和以上方法一样也会模糊掉。
4.OpenGL
这个我就不贴代码了
因为他还是不会对图片有什么帮助
只能在本地加载上图片后显示方面可以用锐化和smooth化修正
可以修改一定的质量但是不会对图片文件本身修改
而且治根不治本还是会模糊
android方面加载其实还是需要其他的的语言进行修改
我这边是通过java
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); image.getGraphics().drawImage(targetImage.getScaledInstance(width, height, image.SCALE_SMOOTH), 0, 0, width, height, null);
去修改图片才可以修改掉
希望可以帮助大家