I want to make PDFs exported by Jasper PDF/UA compliant, but limitations of Jasper are preventing me from doing so. Client is pressuring us to get this done properly.
PDF/UA has a lot of requirements, including but not limited to displaying title and language, embedding fonts, and adding alternate text to images. So far, I have set all the 508 PDF tags, set properties to display title and language, embedded fonts, and added alt text to images all in Jaspersoft Studio. I have also appended the PDF/UA identifier to the output PDF (i.e. after the PDF was generated) via Apache PDFBox. We are using Jaspersoft Studio v6.6.0 coupled with Jasper Reports Library v6.4.0 and Oracle for the DB. From what I've read, Jasper has limited capabilities in this regard due to itext being downgraded back to v2.1.7.js6 because of licensing issues.
<jasperReport xlmns=...>
... // other properties
<property name="net.sf.jasperreports.awt.ignore.missing.font" value="false"/>
<property name="net.sf.jasperreports.export.xls.detect.cell.type" value="false"/>
<property name="net.sf.jasperreports.export.xls.sheet.names.all" value="REPORT SHEET NAME"/>
<property name="net.sjasperreports.default.pdf.font.name" value="Times-Roman"/>
<property name="net.sf.jasperreports.export.xls.ignore.graphics" value="false"/>
<property name="net.sf.jasperreports.default.pdf.embedded" value="true"/>
<property name="net.sf.jasperreports.export.pdf.metadata.title" value="MY REPORT TITLE"/>
<property name="net.sf.jasperreports.export.pdf.display.metadata.title" value="true"/>
<property name="net.sf.jasperreports.export.pdf.tagged" value="true"/>
<property name="net.sf.jasperreports.export.pdf.tag.language" value="EN-US"/>
... // parameters, stored proc call, headings, etc.
<!-- Possible PDF 508 tags to be set on text fields -->
<property name="net.sf.jasperreports.export.pdf.tag.table" value="start"/>
<property name="net.sf.jasperreports.export.pdf.tag.th" value="full"/>
<property name="net.sf.jasperreports.export.pdf.tag.tr" value="start">
<property name="net.sf.jasperreports.export.pdf.tag.td" value="full">
<property name="net.sf.jasperreports.export.pdf.tag.tr" value="end">
<property name="net.sf.jasperreports.export.pdf.tag.table" value="start"/>
...
</jasperReport>
... // other imports
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.XMPSchema;
import org.apache.xmpbox.xml.XmpSerializer;
... // more imports
public class ReportResult {
... // other methods
/*
* #param pdf - The pdf instance created from BAOS
* #param title - Document
* #return BAOS containing metadata (UA-identifier, title)
*/
private ByteArrayOutputStream appendXMPMetaData(PDDocument pdf, String title) throws TransformerException, IOException {
XMPMetadata xmp = XMPMetadata.createXMPMetadata();
xmp.createAndAddDublinCoreSchema();
xmp.getDublinCoreSchema().setTitle(title);
xmp.getDublinCoreSchema().setDescription(title);
xmp.createAndAddPDFAExtensionSchemaWithDefaultNS();
xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfa/ns/schema#", "pdfaSchema");
xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfa/ns/property#", "pdfaProperty");
xmp.getPDFExtensionSchema().addNamespace("http://www.aiim.org/pdfua/ns/id/", "pdfuaid");
XMPSchema uaSchema = new XMPSchema(XMPMetadata.createXMPMetadata(),
"pdfaSchema", "pdfaSchema", "pdfaSchema");
uaSchema.setTextPropertyValue("schema", "PDF/UA Universal Accessibility Schema");
uaSchema.setTextPropertyValue("namespaceURI", "http://www.aiim.org/pdfua/ns/id/");
uaSchema.setTextPropertyValue("prefix", "pdfuaid");
XMPSchema uaProp = new XMPSchema(XMPMetadata.createXMPMetadata(),"pdfaProperty", "pdfaProperty", "pdfaProperty");
uaProp.setTextPropertyValue("name", "part");
uaProp.setTextPropertyValue("valueType", "Integer");
uaProp.setTextPropertyValue("category", "internal");
uaProp.setTextPropertyValue("description", "Indicates, which part of ISO 14289 standard is followed");
uaSchema.addUnqualifiedSequenceValue("property", uaProp);
xmp.getPDFExtensionSchema().addBagValue("schemas", uaSchema);
xmp.getPDFExtensionSchema().setPrefix("pdfuaid");
xmp.getPDFExtensionSchema().setTextPropertyValue("part", "1");
XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.serialize(xmp, baos, true);
PDMetadata metadata = new PDMetadata(pdf);
metadata.importXMPMetadata(baos.toByteArray());
pdf.getDocumentCatalog().setMetadata(metadata);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
pdf.save(byteArrayOutputStream);
pdf.close();
return byteArrayOutputStream;
}
protected void getJasperPDFDoc(ReportConfig reportConfig) throws IOException, TransformerException {
List<ReportParameter> reportParams = reportConfig.getReportParams();
... // cookies and printer config
Map imagesMap = new HashMap();
request.getSession(true).setAttribute("IMAGES_MAP", imagesMap);
ByteArrayOutputStream bs = ReportAccess.Instance.getInstance().generateJasperReport(
getCurrentUserId(), getCurrentUserName(), reportConfig, "PDF",
reportParams, getTmpImageUri(),
imagesMap, rptTemplateLoc);
if (bs != null) {
if (reportConfig.doPrint) {
response.setContentType("text/html");
} else {
log.debug("Got PDF report data");
String fileName = getReportFileName(reportConfig) + ".pdf";
response.setContentType("application/pdf");
String dispositionProperty = "attachment; filename=" + fileName;
response.setHeader("Content-disposition", dispositionProperty);
}
PDDocument pdf = PDDocument.load(new ByteArrayInputStream(bs.toByteArray()));
ByteArrayOutputStream baosWithMetaData = appendXMPMetaData(pdf, reportConfig.getDisplayName());
response.setHeader("Content-length", Integer.toString(baosWithMetaData.size()));
ServletOutputStream os = response.getOutputStream();
baosWithMetaData.writeTo(os);
os.flush();
os.close();
} else {
displayError("PDF");
}
}
... // other methods
}
/* REPORT MANAGER CLASS */
private static void generatePDFDoc(JasperPrint jasperPrint, ByteArrayOutputStream f) {
try {
JasperPrint jr = moveTableOfContents(jasperPrint);
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(new SimpleExporterInput(jr));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(f));
//configuration
SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
configuration.setCompressed(true);
configuration.setTagged(true);
configuration.setTagLanguage("EN-US");
//set configuration
exporter.setConfiguration(configuration);
//export to PDF
exporter.exportReport();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
I noticed a handful of errors reported by Adobe's Preflight checker as well as our client, listed below:
Non-standard tag present
Circular Role Map
Unknown Anchor cell appended to top-left of every page
Table is not properly recognized in table-editor view
Images showing my problem(s). Any help in this regard is kindly appreciated.
If you want to make things simpler, but different way, PD4ML v4 can be an option. There is a minimalistic sample on the page: https://pd4ml.tech/pdf-ua/
It uses available structure and meta info from input HTML/CSS to produce a valid tagged PDF/UA.
If the goal is to pass PDF/UA file format validation only (e.g. by Adobe's Preflight checker) it is sufficient just to choose Constants.PDFUA as an output format.
pd4ml.writePDF(fos, Constants.PDFUA);
If the goal is to produce Matterhorn Protocol-compliant PDFs (and pass a validation by PAC3 https://www.access-for-all.ch/en/pdf-lab/pdf-accessibility-checker-pac.html), most probably you would also need to align your input HTML: to add TITLE, ALT and LANG attributes, to make sure table structures and heading hierarchy are consistent etc.
Related
I am new to Mirth/JavaScript. I have a project where I need to add a segment to an incoming HL7 v3 XML file. I have tried the following JavaScript in the destination transformer;
tmp = msg.copy();
tmp.createSegment('templateId', ClinicalDocument, 1);
tmp.ClinicalDocument['templateId'][1]['#root'] ="2.16.840.1.113883.10.20.22.1.1";
This generates an error.
Also I need to place this new segment before the existing templateID segment.
Currently this is what we receive –
<ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sdtc="urn:hl7-org:sdtc">
<realmCode code="US" />
<typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040" /><br/>
<templateId root="2.16.840.1.113883.10.20.22.1.2" extension="2015-08-01" />
We want to add
Tranformed Output Desired -
Any help on how to accomplish this will be greatly appreciated.
Thank You
I understand your requirement in this way. That you need to add
<templateId root="2.16.840.1.113883.10.20.22.1.1" extension="2015-08-01" />
Exactly before the templateID
<templateId root="2.16.840.1.113883.10.20.22.1.2" extension="2015-08-01" />
If that's the requirement, this JAVA code will work
public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException, TransformerException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
// Source XML
File fXmlFile = new File("C:\\Labs\\POC\\Import_Export\\TEST.xml");
Document doc = dBuilder.parse(fXmlFile);
// Get the element after which template ID code has to be added
Node nodeName = doc.getElementsByTagName("typeId").item(0);
// Code to add new Template ID
Element newTemplateID = doc.createElement("templateId");
newTemplateID.setAttribute("root", "2.16.840.1.113883.10.20.22.1.1");
newTemplateID.setAttribute("extension", "2015-08-01");
// Inserting exactly on specific area
nodeName.getParentNode().insertBefore(newTemplateID, nodeName.getNextSibling());
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
// destination XML
StreamResult result = new StreamResult(new File("C:\\Labs\\POC\\Import_Export\\TESTNew.xml"));
transformer.transform(source, result);
}
you will get an XML like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sdtc="urn:hl7-org:sdtc">
<realmCode code="US"/>
<typeId extension="POCD_HD000040" root="2.16.840.1.113883.1.3"/>
<templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.1.1"/>
<templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.1.2"/>
</ClinicalDocument>
Refactor the above code for Mirth specification u will get same output, else u simply want to add extra tags on the end of xml you can use this code in Mirth script
var addTemplateId = new XML("<templateId></templateId>");
addTemplateId['#root'] = '2.16.840.1.113883.10.20.22.1.1';
addTemplateId['#extension'] = '2015-08-01';
var newValue = msg.appendChild(addTemplateId);
msg = newValue;
This will add new tags at the end of the existing tags of the message. which means your output will be like this
<ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sdtc="urn:hl7-org:sdtc">
<realmCode code="US"/>
<typeId extension="POCD_HD000040" root="2.16.840.1.113883.1.3"/>
<templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.1.2"/>
<templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.1.1"/>
</ClinicalDocument>
When I use ITextRenderer converting html to PDF.this is my code
ByteArrayOutputStream out = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
String inputFile = "C://Users//Administrator//Desktop//aaa2.html";
String url = new File(inputFile).toURI().toURL().toString();
renderer.setDocument(url);
renderer.getSharedContext().setReplacedElementFactory(
new B64ImgReplacedElementFactory());
// 解决阿拉伯语问题
ITextFontResolver fontResolver = renderer.getFontResolver();
try {
fontResolver.addFont("C://Users//Administrator//Desktop//arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
e.printStackTrace();
}
renderer.layout();
OutputStream outputStream = new FileOutputStream("C://Users//Administrator//Desktop//HTMLasPDF.pdf");
renderer.createPDF(outputStream, true);
/*PdfWriter writer = renderer.getWriter();
writer.open();
writer.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
OutputStream outputStream2 = new FileOutputStream( "C://Users//Administrator//Desktop//HTMLasPDFcopy.txt");
renderer.createPDF(outputStream2);*/
renderer.finishPDF();
out.flush();
out.close();
Actual PDF Result:
Expected PDF Result:
How to make arabic ligature?
If you want to do this properly (I assume using iText, since your post is tagged as such), you should use
iText7
pdfHTML (to convert HTML to PDF)
pdfCalligraph (to handle Arabic ligatures properly)
a font that supports these features (as indicated by another answer)
For an example, please consult the HTML to PDF tutorial, more specifically the following FAQ item: How to convert HTML containing Arabic/Hebrew characters to PDF?
You need fonts that contain the glyphs you need, e.g.:
public static final String[] FONTS = {
"src/main/resources/fonts/noto/NotoSans-Regular.ttf",
"src/main/resources/fonts/noto/NotoNaskhArabic-Regular.ttf",
"src/main/resources/fonts/noto/NotoSansHebrew-Regular.ttf"
};
And you need a FontProvider that knows how to find these fonts in the ConverterProperties:
public void createPdf(String src, String[] fonts, String dest) throws IOException {
ConverterProperties properties = new ConverterProperties();
FontProvider fontProvider = new DefaultFontProvider(false, false, false);
for (String font : fonts) {
FontProgram fontProgram = FontProgramFactory.createFont(font);
fontProvider.addFont(fontProgram);
}
properties.setFontProvider(fontProvider);
HtmlConverter.convertToPdf(new File(src), new File(dest), properties);
}
Note that the text will come out all wrong if you don't have the pdfCalligraph add-on. That add-on didn't exist at the time Flying Saucer was created, hence you can't use Flying Saucer for converting documents with text in Arabic, Hindi, Telugu,... Read the pdFCalligraph white paper if you want to know more about ligatures.
Greek characters seemed to be omitted; they didn’t show up in the document.
In flying saucer the generated PDF uses some kind of default
(probably Helvetica) font, that contains a very limited character set,
that obviously does not contain the Greek code page. link
I change the way to convert pdf by using wkhtmltopdf.
I have the following issue:
I’m doing an export of an ASP.Net GridView directly to an excel file.
I’m setting an image as a header in this method:
private static void insertPageHeaderFooter(ExcelInterfaceSoftArtisans excel,DateTime generatedDateTime)
{
StringBuilder builderFooterLeft = new StringBuilder();
builderFooterLeft.Append("&08Comfone AG Tel: +41 31 341 10 10");
builderFooterLeft.Append("\r");
builderFooterLeft.Append("&08Nussbaumstrasse 25 Fax: +41 31 341 10 11");
builderFooterLeft.Append("\r");
builderFooterLeft.Append("&08CH-3000 Bern 22 www.comfone.com");
StringBuilder builderFooterRight = new StringBuilder();
String sDateTime = generatedDateTime.ToString(CultureInfoHandler.ShortDateShortTimeFormat);
builderFooterRight.Append("&08&F");
builderFooterRight.Append("\r");
builderFooterRight.Append(string.Format("&08 {0}", sDateTime));
builderFooterRight.Append("\r"); //new line
builderFooterRight.Append("&08Page &P of &N");
excel.SetHeader("&G", 0.6, HeaderFooterSection.Section.Left, false);
excel.SetFooter(builderFooterLeft.ToString(), HeaderFooterSection.Section.Left, false);
excel.SetFooter(builderFooterRight.ToString(), HeaderFooterSection.Section.Right, false);
}
protected void SetHeader(string sText, double dImageSizeFactor, HeaderFooterSection.Section section, Worksheet sheet)
{
string headerAbsolutePath = HttpContext.Current.Server.MapPath("~/Resources/Mandates/CHECF.png");
Stream imageStream = new FileStream(headerAbsolutePath, FileMode.Open, FileAccess.Read);
Size imageSize = Image.FromStream(imageStream).Size;
imageStream = new FileStream(headerAbsolutePath, FileMode.Open, FileAccess.Read);
HeaderFooterSection header = sheet.PageSetup.GetHeader(section);
header.SetContent(sText, imageStream);
header.SetContent(sText);
header.GetPicture().Height = (int)(imageSize.Height * dImageSizeFactor);
header.GetPicture().Width = (int)(imageSize.Width * dImageSizeFactor);
imageStream.Close();
}
As you can see on the last line, I close the Stream.
Now, I want to save my excel file this way:
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
excel.SaveWorkbook(sFileName, HttpContext.Current.Response, false);
/// <summary>
/// Saves the current Workbook under the given filename
/// </summary>
/// <param name="filename"></param>
/// <param name="response"></param>
/// <param name="openInBrowser"></param>
public void SaveWorkbook(string filename, HttpResponse response, bool openInBrowser)
{
if (book != null)
{
application.Save(book, response, filename, openInBrowser);
}
}
but when I close the stream in the SetHeader method, I get the following error:
Error Message: Cannot access a closed file.
Stack Trace: at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.Seek(Int64 offset, SeekOrigin origin)
and when I don’t close the stream in the SetHeader method, the file is correctly saved.
Are you aware of this bug? How is it possible that I need to have an open stream in order to save an excel file? What can I do to fix that?
I’m attaching you the whole classes I’m using, so you can identify the problem better.
Thanks for your quick answer and solution on this problem.
[Disclaimer: I am the product owner of OfficeWriter]
This issue has been confirmed as a bug and has been submitted to the OfficeWriter development team.
In the meantime, I would recommend Sam's suggested workaround of using the overload that takes the image's file path instead of the image stream.
Here is a generic code snippet for how to insert an image into the header of an Excel file using the file path overload of HeaderFooterSection.SetContent():
//Open the workbook and get a handle on the worksheet that will contain the
//image in the header
ExcelApplication xla = new ExcelApplication();
Workbook wb = xla.Open(Page.MapPath("\\template.xlsx"));
Worksheet ws = wb.Worksheets["Sheet1"];
//Set the header
HeaderFooterSection header = ws.PageSetup.GetHeader(HeaderFooterSection.Section.Left);
header.SetContent("&G", Page.MapPath("\\images\\image1.png"));
Please see our documentation for additional reference on the SetContent() overloads and using ExcelWriter to format headers and footers in workbooks.
This issue has been addressed in the recent 8.5.1 release of OfficeWriter. See the change log.
We have a library of PDF forms that contain fillable fields and that can be opened in Adobe Reader and filled out by our end users. Note that we are NOT generating PDFs but simply using existing PDFs. All of these forms are protected against editing non-fillable fields in Acrobat by means of a password.
The problem is that when we open the PDF in our code to prefill some of the fields the password protection is lost and the form that is served up is editable in Acrobat.
So:
Is there a way to prefill fillable fields using iTextSharp without unlocking the PDF and the resulting output stream?
Is there a way to relock the form while still allowing an end user
to open in Reader, fill fillable fields, print, etc., without
requiring a password?
Here is a simplified example of the code we are currently using. We have tried locking the output stream (code not currently available) but the file could not then Reader prompted the user for a password.
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] password = encoding.GetBytes("secretPassword");
PdfReader reader = null;
MemoryStream outputStream = null;
PdfStamper stamper = null;
pdfStream.Seek(0, SeekOrigin.Begin);
reader = new PdfReader(pdfStream, password);
outputStream = new MemoryStream();
stamper = new PdfStamper(reader, outputStream);
AcroFields fields = stamper.AcroFields;
fields.SetField("prefillField1", "Some text");
stamper.Close();
outputStream.Close();
reader.Close();
// outputStream sent to user/browser. PDF opens in Reader, but the form can be opened in
// Acrobat without a password and edited.
You cannot edit a PDF if it is password protected. You will like you are doing have to open it with the password to edit it. With that it looks like you are creating a copy of that document and presenting to the user. You can encrypt the PDF with an edit password. Here is a copy of a method that I found that I use with itextsharp. If you set the editPassword while leaving the openPassword null then your users should be able to view the pdf and interact with it but won't be able to edit it based on the permissions you set. Hope this helps.
/// <summary>
/// Adds the given Open (User) and Edit (Owner) password to the PDF and optionally sets
/// the various Allow/Not Allowed restrictions
/// </summary>
/// <param name="openPassword">Open/User password</param>
/// <param name="editPassword">Edit/Owner password</param>
/// <param name="allowAssemply">Assembly means merging, extracting, etc the PDF pages</param>
/// <param name="allowCopy">Copy means right-click copying the content of the PDF to the system</param>
/// <param name="allowDegradedPrinting">Can print low quality version of the PDF</param>
/// <param name="allowFillIn">Can insert data into any AcroForms in the PDF</param>
/// <param name="allowModifyAnnotations">Modification of any annotations</param>
/// <param name="allowModifyContents">Modification of any content in the PDF</param>
/// <param name="allowPrinting">Allows printing at any quality level</param>
/// <param name="allowScreenReaders">Allows the content to be parsed/repurposed for screen readers</param>
public byte[] GetEncryptedPDF(byte[] pdf,
string openPassword, string editPassword,
bool allowAssemply, bool allowCopy,
bool allowDegradedPrinting, bool allowFillIn,
bool allowModifyAnnotations, bool allowModifyContents,
bool allowPrinting, bool allowScreenReaders)
{
int permissions = 0;
if (allowAssemply)
permissions = permissions | PdfWriter.ALLOW_ASSEMBLY;
if (allowCopy)
permissions = permissions | PdfWriter.ALLOW_COPY;
if (allowDegradedPrinting)
permissions = permissions | PdfWriter.ALLOW_DEGRADED_PRINTING;
if (allowFillIn)
permissions = permissions | PdfWriter.ALLOW_FILL_IN;
if (allowModifyAnnotations)
permissions = permissions | PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
if (allowModifyContents)
permissions = permissions | PdfWriter.ALLOW_MODIFY_CONTENTS;
if (allowPrinting)
permissions = permissions | PdfWriter.ALLOW_PRINTING;
if (allowScreenReaders)
permissions = permissions | PdfWriter.ALLOW_SCREENREADERS;
PdfReader reader = new PdfReader(pdf);
using (MemoryStream memoryStream = new MemoryStream())
{
PdfEncryptor.Encrypt(reader, memoryStream, true, openPassword, editPassword, permissions);
reader.Close();
return memoryStream.ToArray();
}
}
Am using jasper reports library with GWT application.
The reports is generated well with CSV format but with HTML format it generate the HTML page with icons of missing picture.
I know that jasper using transparent image called "PX", this image not found.
How can i solve this problem?
Thanks in Advance
If you don't have images to show then you can do this:
JasperPrint jasperPrint = JasperFillManager.fillReport(path, parameters, con);
JRHtmlExporter htmlExporter = new JRHtmlExporter();
response.setContentType("text/html");
request.getSession().setAttribute(ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
htmlExporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
htmlExporter.setParameter(JRExporterParameter.OUTPUT_WRITER, out);
htmlExporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, false);
htmlExporter.exportReport();
The important line is this one:
htmlExporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, false);
That will make all the "px" images disappear.
Try passing in your image as a parameter to the report so you won't have to worry about image paths.
You can set the type of the parameter as a BufferedImage or whatever image class suits.
My solution was to use data URIs. This isn't very elegant since it bloats the size of the HTML and doesn't work in IE prior to IE8, but it does allow you to not bother worrying about creating files out of the image attachments Jasper sends you either.
If you're going to implement this, you want to add this argument to your request:
<argument name="IMAGES_URI"><![CDATA[data:]]></argument>
Then you need to parse the report HTML that JasperServer sends back:
foreach ($attachments as $name => $attachment) {
// Cut off the cid: portion of the name.
$name = substr($name, 4);
// Replace any image URIs with a data: uri.
if (strtolower(substr($name, 0, 4)) !== 'uuid' && strtolower($name) !== 'report') {
if (strtoupper(substr($attachment, 0, 3)) === 'GIF') {
// It's a GIF.
$report = str_replace("data:$name", 'data:image/gif;base64,' . base64_encode($attachment), $report);
} elseif (/* more file type tests */) {
// and so on...
}
}
}
For large images, it's best to do as Gordon suggested and pass in a parameter specifying the URL of a file that is permanently stored on the server. This method is more of a failsafe for gracefully handling any unexpected images JasperServer tries throwing at you.
I'm a bit late to this discussion but this is what I've been using. The key is to pass the imagesMap to both the session attribute and exporter parameter, and to set the IMAGES_URI exporter parameter.
private void exportReportAsHtml(HttpServletRequest request, HttpServletResponse response, JasperPrint jasperPrint) throws IOException, JRException {
response.setContentType("text/html");
request.getSession().setAttribute(ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
Map imagesMap = new HashMap();
request.getSession().setAttribute("IMAGES_MAP", imagesMap);
JRHtmlExporter exporter = new JRHtmlExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_WRITER, response.getWriter());
exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, "image?image=");
exporter.exportReport();
}