xUtils源码阅读(8)-ImageDecoder
来源:互联网 发布:linux查看cpu核数命令 编辑:程序博客网 时间:2024/06/11 09:36
图片解析工具类,就是从文件读取图片内容,并处理成我们需要的样式(大小,旋转,修剪等)。
该工具类别看这么的长,实际上就一个函数,那就是
decodeFileWithLock
所有其它的函数都是在为这个函数做服务呢,或者给这个函数做帮手呢。
这样再来看该类,就简单多了。
源码:
/** * Created by wyouflf on 15/10/9. * ImageDecoder for ImageLoader */public final class ImageDecoder { private final static int BITMAP_DECODE_MAX_WORKER;//处理器最大的数量 private final static AtomicInteger bitmapDecodeWorker = new AtomicInteger(0);//锁 private final static Object bitmapDecodeLock = new Object(); private final static Object gifDecodeLock = new Object();//gif锁 private final static byte[] GIF_HEADER = new byte[]{'G', 'I', 'F'};//git文件的头文件标识符 private final static byte[] WEBP_HEADER = new byte[]{'W', 'E', 'B', 'P'};//webp文件头文件标识符 private final static Executor THUMB_CACHE_EXECUTOR = new PriorityExecutor(1, true);//缩略图处理器 private final static LruDiskCache THUMB_CACHE = LruDiskCache.getDiskCache("xUtils_img_thumb");//缩略图硬件缓存 static { int cpuCount = Runtime.getRuntime().availableProcessors(); BITMAP_DECODE_MAX_WORKER = cpuCount > 4 ? 2 : 1; } private ImageDecoder() { } /*package*/ static void clearCacheFiles() { THUMB_CACHE.clearCacheFiles(); } /** * decode image file for ImageLoader * * @param file * @param options * @param cancelable * @return * @throws IOException */ /*package*/ static Drawable decodeFileWithLock(final File file, final ImageOptions options, final Callback.Cancelable cancelable) throws IOException { if (file == null || !file.exists() || file.length() < 1) return null; if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } Drawable result = null; if (!options.isIgnoreGif() && isGif(file)) { Movie movie = null; synchronized (gifDecodeLock) { // decode with lock movie = decodeGif(file, options, cancelable); } if (movie != null) { result = new GifDrawable(movie, (int) file.length()); } } else { Bitmap bitmap = null; { // decode with lock try { while (bitmapDecodeWorker.get() >= BITMAP_DECODE_MAX_WORKER && (cancelable == null || !cancelable.isCancelled())) {//获取处理器资源 synchronized (bitmapDecodeLock) { try { bitmapDecodeLock.wait(); } catch (InterruptedException iex) { throw new Callback.CancelledException("cancelled during decode image"); } catch (Throwable ignored) { } } } if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } bitmapDecodeWorker.incrementAndGet(); // get from thumb cache if (options.isCompress()) {//尝试从缓存中获取 bitmap = getThumbCache(file, options); } if (bitmap == null) { bitmap = decodeBitmap(file, options, cancelable);//具体的解析图片工作 // save to thumb cache if (bitmap != null && options.isCompress()) {//存储到缓存 final Bitmap finalBitmap = bitmap; THUMB_CACHE_EXECUTOR.execute(new Runnable() { @Override public void run() { saveThumbCache(file, options, finalBitmap); } }); } } } finally { bitmapDecodeWorker.decrementAndGet(); synchronized (bitmapDecodeLock) { bitmapDecodeLock.notifyAll(); } } } if (bitmap != null) { result = new ReusableBitmapDrawable(x.app().getResources(), bitmap); } } return result; } public static boolean isGif(File file) {//判断是否为gif FileInputStream in = null; try { in = new FileInputStream(file); byte[] header = IOUtil.readBytes(in, 0, 3); return Arrays.equals(GIF_HEADER, header); } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); } finally { IOUtil.closeQuietly(in); } return false; } public static boolean isWebP(File file) {//判断是否为webp FileInputStream in = null; try { in = new FileInputStream(file); byte[] header = IOUtil.readBytes(in, 8, 4); return Arrays.equals(WEBP_HEADER, header); } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); } finally { IOUtil.closeQuietly(in); } return false; } /** * 转化文件为Bitmap, 更好的支持WEBP. * * @param file * @param options * @param cancelable * @return * @throws IOException */ public static Bitmap decodeBitmap(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException {//最核心的解析图片操作 {// check params if (file == null || !file.exists() || file.length() < 1) return null; if (options == null) { options = ImageOptions.DEFAULT; } if (options.getMaxWidth() <= 0 || options.getMaxHeight() <= 0) { options.optimizeMaxSize(null); } } Bitmap result = null; try { if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } // prepare bitmap options final BitmapFactory.Options bitmapOps = new BitmapFactory.Options(); bitmapOps.inJustDecodeBounds = true; bitmapOps.inPurgeable = true; bitmapOps.inInputShareable = true; BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOps);//第一遍解析获取图片大小 bitmapOps.inJustDecodeBounds = false; bitmapOps.inPreferredConfig = options.getConfig(); int rotateAngle = 0; int rawWidth = bitmapOps.outWidth; int rawHeight = bitmapOps.outHeight; int optionWith = options.getWidth(); int optionHeight = options.getHeight(); if (options.isAutoRotate()) { rotateAngle = getRotateAngle(file.getAbsolutePath()); if ((rotateAngle / 90) % 2 == 1) { rawWidth = bitmapOps.outHeight; rawHeight = bitmapOps.outWidth; } } if (!options.isCrop() && optionWith > 0 && optionHeight > 0) { if ((rotateAngle / 90) % 2 == 1) { bitmapOps.outWidth = optionHeight; bitmapOps.outHeight = optionWith; } else { bitmapOps.outWidth = optionWith; bitmapOps.outHeight = optionHeight; } } bitmapOps.inSampleSize = calculateSampleSize( rawWidth, rawHeight, options.getMaxWidth(), options.getMaxHeight()); if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } // decode file Bitmap bitmap = null; if (isWebP(file)) { bitmap = WebPFactory.decodeFile(file.getAbsolutePath(), bitmapOps);//解析具体内容 } if (bitmap == null) { bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOps);//第二遍解析具体内容 } if (bitmap == null) { throw new IOException("decode image error"); } { // 旋转和缩放处理 if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } if (rotateAngle != 0) { bitmap = rotate(bitmap, rotateAngle, true); } if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } if (options.isCrop() && optionWith > 0 && optionHeight > 0) { bitmap = cut2ScaleSize(bitmap, optionWith, optionHeight, true); } } if (bitmap == null) { throw new IOException("decode image error"); } { // 圆角和方块处理 if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } if (options.isCircular()) { bitmap = cut2Circular(bitmap, true); } else if (options.getRadius() > 0) { bitmap = cut2RoundCorner(bitmap, options.getRadius(), options.isSquare(), true); } else if (options.isSquare()) { bitmap = cut2Square(bitmap, true); } } if (bitmap == null) { throw new IOException("decode image error"); } result = bitmap; } catch (IOException ex) { throw ex; } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); result = null; } return result; } /** * 转换文件为Movie, 可用于创建GifDrawable. * * @param file * @param options * @param cancelable * @return * @throws IOException */ public static Movie decodeGif(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException { {// check params if (file == null || !file.exists() || file.length() < 1) return null; /*if (options == null) { options = ImageOptions.DEFAULT; // not use } if (options.getMaxWidth() <= 0 || options.getMaxHeight() <= 0) { options.optimizeMaxSize(null); }*/ } InputStream in = null; try { if (cancelable != null && cancelable.isCancelled()) { throw new Callback.CancelledException("cancelled during decode image"); } int buffSize = 1024 * 16; in = new BufferedInputStream(new FileInputStream(file), buffSize); in.mark(buffSize); Movie movie = Movie.decodeStream(in); if (movie == null) { throw new IOException("decode image error"); } return movie; } catch (IOException ex) { throw ex; } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); return null; } finally { IOUtil.closeQuietly(in); } } /** * 计算压缩采样倍数 * * @param rawWidth * @param rawHeight * @param maxWidth * @param maxHeight * @return */ public static int calculateSampleSize(final int rawWidth, final int rawHeight, final int maxWidth, final int maxHeight) { int sampleSize = 1; if (rawWidth > maxWidth || rawHeight > maxHeight) { if (rawWidth > rawHeight) { sampleSize = Math.round((float) rawHeight / (float) maxHeight); } else { sampleSize = Math.round((float) rawWidth / (float) maxWidth); } if (sampleSize < 1) { sampleSize = 1; } final float totalPixels = rawWidth * rawHeight; final float maxTotalPixels = maxWidth * maxHeight * 2; while (totalPixels / (sampleSize * sampleSize) > maxTotalPixels) { sampleSize++; } } return sampleSize; } /** * 裁剪方形图片 * * @param source * @param recycleSource 裁剪成功后销毁原图 * @return */ public static Bitmap cut2Square(Bitmap source, boolean recycleSource) { int width = source.getWidth(); int height = source.getHeight(); if (width == height) { return source; } int squareWith = Math.min(width, height); Bitmap result = Bitmap.createBitmap(source, (width - squareWith) / 2, (height - squareWith) / 2, squareWith, squareWith); if (result != null) { if (recycleSource && result != source) { source.recycle(); source = null; } } else { result = source; } return result; } /** * 裁剪圆形图片 * * @param source * @param recycleSource 裁剪成功后销毁原图 * @return */ public static Bitmap cut2Circular(Bitmap source, boolean recycleSource) { int width = source.getWidth(); int height = source.getHeight(); int diameter = Math.min(width, height); Paint paint = new Paint(); paint.setAntiAlias(true); Bitmap result = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888); if (result != null) { Canvas canvas = new Canvas(result); canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(source, (diameter - width) / 2, (diameter - height) / 2, paint); if (recycleSource) { source.recycle(); source = null; } } else { result = source; } return result; } /** * 裁剪圆角 * * @param source * @param radius * @param isSquare * @param recycleSource 裁剪成功后销毁原图 * @return */ public static Bitmap cut2RoundCorner(Bitmap source, int radius, boolean isSquare, boolean recycleSource) { if (radius <= 0) return source; int sourceWidth = source.getWidth(); int sourceHeight = source.getHeight(); int targetWidth = sourceWidth; int targetHeight = sourceHeight; if (isSquare) { targetWidth = targetHeight = Math.min(sourceWidth, sourceHeight); } Paint paint = new Paint(); paint.setAntiAlias(true); Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888); if (result != null) { Canvas canvas = new Canvas(result); RectF rect = new RectF(0, 0, targetWidth, targetHeight); canvas.drawRoundRect(rect, radius, radius, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(source, (targetWidth - sourceWidth) / 2, (targetHeight - sourceHeight) / 2, paint); if (recycleSource) { source.recycle(); source = null; } } else { result = source; } return result; } /** * 裁剪并缩放至指定大小 * * @param source * @param dstWidth * @param dstHeight * @param recycleSource 裁剪成功后销毁原图 * @return */ public static Bitmap cut2ScaleSize(Bitmap source, int dstWidth, int dstHeight, boolean recycleSource) { final int width = source.getWidth(); final int height = source.getHeight(); if (width == dstWidth && height == dstHeight) { return source; } // scale Matrix m = new Matrix(); int l = 0, t = 0, r = width, b = height; { float sx = dstWidth / (float) width; float sy = dstHeight / (float) height; if (sx > sy) { sy = sx; l = 0; r = width; t = (int) ((height - dstHeight / sx) / 2); b = (int) ((height + dstHeight / sx) / 2); } else { sx = sy; l = (int) ((width - dstWidth / sx) / 2); r = (int) ((width + dstWidth / sx) / 2); t = 0; b = height; } m.setScale(sx, sy); } Bitmap result = Bitmap.createBitmap(source, l, t, r - l, b - t, m, true); if (result != null) { if (recycleSource && result != source) { source.recycle(); source = null; } } else { result = source; } return result; } /** * 旋转图片 * * @param source * @param angle * @param recycleSource * @return */ public static Bitmap rotate(Bitmap source, int angle, boolean recycleSource) { Bitmap result = null; if (angle != 0) { Matrix m = new Matrix(); m.setRotate(angle); try { result = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), m, true); } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); } } if (result != null) { if (recycleSource && result != source) { source.recycle(); source = null; } } else { result = source; } return result; } /** * 获取图片旋转角度 * * @param filePath * @return */ public static int getRotateAngle(String filePath) { int angle = 0; try { ExifInterface exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: angle = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: angle = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: angle = 270; break; default: angle = 0; break; } } catch (Throwable ex) { LogUtil.e(ex.getMessage(), ex); } return angle; } /** * 压缩bitmap, 更好的支持webp. * * @param bitmap * @param format * @param quality * @param out * @throws IOException */ public static void compress(Bitmap bitmap, Bitmap.CompressFormat format, int quality, OutputStream out) throws IOException { if (format == Bitmap.CompressFormat.WEBP) { byte[] data = WebPFactory.encodeBitmap(bitmap, quality); out.write(data); } else { bitmap.compress(format, quality, out); } } /** * 根据文件的修改时间和图片的属性保存缩略图 * * @param file * @param options * @param thumbBitmap */ private static void saveThumbCache(File file, ImageOptions options, Bitmap thumbBitmap) { if (!WebPFactory.available()) return; DiskCacheEntity entity = new DiskCacheEntity(); entity.setKey( file.getAbsolutePath() + "@" + file.lastModified() + options.toString()); DiskCacheFile cacheFile = null; OutputStream out = null; try { cacheFile = THUMB_CACHE.createDiskCacheFile(entity); if (cacheFile != null) { out = new FileOutputStream(cacheFile); byte[] encoded = WebPFactory.encodeBitmap(thumbBitmap, 80); out.write(encoded); out.flush(); cacheFile = cacheFile.commit(); } } catch (Throwable ex) { IOUtil.deleteFileOrDir(cacheFile); LogUtil.w(ex.getMessage(), ex); } finally { IOUtil.closeQuietly(cacheFile); IOUtil.closeQuietly(out); } } /** * 根据文件的修改时间和图片的属性获取缩略图 * * @param file * @param options * @return */ private static Bitmap getThumbCache(File file, ImageOptions options) { if (!WebPFactory.available()) return null; DiskCacheFile cacheFile = null; try { cacheFile = THUMB_CACHE.getDiskCacheFile( file.getAbsolutePath() + "@" + file.lastModified() + options.toString()); if (cacheFile != null && cacheFile.exists()) { BitmapFactory.Options bitmapOps = new BitmapFactory.Options(); bitmapOps.inJustDecodeBounds = false; bitmapOps.inPurgeable = true; bitmapOps.inInputShareable = true; bitmapOps.inPreferredConfig = Bitmap.Config.ARGB_8888; return WebPFactory.decodeFile(cacheFile.getAbsolutePath(), bitmapOps); } } catch (Throwable ex) { LogUtil.w(ex.getMessage(), ex); } finally { IOUtil.closeQuietly(cacheFile); } return null; }}
0 0
- xUtils源码阅读(8)-ImageDecoder
- Universal-Image-Loader源码阅读(34)-ImageDecoder
- xUtils源码阅读(1)- x
- xUtils源码阅读(3)-ImageManagerImpl
- xUtils源码阅读(4)-MemCacheKey
- xUtils源码阅读(5)-ReuseableBitmapDrawable
- xUtils源码阅读(6)-AsyncDrawable
- xUtils源码阅读(7)-GitDrawable
- xUtils源码阅读(2)-ImageManager
- XUtils源码分析之HttpUtils(一)
- xUtils 源码解析
- xUtils 源码解析
- xUtils 源码解析
- xUtils 源码解析
- xUtils 源码解析
- XUtils 源码解析
- xUtils 源码解析
- Eclipse 导入 xUtils 源码
- iOS学习笔记 网络(三)WebView
- 快速点击多次进入Activity
- Redis——简介
- C 语言中的constructor与destructor
- 设置HTML:target=_blank,在新窗口中打开链接
- xUtils源码阅读(8)-ImageDecoder
- Spring 源码梳理(八) Spring常用配置
- 一、logo载入界面
- HTML character codes
- JSP页面用EL表达式 输出date格式
- HDU 1166 敌兵布阵 树状数组-(模板)
- Swift语言2.2版本,够初学者学习
- Android 广告(banner)图片轮播、图片浏览、仿微信大图查看控件(支持视频和gif图片)、支持动态添加数据
- Android 之下拉刷新控件XRefreshableView