All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.objects.acroforms.overridingImplementations.ReadOnlyTextIcon Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * ReadOnlyTextIcon.java
 * ---------------
 */
package org.jpedal.objects.acroforms.overridingImplementations;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.StringTokenizer;

import javax.swing.*;

import org.jpedal.io.PdfObjectReader;
import org.jpedal.objects.acroforms.GUIData;
import org.jpedal.objects.raw.FormObject;
import org.jpedal.objects.raw.FormStream;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.objects.raw.XObject;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.StringUtils;

/** this class is used to display the text fields in the defined font, but is used for readonly fields only. */
public class ReadOnlyTextIcon extends CustomImageIcon implements Icon, SwingConstants {
    
    /** used to tell the paint method that we need to scale up the image for printing */
    private boolean currentlyPrinting;
    private int printMultiplier = 1;
    
    private int alignment=-1;
    
    private static final long serialVersionUID = 8946195842453749725L;
    
    /** stores the root image for selected and unselected icons */
    private BufferedImage rootImage;
    /** stores the final image after any icon rotation */
    private BufferedImage finalImage;
    
    private PdfObject fakeObj;
    
    /** tells us if the text for this icon has chnaged and so if we need to redraw the icon*/
    private boolean textChanged;
    private String preFontStream="",betweenFontAndTextStream="",afterTextStream="",text="";
    
    private String fontName="",fontSize="12",fontCommand="";
    
    /** our full command Stream*/
    private String fullCommandString;
    
    private final PdfObjectReader currentpdffile;
    private int subtype=-1;
    private final PdfObject resources;
    
    private final PdfObject form;
    
    /** new code to store the data to create the image when needed to the size needed
     * offset = if 0 no change, 1 offset image, 2 invert image
     * 
NOTE if decipherAppObject ios not called this will cause problems. */ public ReadOnlyTextIcon(final PdfObject form, final int iconRot, final PdfObjectReader pdfObjectReader, final PdfObject res){ super(iconRot); this.form=form; currentpdffile = pdfObjectReader; resources = res; // if(selObj.getObjectRefAsString().equals("128 0 R") || selObj.getObjectRefAsString().equals("130 0 R")) // debug = true; } /** returns the currently selected Image*/ @Override public Image getImage(){ final Image image; checkAndCreateimage(); image = finalImage; return image; } /** draws the form to a BufferedImage the size of the Icon and returns it, * uses the paintIcon method for the drawing so future changes should only be in one place */ public BufferedImage drawToBufferedImage(){ final BufferedImage bufImg = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB); final Graphics g = bufImg.getGraphics(); paintIcon(null, g, 0, 0); g.dispose(); return bufImg; } @Override public synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) { final BufferedImage image = (BufferedImage) getImage(); if (image == null) { return; } if (c!=null && c.isEnabled()) { g.setColor(c.getBackground()); } else { g.setColor(Color.gray); } final Graphics2D g2 = (Graphics2D) g; if (iconWidth > 0 && iconHeight > 0) { int drawWidth = iconWidth; int drawHeight = iconHeight; if(displaySingle && (iconRotation==270 || iconRotation==90)){ //swap width and height so that the image is drawn in the corect orientation //without changing the raw width and height for the icon size drawWidth = iconHeight; drawHeight = iconWidth; } //only work out scaling if we have a dictionary of an image, as otherwise it could be a blank image (i.e. 1 x 1). if(currentpdffile!=null){ //work out w,h which we want to draw inside our icon to maintain aspect ratio. final float ws = (float)drawWidth / (float)image.getWidth(null); final float hs = (float)drawHeight / (float)image.getHeight(null); if(ws (rootImage.getWidth(null)) || newHeight > (rootImage.getHeight(null)) || newWidth < (rootImage.getWidth(null)/MAXSCALEFACTOR) || newHeight < (rootImage.getHeight(null)/MAXSCALEFACTOR)){ //System.out.println(fakeObj.getObjectRefAsString()+" command="+fullCommandString); rootImage = FormStream.decode(form,currentpdffile, fakeObj, subtype,newWidth,newHeight,0,1); finalImage = FormStream.rotate(rootImage,iconRotation); //make text as redrawn textChanged = false; }//icon rotation is always defined in the constructor so we dont need to change it } public void setText(String str){ if(str==null) { str = ""; } if(str.equals(text)) { return; } textChanged = true; this.text = str; //check afterTextStream to try and sto duplicate TJs with same wording final PdfObject xobj = new PdfObject("1 10 X"); while(true){ xobj.setDecodedStream(StringUtils.toBytes(afterTextStream)); final String tj = FormStream.decipherTextFromAP(currentpdffile,xobj); if(tj!=null && text.contains(tj)){ final int endOfTj = afterTextStream.indexOf(" Tj", afterTextStream.indexOf(tj))+3; afterTextStream = afterTextStream.substring(endOfTj); if(afterTextStream.isEmpty()) { break; } }else { break; } } try { if(text.contains("\n")){//multiline text final StringTokenizer lines=new StringTokenizer(text,"\n",false); String nextLine; //Add 2 to simulate form padding String textAlignment; int alignmentX = 2; int alignmentY = ((FormObject)form).getBoundingRectangle().height; textAlignment = " "+alignmentX+ ' ' +alignmentY+" Td "; this.fullCommandString = preFontStream+fontName+fontSize+fontCommand+ betweenFontAndTextStream + textAlignment; // int y = ((FormObject)form).getBoundingRectangle().height; int xPoint = 0; while(lines.hasMoreTokens()){ nextLine=lines.nextToken(); final FontMetrics fm = new Canvas().getFontMetrics(new Font(fontName, Font.PLAIN, (int)Float.parseFloat(fontSize))); final Rectangle2D r = fm.getStringBounds(nextLine, null); if(((FormObject)form).getAlignment()!=-1){ switch(((FormObject)form).getAlignment()){ case SwingConstants.LEFT : alignmentX=0; break; case SwingConstants.CENTER : alignmentX = ((int)(((FormObject)form).getBoundingRectangle().width - r.getWidth()))/2; alignmentX -= xPoint; break; case SwingConstants.RIGHT : alignmentX = ((int)(((FormObject)form).getBoundingRectangle().width - r.getWidth())); alignmentX -= xPoint; break; } } alignmentY = (int)-(r.getHeight()+2); //Construction alignment string textAlignment = " "+alignmentX+ ' ' +alignmentY+" Td "; this.fullCommandString += textAlignment+'(' +nextLine+")Tj "; xPoint += alignmentX; } this.fullCommandString += afterTextStream; }else{ //Add 2 to simulate form padding int alignmentX = 2; int alignmentY = ((int) (((FormObject) form).getBoundingRectangle().height - Float.parseFloat(fontSize)))+2; if (form.getParameterConstant(PdfDictionary.Subtype) != PdfDictionary.FreeText) { alignmentY = ((int) (((FormObject) form).getBoundingRectangle().height - Float.parseFloat(fontSize))) / 2; if (alignmentY < 2) { alignmentY = 2; } if (((FormObject) form).getAlignment() != SwingConstants.LEFT) { final FontMetrics fm = new Canvas().getFontMetrics(new Font(fontName, Font.PLAIN, (int) Float.parseFloat(fontSize))); final Rectangle2D r = fm.getStringBounds(text, null); switch (((FormObject) form).getAlignment()) { case SwingConstants.CENTER: alignmentX = ((int) (((FormObject) form).getBoundingRectangle().width - r.getWidth())) / 2; break; case SwingConstants.RIGHT: alignmentX = ((int) (((FormObject) form).getBoundingRectangle().width - r.getWidth())) - 2; break; } } } //Construction alignment string String textAlignment = alignmentX+" "+alignmentY+" Td "; this.fullCommandString = preFontStream+fontName+fontSize+fontCommand+ betweenFontAndTextStream+ textAlignment+'(' +text+")Tj "+afterTextStream; } Color BG = null; // Color BC = new Color(0, 0, 0, 0); if(form.getDictionary(PdfDictionary.MK)!=null){ final PdfObject MK = form.getDictionary(PdfDictionary.MK); // float[] bc = MK.getFloatArray(PdfDictionary.BC); final float[] bg = MK.getFloatArray(PdfDictionary.BG); /* * Some files do not store colour values between 0 and 1. * Catch these and convert them */ //Check BG values if(bg!=null){ boolean colorOutOfBounds = false; for(int i=0; i!=bg.length; i++){ if(bg[i]>1.0f){ colorOutOfBounds = true; break; } } if(colorOutOfBounds){ for(int i=0; i!=bg.length; i++){ if(bg[i]>1.0f) { bg[i] /= 255; } } } } //Check BC values // if(bc!=null){ // boolean colorOutOfBounds = false; // for(int i=0; i!=bc.length; i++){ // if(bc[i]>1.0f){ // colorOutOfBounds = true; // break; // } // } // if(colorOutOfBounds){ // for(int i=0; i!=bc.length; i++){ // if(bg[i]>1.0f) // bc[i] = bc[i]/255; // } // } // } // // // if(bc != null && bc.length>0){ // switch(bc.length){ // case 1 : // BC = new Color(bc[0],bc[0],bc[0],1.0f); // break; // case 3 : // BC = new Color(bc[0],bc[1],bc[2],1.0f); // break; // case 4 : //// BC = new Color(bc[0],bc[0],bc[0],1.0f); // break; // } // } if(bg != null && bg.length>0){ switch(bg.length){ case 1 : BG = new Color(bg[0],bg[0],bg[0],1.0f); break; case 3 : BG = new Color(bg[0],bg[1],bg[2],1.0f); break; case 4 : // BG = new Color(bg[0],bg[0],bg[0],1.0f); break; } } } //Fill Background if set if(BG!=null){ this.fullCommandString = BG.getRed()+" "+BG.getGreen()+ ' ' +BG.getBlue()+" rg 0 0 "+(((FormObject)form).getBoundingRectangle().width-3)+ ' ' +(((FormObject)form).getBoundingRectangle().height-3)+" re f "+fullCommandString; } //we may need to actually check encoding on font here rather than assume win fakeObj.setDecodedStream(fullCommandString.getBytes("Cp1252")); } catch (final IOException e) { LogWriter.writeLog("Exception: " + e.getMessage()); } } /** decodes and saves all information needed to decode the object on the fly, * the test and font can be altered with specific methods. * @return boolean true if it all worked. */ public boolean decipherAppObject(final FormObject form) { //read the command from file if there is one String fontStr=""; final PdfObject appObj = form.getDictionary(PdfDictionary.AP).getDictionary(PdfDictionary.N); if(appObj!=null){ final byte[] bytes = appObj.getDecodedStream(); if(bytes!=null){ int startTf=-1; int endTf=-1; int startTj; int endTj=-1; final int end=bytes.length; //find index of Tf command for (int i = 0; i < end-1; i++) { if((((char)bytes[i])=='T' && ((char)bytes[i+1])=='f') && (i+2>=end || bytes[i+2]==10 || bytes[i+2]==13 || bytes[i+2]==' ')){ endTf = i+2; break; } } if(endTf==-1){ startTf = 0; endTf = 0; }else { //find beginning of Tf command // int strs = 0; // boolean strFound = false; for (int i = endTf-3; i > startTf; i--) { //this is kept until its passed tests. // if(bytes[i]==' ' || bytes[i]==10 || bytes[i]==13){ // if(strFound){ // strs++; // if(strs==2){ // startTj = i+1;//to allow for the gap // //should give the same index as the '/' // break; // } // } // continue; // }else if(bytes[i]=='/'){ startTf = i; break; // }else { // strFound = true; } } //******startTf and endTf should both have a value, and start should be before end****** } //find index of Tj command for (int i = endTf; i < end-1; i++) { if((((char)bytes[i])=='T' && ((char)bytes[i+1])=='j') && (i+2>=end || bytes[i+2]==10 || bytes[i+2]==13 || bytes[i+2]==' ')){ endTj = i+2; break; } } if(endTj==-1){ startTj = endTf; endTj = endTf; }else { startTj = endTf; //find the start of the Tj command int brackets = 0; boolean strFound = false; for (int i = endTj-3; i > startTj; i--) { if(bytes[i]==' ' || bytes[i]==10 || bytes[i]==13){ if(strFound && brackets==0){ //+1 as we dont want the gap we just found in our text string startTj = i+1; break; } }else if(bytes[i]==')'){ brackets++; }else if(bytes[i]=='('){ brackets--; if(brackets==0 && strFound){ startTj = i; break; } }else { strFound = true; } } //******* startTJ and endTj should both have a value and start should be before end ****** } //find actual end of Tf including any rg or g command after the Tf. for (int i = endTf; i < startTj; i++) { if(bytes[i]==' ' || bytes[i]==10 || bytes[i]==13){ }else if(bytes[i]>47 && bytes[i]<58){ //number }else { if(bytes[i]=='g' && i+1




© 2015 - 2024 Weber Informatics LLC | Privacy Policy