我在Android上进行PDF打印时遇到了麻烦。我要做的是在WebView中渲染一些HTML,然后在PDF画布上绘制WebView内容,最后将PDF写入文件。我遇到的问题是,当我绘制到PDF画布时,即使有足够的画布,内容也会被剪裁。我已经尝试使用.clipRect(Rect rect, Op op)
来调整画布大小,这种方式有效,但不如我喜欢的那样好。
我也不知道如何将HTML px测量值可靠地转换为PDF PostScript 1/72英寸测量值。
这是我正在使用的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView wv = (WebView) this.findViewById(R.id.webView1);
wv.loadUrl("file:///android_asset/temp.html");
}
public void button1onClick(View v)
{
//Create PDF document
PdfDocument doc = new PdfDocument();
//Create A4 sized PDF page
PageInfo pageInfo = new PageInfo.Builder(595,842,1).create();
Page page = doc.startPage(pageInfo);
WebView wv = (WebView) this.findViewById(R.id.webView1);
page.getCanvas().setDensity(200);
//Draw the webview to the canvas
wv.draw(page.getCanvas());
doc.finishPage(page);
try
{
//Create the PDF file
File root = Environment.getExternalStorageDirectory();
File file = new File(root,"webview.pdf");
FileOutputStream out = new FileOutputStream(file);
doc.writeTo(out);
out.close();
doc.close();
//Open the PDF
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
}
catch(Exception e)
{
throw new RuntimeException("Error generating file", e);
}
}
基本上,程序只是将temp.html文件加载到webview,并向我呈现一个可用于创建PDF的按钮。
temp.html文件如下所示:
<html>
<head>
<style>
div.border
{
width:600px;
height:800px;
border:1px solid black;
}
</style>
</head>
<body>
<div class="border"></div>
</body>
以下是手动添加黑色边框以显示比例的结果:
我非常感谢有关如何在Android上可靠地将HTML转换为PDF的一些提示,而不使用需要商业用途许可的库。
答案 0 :(得分:3)
要点: 不要修改密度(应该在您的设备上设置,可能是中等160 dpi),而是使用比例尺。 如果你只需要PDF中的HTML页面的位图(没有超链接功能),这是有效的。 这是您的代码生成的代码,使用以下代码:
//Create PDF document
PdfDocument doc = new PdfDocument();
//Create A4 sized PDF page
int my_width = 595;
int my_height = 842;
PageInfo pageInfo = new PageInfo.Builder(my_width,my_height,1).create();
// PageInfo pageInfo = new PageInfo.Builder(650,850,1).create();
Page page = doc.startPage(pageInfo);
WebView wv = (WebView) this.findViewById(R.id.webView1);
Canvas canvas = page.getCanvas();
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
final DisplayMetrics displayMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
float density = displayMetrics.density;
int wvWidth = wv.getWidth();
int wvHeight= wv.getHeight();
float wvScaleX= wv.getScaleX();
float wvScaleY= wv.getScaleY();
// canvas.setDensity(100);//200 Bitmap.DENSITY_NONE
int cdensity = canvas.getDensity();
float scaleWidth = (float)width/(float)my_width;
float scaleHeight = (float)height/(float)my_height;
canvas.scale(scaleWidth, scaleHeight);
Log.e("button1onClick","canvas width:" + canvas.getHeight() + " canvas height:" + canvas.getWidth());
Log.e("button1onClick","metrics width:" + width + " metrics height:" + height + "metrics density:" + density);
Log.e("button1onClick"," wvWidth:" + wvWidth + " wvHeight:" + wvHeight);
Log.e("button1onClick"," scaleWidth: " + scaleWidth +
" scaleHeight:" + scaleHeight +" cdensity:" + cdensity);
Paint paint = new Paint();
// paint.setStyle(Style.FILL);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
//Draw the webview to the canvas
wv.draw(canvas);
canvas.scale(1f, 1f);
canvas.drawRect(0, 0, canvas.getWidth()-1, canvas.getHeight()-1, paint);
canvas.drawText("Direct drawn Red Rectangle to fill page canvas 0, 0," +
canvas.getWidth() + "," + canvas.getHeight(), 100, 100, paint);
doc.finishPage(page);
答案 1 :(得分:1)
基本上对我来说,这一切都归结为Hyper-Link和外部.css支持(级联样式表)(X)HTML到PDF(类)。
div border is not supported on android in anyway I have found in free to use code.
div颜色是的,那是什么。 PdfDocument。 (API 19或以上)。 也许是一个更好的lib itextg(API16可能更少)(itext子集省略android框架不允许的类)。 (使用XMLWorkerHelper类) (div border == no)但是td ==是的yippi! (pdf支持的边框元素)。 也许是itextg的时间。 一致性: http://demo.itextsupport.com/xmlworker/itextdoc/CSS-conformance-list.htm 很可怜。 继续... 不确定你想要什么, 如果它只是一个边界我可以在td元素上做到这一点。 很确定你想要更多。 继续... 我可以使用支持的元素进行外部.css文件读取(参见链接),非常酷。 (飞碟......不适合我和#34; JAVA图书馆&#34;不支持Android)。所以这样的事情:
public boolean createPDF(String htmlText, String absoluteFilePath) throws DocumentException, CssResolverException { try { // step 1 new doc Document document = new Document(); // step 2 create PdfWriter PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(absoluteFilePath)); writer.setInitialLeading(12.5f); // step 3 open doc document.open(); document.add(new Chunk("")); // HtmlPipelineContext htmlContext = new HtmlPipelineContext(null); htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); CSSResolver cssResolver = null; if(true) { // step 4 CSS cssResolver = new StyleAttrCSSResolver(); java.io.InputStream csspathtest = null; try { csspathtest = getResources().getAssets().open("itextweb.css"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } CssFile cssfiletest = XMLWorkerHelper.getCSS(csspathtest); cssResolver.addCss(cssfiletest); Log.i("cssfiletest",cssfiletest.toString()); } else { cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(false); cssResolver.addCss("td {border-right: white .1px solid;}", true); cssResolver.addCss("div {border: green 2px solid;}", true); } Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer))); XMLWorker worker1 = new XMLWorker(pipeline, true); XMLParser p = new XMLParser(worker1); ByteArrayInputStream inputRawHTML = new ByteArrayInputStream(htmlText.getBytes()); Tidy tidy = new Tidy(); // obtain a new Tidy instance tidy.setXHTML(true); // set desired config options using tidy setters ByteArrayOutputStream output = new ByteArrayOutputStream(); // tidy.setCharEncoding(Configuration.UTF8); tidy.parse(inputRawHTML, output); String preparedText = output.toString("UTF-8"); Log.i("CHECKING", "JTidy Out: " + preparedText); ByteArrayInputStream inputPREP = new ByteArrayInputStream(preparedText.getBytes()); // step 5 parse html p.parse(inputPREP);
所以有些图片:
代表HTML:
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <title>My first web page</title> <LINK REL=StyleSheet HREF="itextweb.css" TYPE="text/css" MEDIA=screen> </head> <body> <!-- The <div> tag enables you to group sections of HTML elements together and format them with CSS.--> <div> <p>helloworld with green border if style worked</p> </div> <div> <h1>helloworld with green border if style worked</h1> </div> <div style="border: 3px yellow solid"> <p>"SHOULD be red text if p style worked, else yellow border from div style" </p> other text div yellow inline border </div> <div style="color: red">red text if div style worked</div> <h2>unsorted list</h2> <ul> <li>To learn HTML</li> <li>To show off</li> </ul> <table> <tr> <td>Row 1, cell 1</td> <td>Row 1, cell 2</td> <td>Row 1, cell 3</td> </tr> </table> <textarea rows="5" cols="20">A big load of text</textarea> <a href="http://www.htmldog.com">blue HTML Dog link</a> </body> </html>
答案 2 :(得分:1)
这是有趣的地方。 那些画布的硬编码值怎么样?: -
PageInfo pageInfo = new PageInfo.Builder(595,842,1).create();
您需要宽度和高度的WebView 目录, 加载HTML后。 是的,但是没有 getContentWidth 方法(只有视图端口值),AND getContentHeight ()不准确!
答案:子类 WebView:
/* Jon Goodwin */ package com.example.html2pdf;//your package import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.webkit.WebView; class CustomWebView extends WebView { public int rawContentWidth = 0; //unneeded public int rawContentHeight = 0; //unneeded Context mContext = null; //unneeded public CustomWebView(Context context) //unused constructor { super(context); mContext = this.getContext(); } public CustomWebView(Context context, AttributeSet attrs) //inflate constructor { super(context,attrs); mContext = context; } public int getContentWidth() { int ret = super.computeHorizontalScrollRange();//working after load of page rawContentWidth = ret; return ret; } public int getContentHeight() { int ret = super.computeVerticalScrollRange(); //working after load of page rawContentHeight = ret; return ret; } public void onPageFinished(WebView page, String url) { //never gets called, don't know why, but getContentHeight & getContentWidth function after load of page rawContentWidth = ((CustomWebView) page).getContentWidth(); rawContentHeight = ((CustomWebView) page).getContentHeight(); Log.e("CustomWebView:onPageFinished","ContentWidth: " + ((CustomWebView) page).getContentWidth()); Log.e("CustomWebView:onPageFinished","ContentHeight: " + ((CustomWebView) page).getContentHeight()); } //========= }//class //=========
在我修改的代码中(在另一个答案中)更改:
private CustomWebView wv; wv = (CustomWebView) this.findViewById(R.id.webView1); int my_width = wv.getContentWidth(); int my_height = wv.getContentHeight();
并将您的布局类条目从WebView更改为com.example.html2pdf.CustomWebView。
然后你好好去!
答案 3 :(得分:0)
我遇到了同样的问题。
我用非常简单的技巧解决了它。
将
MediaSize
设为PrintAttributes.MediaSize.ISO_A1
。这个解决方案的缺点是pdf大小:即使是一页PDF格式的文本也只有5MB左右。
工作代码段 (从视图生成pdf并将其导出到文件):
@TargetApi(19) private void generatePdf() { PrintAttributes.Builder builder = new PrintAttributes.Builder(); builder.setColorMode(PrintAttributes.COLOR_MODE_COLOR); builder.setMediaSize(PrintAttributes.MediaSize.ISO_A1); // or ISO_A0 builder.setMinMargins(PrintAttributes.Margins.NO_MARGINS); builder.setResolution(new PrintAttributes.Resolution("1", "label", 300, 300)); PrintedPdfDocument document = new PrintedPdfDocument(this, builder.build()); PdfDocument.Page page = document.startPage(1); View content = yourView; content.draw(page.getCanvas()); document.finishPage(page); try { File file = new File(getExternalFilesDir(null).getAbsolutePath(), "document.pdf"); document.writeTo(new FileOutputStream(file)); } catch (IOException e) { Log.e("cannot generate pdf", e); } document.close(); }