android pdf框架-11,查看圖片

前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上也不太容易.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42310.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42310.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42310.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C++】string的底層原理及實現

文章目錄 string類的存儲結構默認成員函數構造函數析構函數拷貝構造函數賦值重載 容量操作size()capacity()reserve()resize()clear() 遍歷與訪問operator[ ]迭代器范圍與for 增刪查改push_back()pop_back()append()operatorinsert()erase()c_str()find()substr() 非成員函數op…

c#的List<T>的SelectMany 和Select

在C#中&#xff0c;List<T>&#xff08;以及任何實現了IEnumerable<T>的集合&#xff09;的Select和SelectMany擴展方法都是LINQ&#xff08;Language Integrated Query&#xff09;的一部分&#xff0c;用于對集合中的元素進行查詢和轉換。 盡管它們的作用有些相…

Virtualbox和ubuntu之間的關系

1、什么是ubuntu Ubuntu 是一個類似于 Windows 的操作系統&#xff0c;但它是基于 Linux 內核開發的開源操作系統 2、什么是Virtualbox VirtualBox 是一款虛擬機軟件&#xff0c;使我們可以物理機上創建和運行虛擬機 也就是說,VirtualBox 提供了一個可以安裝和運行其他操作系…

力扣考研經典題 反轉鏈表

核心思想 頭插法&#xff1a; 不斷的將cur指針所指向的節點放到頭節點之前&#xff0c;然后頭節點指向cur節點&#xff0c;因為最后返回的是head.next 。 解題思路 1.如果頭節點是空的&#xff0c;或者是只有一個節點&#xff0c;只需要返回head節點即可。 if (head null …

算法訓練營day70

題目1&#xff1a;108. 冗余連接 (kamacoder.com) #include<iostream> #include<vector>using namespace std;int n; vector<int> father(10001, 0);void init() {for(int i 1;i < n;i) father[i] i; }int find(int u) {return u father[u] ? u : fa…

Echarts中的熱力圖和漏斗圖(在Vue中使用熱力圖和漏斗圖)

熱力圖 (Heatmap) Echarts的熱力圖用于展示兩個維度數據矩陣中的值分布情況。它通過在平面上劃分成多個矩形區域&#xff0c;并用不同的顏色填充這些區域來表示數據的大小或強度。顏色漸變從淺到深通常映射著數值從小到大&#xff0c;從而直觀展示數據的集中程度和分布模式。熱…

Mojolicious測試驅動開發:單元與集成測試的藝術

標題&#xff1a;Mojolicious測試驅動開發&#xff1a;單元與集成測試的藝術 Mojolicious是一個現代化的Perl Web開發框架&#xff0c;它不僅提供了強大的Web應用開發能力&#xff0c;還內置了豐富的測試工具來支持單元測試和集成測試。本文將深入探討如何在Mojolicious中進行…

人工智能期末復習簡答題

簡答: 子句集的化簡(1).消去連接詞”—>”和”<—>” (2)減少否定符號的轄域 (3)對變元標準化 (4)化為前束范式 (5)消去存在量詞 (6)化為Skolem標準形 (7)消去全稱量詞 (8)消去合取詞 (9)更換變元名稱 2.在狀態空間搜索中,Open表與Close…

半同步主從復制

半同步主從復制的概念 半同步主從復制&#xff08;Semisynchronous Replication, SBR&#xff09;是MySQL數據庫中的一種數據復制方式&#xff0c;它在異步復制的基礎上增加了一定程度的同步性&#xff0c;旨在提高數據安全性&#xff0c;減少數據丟失的風險。 半同步主從復制…

LeetCode 3101.交替子數組計數:等差數列求和(較詳題解)

【LetMeFly】3101.交替子數組計數&#xff1a;等差數列求和&#xff08;較詳題解&#xff09; 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/count-alternating-subarrays/ 給你一個二進制數組 nums 。 如果一個子數組中 不存在 兩個 相鄰 元素的值 相同 的情況&a…

階段三:項目開發---大數據開發運行環境搭建:任務8:安裝配置Redis

任務描述 知識點&#xff1a;安裝配置Redis 重 點&#xff1a; 安裝配置Redis 難 點&#xff1a;無 內 容&#xff1a; Redis&#xff08;Remote Dictionary Server )&#xff0c;即遠程字典服務&#xff0c;是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可…

【C++:運算符重載】

運算符重載 特點&#xff1a; 函數名由operator運算符組成 注&#xff1a; 不能通過其他符號創建新的操作符&#xff0c;只能使用C/C語法存在的操作符重載操作符必須有一個類類型參數&#xff0c;原因&#xff1a;不能重載操作符改變內置類型的行為當類成員操作符重載時&#…

web自動化(五)上傳文件

我們需要準備一個上傳文件的html&#xff0c;創建a.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>文件上傳示例</title> </head> <body><form action"/upload"…

電路基礎知識匯總

1.0 串連&#xff0c;并聯&#xff0c;混連 串聯的定義 電路串聯是一種電路元件的連接方式&#xff0c;其中各個元件沿著單一路徑互相連接&#xff0c;形成一個連續的鏈。在串聯電路中&#xff0c;每個節點最多只連接兩個元件&#xff0c;這意味著電流只有一條路徑可以通過整個…

Apache Seata Mac下的Seata Demo環境搭建

本文來自 Apache Seata官方文檔&#xff0c;歡迎訪問官網&#xff0c;查看更多深度文章。 本文來自 Apache Seata官方文檔&#xff0c;歡迎訪問官網&#xff0c;查看更多深度文章。 Mac下的Seata Demo環境搭建&#xff08;AT模式&#xff09; 前言 最近因為工作需要&#xf…

Git教程

文章目錄 Git分布式版本控制工具版本控制器的方式常用命令遠程倉庫Tip Git分布式版本控制工具 ? Git是一個開源的分布式版本控制系統&#xff0c;可以有效、高速地處理從很小到非常大的項目版本管理。 ? Git是分布式的&#xff0c;Git不需要有中心服務器&#xff0c;我們每…

【感謝告知】本賬號內容調整,聚焦于Google賬號和產品的使用經驗和問題案例分析

親愛的各位朋友&#xff1a; 感謝您對本賬號的關注和支持&#xff01; 基于對朋友們需求的分析和個人興趣的轉變&#xff0c;該賬號從今天將對內容做一些調整&#xff0c;有原來的內容改為Google&#xff08;谷歌&#xff09;賬號和產品的使用經驗&#xff0c;以及相關問題的…

24西安電子科技大學經濟與管理學院—考研錄取情況

24西安電子科技大學—經理與管理學院—考研錄取統計 01、經理與管理學院各個方向 02、24經濟與管理近三年復試分數線對比 1、經管院24年院線相對于23年院線普遍下降2-15分&#xff0c;個別專業上漲4-10分。 2、經管院應用經濟學2024年院線350分&#xff1b;管理科學與工程院線…

java join與yield方法

join() join() 方法的主要作用是使當前線程&#xff08;調用 join() 方法的線程&#xff09;等待目標線程完成執行。當目標線程執行完畢后&#xff0c;當前線程才會繼續執行。 代碼示例&#xff1a; public class JoinExample {public static void main(String[] args) {Thr…

保研復習 | 數據結構

目錄 CH1?緒論☆ 數據項、數據元素、數據結構☆ 邏輯結構和存儲結構的區別☆ 順序存儲結構和鏈式存儲結構的比較☆ 算法的重要特性☆ 算法的復雜度 CH2?線性表☆ 單鏈表 CH3?棧、隊列和數組☆ 棧和堆是什么&#xff1f;☆ 棧在括號匹配中的應用☆ 棧在表達式求值中的應用☆ …