使用 itext 从带有图像的 Html 字符串和 android 的 css 生成 Pdf
Generate Pdf from Html string with image and css for android using itext
我正在使用 itext-5.3.4.jar 和 xmlworker-1.2.1.jar 库从 html 字符串生成 pdf,html 包含图像徽标和内联 css.
我的 html 文件和图像在 Asset 文件夹中,使用这个库我的 pdf 生成成功但没有图像显示,也没有 css 样式排序。如果任何其他库或从 html 生成 pdf 的任何其他选项会有所帮助,任何人都建议我应该如何解决此问题。
我正在使用这些函数生成 pdf:
public static void generatePdfFromHtlm(String fileName, String htmlString){
try {
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), AppConfig.getContext().getPackageName() + "/" + "Pdf");
if (!mediaStorageDir.exists()) {
mediaStorageDir.mkdirs();
}
File fileWithinMyDir = new File(mediaStorageDir, fileName);
FontFactory.registerDirectories();
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream(fileWithinMyDir));
document.open();
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
Uri uri = Uri.parse("file:///android_asset/");
String newPath = uri.toString();
return newPath;
}
});
CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(false);
/*Pipeline<?> pipeline =
new CssResolverPipeline(cssResolver,
new HtmlPipeline(htmlContext,
new PdfWriterPipeline(document, writer)));*/
// Pipelines
PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
InputStream is = new ByteArrayInputStream(htmlString.getBytes());
p.parse(is);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
我的 html 文件是
<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if !IE]><!-->
<html lang="en"> <!--<![endif]-->
<!-- BEGIN HEAD -->
<head>
<meta charset="utf-8" />
<title>WeighInsheet</title>
<style type="text/css">
body { font-family:Arial; }
.Wrapper { border:1px solid #cccccc; height:auto; margin:0px 65px;}
.header { height:105px; margin:5px; float:left;}
.logo { width:100px; height:100px; float:left; }
.heading { width:600px;}
h2{ margin:40px 0px 0px 0px;font-size: 22px; font-weight:bold;}
h3{ margin:0px; font-weight:normal;font-size: 16px;}
table { border-collapse: collapse; border-spacing: 0; width:100%; }
table td { font-family: arial; font-size: 14px; padding: 10px 5px; border: 1px solid #ddd; }
table th { background-color:#000000; color:#ffffff; font-family: arial; font-size: 16px; font-weight: bold;
border: 1px solid #ddd; }
</style>
</head>
<!-- END HEAD -->
<!-- BEGIN BODY -->
<body>
<div class="Wrapper">
<div class="header">
<div class="logo"><img src="logo.jpg" class="logo"/></div>
<div class="heading" align="center">
<h2>Description</h2>
<h3>Title Meta</h3>
</div>
</div>
<table>
<thead>
##CHANGEHEADER##
</thead>
<tbody>
##CHANGEBODY##
</tbody>
</table>
</div>
</body>
<!-- END BODY -->
</html>
我的图像文件 "logo.jpg" 在资产文件夹中。
我已经修复了 Xml Worker class.
的 Pdf 生成问题
为了克服 CSS 问题,我创建了外部 css 文件并将其与 html.
一起应用
例如
InputStream is = new ByteArrayInputStream(aHtmlString.getBytes());
InputStream css = new ByteArrayInputStream(cssString.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, css);
对于图像显示问题,将您的图像从资产文件夹复制到手机内部文件夹。
将您的 img 标签添加到该文件夹图像路径。
例如
<img src="/storage/emulated/0/MyApp/Images/my_logo.jpg"/>
使用此方法将文件从资产复制到文件夹。
public static void listAssetFiles(String path,Context ctx,String folderPath) {
String [] list;
try {
list = ctx.getAssets().list(path);
if (list.length > 0) {
// This is a folder
for (String file : list) {
copyIntoFolder(file,ctx,path+"/",folderPath);
}
}
} catch (IOException e) {
}
}
public static void copyIntoFolder(String fileName, Context ctx, String filePath, String folderPath){
AssetManager assetManager = ctx.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filePath+fileName);
File outFile = new File(folderPath , fileName);
out = new FileOutputStream(outFile);
Utility.copyFile(in, out);
in.close();
// in = null;
out.flush();
out.close();
//out = null;
} catch(IOException e) {
Log.e("IOException", "copyIntoFolder: ",e );
}
}
Itext 不支持所有 css 属性下面是支持的 css 属性列表,请根据此支持的 css 属性创建您的 html。
不支持所有 iText Sharp css property.You 可以在 webview 中加载 html 并使用此代码生成 pdf。
private void createWebPrintJob(WebView webView) {
try {
PrintDocumentAdapter printAdapter;
String jobName = getString(R.string.app_name) + " Document";
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS).build();
File path = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/AamirPDF/");
path.mkdirs();
PdfPrint pdfPrint = new PdfPrint(attributes);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
printAdapter = webView.createPrintDocumentAdapter(jobName);
} else {
printAdapter = webView.createPrintDocumentAdapter();
}
pdfPrint.printNew(printAdapter, path, "output_" + System.currentTimeMillis() + ".pdf", getActivity().getCacheDir().getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
PdfPrint class 用于生成 PDF。
package com.example.nisarg.invoice;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.util.Log;
import com.example.nisarg.invoice.android.print.ProxyBuilder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static com.example.nisarg.invoice.Database.appglobal.context;
public class PdfPrint {
public static final String TAG = PdfPrint.class.getSimpleName();
public static PrintAttributes printAttributes;
File cacheFolder;
public PdfPrint(PrintAttributes printAttributes) {
this.printAttributes = printAttributes;
cacheFolder = new File(context.getFilesDir() + "/etemp/");
}
public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
/* public void print(final PrintDocumentAdapter printAdapter, final File path, final String fileName) {
printAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
try {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onWriteFinished")) {
// pdfCallback.onPdfCreated();
} else {
Log.e(TAG, "Layout failed");
// pdfCallback.onPdfFailed();
}
return null;
}
}, null);
printAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(path, fileName), new CancellationSignal(), callback);
} catch (IOException e) {
e.printStackTrace();
}
}
}, null);
}*/
public void printNew(final PrintDocumentAdapter printAdapter, final File path, final String fileName, final String fileNamenew) {
try {
printAdapter.onStart();
printAdapter.onLayout(null, printAttributes, new CancellationSignal(), getLayoutResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onLayoutFinished")) {
onLayoutSuccess(printAdapter, path, fileName, fileNamenew);
} else {
Log.e(TAG, "Layout failed");
}
return null;
}
}, new File(fileNamenew)), new Bundle());
} catch (Exception e) {
e.printStackTrace();
}
}
private void onLayoutSuccess(PrintDocumentAdapter printAdapter, File path, String fileName, String filenamenew) throws IOException {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onWriteFinished")) {
System.out.print("hello");
} else {
Log.e(TAG, "Layout failed");
}
return null;
}
}, new File(filenamenew));
printAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(path, fileName), new CancellationSignal(), callback);
}
private ParcelFileDescriptor getOutputFile(File path, String fileName) {
if (!path.exists()) {
path.mkdirs();
}
File file = new File(path, fileName);
try {
file.createNewFile();
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
} catch (Exception e) {
Log.e(TAG, "Failed to open ParcelFileDescriptor", e);
}
return null;
}
}
生成 class 的代理。[https://gist.github.com/brettwold/838c092329c486b6112c8ebe94c8007e]
对于代理构建器中使用的依赖项 class 在 gradle 中添加此行。
compile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'
我正在使用 itext-5.3.4.jar 和 xmlworker-1.2.1.jar 库从 html 字符串生成 pdf,html 包含图像徽标和内联 css.
我的 html 文件和图像在 Asset 文件夹中,使用这个库我的 pdf 生成成功但没有图像显示,也没有 css 样式排序。如果任何其他库或从 html 生成 pdf 的任何其他选项会有所帮助,任何人都建议我应该如何解决此问题。
我正在使用这些函数生成 pdf:
public static void generatePdfFromHtlm(String fileName, String htmlString){
try {
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), AppConfig.getContext().getPackageName() + "/" + "Pdf");
if (!mediaStorageDir.exists()) {
mediaStorageDir.mkdirs();
}
File fileWithinMyDir = new File(mediaStorageDir, fileName);
FontFactory.registerDirectories();
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream(fileWithinMyDir));
document.open();
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
Uri uri = Uri.parse("file:///android_asset/");
String newPath = uri.toString();
return newPath;
}
});
CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(false);
/*Pipeline<?> pipeline =
new CssResolverPipeline(cssResolver,
new HtmlPipeline(htmlContext,
new PdfWriterPipeline(document, writer)));*/
// Pipelines
PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
InputStream is = new ByteArrayInputStream(htmlString.getBytes());
p.parse(is);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
我的 html 文件是
<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if !IE]><!-->
<html lang="en"> <!--<![endif]-->
<!-- BEGIN HEAD -->
<head>
<meta charset="utf-8" />
<title>WeighInsheet</title>
<style type="text/css">
body { font-family:Arial; }
.Wrapper { border:1px solid #cccccc; height:auto; margin:0px 65px;}
.header { height:105px; margin:5px; float:left;}
.logo { width:100px; height:100px; float:left; }
.heading { width:600px;}
h2{ margin:40px 0px 0px 0px;font-size: 22px; font-weight:bold;}
h3{ margin:0px; font-weight:normal;font-size: 16px;}
table { border-collapse: collapse; border-spacing: 0; width:100%; }
table td { font-family: arial; font-size: 14px; padding: 10px 5px; border: 1px solid #ddd; }
table th { background-color:#000000; color:#ffffff; font-family: arial; font-size: 16px; font-weight: bold;
border: 1px solid #ddd; }
</style>
</head>
<!-- END HEAD -->
<!-- BEGIN BODY -->
<body>
<div class="Wrapper">
<div class="header">
<div class="logo"><img src="logo.jpg" class="logo"/></div>
<div class="heading" align="center">
<h2>Description</h2>
<h3>Title Meta</h3>
</div>
</div>
<table>
<thead>
##CHANGEHEADER##
</thead>
<tbody>
##CHANGEBODY##
</tbody>
</table>
</div>
</body>
<!-- END BODY -->
</html>
我的图像文件 "logo.jpg" 在资产文件夹中。
我已经修复了 Xml Worker class.
的 Pdf 生成问题为了克服 CSS 问题,我创建了外部 css 文件并将其与 html.
一起应用例如
InputStream is = new ByteArrayInputStream(aHtmlString.getBytes());
InputStream css = new ByteArrayInputStream(cssString.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, css);
对于图像显示问题,将您的图像从资产文件夹复制到手机内部文件夹。
将您的 img 标签添加到该文件夹图像路径。
例如
<img src="/storage/emulated/0/MyApp/Images/my_logo.jpg"/>
使用此方法将文件从资产复制到文件夹。
public static void listAssetFiles(String path,Context ctx,String folderPath) {
String [] list;
try {
list = ctx.getAssets().list(path);
if (list.length > 0) {
// This is a folder
for (String file : list) {
copyIntoFolder(file,ctx,path+"/",folderPath);
}
}
} catch (IOException e) {
}
}
public static void copyIntoFolder(String fileName, Context ctx, String filePath, String folderPath){
AssetManager assetManager = ctx.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filePath+fileName);
File outFile = new File(folderPath , fileName);
out = new FileOutputStream(outFile);
Utility.copyFile(in, out);
in.close();
// in = null;
out.flush();
out.close();
//out = null;
} catch(IOException e) {
Log.e("IOException", "copyIntoFolder: ",e );
}
}
Itext 不支持所有 css 属性下面是支持的 css 属性列表,请根据此支持的 css 属性创建您的 html。
不支持所有 iText Sharp css property.You 可以在 webview 中加载 html 并使用此代码生成 pdf。
private void createWebPrintJob(WebView webView) {
try {
PrintDocumentAdapter printAdapter;
String jobName = getString(R.string.app_name) + " Document";
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS).build();
File path = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/AamirPDF/");
path.mkdirs();
PdfPrint pdfPrint = new PdfPrint(attributes);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
printAdapter = webView.createPrintDocumentAdapter(jobName);
} else {
printAdapter = webView.createPrintDocumentAdapter();
}
pdfPrint.printNew(printAdapter, path, "output_" + System.currentTimeMillis() + ".pdf", getActivity().getCacheDir().getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
PdfPrint class 用于生成 PDF。
package com.example.nisarg.invoice;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.util.Log;
import com.example.nisarg.invoice.android.print.ProxyBuilder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static com.example.nisarg.invoice.Database.appglobal.context;
public class PdfPrint {
public static final String TAG = PdfPrint.class.getSimpleName();
public static PrintAttributes printAttributes;
File cacheFolder;
public PdfPrint(PrintAttributes printAttributes) {
this.printAttributes = printAttributes;
cacheFolder = new File(context.getFilesDir() + "/etemp/");
}
public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
/* public void print(final PrintDocumentAdapter printAdapter, final File path, final String fileName) {
printAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
try {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onWriteFinished")) {
// pdfCallback.onPdfCreated();
} else {
Log.e(TAG, "Layout failed");
// pdfCallback.onPdfFailed();
}
return null;
}
}, null);
printAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(path, fileName), new CancellationSignal(), callback);
} catch (IOException e) {
e.printStackTrace();
}
}
}, null);
}*/
public void printNew(final PrintDocumentAdapter printAdapter, final File path, final String fileName, final String fileNamenew) {
try {
printAdapter.onStart();
printAdapter.onLayout(null, printAttributes, new CancellationSignal(), getLayoutResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onLayoutFinished")) {
onLayoutSuccess(printAdapter, path, fileName, fileNamenew);
} else {
Log.e(TAG, "Layout failed");
}
return null;
}
}, new File(fileNamenew)), new Bundle());
} catch (Exception e) {
e.printStackTrace();
}
}
private void onLayoutSuccess(PrintDocumentAdapter printAdapter, File path, String fileName, String filenamenew) throws IOException {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onWriteFinished")) {
System.out.print("hello");
} else {
Log.e(TAG, "Layout failed");
}
return null;
}
}, new File(filenamenew));
printAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(path, fileName), new CancellationSignal(), callback);
}
private ParcelFileDescriptor getOutputFile(File path, String fileName) {
if (!path.exists()) {
path.mkdirs();
}
File file = new File(path, fileName);
try {
file.createNewFile();
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
} catch (Exception e) {
Log.e(TAG, "Failed to open ParcelFileDescriptor", e);
}
return null;
}
}
生成 class 的代理。[https://gist.github.com/brettwold/838c092329c486b6112c8ebe94c8007e]
对于代理构建器中使用的依赖项 class 在 gradle 中添加此行。
compile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'