压缩图片和改变图片图形
压缩图片和改变图片图形
GitHub网址:https://github.com/qianshao1030/BitmapDemo
包名:compile 'jp.wasabeef:glide-transformations:3.0.1'
代码实现:
MainActivity:
1 /* 2 1,质量压缩法 3 1.1质量压缩不会减少图片的像素 4 1.2在像素不变的前提下改变图片的位深及透明度等,来达到压缩图片的目的。 5 1.3压缩的图片文件大小会有改变,但是导入成bitmap后占得内存是不变的 6 2,采样率压缩法 7 2.1内存的使用少,不会过多的占用内存 8 2.2可以先只读取图片的边,通过宽和高设定好取样率后再加载图片 9 2.3 10 3,缩放法 11 3.1通过缩放图片像素来减少图片占用内存大小 12 */ 13 public class MainActivity extends AppCompatActivity implements View.OnClickListener { 14 15 private static final String IMG_URL_0 = "http://pic.xiami.net/images/artistlogo/77/14677816895777.jpg"; 16 protected TextView tvOld; 17 protected TextView tv3; 18 private String baseUrl = "http://pic.xiami.net"; 19 private int contentLength; 20 private String IMG_URL_1 = "http://pic9.nipic.com/20100823/4361515_000842599423_2.jpg"; 21 private String IMG_URL_2 = "http://attachments.gfan.com/forum/attachments2/201302/03/11281446n2st1its4152n5.jpg"; 22 private String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bitmaps/"; 23 24 private void showList() { 25 DialogUtil.showListDialog(this, "Android中图片压缩方案", new String[]{ 26 "0,加载原图", 27 "1,下载原图", 28 "2,质量压缩法,不压缩保存到本地", 29 "3,质量压缩法,质量压缩保存到本地", 30 "4,采样率压缩法,保存", 31 "5,缩放法,方式一!", 32 "6,缩放法,方式二!", 33 }, new DialogInterface.OnClickListener() { 34 @Override 35 public void onClick(DialogInterface dialog, int which) { 36 switch (which) { 37 case 0: 38 //加载原图,并且展示! 39 load0(); 40 break; 41 case 1: 42 //下载原图,并且保存本地,从本加载展示! 43 load1(); 44 break; 45 case 2: 46 // 47 load2(); 48 break; 49 case 3: 50 load3(); 51 break; 52 case 4: 53 load4(); 54 break; 55 case 5: 56 load5(); 57 break; 58 case 6: 59 load6(); 60 break; 61 } 62 } 63 }); 64 } 65 66 private void load6() { 67 Observable.create(new ObservableOnSubscribe<String>() { 68 @Override 69 public void subscribe(ObservableEmitter<String> e) throws Exception { 70 ResponseBody body = new Retrofit.Builder() 71 .baseUrl(baseUrl) 72 .build() 73 .create(NetServerInterface.class) 74 .getBitmap(IMG_URL_1) 75 .execute() 76 .body(); 77 contentLength = (int) body.contentLength() / 1024; 78 InputStream stream = body 79 .byteStream(); 80 Bitmap image = BitmapFactory.decodeStream(stream); 81 82 ByteArrayOutputStream out = new ByteArrayOutputStream(); 83 image.compress(Bitmap.CompressFormat.JPEG, 85, out); 84 int size = contentLength; 85 //--原大小/内存小小后,开平方根. 86 float zoom = (float)Math.sqrt(size * 1024 / (float)out.toByteArray().length); 87 // 88 Matrix matrix = new Matrix(); 89 matrix.setScale(zoom, zoom); 90 91 Bitmap result = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true); 92 //清空. 93 out.reset(); 94 result.compress(Bitmap.CompressFormat.JPEG, 85, out); 95 while(out.toByteArray().length > size * 1024){ 96 DemonstrateUtil.showLogResult(out.toByteArray().length+"***"); 97 matrix.setScale(0.9f, 0.9f); 98 result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true); 99 out.reset(); 100 result.compress(Bitmap.CompressFormat.JPEG, 85, out); 101 } 102 103 File file = new File(Environment.getExternalStorageDirectory(), "load6.jpg"); 104 FileOutputStream fos = new FileOutputStream(file); 105 fos.write(out.toByteArray()); 106 fos.flush(); 107 fos.close(); 108 String filePath = file.getPath(); 109 e.onNext(filePath); 110 } 111 }) 112 .subscribeOn(Schedulers.io()) 113 .observeOn(AndroidSchedulers.mainThread()) 114 .subscribe(new Consumer<String>() { 115 @Override 116 public void accept(String path) throws Exception { 117 tvOld.setText("原始大小:" + contentLength + "kb"); 118 File file = new File(path); 119 int fileLenth = (int) (file.length() / 1024); 120 tv.setText("保存后大小:" + fileLenth + "kb"); 121 122 Bitmap bitmap = BitmapFactory.decodeFile(path); 123 int byteCount = bitmap.getByteCount() / 1024; 124 tv3.setText("加载到内存的大小:" + byteCount); 125 iv.setImageBitmap(bitmap); 126 } 127 }); 128 } 129 130 private void load5() { 131 Observable.create(new ObservableOnSubscribe<String>() { 132 @Override 133 public void subscribe(ObservableEmitter<String> e) throws Exception { 134 ResponseBody body = new Retrofit.Builder() 135 .baseUrl(baseUrl) 136 .build() 137 .create(NetServerInterface.class) 138 .getBitmap(IMG_URL_1) 139 .execute() 140 .body(); 141 contentLength = (int) body.contentLength() / 1024; 142 InputStream stream = body 143 .byteStream(); 144 Bitmap bmp = BitmapFactory.decodeStream(stream); 145 146 // 尺寸压缩倍数,值越大,图片尺寸越小 147 int ratio = 2; 148 // 压缩Bitmap到对应尺寸 149 //int width,宽 int height,高 Config config,决定图片质量. 150 Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, Bitmap.Config.ARGB_8888); 151 Canvas canvas = new Canvas(result); 152 Rect rect = new Rect(0, 0, bmp.getWidth() / ratio, bmp.getHeight() / ratio); 153 canvas.drawBitmap(bmp, null, rect, null); 154 155 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 156 // 把压缩后的数据存放到baos中 157 result.compress(Bitmap.CompressFormat.JPEG, 100, baos); 158 File file = new File(Environment.getExternalStorageDirectory(), "load5.jpg"); 159 FileOutputStream fos = new FileOutputStream(file); 160 fos.write(baos.toByteArray()); 161 fos.flush(); 162 fos.close(); 163 String filePath = file.getPath(); 164 e.onNext(filePath); 165 } 166 }) 167 .subscribeOn(Schedulers.io()) 168 .observeOn(AndroidSchedulers.mainThread()) 169 .subscribe(new Consumer<String>() { 170 @Override 171 public void accept(String path) throws Exception { 172 tvOld.setText("原始大小:" + contentLength + "kb"); 173 File file = new File(path); 174 int fileLenth = (int) (file.length() / 1024); 175 tv.setText("保存后大小:" + fileLenth + "kb"); 176 177 Bitmap bitmap = BitmapFactory.decodeFile(path); 178 int byteCount = bitmap.getByteCount() / 1024; 179 tv3.setText("加载到内存的大小:" + byteCount); 180 iv.setImageBitmap(bitmap); 181 } 182 }); 183 } 184 185 private void load4() { 186 Observable.create(new ObservableOnSubscribe<String>() { 187 @Override 188 public void subscribe(ObservableEmitter<String> e) throws Exception { 189 ResponseBody body = new Retrofit.Builder() 190 .baseUrl(baseUrl) 191 .build() 192 .create(NetServerInterface.class) 193 .getBitmap(IMG_URL_2) 194 .execute() 195 .body(); 196 contentLength = (int) body.contentLength() / 1024; 197 InputStream stream = body 198 .byteStream(); 199 File file = new File(Environment.getExternalStorageDirectory(), "load4.jpg"); 200 FileOutputStream out = new FileOutputStream(file); 201 out.write(body.bytes()); 202 out.close(); 203 String filePath = file.getPath(); 204 e.onNext(filePath); 205 } 206 }) 207 .subscribeOn(Schedulers.io()) 208 .observeOn(AndroidSchedulers.mainThread()) 209 .subscribe(new Consumer<String>() { 210 @Override 211 public void accept(String path) throws Exception { 212 tvOld.setText("原始大小:" + contentLength + "kb"); 213 File file = new File(path); 214 int fileLenth = (int) (file.length() / 1024); 215 tv.setText("保存后大小:" + fileLenth + "kb"); 216 217 //使用采样率进行压缩 218 BitmapFactory.Options newOpts = new BitmapFactory.Options(); 219 //开始读入图片,此时把options.inJustDecodeBounds 设回true了 220 newOpts.inJustDecodeBounds = true; 221 //此时返回bitmap为空 222 Bitmap bitmap = BitmapFactory.decodeFile(path, newOpts); 223 224 newOpts.inJustDecodeBounds = false; 225 int w = newOpts.outWidth; 226 int h = newOpts.outHeight; 227 //现在主流手机比较多是1280*720分辨率,所以高和宽我们设置为 228 //这里设置高度为1280f 229 float hh = 1280f; 230 //这里设置宽度为720f 231 float ww = 720f; 232 //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 233 //be=1表示不缩放 234 int be = 1; 235 if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 236 be = (int) (newOpts.outWidth / ww); 237 } else if (w < h && h > hh) {//如果高度高的话根据高度固定大小缩放 238 be = (int) (newOpts.outHeight / hh); 239 } 240 if (be <= 0) { 241 be = 1; 242 } 243 244 //设置缩放比例 245 newOpts.inSampleSize = be; 246 //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 247 bitmap = BitmapFactory.decodeFile(path, newOpts); 248 249 //压缩好比例大小后再进行质量压缩 250 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 251 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 252 int options = 100; 253 while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩 254 //重置baos即清空baos 255 baos.reset(); 256 //这里压缩options%,把压缩后的数据存放到baos中 257 bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos); 258 options -= 10;//每次都减少10 259 } 260 261 int len = baos.toByteArray().length / 1024; 262 tv3.setText("内存中的大小:" + len + "kb"); 263 //把压缩后的数据baos存放到ByteArrayInputStream中 264 ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); 265 //把ByteArrayInputStream数据生成图片 266 Bitmap bitmap3 = BitmapFactory.decodeStream(isBm, null, null); 267 tv.setText("保存后大小:" + fileLenth + "kb"+"bitmap:"+bitmap3.getByteCount()/1024+"--"); 268 iv.setImageBitmap(bitmap3); 269 270 /*File file5 = new File(Environment.getExternalStorageDirectory(), "load5.jpg"); 271 FileOutputStream out = new FileOutputStream(file5); 272 out.write(baos.toByteArray()); 273 out.close(); 274 baos.close();*/ 275 } 276 }); 277 } 278 279 private void load3() { 280 Observable.create(new ObservableOnSubscribe<String>() { 281 @Override 282 public void subscribe(ObservableEmitter<String> e) throws Exception { 283 ResponseBody body = new Retrofit.Builder() 284 .baseUrl(baseUrl) 285 .build() 286 .create(NetServerInterface.class) 287 .getBitmap(IMG_URL_1) 288 .execute() 289 .body(); 290 contentLength = (int) body.contentLength() / 1024; 291 InputStream stream = body 292 .byteStream(); 293 294 Bitmap bitmap = BitmapFactory.decodeStream(stream); 295 296 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 297 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 298 int options = 100; 299 while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩 300 //重置baos即清空baos 301 baos.reset(); 302 //这里压缩options%,把压缩后的数据存放到baos中 303 bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos); 304 options -= 10;//每次都减少10 305 } 306 307 File file = new File(Environment.getExternalStorageDirectory(), "load3.jpg"); 308 FileOutputStream out = new FileOutputStream(file); 309 out.write(baos.toByteArray()); 310 out.close(); 311 baos.close(); 312 String filePath = file.getPath(); 313 e.onNext(filePath); 314 } 315 }) 316 .subscribeOn(Schedulers.io()) 317 .observeOn(AndroidSchedulers.mainThread()) 318 .subscribe(new Consumer<String>() { 319 @Override 320 public void accept(String path) throws Exception { 321 tvOld.setText("原始大小:" + contentLength + "kb"); 322 File file = new File(path); 323 int fileLenth = (int) (file.length() / 1024); 324 tv.setText("保存后大小:" + fileLenth + "kb"); 325 Bitmap bitmap = BitmapFactory.decodeFile(path); 326 327 int byteCount = bitmap.getByteCount() / 1024; 328 tv3.setText("加载到内存的大小:" + byteCount); 329 iv.setImageBitmap(bitmap); 330 } 331 }); 332 } 333 334 private void load2() { 335 Observable.create(new ObservableOnSubscribe<String>() { 336 @Override 337 public void subscribe(ObservableEmitter<String> e) throws Exception { 338 ResponseBody body = new Retrofit.Builder() 339 .baseUrl(baseUrl) 340 .build() 341 .create(NetServerInterface.class) 342 .getBitmap(IMG_URL_1) 343 .execute() 344 .body(); 345 contentLength = (int) body.contentLength() / 1024; 346 InputStream stream = body 347 .byteStream(); 348 //压缩100,图片并将Bitmap保存到本地 349 Bitmap bitmap = BitmapFactory.decodeStream(stream); 350 File file = new File(Environment.getExternalStorageDirectory(), "load2.jpg"); 351 FileOutputStream out = new FileOutputStream(file); 352 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); 353 String filePath = file.getPath(); 354 e.onNext(filePath); 355 } 356 }) 357 .subscribeOn(Schedulers.io()) 358 .observeOn(AndroidSchedulers.mainThread()) 359 .subscribe(new Consumer<String>() { 360 @Override 361 public void accept(String path) throws Exception { 362 tvOld.setText("原始大小:" + contentLength + "kb"); 363 File file = new File(path); 364 int fileLenth = (int) (file.length() / 1024); 365 tv.setText("保存后大小:" + fileLenth + "kb"); 366 Bitmap bitmap = BitmapFactory.decodeFile(path); 367 int byteCount = bitmap.getByteCount() / 1024; 368 tv3.setText("加载到内存的大小:" + byteCount); 369 iv.setImageBitmap(bitmap); 370 } 371 }); 372 } 373 374 private void load1() { 375 Observable.create(new ObservableOnSubscribe<String>() { 376 @Override 377 public void subscribe(ObservableEmitter<String> e) throws Exception { 378 ResponseBody body = new Retrofit.Builder() 379 .baseUrl(baseUrl) 380 .build() 381 .create(NetServerInterface.class) 382 .getBitmap(IMG_URL_1) 383 .execute() 384 .body(); 385 contentLength = (int) body.contentLength() / 1024; 386 InputStream stream = body 387 .byteStream(); 388 //压缩图片并将Bitmap保存到本地 389 // Bitmap bitmap = BitmapFactory.decodeStream(stream); 390 // bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); 391 File file = new File(Environment.getExternalStorageDirectory(), "load1.jpg"); 392 FileOutputStream out = new FileOutputStream(file); 393 out.write(body.bytes()); 394 out.close(); 395 String filePath = file.getPath(); 396 e.onNext(filePath); 397 } 398 }) 399 .subscribeOn(Schedulers.io()) 400 .observeOn(AndroidSchedulers.mainThread()) 401 .subscribe(new Consumer<String>() { 402 @Override 403 public void accept(String path) throws Exception { 404 tvOld.setText("原始大小:" + contentLength + "kb"); 405 File file = new File(path); 406 int fileLenth = (int) (file.length() / 1024); 407 tv.setText("保存后大小:" + fileLenth + "kb"); 408 Bitmap bitmap = BitmapFactory.decodeFile(path); 409 int byteCount = bitmap.getByteCount() / 1024; 410 tv3.setText("加载到内存的大小:" + byteCount); 411 iv.setImageBitmap(bitmap); 412 } 413 }); 414 } 415 416 private void load0() { 417 Observable 418 .create(new ObservableOnSubscribe<Bitmap>() { 419 @Override 420 public void subscribe(ObservableEmitter<Bitmap> e) throws Exception { 421 Response<ResponseBody> response = new Retrofit.Builder() 422 .baseUrl(baseUrl) 423 .build() 424 .create(NetServerInterface.class) 425 .getBitmap(IMG_URL_0) 426 .execute(); 427 contentLength = (int) (response.body().contentLength() / 1024); 428 InputStream stream = response.body().byteStream(); 429 Bitmap bitmap = BitmapFactory.decodeStream(stream); 430 e.onNext(bitmap); 431 } 432 }).subscribeOn(Schedulers.io()) 433 .observeOn(AndroidSchedulers.mainThread()) 434 .subscribe(new Consumer<Bitmap>() { 435 @Override 436 public void accept(Bitmap bitmap) throws Exception { 437 tvOld.setText("原图片大小为:" + contentLength + "kb"); 438 iv.setImageBitmap(bitmap); 439 } 440 }); 441 } 442 443 protected Button btn; 444 protected TextView tv; 445 protected ImageView iv; 446 447 @Override 448 protected void onCreate(Bundle savedInstanceState) { 449 super.onCreate(savedInstanceState); 450 super.setContentView(R.layout.activity_main); 451 initView(); 452 } 453 454 @Override 455 public void onClick(View view) { 456 if (view.getId() == R.id.btn) { 457 showList(); 458 } 459 } 460 461 462 private void initView() { 463 btn = (Button) findViewById(R.id.btn); 464 btn.setOnClickListener(MainActivity.this); 465 tv = (TextView) findViewById(R.id.tv); 466 iv = (ImageView) findViewById(R.id.iv); 467 tvOld = (TextView) findViewById(R.id.tv_old); 468 tv3 = (TextView) findViewById(R.id.tv3); 469 } 470 }
BecomeActivity:
1 public class BecomeActivity extends AppCompatActivity implements View.OnClickListener { 2 3 protected Button btn; 4 protected ImageView iv; 5 private String IMG_URL_0 = "http://zhanhui.3158.cn/data/attachment/exhibition/data/attachment/exhibition/article/2016/02/17/0d6437a313155f933c13971a0ba22cf4.jpg"; 6 private String IMG_URL_1 = "http://img2015.zdface.com/20171115/89eef31e783ccd13f2cdf12ab04298e3.jpg"; 7 private String IMG_URL_2 = "http://img003.21cnimg.com/photos/album/20161114/m600/6CDB31F812CC273DD89E4AA58594A217.jpeg"; 8 private String IMG_URL_3 = "http://p0.so.qhimgs1.com/t0195918c00ff0b8c1c.jpg"; 9 private String IMG_URL_4 = "http://himg2.huanqiu.com/attachment2010/2016/1026/15/06/20161026030615719.jpg"; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 super.setContentView(R.layout.activity_become); 15 initView(); 16 } 17 18 @Override 19 public void onClick(View view) { 20 if (view.getId() == R.id.btn) { 21 showDialog(); 22 } 23 } 24 25 private void showDialog() { 26 DialogUtil.showListDialog(this, "图片的形状的变换!", new String[]{ 27 "0,将图像剪切成圆", 28 "1,将图像剪切成三角形", 29 "2,将图像剪切成多角形", 30 "3,将图像剪切成曲线形", 31 "4,将图像剪切成圆角形", 32 }, new DialogInterface.OnClickListener() { 33 @Override 34 public void onClick(DialogInterface dialog, int which) { 35 switch (which) { 36 case 0: 37 Glide.with(BecomeActivity.this) 38 .load(IMG_URL_0) 39 .apply(RequestOptions.bitmapTransform(new CropCircleTransformation())) 40 .into(iv); 41 break; 42 case 1: 43 MultiTransformation<Bitmap> transformation 44 = new MultiTransformation<>(new CenterCrop(), new MaskTransformation(R.mipmap.mask_trangle)); 45 46 Glide.with(BecomeActivity.this) 47 .load(IMG_URL_1) 48 .apply(bitmapTransform(transformation)) 49 .into(iv); 50 break; 51 case 2: 52 Glide.with(BecomeActivity.this) 53 .load(IMG_URL_2) 54 .apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(), new MaskTransformation(R.mipmap.mask_starfish)))) 55 .into(iv); 56 break; 57 case 3: 58 Glide.with(BecomeActivity.this) 59 .load(IMG_URL_3) 60 .apply(bitmapTransform(new MultiTransformation<>(new CenterCrop(), new MaskTransformation(R.drawable.mask_chat_right)))) 61 .into(iv); 62 break; 63 case 4: 64 Glide.with(BecomeActivity.this) 65 .load(IMG_URL_4) 66 .apply(bitmapTransform(new RoundedCornersTransformation(45, 0, 67 RoundedCornersTransformation.CornerType.BOTTOM))) 68 .into(iv); 69 break; 70 } 71 } 72 }); 73 } 74 75 private void initView() { 76 btn = (Button) findViewById(R.id.btn); 77 btn.setOnClickListener(BecomeActivity.this); 78 iv = (ImageView) findViewById(R.id.iv); 79 } 80 }
NetServerInterface:
1 public interface NetServerInterface { 2 3 @GET 4 Call<ResponseBody> getBitmap(@Url String url); 5 }
StartActivity:
1 public class StartActivity extends AppCompatActivity implements View.OnClickListener { 2 3 protected Button btnBitmap; 4 protected Button btnBecome; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 super.setContentView(R.layout.activity_start); 10 initView(); 11 } 12 13 @Override 14 public void onClick(View view) { 15 if (view.getId() == R.id.btn_bitmap) { 16 startActivity(new Intent(this,MainActivity.class)); 17 } else if (view.getId() == R.id.btn_become) { 18 startActivity(new Intent(this,BecomeActivity.class)); 19 } 20 } 21 22 private void initView() { 23 btnBitmap = (Button) findViewById(R.id.btn_bitmap); 24 btnBitmap.setOnClickListener(StartActivity.this); 25 btnBecome = (Button) findViewById(R.id.btn_become); 26 btnBecome.setOnClickListener(StartActivity.this); 27 } 28 }