做app网站需要什么条件,欧模网室内设计网官网,建立网站做家教辅导,什么网站可以做ui兼职前10篇文章,9章关于pdf的,pdf解析后,里面也是有各种图片,于是利用pdf的view来展示图片,似乎也是个不错的想法.
android手机中的图片查看功能,有的可以展示,有的不能.比如华为,荣耀对大体积的png是可以显示的,小米是不显示,只有缩略图.
一张png50m大,比如清明上河图,原图是tif…前10篇文章,9章关于pdf的,pdf解析后,里面也是有各种图片,于是利用pdf的view来展示图片,似乎也是个不错的想法.
android手机中的图片查看功能,有的可以展示,有的不能.比如华为,荣耀对大体积的png是可以显示的,小米是不显示,只有缩略图.
一张png50m大,比如清明上河图,原图是tiff,2g左右,这是adobe收购公司发明的,也是ps常用的.
对于tiff,华为,小米都显示不了,一方面可能是太大了,我有两张,一张300多m,一张2g,还有一张600多清明上河图原图扫描版的缩略图. 查阅了不少关于tiff的解析,目前没有提供好的android可以直接用的so库或lib库,TiffBitmapFactory有一个解析版,比较老了,它解析每次都是从头解析,虽然有area,但还是不行,对于300m的图片,解析一次要7s多,不管这块是多大,就算只有100*100像素也是如此.
tif库4.1.0才支持按需加载,我还没有实现这个功能,它是链表存储的,解析每一块,要从头开始查询fd的位置. mupdf里面有一个load-tiff.c的解析代码,每一次加载也是7s左右,后面的就不用了,于是就想到,我把它直接展示不就行了.
原来的apk已经具备了查看图片的功能,但对于pdf的view来显示图片,有几个不好的方面:
手势,pdfview目前不支持双击放大这些操作,是针对pdf的手势.缩放比例,当前没有设置很大的比例.加载速度,不支持多线程,mupdf的问题,暂时没有处理. 加载大图用的是subsampling-scale-image-view,这个在github上比较有名,它具备tile的按块加载,只需解码的时候 实现regiondecoder就可以了.
而且写的很好,文档注释很全.
代码:
要实现两个类,一个是pooled的解码类,一个是普通的解码.它首先会先用pooled类,去检测高与宽.
public class MupdfPooledImageRegionDecoder implements ImageRegionDecoder
public class MupdfImageDecoder implements ImageDecoder
官方的解码skia有三个类,这里不需要,两个就够了.
首先,对于体积超过10m的图片,获取exif可能会有内存不足的问题,所以subsampling-scale-image-view的源码,把相关获取exif的去了,去了以后,有些图片的方向不对,手机转一下就可以了.目前没有好的解决方案,这只是对于三星手机拍的照片有这个问题. 图片展示要分两类,一类是android支持的各种图片,一类是tiff.因为tiff通常是比较大的.比如地图,星空,航天这些领域. 具体实现:
if (path!!.endsWith(tif) || path.endsWith(tiff)) {binding.imageView.setBitmapDecoderFactory(CompatDecoderFactory(MupdfImageDecoder::class.java,Bitmap.Config.ARGB_8888))binding.imageView.setRegionDecoderFactory(CompatDecoderFactory(MupdfPooledImageRegionDecoder::class.java,Bitmap.Config.ARGB_8888))} else {binding.imageView.setBitmapDecoderFactory(CompatDecoderFactory(SkiaImageDecoder::class.java,Bitmap.Config.ARGB_8888))binding.imageView.setRegionDecoderFactory(CompatDecoderFactory(SkiaPooledImageRegionDecoder::class.java,Bitmap.Config.ARGB_8888))}
tiff的设置解码器与其它不同,针对小内存的手机,可以尝试rgb565,由于mupdf现在没有支持,所以都用argb_8888.
先看MupdfImageDecoder,这是解析整张图片的.当它判断高宽在一定范围内,不需要分块加载,就会调用这个解码
public Bitmap decode(Context context, NonNull Uri uri) throws Exception {Bitmap bitmap null;String uriString uri.toString();if (uriString.startsWith(FILE_PREFIX)) {String path uriString.substring(FILE_PREFIX.length());Log.e(TAG, mupdf trying to open path);try {document Document.openDocument(path);} catch (Exception e) {Log.e(TAG, e.getMessage());return null;}bitmap renderBitmap();} else {}if (bitmap null) {throw new RuntimeException(Mupdf image region decoder returned null bitmap - image format may not be supported);}return bitmap;}
这里先只支持path这种源.
剩下的解码,mupdf的解码就比较简单了
private Bitmap renderBitmap() {Page page document.loadPage(0);Rect b page.getBounds();float width (b.x1 - b.x0);float height (b.y1 - b.y0);Bitmap bitmap BitmapPool.getInstance().acquire((int) width, (int) height);float zoom 2f;Matrix ctm new Matrix(zoom, zoom);RectI bbox new RectI(page.getBounds().transform(ctm));float xscale width / (bbox.x1 - bbox.x0);float yscale height / (bbox.y1 - bbox.y0);ctm.scale(xscale, yscale);AndroidDrawDevice dev new AndroidDrawDevice(bitmap, 0, 0, 0, 0,bitmap.getWidth(), bitmap.getHeight());page.run(dev, ctm, null);page.destroy();dev.close();dev.destroy();return bitmap;}
图片只有一张,所以直接加载第0页,然后计算高宽,解码. MupdfPooledImageRegionDecoder,也只支持path.
public Point init(final Context context, NonNull final Uri uri) throws Exception {this.context context;this.uri uri;initialiseDecoder();return this.imageDimensions;}
这里初始化解码器,然后返回图片的高宽维度.
private void initialiseDecoder() {String uriString uri.toString();long fileLength Long.MAX_VALUE;if (uriString.startsWith(FILE_PREFIX)) {String path uriString.substring(FILE_PREFIX.length());File file new File(path);if (file.exists()) {fileLength file.length();}debug(mupdf trying to open path);try {decoder Document.openDocument(path);} catch (Exception e) {debug(e.getMessage());return;}} else {}if (fileLength SHOW_LOADING_SIZE) { //对于图片过大,需要一个等待状态,因为tiff很大,加载时间会比较长,可能要十几秒.showLoading();}this.fileLength fileLength;page decoder.loadPage(0); //这个速度很快,可以很快得到图片的高宽Rect b page.getBounds();int width (int) (b.x1 - b.x0);int height (int) (b.y1 - b.y0);this.imageDimensions.set(width, height);hideLoading();}
上面初始化后,如果判断图片的高宽超过指定范围,它会启动分块加载,后续的分块加载全在这个pooled类里面实现.
public Bitmap decodeRegion(NonNull android.graphics.Rect sRect, int sampleSize) {debug(Decode region sRect on thread Thread.currentThread().getName());if (sRect.width() imageDimensions.x || sRect.height() imageDimensions.y) {if (null decoder) {try {initialiseDecoder();} catch (Exception e) {}}}try {if (decoder ! null) {Bitmap bitmap renderBitmap(sRect, sampleSize);if (bitmap null) {throw new RuntimeException(Mupdf image decoder returned null bitmap - image format may not be supported);}return bitmap;}} catch (Exception e) {debug(e.getMessage());}return null;}
public Bitmap renderBitmap(android.graphics.Rect cropBound, int sampleSize) {float scale 1f / sampleSize; 缩放这里面要倒过来,其它没什么好说的了int pageW;int pageH;int patchX;int patchY;//如果页面的缩放为1,那么这时的pageW就是view的宽.pageW (int) (cropBound.width() * scale);pageH (int) (cropBound.height() * scale);patchX (int) (cropBound.left * scale);patchY (int) (cropBound.top * scale);Bitmap bitmap BitmapPool.getInstance().acquire(pageW, pageH);if (null page) {page decoder.loadPage(0);}com.artifex.mupdf.fitz.Matrix ctm new com.artifex.mupdf.fitz.Matrix(scale);AndroidDrawDevice dev new AndroidDrawDevice(bitmap, patchX, patchY, 0, 0, pageW, pageH);try {page.run(dev, ctm, null);} catch (Exception e) {debug(e.getMessage());}dev.close();dev.destroy();return bitmap;}
剩下的实现接口的方法就不多说了.这样一个图片查看器就实现了.
具备了一般图片app的不具备,或者不太支持的功能.
支持大的png,jpg,20mb,50mb,甚至更大的都可以快速打开.支持600mb(实测)的tiff图片的解析,初始化慢一些,后来就比较顺滑了. 到这里,打开300m的tiff是可以的,但是打开600m的会失败,打开2g的也是失败.因为mupdf的load-tiff.c解码前会经过它stream-read.c,这个里面判断了,如果超过一定值,会抛出异常,认为这是一个压缩炸弹,忽略.我把这个限制去了.600mb的图片没有问题.但2gb的依然不行.应该采用按需加载的形式. 虽然大图片能打开,但还是存在一些问题,tiff的解码不能按需加载,运行这个app后,会消耗大量的内存,导致其它app被回收了.但总算是能打开了. 关于查看tiff的apk,multi tiff view.apk这个虽然可以解析,但耗时也不短,另外移动缩放这些惨不忍睹, 它是目前我用的,唯一手机上能打开2gb的tiff的图片.
fast image,这个打开是各种慢,300mb就不行了. bigtiff,这个开源的解析库是因为tiff的4g限制,以前tiff不能存储大于4gb的图片,后来改了,而bigtiff可以存储40,400gb的图片,官网上有介绍的,只是没有看到解析应用.如果能包装成jni可调用的,应该会是个不错的.
另一个服务器解码的应用非常不错.具体的名字下周去公司电脑上把相关链接都放上.这个可以解析大图,按需加载,由于对c好久没弄,生疏了,想要弄到android上也不太容易.