Why doesn't ABCPDF count a PDF's layers correctly? - layer

I have the below method that was supposed to return the number of layers in a PDF but it doesn't appear to work. When I pass the path to a PDF file containing two layers, the layer count property has a value of 1. I confirmed with two different PDF readers that there are two layers in the PDF. My only thought is ABCPDF is flattening the PDF layers during the read. If so, how can I prevent that so an accurate count of the number of layers in the PDF is returned?
Thank you
public static int GetPDFLayerCount(string pdfFile)
{
int layerCount = 0;
Doc doc = new Doc();
doc.SetInfo(0, "License", _License);
// Attempt to read File
try
{
if (System.IO.File.Exists(pdfFile) == false)
{
throw new ApplicationException("File does not exist.");
}
doc.Read(pdfFile);
layerCount = doc.LayerCount;
doc.Clear();
doc.Dispose();
}
catch (Exception ex)
{
System.ApplicationException appException = new ApplicationException(ex.Message + "\r\n\r\n" + pdfFile,ex);
throw appException;
}
return layerCount;
}

Below is the same method using iTextSharp. I tested with layered PDF files created in ABCPDF and those that were not and it worked in both instances.
public static int GetPDFLayerCount(string pdfFile, bool includeHiddenLayersInCount = true)
{
int layerCount = 0;
string tempOutputFile = "";
try
{
tempOutputFile = System.IO.Path.GetTempFileName();
iTextSharp.text.pdf.PdfReader pdfReader = new iTextSharp.text.pdf.PdfReader(pdfFile);
iTextSharp.text.pdf.PdfStamper pdfStamper = new iTextSharp.text.pdf.PdfStamper(pdfReader, new System.IO.FileStream(tempOutputFile, System.IO.FileMode.Create));
System.Collections.Generic.Dictionary<string, iTextSharp.text.pdf.PdfLayer> layers = pdfStamper.GetPdfLayers();
layerCount = layers.Count;
if (!includeHiddenLayersInCount)
{
foreach (System.Collections.Generic.KeyValuePair<string, iTextSharp.text.pdf.PdfLayer> dictLayer in layers)
{
iTextSharp.text.pdf.PdfLayer layer = (iTextSharp.text.pdf.PdfLayer)dictLayer.Value;
//On = whether a layer is hidden or visible. If false, layer is hidden.
//
//OnPanel = the visibility of the layer in Acrobat's layer panel. If false, the layer cannot be directly manipulated by the user and appears hidden.
//Note that any children layers will also be absent from the panel.
if (layer.Value.On == false || layer.Value.OnPanel == false)
{
layerCount--;
}
}
}
pdfStamper.Close();
pdfReader.Close();
}
catch (Exception ex)
{
System.ApplicationException appException = new ApplicationException(ex.Message + "\r\n\r\n" + pdfFile, ex);
throw appException;
}
finally
{
try
{
if (!String.IsNullOrEmpty(tempOutputFile))
{
System.IO.File.Delete(tempOutputFile);
}
}
catch (Exception ex)
{
}
}
}

Related

Adding ColorSpace to resources causes the stream to close

I am trying very simple steps to add colorspace to resources using PDFBOX version 2.0.7, but it is not working.
I have PDF "pdf1.pdf", I am reading the colorspaces from this file and adding them to HashMap, then I am creating new resources and trying to add the colorspaces to the newly created resources. But it is not working
So the first Step, I read the colorSpaces from the sourcePdf file and add them to HashMap:
seperationColors = new HashMap<COSName, PDColorSpace>();
PDDocument sourcePdfFile = null;
try {
sourcePdfFile = PDDocument.load(new FileInputStream(new File(pdfPath)));
PDPage page = sourcePdfFile.getPages().get(0);
page.getContents();
for (COSName name : page.getResources().getColorSpaceNames()) {
PDColor color = page.getResources().getColorSpace(name).getInitialColor();
if (color.getColorSpace() instanceof PDSeparation) {
seperationColors.put(name, page.getResources().getColorSpace(name));
}
}
} catch (FileNotFoundException e) {
// e.printStackTrace();
} catch (IOException e) {
// e.printStackTrace();
} finally {
if (sourcePdfFile != null)
try {
sourcePdfFile.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
sourcePdfFile = null;
}
}
}
Then, at later stages in the code, I want to create new PDF document, and add the colorSpaces from the source Pdf to the new one.
PDResources newResources = new PDResources();
PDColorSpace colorSpace = originalDocumentColorSpaces.values().iterator().next();
newResources.add(colorSpace);
newResources will have the error: COSDictionary{COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?}
after the add operation (line 3)
colorSpace is of type PDSeperation.
Any clue?

Using pdfbox to convert a color PDF to a b/w tiff

I am have a bit of a problem converting some color PDFs to tiff images. The PDFs I am having problems with have hand written signatures written in blue ink. These signatures do not appear in the generated binary tiffs. I suspect there is a threshold value somewhere to determine which pixels will be black and which will be white.
#SuppressWarnings("serial")
private static void convertPdfToTiff(final File pdf, final File tif) throws Exception {
try
{
final Iterator<ImageWriter> imageWriterIterator = ImageIO.getImageWritersByFormatName("TIF");
final ImageWriter imageWriter = imageWriterIterator.hasNext() ? imageWriterIterator.next() : null;
final TIFFImageWriteParam writeParam = new TIFFImageWriteParam(Locale.getDefault());
writeParam.setCompressionMode(TIFFImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("LZW");
PDDocument pdfDocument = PDDocument.load(pdf);
PDFRenderer pdfRenderer = new PDFRenderer(pdfDocument);
OutputStream out = new FileOutputStream(tif);
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out);
final ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(bufferedOutputStream);
imageWriter.setOutput(imageOutputStream);
imageWriter.prepareWriteSequence(null);
int pageCounter = 0;
for (PDPage page : pdfDocument.getPages())
{
BufferedImage image = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.BINARY);
final IIOImage s = new IIOImage(image, null, new TIFFImageMetadata(new TIFFIFD(new Vector<BaselineTIFFTagSet>()
{
{
add(BaselineTIFFTagSet.getInstance());
}
})))
{
{
final TIFFImageMetadata tiffMetadata = (TIFFImageMetadata) getMetadata();
final TIFFIFD rootIFD = tiffMetadata.getRootIFD();
final BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, new long[][] { { 300, 1 } }));
rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, new long[][] { { 300, 1 } }));
}
};
imageWriter.writeToSequence(s, writeParam);
pageCounter++;
}
imageWriter.dispose();
imageOutputStream.flush();
imageOutputStream.close();
bufferedOutputStream.flush();
bufferedOutputStream.close();
pdfDocument.close();
out.flush();
out.close();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}
I had the same problem (blue signatures) some time ago and I did this:
render to RGB
convert to b/w with a filter from JH Labs (I got pointed to this by a comment in this answer)
I initially tried the dither and the diffusion filter
the filter that worked best for me was the bias part (I think I used 0.3) of the gain filter combined with the diffusion filter.
you can combine two filters with the compound filter.
the jhlabs stuff is not available as .jar file, but you can download the sources and add it to your project
some examples
Btw, save your files not as LZW, but as G4, that'll make them smaller. PDFBox has methods to efficiently save into images, see here. ImageIOUtil.writeImage() will save to G4 compressed TIFF if your BufferedImage is of type BITONAL.
I ended up rendering the image as grayscale and re drawing it to a second bw image.
#SuppressWarnings("serial")
private static void convertPdfToTiff(final File pdf, final File tif) throws Exception {
try
{
final Iterator<ImageWriter> imageWriterIterator = ImageIO.getImageWritersByFormatName("TIF");
final ImageWriter imageWriter = imageWriterIterator.hasNext() ? imageWriterIterator.next() : null;
final TIFFImageWriteParam writeParam = new TIFFImageWriteParam(Locale.getDefault());
writeParam.setCompressionMode(TIFFImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType("CCITT T.6");
PDDocument pdfDocument = PDDocument.load(pdf);
PDFRenderer pdfRenderer = new PDFRenderer(pdfDocument);
OutputStream out = new FileOutputStream(tif);
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out);
final ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(bufferedOutputStream);
imageWriter.setOutput(imageOutputStream);
imageWriter.prepareWriteSequence(null);
int pageCounter = 0;
for (PDPage page : pdfDocument.getPages())
{
BufferedImage image = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.GRAY);
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g = image2.createGraphics();
g.drawRenderedImage(image, null);
g.dispose();
final IIOImage s = new IIOImage(image2, null, new TIFFImageMetadata(new TIFFIFD(new Vector<BaselineTIFFTagSet>()
{
{
add(BaselineTIFFTagSet.getInstance());
}
})))
{
{
final TIFFImageMetadata tiffMetadata = (TIFFImageMetadata) getMetadata();
final TIFFIFD rootIFD = tiffMetadata.getRootIFD();
final BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, new long[][] { { 300, 1 } }));
rootIFD.addTIFFField(new TIFFField(base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), TIFFTag.TIFF_RATIONAL, 1, new long[][] { { 300, 1 } }));
}
};
imageWriter.writeToSequence(s, writeParam);
pageCounter++;
}
imageWriter.dispose();
imageOutputStream.flush();
imageOutputStream.close();
bufferedOutputStream.flush();
bufferedOutputStream.close();
pdfDocument.close();
out.flush();
out.close();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}

How to display a pdf file using PDFBox in JPanel?

I have already created a JForm in netbeans which can read pdf file using PDFBox. But the problem is that I have used the method PDPage.convertToImage() which is really very slow. Can anyone please help me in displaying the pdf using PDFBox in the JPanel at a faster speed ?
The code I have written is inside an ActionListener for a JButton.
File f = null;
ArrayList<JLabel> jl = new ArrayList<JLabel>();
BufferedImage bi = null;
JFileChooser fc = new JFileChooser();
int x=fc.showOpenDialog(null);
if(x==JFileChooser.APPROVE_OPTION)
{
f=fc.getSelectedFile();
}
PDDocument doc=null;
try {
doc = PDDocument.load(f);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "not done\n"+ex);
}
List pages = doc.getDocumentCatalog().getAllPages();
Iterator itr = pages.iterator();
int q=0;
while(itr.hasNext())
{
PDPage page = (PDPage)itr.next();
try
{
bi = page.convertToImage();
q++;
jl.add(new JLabel(new ImageIcon(bi)));
}catch(Exception e)
{
JOptionPane.showMessageDialog(null, e);
}
}
itr = jl.iterator();
while(itr.hasNext())
{
viewPanel.setVisible(false);
viewPanel.add((JLabel)itr.next());
viewPanel.setVisible(true);
}
JOptionPane.showMessageDialog(null, "done");
NetBeans has several plugins to display PDFs
http://plugins.netbeans.org/plugin/5809/java-pdf-reader
http://plugins.netbeans.org/plugin/11676/netbeans-pdfviewer
http://plugins.netbeans.org/plugin/17/pdf-viewer-javafx-converter-and-bookmarking-application
HAve you tried any of them?

Modify Printing attribute for Media Name Java Apache FOP API

Am using Apache FOP API to print a document which was working well for a while but now it is trying to print on a legal size paper on tray 1. Am wondering if i can change that to Letter size so that users do not manually have to hit button on the printer to make that happen.
public void printDocument() {
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
PrintRequestAttributeSet aset =
new HashPrintRequestAttributeSet();
PrintService prnSvc = null;
/* locate a print service that can handle it */
PrintService[] pservices =
PrintServiceLookup.lookupPrintServices(null, null);
if (pservices.length > 0) {
int ii = 0;
while (ii < pservices.length) {
System.out.println("Named Printer found: " + pservices[ii].getName());
if (pservices[ii].getName().endsWith("xyz")) {
prnSvc = pservices[ii];
System.out.println("Named Printer selected: " + pservices[ii].getName() + "*");
break;
}
ii++;
}
/* create a print job for the chosen service */
DocPrintJob pj = prnSvc.createPrintJob();
try {
File file = new File("test.pcl");
FileInputStream fis = new FileInputStream(file); //Doc encapsulating the print data
Doc doc = new SimpleDoc(fis, flavor, null);
/* print the doc as specified */
pj.print(doc, aset);
} catch (IOException ie) {
System.err.println(ie);
} catch (PrintException e) {
e.printStackTrace();
System.err.println(e);
}
}
}
Would highly appreciate if anyone can provide any recommendations around the same.
You'll need to specify the paper size by adding it to aset:
aset.add(javax.print.attribute.standard.MediaSizeName.<desired paper size>);
(Javadoc for MediaSizeName). For letter size, use
aset.add(javax.print.attribute.standard.MediaSizeName.NA_LETTER);

excel file upload using apache file upload

I am developing an testing automation tool in linux system. I dont have write permissions for tomcat directory which is located on server. I need to develop an application where we can select an excel file so that the excel content is automatically stored in already existing table.
For this pupose i have written an form to select an file which is posted to a servlet CommonsFileUploadServlet where i am storing the uploaded file and then calling ReadExcelFile class which reads the file path and create a vector for data in file which is used to sstore data in database.
My problem is that i am not able to store the uploaded file in directory. Is it necessary to have permission rights for tomcat to do this. Can i store the file on my system and pass the path to ReadExcelFile.class
Please guide me
My code is as follows:
Form in jsp
CommonsFileUploadServlet class code:
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/plain");
out.println("<h1>Servlet File Upload Example using Commons File Upload</h1>");
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory ();
fileItemFactory.setSizeThreshold(1*1024*1024);
fileItemFactory.setRepository(new File("/home/example/Documents/Project/WEB-INF/tmp"));
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
try {
List items = uploadHandler.parseRequest(request);
Iterator itr = items.iterator();
while(itr.hasNext()) {
FileItem item = (FileItem) itr.next();
if(item.isFormField()) {
out.println("File Name = "+item.getFieldName()+", Value = "+item.getString());
} else {
out.println("Field Name = "+item.getFieldName()+
", File Name = "+item.getName()+
", Content type = "+item.getContentType()+
", File Size = "+item.getSize());
File file = new File("/",item.getName());
String realPath = getServletContext().getRealPath("/")+"/"+item.getName();
item.write(file);
ReadExcelFile ref= new ReadExcelFile();
String res=ref.insertReq(realPath,"1");
}
out.close();
}
}catch(FileUploadException ex) {
log("Error encountered while parsing the request",ex);
} catch(Exception ex) {
log("Error encountered while uploading file",ex);
}
}
}
ReadExcelFile code:
public static String insertReq(String fileName,String sno) {
//Read an Excel File and Store in a Vector
Vector dataHolder=readExcelFile(fileName,sno);
//store the data to database
storeCellDataToDatabase(dataHolder);
}
public static Vector readExcelFile(String fileName,String Sno)
{
/** --Define a Vector
--Holds Vectors Of Cells
*/
Vector cellVectorHolder = new Vector();
try{
/** Creating Input Stream**/
//InputStream myInput= ReadExcelFile.class.getResourceAsStream( fileName );
FileInputStream myInput = new FileInputStream(fileName);
/** Create a POIFSFileSystem object**/
POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);
/** Create a workbook using the File System**/
HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem);
int s=Integer.valueOf(Sno);
/** Get the first sheet from workbook**/
HSSFSheet mySheet = myWorkBook.getSheetAt(s);
/** We now need something to iterate through the cells.**/
Iterator rowIter = mySheet.rowIterator();
while(rowIter.hasNext())
{
HSSFRow myRow = (HSSFRow) rowIter.next();
Iterator cellIter = myRow.cellIterator();
Vector cellStoreVector=new Vector();
short minColIndex = myRow.getFirstCellNum();
short maxColIndex = myRow.getLastCellNum();
for(short colIndex = minColIndex; colIndex < maxColIndex; colIndex++)
{
HSSFCell myCell = myRow.getCell(colIndex);
if(myCell == null)
{
cellStoreVector.addElement(myCell);
}
else
{
cellStoreVector.addElement(myCell);
}
}
cellVectorHolder.addElement(cellStoreVector);
}
}catch (Exception e){e.printStackTrace(); }
return cellVectorHolder;
}
private static void storeCellDataToDatabase(Vector dataHolder)
{
Connection conn;
Statement stmt;
String query;
try
{
// get connection and declare statement
int z;
for (int i=1;i<dataHolder.size(); i++)
{
z=0;
Vector cellStoreVector=(Vector)dataHolder.elementAt(i);
String []stringCellValue=new String[10];
for (int j=0; j < cellStoreVector.size();j++,z++)
{
HSSFCell myCell = (HSSFCell)cellStoreVector.elementAt(j);
if(myCell==null)
stringCellValue[z]=" ";
else
stringCellValue[z] = myCell.toString();
}
try
{
//inserting into database
}
catch(Exception error)
{
String e="Error"+error;
System.out.println(e);
}
}
stmt.close();
conn.close();
System.out.println("success");
}
catch(Exception error)
{
String e="Error"+error;
System.out.println(e);
}
}
POI will happily open from an old InputStream, it needn't be a File one.
I'd suggest you look at the Commons FileUpload Streaming API and consider just passing the excel part straight to POI without touching the disk