gpt4 book ai didi

android - 如何实现异步加载页面的 PDF 查看器

转载 作者:技术小花猫 更新时间:2023-10-29 10:26:31 29 4
gpt4 key购买 nike

我们需要让我们的移动应用程序的用户能够以快速、流畅的体验浏览杂志,并且感觉是平台原生的(类似于 iBooks/Google Books)。

我们需要的一些功能是能够看到整本杂志的缩略图,以及搜索特定文本。

问题是我们的杂志超过 140 页,我们不能强制用户必须事先完整下载整本电子书/PDF。我们需要异步加载页面,即让用户无需完全下载内容即可开始阅读。

我研究了 iOS 的 PDFKit,但是我没有在文档中找到任何关于异步下载 PDF 的提及。

是否有任何解决方案/库可以在 iOS 和 Android 上实现此功能?

最佳答案

你要找的是linearization,根据this answer .

The first object immediately after the %PDF-1.x header line shall contain a dictionary key indicating the /Linearized property of the file.

This overall structure allows a conforming reader to learn the complete list of object addresses very quickly, without needing to download the complete file from beginning to end:

  • The viewer can display the first page(s) very fast, before the complete file is downloaded.

  • The user can click on a thumbnail page preview (or a link in the ToC of the file) in order to jump to, say, page 445, immediately after the first page(s) have been displayed, and the viewer can then request all the objects required for page 445 by asking the remote server via byte range requests to deliver these "out of order" so the viewer can display this page faster. (While the user reads pages out of order, the downloading of the complete document will still go on in the background...)

您可以使用 this native library对 PDF 进行线性化

但是我不建议让它渲染 PDF 不会快速、流畅或感觉原生。出于这些原因,据我所知,没有执行线性化 的 native 移动应用程序。此外,您必须为 PDF 创建自己的渲染引擎,因为大多数 PDF 查看库不支持 linearization 。您应该做的是在服务器端将 PDF 中的每个单独页面转换为 HTML,并让客户端仅在需要时加载页面并缓存。我们还将单独保存 PDF 计划文本,以便进行搜索。这样一切都会很顺利,因为资源将被延迟加载。为了实现这一点,您可以执行以下操作。

首先在服务器端,每当您发布 PDF 时,PDF 的页面都应拆分为 HTML 文件,如上文所述。还应该从这些页面生成页面缩略图。假设您的服务器正在使用 flask 微框架python 上运行,这就是您所做的。

from flask import Flask,request
from werkzeug import secure_filename
import os
from pyPdf import PdfFileWriter, PdfFileReader
import imgkit
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io
import sqlite3
import Image

app = Flask(__name__)


@app.route('/publish',methods=['GET','POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
filePath = "pdfs/"+secure_filename(f.filename)
f.save(filePath)
savePdfText(filePath)
inputpdf = PdfFileReader(open(filePath, "rb"))

for i in xrange(inputpdf.numPages):
output = PdfFileWriter()
output.addPage(inputpdf.getPage(i))
with open("document-page%s.pdf" % i, "wb") as outputStream:
output.write(outputStream)
imgkit.from_file("document-page%s.pdf" % i, "document-page%s.jpg" % i)
saveThum("document-page%s.jpg" % i)
os.system("pdf2htmlEX --zoom 1.3 pdf/"+"document-page%s.pdf" % i)

def saveThum(infile):
save = 124,124
outfile = os.path.splitext(infile)[0] + ".thumbnail"
if infile != outfile:
try:
im = Image.open(infile)
im.thumbnail(size, Image.ANTIALIAS)
im.save(outfile, "JPEG")
except IOError:
print("cannot create thumbnail for '%s'" % infile)

def savePdfText(data):
fp = open(data, 'rb')
rsrcmgr = PDFResourceManager()
retstr = io.StringIO()
codec = 'utf-8'
laparams = LAParams()
device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
# Create a PDF interpreter object.
interpreter = PDFPageInterpreter(rsrcmgr, device)
# Process each page contained in the document.
db = sqlite3.connect("pdfText.db")
cursor = db.cursor()
cursor.execute('create table if not exists pagesTextTables(id INTEGER PRIMARY KEY,pageNum TEXT,pageText TEXT)')
db.commit()
pageNum = 1
for page in PDFPage.get_pages(fp):
interpreter.process_page(page)
data = retstr.getvalue()
cursor.execute('INSERT INTO pagesTextTables(pageNum,pageText) values(?,?) ',(str(pageNum),data ))
db.commit()
pageNum = pageNum+1

@app.route('/page',methods=['GET','POST'])
def getPage():
if request.method == 'GET':
page_num = request.files['page_num']
return send_file("document-page%s.html" % page_num, as_attachment=True)

@app.route('/thumb',methods=['GET','POST'])
def getThum():
if request.method == 'GET':
page_num = request.files['page_num']
return send_file("document-page%s.thumbnail" % page_num, as_attachment=True)

@app.route('/search',methods=['GET','POST'])
def search():
if request.method == 'GET':
query = request.files['query ']
db = sqlite3.connect("pdfText.db")
cursor = db.cursor()
cursor.execute("SELECT * from pagesTextTables Where pageText LIKE '%"+query +"%'")
result = cursor.fetchone()
response = Response()
response.headers['queryResults'] = result
return response

这里解释了 flask 应用程序正在做什么。

  1. /publish 路由负责发布您的杂志,将页面转换为 HTML,将 PDF 文本保存到 SQlite 数据库并为这些页面生成缩略图。我用过 pyPDF用于将 PDF 拆分为单独的页面,pdfToHtmlEx将页面转换为 HTML,imgkit生成这些 HTML 图像和 PIL从这些图像生成拇指。此外,一个简单的 Sqlite db 可以保存页面的文本。
  2. /page/thumb/search 路由是不言自明的。它们只是返回 HTML、缩略图或搜索查询结果。

其次,在客户端,只要用户滚动到它,您就可以下载 HTML 页面。让我举一个Android操作系统的例子。首先,您需要创建一些 Utils 来处理 GET 请求者

public static byte[] GetPage(int mPageNum){
return CallServer("page","page_num",Integer.toString(mPageNum))
}

public static byte[] GetThum(int mPageNum){
return CallServer("thumb","page_num",Integer.toString(mPageNum))
}

private static byte[] CallServer(String route,String requestName,String requestValue) throws IOException{

OkHttpClient client = new OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build();
MultipartBody.Builder mMultipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart(requestName,requestValue);

RequestBody mRequestBody = mMultipartBody.build();
Request request = new Request.Builder()
.url("yourUrl/"+route).post(mRequestBody)
.build();
Response response = client.newCall(request).execute();
return response.body().bytes();
}

上面的帮助器实用程序简单地为您处理对服务器的查询,它们应该是不言自明的。接下来,您只需创建一个带有 WebView viewHolder 或更好的 advanced webviewRecyclerView因为它将为您提供更多自定义功能。

    public static class ViewHolder extends RecyclerView.ViewHolder {
private AdvancedWebView mWebView;
public ViewHolder(View itemView) {
super(itemView);
mWebView = (AdvancedWebView)itemView;}
}
private class ContentAdapter extends RecyclerView.Adapter<YourFrament.ViewHolder>{
@Override
public ViewHolder onCreateViewHolder(ViewGroup container, int viewType) {

return new ViewHolder(new AdvancedWebView(container.getContext()));
}

@Override
public int getItemViewType(int position) {

return 0;
}

@Override
public void onBindViewHolder( ViewHolder holder, int position) {
handlePageDownload(holder.mWebView);
}
private void handlePageDownload(AdvancedWebView mWebView){....}

@Override
public int getItemCount() {
return numberOfPages;
}
}

应该就是这样了。

关于android - 如何实现异步加载页面的 PDF 查看器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50195842/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com