]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
PR:
authorTore Engvig <tore@apache.org>
Sun, 2 Dec 2001 22:17:30 +0000 (22:17 +0000)
committerTore Engvig <tore@apache.org>
Sun, 2 Dec 2001 22:17:30 +0000 (22:17 +0000)
Obtained from:
Submitted by:
Reviewed by:

Support for CMYK and embedded ICC profiles in jpeg images
Support for jpeg images in PS Renderer
Support for EPS images in PostScript renderer and limited EPS support in
PDF Renderer
Bugfix for TTFReader (submitted by Cristi Ruja, c_ruja@yahoo.com)
Support for letterspacing (submitted by Raymond Penners <raymond@duologix.nl>)

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_20_2-maintain@194581 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/codegen/foproperties.xml
src/org/apache/fop/datatypes/ColorSpace.java
src/org/apache/fop/fo/FOText.java
src/org/apache/fop/fonts/TTFFile.java
src/org/apache/fop/image/AbstractFopImage.java
src/org/apache/fop/image/EPSImage.java
src/org/apache/fop/image/FopImage.java
src/org/apache/fop/image/FopImageFactory.java
src/org/apache/fop/image/JpegImage.java
src/org/apache/fop/image/analyser/EPSReader.java
src/org/apache/fop/image/analyser/ImageReaderFactory.java
src/org/apache/fop/layout/FontState.java
src/org/apache/fop/pdf/PDFDocument.java
src/org/apache/fop/pdf/PDFICCStream.java
src/org/apache/fop/pdf/PDFT1Stream.java
src/org/apache/fop/pdf/PDFTTFStream.java
src/org/apache/fop/pdf/PDFXObject.java
src/org/apache/fop/render/pdf/PDFRenderer.java
src/org/apache/fop/render/ps/PSRenderer.java
src/org/apache/fop/render/ps/PSStream.java

index ce2a7503c387e2cfc3a6bddbaac6aa1a616cb785..a73eb40e9bba46027668a44565447118141415e2 100644 (file)
 <?xml version="1.0" standalone="yes" ?>
 <property-list family="FO">
  <generic-property-list>
-       <property type="generic">
-               <name>generic-color</name>
-               <class-name>GenericColor</class-name>
-               <datatype>ColorType</datatype>
-               <extfile href="colorkw.xml"/>
+    <property type="generic">
+        <name>generic-color</name>
+        <class-name>GenericColor</class-name>
+        <datatype>ColorType</datatype>
+        <extfile href="colorkw.xml"/>
 <!--
-               <datatype-conversion from-type="String" varname="strval">
-                        new ColorType(strval)</datatype-conversion>
+        <datatype-conversion from-type="String" varname="strval">
+             new ColorType(strval)</datatype-conversion>
 -->
-       </property>
-       <property type="generic">
-               <name>generic-boolean</name>
-               <class-name>GenericBoolean</class-name>
-               <datatype>Enum</datatype>
-                       <enumeration>
-                               <value const="TRUE">true</value>
-                               <value const="FALSE">false</value>
-                       </enumeration>
-       </property>
-       <property type="generic">
-               <name>generic-keep</name>
-               <class-name>GenericKeep</class-name>
-               <datatype>Keep</datatype> <!-- CompoundDatatype -->
-               <compound>
-                       <subproperty set-by-shorthand="true">
-                               <name>within-page</name>
-               <datatype>Number</datatype>
-               <default>auto</default>
-                       <enumeration>
-                               <value const="AUTO">auto</value>
-                               <value const="ALWAYS">always</value>
-                       </enumeration>
-                       </subproperty>
-                       <subproperty set-by-shorthand="true">
-                               <name>within-line</name>
-               <datatype>Number</datatype>
-               <default>auto</default>
-                       <enumeration>
-                               <value const="AUTO">auto</value>
-                               <value const="ALWAYS">always</value>
-                       </enumeration>
-                       </subproperty>
-                       <subproperty set-by-shorthand="true">
-                               <name>within-column</name>
-               <datatype>Number</datatype>
-               <default>auto</default>
-                       <enumeration>
-                               <value const="AUTO">auto</value>
-                               <value const="ALWAYS">always</value>
-                       </enumeration>
-                       </subproperty>
-               </compound>
-       </property>
-       <property type="generic">
-               <name>conditional-length-template</name>
-               <class-name>GenericCondLength</class-name>
-               <datatype>CondLength</datatype>
-               <compound>
-                       <subproperty set-by-shorthand="true">
-                               <name>length</name>
-                               <datatype>Length</datatype>
-                       </subproperty>
-                       <subproperty>
-                               <name>conditionality</name>
-                               <datatype>Enum</datatype>
-                               <enumeration>
-                                       <value const="DISCARD">discard</value>
-                                       <value const="RETAIN">retain</value>
-                               </enumeration>
-                       </subproperty>
-               </compound>
-       </property>
-       <property type="generic">
-               <name>padding-template</name>
-               <class-name>GenericCondPadding</class-name>
-               <use-generic>GenericCondLength</use-generic>
-               <inherited>false</inherited>
-               <default subproperty="length">0pt</default>
-       </property>
-       <property type="generic">
-               <name>padding-template</name>
-               <class-name>GenericPadding</class-name>
-               <datatype>Length</datatype>
-               <inherited>false</inherited>
-               <default>0pt</default>
+    </property>
+    <property type="generic">
+        <name>generic-boolean</name>
+        <class-name>GenericBoolean</class-name>
+        <datatype>Enum</datatype>
+            <enumeration>
+                <value const="TRUE">true</value>
+                <value const="FALSE">false</value>
+            </enumeration>
+    </property>
+    <property type="generic">
+        <name>generic-keep</name>
+        <class-name>GenericKeep</class-name>
+        <datatype>Keep</datatype> <!-- CompoundDatatype -->
+        <compound>
+            <subproperty set-by-shorthand="true">
+                <name>within-page</name>
+        <datatype>Number</datatype>
+        <default>auto</default>
+            <enumeration>
+                <value const="AUTO">auto</value>
+                <value const="ALWAYS">always</value>
+            </enumeration>
+            </subproperty>
+            <subproperty set-by-shorthand="true">
+                <name>within-line</name>
+        <datatype>Number</datatype>
+        <default>auto</default>
+            <enumeration>
+                <value const="AUTO">auto</value>
+                <value const="ALWAYS">always</value>
+            </enumeration>
+            </subproperty>
+            <subproperty set-by-shorthand="true">
+                <name>within-column</name>
+        <datatype>Number</datatype>
+        <default>auto</default>
+            <enumeration>
+                <value const="AUTO">auto</value>
+                <value const="ALWAYS">always</value>
+            </enumeration>
+            </subproperty>
+        </compound>
+    </property>
+    <property type="generic">
+        <name>conditional-length-template</name>
+        <class-name>GenericCondLength</class-name>
+        <datatype>CondLength</datatype>
+        <compound>
+            <subproperty set-by-shorthand="true">
+                <name>length</name>
+                <datatype>Length</datatype>
+            </subproperty>
+            <subproperty>
+                <name>conditionality</name>
+                <datatype>Enum</datatype>
+                <enumeration>
+                    <value const="DISCARD">discard</value>
+                    <value const="RETAIN">retain</value>
+                </enumeration>
+            </subproperty>
+        </compound>
+    </property>
+    <property type="generic">
+        <name>padding-template</name>
+        <class-name>GenericCondPadding</class-name>
+        <use-generic>GenericCondLength</use-generic>
+        <inherited>false</inherited>
+        <default subproperty="length">0pt</default>
+    </property>
+    <property type="generic">
+        <name>padding-template</name>
+        <class-name>GenericPadding</class-name>
+        <datatype>Length</datatype>
+        <inherited>false</inherited>
+        <default>0pt</default>
                 <shorthand>padding</shorthand>
-       </property>
+    </property>
 
 <!-- Before, After, Start, End border width props -->
 <!-- CondLength, but adds keyword values both to the "shorthand" setting
-                and to the length component. So we redefine the components here,
-                rather than doing a "use-generic" on GenericCondLength.
+         and to the length component. So we redefine the components here,
+         rather than doing a "use-generic" on GenericCondLength.
 -->
-       <property type="generic">
-               <name>border-cond-width-template</name>
-               <class-name>GenericCondBorderWidth</class-name>
-               <keyword-equiv match="thin">0.5pt</keyword-equiv>
-               <keyword-equiv match="medium">1pt</keyword-equiv>
-               <keyword-equiv match="thick">2pt</keyword-equiv>
-               <inherited>false</inherited>
-               <datatype>CondLength</datatype>
-               <compound>
-                       <subproperty set-by-shorthand="true">
-                               <name>length</name>
-                               <datatype>Length</datatype>
-                               <keyword-equiv match="thin">0.5pt</keyword-equiv>
-                               <keyword-equiv match="medium">1pt</keyword-equiv>
-                               <keyword-equiv match="thick">2pt</keyword-equiv>
-                               <default>medium</default>
-                       </subproperty>
-                       <subproperty>
-                               <datatype>Enum</datatype>
-                               <name>conditionality</name>
-                               <enumeration>
-                                       <value const="DISCARD">discard</value>
-                                       <value const="RETAIN">retain</value>
-                               </enumeration>
-                       </subproperty>
-               </compound>
-       </property>
+    <property type="generic">
+        <name>border-cond-width-template</name>
+        <class-name>GenericCondBorderWidth</class-name>
+        <keyword-equiv match="thin">0.5pt</keyword-equiv>
+        <keyword-equiv match="medium">1pt</keyword-equiv>
+        <keyword-equiv match="thick">2pt</keyword-equiv>
+        <inherited>false</inherited>
+        <datatype>CondLength</datatype>
+        <compound>
+            <subproperty set-by-shorthand="true">
+                <name>length</name>
+                <datatype>Length</datatype>
+                <keyword-equiv match="thin">0.5pt</keyword-equiv>
+                <keyword-equiv match="medium">1pt</keyword-equiv>
+                <keyword-equiv match="thick">2pt</keyword-equiv>
+                <default>medium</default>
+            </subproperty>
+            <subproperty>
+                <datatype>Enum</datatype>
+                <name>conditionality</name>
+                <enumeration>
+                    <value const="DISCARD">discard</value>
+                    <value const="RETAIN">retain</value>
+                </enumeration>
+            </subproperty>
+        </compound>
+    </property>
 <!-- Left, Right, Top, Bottom borderwidth props -->
-       <property type="generic">
-               <name>border-width-template</name>
-               <class-name>GenericBorderWidth</class-name>
-               <datatype>Length</datatype>
-               <keyword-equiv match="thin">0.5pt</keyword-equiv>
-               <keyword-equiv match="medium">1pt</keyword-equiv>
-               <keyword-equiv match="thick">2pt</keyword-equiv>
-               <inherited>false</inherited>
-               <default>0pt</default>
-               <shorthand>border-width</shorthand>
-       </property>
-       <property type="generic">
-               <name>border-style-template</name>
-               <class-name>GenericBorderStyle</class-name>
-               <inherited>false</inherited>
-               <datatype>Enum</datatype>
-                       <enumeration>
-                               <value const="NONE">none</value>
-                               <value const="HIDDEN">hidden</value>
-                               <value const="DOTTED">dotted</value>
-                               <value const="DASHED">dashed</value>
-                               <value const="SOLID">solid</value>
-                               <value const="DOUBLE">double</value>
-                               <value const="GROOVE">groove</value>
-                               <value const="RIDGE">ridge</value>
-                               <value const="INSET">inset</value>
-                               <value const="OUTSET">outset</value>
-                       </enumeration>
-               <default>none</default>
-               <shorthand>border-style</shorthand>
-       </property>
-       <property type="generic">
-               <name>break-template</name>
-               <class-name>GenericBreak</class-name>
-               <inherited>false</inherited>
-               <datatype>Enum</datatype>
-                       <enumeration>
-                               <value const="AUTO">auto</value>
-                               <value const="COLUMN">column</value>
-                               <value const="PAGE">page</value>
-                               <value const="EVEN_PAGE">even-page</value>
-                               <value const="ODD_PAGE">odd-page</value>
-                       </enumeration>
-               <default>auto</default>
-       </property>
-       <property type="generic">
-               <name>generic-space</name>
-               <class-name>GenericSpace</class-name>
-               <inherited>false</inherited>
-               <datatype>Space</datatype>
-               <compound>
-                       <subproperty set-by-shorthand="true">
-                               <name>minimum</name>
-                               <datatype>Length</datatype>
-                               <default>0pt</default>
-                       </subproperty>
-                       <subproperty set-by-shorthand="true">
-                               <name>optimum</name>
-                               <datatype>Length</datatype>
-                               <default>0pt</default>
-                       </subproperty>
-                       <subproperty set-by-shorthand="true">
-                               <name>maximum</name>
-                               <datatype>Length</datatype>
-                               <default>0pt</default>
-                       </subproperty>
-                       <subproperty>
-                               <name>precedence</name>
-                               <datatype>Number</datatype>
-                               <enumeration>
-                                       <value const="FORCE">force</value>
-                               </enumeration>
-                               <default>0</default>
-                       </subproperty>
-                       <subproperty>
-                               <name>conditionality</name>
-                               <datatype>Enum</datatype>
-                               <enumeration>
-                                       <value const="DISCARD">discard</value>
-                                       <value const="RETAIN">retain</value>
-                               </enumeration>
-                               <default>discard</default>
-                       </subproperty>
-               </compound>
-       </property>
+    <property type="generic">
+        <name>border-width-template</name>
+        <class-name>GenericBorderWidth</class-name>
+        <datatype>Length</datatype>
+        <keyword-equiv match="thin">0.5pt</keyword-equiv>
+        <keyword-equiv match="medium">1pt</keyword-equiv>
+        <keyword-equiv match="thick">2pt</keyword-equiv>
+        <inherited>false</inherited>
+        <default>0pt</default>
+        <shorthand>border-width</shorthand>
+    </property>
+    <property type="generic">
+        <name>border-style-template</name>
+        <class-name>GenericBorderStyle</class-name>
+        <inherited>false</inherited>
+        <datatype>Enum</datatype>
+            <enumeration>
+                <value const="NONE">none</value>
+                <value const="HIDDEN">hidden</value>
+                <value const="DOTTED">dotted</value>
+                <value const="DASHED">dashed</value>
+                <value const="SOLID">solid</value>
+                <value const="DOUBLE">double</value>
+                <value const="GROOVE">groove</value>
+                <value const="RIDGE">ridge</value>
+                <value const="INSET">inset</value>
+                <value const="OUTSET">outset</value>
+            </enumeration>
+        <default>none</default>
+        <shorthand>border-style</shorthand>
+    </property>
+    <property type="generic">
+        <name>break-template</name>
+        <class-name>GenericBreak</class-name>
+        <inherited>false</inherited>
+        <datatype>Enum</datatype>
+            <enumeration>
+                <value const="AUTO">auto</value>
+                <value const="COLUMN">column</value>
+                <value const="PAGE">page</value>
+                <value const="EVEN_PAGE">even-page</value>
+                <value const="ODD_PAGE">odd-page</value>
+            </enumeration>
+        <default>auto</default>
+    </property>
+    <property type="generic">
+        <name>generic-space</name>
+        <class-name>GenericSpace</class-name>
+        <inherited>false</inherited>
+        <datatype>Space</datatype>
+        <compound>
+            <subproperty set-by-shorthand="true">
+                <name>minimum</name>
+                <datatype>Length</datatype>
+                <default>0pt</default>
+            </subproperty>
+            <subproperty set-by-shorthand="true">
+                <name>optimum</name>
+                <datatype>Length</datatype>
+                <default>0pt</default>
+            </subproperty>
+            <subproperty set-by-shorthand="true">
+                <name>maximum</name>
+                <datatype>Length</datatype>
+                <default>0pt</default>
+            </subproperty>
+            <subproperty>
+                <name>precedence</name>
+                <datatype>Number</datatype>
+                <enumeration>
+                    <value const="FORCE">force</value>
+                </enumeration>
+                <default>0</default>
+            </subproperty>
+            <subproperty>
+                <name>conditionality</name>
+                <datatype>Enum</datatype>
+                <enumeration>
+                    <value const="DISCARD">discard</value>
+                    <value const="RETAIN">retain</value>
+                </enumeration>
+                <default>discard</default>
+            </subproperty>
+        </compound>
+    </property>
 
 <!-- Common Accessibility Properties -->
 
   <property>
     <name>letter-spacing</name>
     <inherited>true</inherited>
-    <datatype>ToBeImplemented</datatype>
-    <default>normal</default>
+    <datatype>Length</datatype>
+    <default>0pt</default>
   </property>
   <property>
     <name>suppress-at-line-break</name>
index 9b289369f6610ca9954d43faf71ad81b61efb41d..01fcf221a359c4642b9737a50bdfcf7731068c59 100644 (file)
@@ -8,6 +8,10 @@
 package org.apache.fop.datatypes;
 
 public class ColorSpace {
+    private boolean hasICCProfile;
+    private byte[] iccProfile;
+    private int numComponents;
+
     // Ok... so I had some grand purpose for this, but I can't recall.
     // I'm just writing it
 
@@ -18,21 +22,55 @@ public class ColorSpace {
     public static int DEVICE_RGB = 2;
     public static int DEVICE_CMYK = 3;
 
+
     // Are there any others?
 
     protected int currentColorSpace = -1;
 
     public ColorSpace(int theColorSpace) {
         this.currentColorSpace = theColorSpace;
+        hasICCProfile = false;
+        numComponents = calculateNumComponents();
+    }
+
+    private int calculateNumComponents() {
+        if (currentColorSpace == DEVICE_GRAY)
+            return 1;
+        else if (currentColorSpace == DEVICE_RGB)
+            return 3;
+        else if (currentColorSpace == DEVICE_CMYK)
+            return 4;
+        else
+            return 0;
+    }
 
+    public void setColorSpace(int theColorSpace) {
+        this.currentColorSpace = theColorSpace;
+        numComponents = calculateNumComponents();
+    }
+
+    public boolean hasICCProfile() {
+        return hasICCProfile;
+    }
+
+    public byte[] getICCProfile() {
+        if (hasICCProfile)
+            return iccProfile;
+        else
+            return new byte[0];
+    }
+
+    public void setICCProfile(byte[] iccProfile) {
+        this.iccProfile = iccProfile;
+        hasICCProfile = true;
     }
 
     public int getColorSpace() {
         return (this.currentColorSpace);
     }
 
-    public void setColorSpace(int theColorSpace) {
-        this.currentColorSpace = theColorSpace;
+    public int getNumComponents() {
+        return numComponents;
     }
 
     public String getColorSpacePDFString() {    // this is for PDF Output. Does anyone else need a string representation?
index bc86aba2067d2df0ae2038add871c6218d6ec23d..3eb6c3972de746b1d3f478541fc5e89e021909c2 100644 (file)
@@ -123,9 +123,11 @@ public class FOText extends FONode {
             int fontVariant =
                 this.parent.properties.get("font-variant").getEnum();
 
+            int letterSpacing =
+                this.parent.properties.get("letter-spacing").getLength().mvalue();
             this.fs = new FontState(area.getFontInfo(), fontFamily,
                                     fontStyle, fontWeight, fontSize,
-                                    fontVariant);
+                                    fontVariant, letterSpacing);
 
             ColorType c = this.parent.properties.get("color").getColorType();
             this.red = c.red();
index d48a1948eebbd3c4817c8ff29772a3d5fca39294..d7cb6a447a54b5c82d588470067b96886ba76111 100644 (file)
@@ -669,7 +669,7 @@ public class TTFFile {
             mtx_tab[i] = new TTFMtxEntry();
         for (int i = 0; i < nhmtx; i++) {
             mtx_tab[i].wx = in.readTTFUShort();
-            mtx_tab[i].lsb = in.readTTFUShort();
+            mtx_tab[i].lsb = in.readTTFShort();
             /*
              * System.out.println("   width["+i+"] = "+
              * get_ttf_funit(mtx_tab[i].wx)+";");
@@ -681,7 +681,7 @@ public class TTFFile {
             int lastWidth = mtx_tab[nhmtx - 1].wx;
             for (int i = nhmtx; i < mtx_size; i++) {
                 mtx_tab[i].wx = lastWidth;
-                mtx_tab[i].lsb = in.readTTFUShort();
+                mtx_tab[i].lsb = in.readTTFShort();
             }
         }
     }
index 4669758c7a0e72d3c470207cb640133bb3d7d011..e37516287dd96a4715f1d3ea574e04b663c2782a 100644 (file)
@@ -26,6 +26,11 @@ import org.apache.fop.image.analyser.ImageReader;
  */
 public abstract class AbstractFopImage implements FopImage {
 
+    /**
+    * Photoshop generated cmykl jpeg's are inverted.
+    */
+    protected boolean m_invertImage = false;
+
     /**
      * Image width (in pixel).
      */
@@ -135,6 +140,13 @@ public abstract class AbstractFopImage implements FopImage {
      */
     abstract protected void loadImage() throws FopImageException;
 
+    /**
+    * If true, image data are inverted
+    */
+    public boolean invertImage() {
+        return m_invertImage;
+    }
+
     /**
      * Return the image URL.
      * @return the image URL (as String)
index e766fb733b10987f4f94007284c7f18d0c70e4d2..125652b22f3436fb97edc2ed5b50ef6ac4ec1413 100644 (file)
@@ -15,6 +15,7 @@ import java.io.IOException;
 
 // FOP
 import org.apache.fop.apps.Driver;
+import org.apache.fop.messaging.*;
 import org.apache.fop.datatypes.ColorSpace;
 import org.apache.fop.pdf.PDFColor;
 import org.apache.fop.image.analyser.ImageReader;
@@ -31,42 +32,42 @@ import org.xml.sax.XMLReader;
 public class EPSImage extends AbstractFopImage {
     private String docName;
     private int[] bbox;
-    
+
     private byte[] epsImage = null;
     private EPSReader epsReader = null;
-    
-       /**
-         * Initialize docName and bounding box
-         */
+
+    /**
+    * Initialize docName and bounding box
+    */
     private void init(URL href) {
         bbox = new int[4];
         bbox[0] = 0;
         bbox[1] = 0;
         bbox[2] = 0;
         bbox[3] = 0;
-        
+
         docName = href.toString();
     }
-    
-       /**
-         * Return the name of the eps
-         */
+
+    /**
+    * Return the name of the eps
+    */
     public String getDocName() {
         return docName;
     }
-    
-       /**
-         * Return the bounding box
-         */
+
+    /**
+    * Return the bounding box
+    */
     public int[] getBBox() {
         return bbox;
     }
-    
+
     public EPSImage(URL href) throws FopImageException {
         super(href);
         init(href);
     }
-    
+
     public EPSImage(URL href,
                     ImageReader imgReader) throws FopImageException {
         super(href, imgReader);
@@ -79,16 +80,15 @@ public class EPSImage extends AbstractFopImage {
             bbox = eimgReader.getBBox();
         }
     }
-    
+
     protected void loadImage() throws FopImageException {
-            // Image is loaded in reader
+        // Image is loaded in reader
     }
-    
+
     public byte[] getEPSImage() throws FopImageException {
-               if (epsImage == null) {
-            //log.error("ERROR LOADING EXTERNAL EPS");
-        }
+        if (epsImage == null)
+            MessageHandler.errorln("ERROR LOADING EXTERNAL EPS");
         return epsImage;
     }
-    
+
 }
index 2cbcc45c5a623803c0013d4fe1f298bb500d8815..a6628b5efc7a37f780bce3bd5cb21a42aa91af1c 100644 (file)
@@ -25,7 +25,9 @@ public interface FopImage {
     // Methods throw exception because they can retrieve data
     // when needed.
 
-    // Ressource location
+    public boolean invertImage();
+
+    // Resource location
     public String getURL();
 
     // image size
index 4e1ea97e660c661d17e47b9cf0248f468496ad4c..908abcf3ba341c55e60a99b29feea4b8768b9b86 100644 (file)
@@ -77,11 +77,13 @@ public class FopImageFactory {
             // maybe relative
             URL context_url = null;
             String base = Configuration.getStringValue("baseDir");
+
             if(base == null) {
                 throw new FopImageException("Error with image URL: "
                                              + e.getMessage()
                                              + " and no base directory is specified");
             }
+
             try {
                 absoluteURL = new URL(Configuration.getStringValue("baseDir")
                                       + absoluteURL.getFile());
@@ -138,6 +140,8 @@ public class FopImageFactory {
         } else if ("image/tga".equals(imgMimeType)) {
             imgClassName = "org.apache.fop.image.JimiImage";
             // imgClassName = "org.apache.fop.image.JAIImage";
+        } else if ("image/eps".equals(imgMimeType)) {
+            imgClassName = "org.apache.fop.image.EPSImage";
         } else if ("image/tiff".equals(imgMimeType)) {
             imgClassName = "org.apache.fop.image.JimiImage";
             // imgClassName = "org.apache.fop.image.JAIImage";
index e725b79f59c72ba9ac8b3140dd3e540f237ed1d6..0e439a8a85bd9dada532f61c49214d7a52193a2b 100644 (file)
@@ -28,6 +28,10 @@ import org.apache.fop.image.analyser.ImageReader;
  * @see FopImage
  */
 public class JpegImage extends AbstractFopImage {
+    boolean hasAPPEMarker = false;
+    boolean found_icc_profile = false;
+    boolean found_dimensions = false;
+
     public JpegImage(URL href) throws FopImageException {
         super(href);
     }
@@ -39,8 +43,9 @@ public class JpegImage extends AbstractFopImage {
 
     protected void loadImage() throws FopImageException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ByteArrayOutputStream iccStream = new ByteArrayOutputStream();
         InputStream inStream;
-
+        this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_UNKNOWN);
         byte[] readBuf = new byte[4096];
         int bytes_read;
         int index = 0;
@@ -85,39 +90,94 @@ public class JpegImage extends AbstractFopImage {
                                                  this.m_bitmaps[index + 8]);
 
                         if (this.m_bitmaps[index + 9] == 1) {
-                            this.m_colorSpace = new ColorSpace(
-                                                  ColorSpace.DEVICE_GRAY);
+                            this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_GRAY);
                         } else if (this.m_bitmaps[index + 9] == 3) {
-                            this.m_colorSpace =
-                              new ColorSpace(ColorSpace.DEVICE_RGB);
-                        } else {
+                            this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_RGB);
+                        } else if (this.m_bitmaps[index + 9] == 4) {
+                            this.m_colorSpace.setColorSpace(ColorSpace.DEVICE_CMYK);
+                        }
+
+                        found_dimensions = true;
+                        if (found_icc_profile) {
                             cont = false;
-                            throw new FopImageException(
-                              "\n2 Error while loading image " +
-                              this.m_href.toString() +
-                              " : JpegImage - Invalid JPEG Header (bad color space " +
-                              this.m_bitmaps[index + 9] + ").");
+                            break;
+                        }
+                        index += calcBytes(this.m_bitmaps[index + 2],
+                                           this.m_bitmaps[index + 3]) + 2;
+
+                    } else if (uByte(this.m_bitmaps[index+1]) == 226 &&
+                               this.m_bitmaps.length > (index+60)) {
+                        // Check if ICC profile
+                        byte[] icc_string = new byte[11];
+                        System.arraycopy(this.m_bitmaps, index+4, icc_string, 0, 11);
+
+                        /*
+                        byte[] acsp = new byte[4];
+                        System.arraycopy(this.m_bitmaps, index+18+36, acsp, 0, 4);
+                        boolean first_chunk = false;
+                        if ("acsp".equals(new String(acsp))) {
+                            System.out.println("1st icc chunk");
+                            first_chunk = true;
                         }
+                        */
+                        if ("ICC_PROFILE".equals(new String(icc_string))){
+                            int chunkSize = calcBytes(this.m_bitmaps[index + 2],
+                                                      this.m_bitmaps[index + 3]) + 2;
 
-                        cont = false;
-                        break;
+                            if (iccStream.size() == 0)
+                                iccStream.write(this.m_bitmaps, index+18, chunkSize - 20);
+                            else
+                                iccStream.write(this.m_bitmaps, index+16, chunkSize - 18); // eller 18..
+
+                        }
 
-                    } else { // if (uByte(this.m_bitmaps[index + 1]) == headers[headerIndex]) {
+                        index += calcBytes(this.m_bitmaps[index + 2],
+                                           this.m_bitmaps[index + 3]) + 2;
+                      // Check for Adobe APPE Marker
+                    } else if ((uByte(this.m_bitmaps[index]) == 0xff &&
+                                uByte(this.m_bitmaps[index+1]) == 0xee &&
+                                uByte(this.m_bitmaps[index+2]) == 0 &&
+                                uByte(this.m_bitmaps[index+3]) == 14 &&
+                                "Adobe".equals(new String(this.m_bitmaps, index+4, 5)))) {
+                        // The reason for reading the APPE marker is that photoshop
+                        // generates cmyk jpeg's with inverted values. The correct thing
+                        // to do would be to interpret the values in the marker, but for now
+                        // only assume that if APPE marker is present and colorspace is CMYK,
+                        // the image is inverted.
+                        hasAPPEMarker = true;
+
+                        index += calcBytes(this.m_bitmaps[index + 2],
+                                           this.m_bitmaps[index + 3]) + 2;
+                    } else {
                         index += calcBytes(this.m_bitmaps[index + 2],
                                            this.m_bitmaps[index + 3]) + 2;
                     }
 
+
                 } else {
                     cont = false;
+                    /*
                     throw new FopImageException(
                       "\n2 Error while loading image " +
                       this.m_href.toString() + " : JpegImage - Invalid JPEG Header (bad header byte).");
+                      */
                 }
             }
         } else {
             throw new FopImageException( "\n1 Error while loading image " +
                                          this.m_href.toString() + " : JpegImage - Invalid JPEG Header.");
         }
+        if (iccStream.size() > 0) {
+            byte[] align = new byte[((iccStream.size()) % 8) + 8];
+            try {iccStream.write(align);} catch (Exception e) {
+                throw new FopImageException( "\n1 Error while loading image " +
+                              this.m_href.toString() + " : " + e.getMessage());
+            }
+            this.m_colorSpace.setICCProfile(iccStream.toByteArray());
+        }
+
+        if (hasAPPEMarker && this.m_colorSpace.getColorSpace() == ColorSpace.DEVICE_CMYK)
+            this.m_invertImage = true;
     }
 
     private int calcBytes(byte bOne, byte bTwo) {
index 23ffaee3b87768e11dae93eb420042dd9187c78a..3eee39270966c31a020279d036985ec1f3bb2d5f 100644 (file)
@@ -14,62 +14,70 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 
+
+// FOP
+import org.apache.fop.messaging.*;
+import org.apache.fop.image.SVGImage;
+
 import org.xml.sax.InputSource;
 import org.xml.sax.XMLReader;
 
+
 /**
- * ImageReader object for EPS document image type.
+ * ImageReader object for SVG document image type.
  */
 public class EPSReader extends AbstractImageReader {
     private long[] bbox;
     private boolean isAscii; // True if plain ascii eps file
-    
-       // offsets if not ascii
+
+    // offsets if not ascii
     long psStart = 0;
     long psLength = 0;
     long wmfStart = 0;
     long wmfLength = 0;
     long tiffStart = 0;
     long tiffLength = 0;
-    
-       /** raw eps file */
+
+    /** raw eps file */
     private byte[] rawEps;
-       /** eps part */
+    /** eps part */
     private byte[] epsFile;
     private byte[] preview = null;
-    
+
     private long getLong(byte[] buf, int idx) {
         int b1 = buf[idx] & 0xff;
         int b2 = buf[idx+1] & 0xff;
         int b3 = buf[idx+2] & 0xff;
         int b4 = buf[idx+3] & 0xff;
-        
+
+        //return (long)((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
         return (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
     }
-    
+
     public boolean verifySignature(String uri, BufferedInputStream fis)
-        throws IOException {
+            throws IOException {
         boolean isEPS = false;
         this.imageStream = fis;
         fis.mark(32);
         byte[] header = new byte[30];
         fis.read(header, 0, 30);
         fis.reset();
-        
-            // Check if binary header
+
+        // Check if binary header
+        //if (getLong(header, 0) == 0xC5D0D3C6) {
         if (getLong(header, 0) == 0xC6D3D0C5) {
             isAscii = false;
             isEPS = true;
-            
+
             psStart = getLong(header, 4);
             psLength = getLong(header, 8);
             wmfStart = getLong(header, 12);
             wmfLength = getLong(header, 16);
             tiffStart = getLong(header, 20);
             tiffLength = getLong(header, 24);
-            
+
         } else {
-                // Check if plain ascii
+            // Check if plain ascii
             byte[] epsh = "%!PS".getBytes();
             if (epsh[0] == header[0] &&
                 epsh[1] == header[1] &&
@@ -79,24 +87,24 @@ public class EPSReader extends AbstractImageReader {
                 isEPS = true;
             }
         }
-        
+
         if (isEPS) {
             readEPSImage(fis);
             bbox = readBBox();
-            
+
             if (bbox != null) {
                 width = (int)(bbox[2]-bbox[0]);
                 height = (int)(bbox[3]-bbox[1]);
             } else {
-                // Ain't eps if no BoundingBox
+                // Ain't eps if no BoundingBox
                 isEPS = false;
             }
         }
-        
+
         return isEPS;
     }
-    
-       /** read the eps file and extract eps part */
+
+    /** read the eps file and extract eps part */
     private void readEPSImage(BufferedInputStream fis) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         byte[] file;
@@ -104,8 +112,8 @@ public class EPSReader extends AbstractImageReader {
         int bytes_read;
         int index = 0;
         boolean cont = true;
-        
-        
+
+
         try {
             while ((bytes_read = fis.read(readBuf)) != -1) {
                 baos.write(readBuf, 0, bytes_read);
@@ -113,9 +121,9 @@ public class EPSReader extends AbstractImageReader {
         } catch (java.io.IOException ex) {
             throw new IOException("Error while loading EPS image " + ex.getMessage());
         }
-        
+
         file = baos.toByteArray();
-        
+
         if (isAscii) {
             rawEps = null;
             epsFile = new byte[file.length];
@@ -127,12 +135,12 @@ public class EPSReader extends AbstractImageReader {
             System.arraycopy(rawEps, (int)psStart, epsFile, 0, (int)psLength);
         }
     }
-    
+
     public byte[] getEpsFile() {
         return epsFile;
     }
-    
-       /* Get embedded preview or null */
+
+    /* Get embedded preview or null */
     public byte[] getPreview() {
         InputStream is = null;
         if (preview == null) {
@@ -143,15 +151,15 @@ public class EPSReader extends AbstractImageReader {
         }
         return preview;
     }
-    
-       /** Extract bounding box from eps part
-         */
+
+    /** Extract bounding box from eps part
+    */
     private long[] readBBox() {
         long[] mbbox = null;
         int idx = 0;
         byte[] bbxName = "%%BoundingBox: ".getBytes();
         boolean found = false;
-        
+
         while (!found && (epsFile.length  > (idx + bbxName.length))) {
             boolean sfound = true;
             int i = idx;
@@ -166,46 +174,46 @@ public class EPSReader extends AbstractImageReader {
                 idx++;
             }
         }
-        
+
         if (!found)
             return mbbox;
-        
-        
+
+
         mbbox = new long[4];
         idx += readLongString(mbbox, 0, idx);
         idx += readLongString(mbbox, 1, idx);
         idx += readLongString(mbbox, 2, idx);
         idx += readLongString(mbbox, 3, idx);
-        
+
         return mbbox;
     }
-    
+
     private int readLongString(long[] mbbox, int i, int idx) {
         while (idx < epsFile.length &&
                (epsFile[idx] == 32))
-            idx++;
-        
+               idx++;
+
         int nidx = idx;
-        
+
         while (nidx < epsFile.length &&
-               (epsFile[nidx] >= 48 && epsFile[nidx] <= 57))
+            (epsFile[nidx] >= 48 && epsFile[nidx] <= 57))
             nidx++;
-        
+
         byte[] num = new byte[nidx - idx];
         System.arraycopy(epsFile, idx, num, 0, nidx-idx);
         String ns = new String(num);
         mbbox[i] = Long.parseLong(ns);
-        
+
         return (1+nidx - idx);
     }
-    
+
     public String getMimeType() {
         return "image/eps";
     }
-    
-       /**
-         * Return the BoundingBox
-         */
+
+    /**
+    * Return the BoundingBox
+    */
     public int[] getBBox() {
         int[] bbox = new int[4];
         bbox[0] = (int)this.bbox[0];
index e9b5ce3f024ec258a2579bf1f2f17774177b3034..f2c2160b75f162fc1c802c4f96a9778f4bdac318 100644 (file)
@@ -42,6 +42,7 @@ public class ImageReaderFactory {
         formats.addElement(new GIFReader());
         formats.addElement(new PNGReader());
         formats.addElement(new TIFFReader());
+        formats.addElement(new EPSReader());
         formats.addElement(new SVGReader());
         //
 
index 498db1000c141487bb7b432226079b954ddc5262..f951f11b3cbdb9590ee5d827878c1bd634e18730 100644 (file)
@@ -23,6 +23,7 @@ public class FontState {
     private int _fontVariant;
 
     private FontMetric _metric;
+    private int _letterSpacing;
 
     private static Hashtable EMPTY_HASHTABLE = new Hashtable();
 
@@ -38,12 +39,27 @@ public class FontState {
         _fontName = fontInfo.fontLookup(fontFamily, fontStyle, fontWeight);
         _metric = fontInfo.getMetricsFor(_fontName);
         _fontVariant = fontVariant;
+        _letterSpacing = 0;
     }
 
+    public FontState(FontInfo fontInfo, String fontFamily, String fontStyle,
+                     String fontWeight, int fontSize,
+                     int fontVariant, int letterSpacing) throws FOPException {
+        this(fontInfo, fontFamily, fontStyle, fontWeight, fontSize,
+             fontVariant);
+        _letterSpacing = letterSpacing;
+    }
+
+
     public int getAscender() {
         return _metric.getAscender(_fontSize) / 1000;
     }
 
+    public int getLetterSpacing() {
+        return _letterSpacing;
+    }
+
+
     public int getCapHeight() {
         return _metric.getCapHeight(_fontSize) / 1000;
     }
@@ -95,7 +111,7 @@ public class FontState {
 
     public int width(int charnum) {
         // returns width of given character number in millipoints
-        return (_metric.width(charnum, _fontSize) / 1000);
+        return _letterSpacing + (_metric.width(charnum, _fontSize) / 1000);
     }
 
     /**
index cdf039b9f1d08b01743a1f343474031fed189ae2..3d4393f0a511a3860434257d113000b974bdcad4 100644 (file)
@@ -156,7 +156,7 @@ public class PDFDocument {
 
     /**
      * creates an empty PDF document <p>
-     * 
+     *
      * The constructor creates a /Root and /Pages object to
      * track the document but does not write these objects until
      * the trailer is written. Note that the object ID of the
@@ -761,6 +761,12 @@ public class PDFDocument {
     }
 
 
+    public PDFICCStream makePDFICCStream() {
+        PDFICCStream iccStream = new PDFICCStream(++this.objectcount);
+        this.objects.addElement(iccStream);
+        return iccStream;
+    }
+
     /**
      * make a Type1 /Font object
      *
@@ -918,8 +924,7 @@ public class PDFDocument {
         if (xObject != null)
             return xObject.getXNumber();
         // else, create a new one
-        xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount,
-                                 img);
+        xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount, img, this);
         this.objects.addElement(xObject);
         this.xObjects.addElement(xObject);
         this.xObjectsMap.put(url, xObject);
@@ -1033,8 +1038,8 @@ public class PDFDocument {
             //next line by lmckenzi@ca.ibm.com
             //solves when IDNode made before IDReferences.createID called
             //idReferences.createNewId(destination);
-            idReferences.createUnvalidatedID(destination); 
+
+            idReferences.createUnvalidatedID(destination);
             idReferences.addToIdValidationList(destination);
             goToReference = idReferences.createInternalLinkGoTo(destination,
                             ++this.objectcount);
index 7890b51a9a2f4330df1ecf3325e9f18042b39fda..5d96be0cd26158c9359d277fcd9900cf508f25fa 100644 (file)
@@ -12,37 +12,37 @@ public class PDFICCStream extends PDFStream {
     private int origLength;
     private int len1, len3;
     private byte[] originalData = null;
-    
+
     private ColorSpace cs;
-    
+
     public void setColorSpace(ColorSpace cs) throws java.io.IOException {
         this.cs = cs;
         setData(cs.getICCProfile());
     }
-    
+
     public PDFICCStream(int num) {
         super(num);
         cs = null;
     }
-    
+
     public PDFICCStream(int num, ColorSpace cs) throws java.io.IOException {
         super(num);
         setColorSpace(cs);
     }
-    
-        // overload the base object method so we don't have to copy
-        // byte arrays around so much
+
+    // overload the base object method so we don't have to copy
+    // byte arrays around so much
     protected int output(java.io.OutputStream stream)
-        throws java.io.IOException {
+            throws java.io.IOException {
         int length = 0;
         String filterEntry = applyFilters();
         StringBuffer pb = new StringBuffer();
         pb.append(this.number).append(" ").append(this.generation).append(" obj\n<< ");
         pb.append("/N ").append(cs.getNumComponents()).append(" ");
-        
+
         if (cs.getColorSpace() > 0)
             pb.append("/Alternate /").append(cs.getColorSpacePDFString()).append(" ");
-        
+
         pb.append("/Length ").append((_data.size() + 1)).append(" ").append(filterEntry);
         pb.append(" >>\n");
         byte[] p = pb.toString().getBytes();
@@ -54,4 +54,6 @@ public class PDFICCStream extends PDFStream {
         length += p.length;
         return length;
     }
+
+
 }
index 8de99f2608cc34f318bce65bf8d42a475d58bf2d..a651a0637bae4e83a0a7805a56d43bc6f2c651f2 100644 (file)
@@ -93,7 +93,7 @@ public class PDFT1Stream extends PDFStream {
         p = "endobj\n".getBytes();
         stream.write(p);
         length += p.length;
-        System.out.println("Embedded Type1 font");
+        //System.out.println("Embedded Type1 font");
         return length;
     }
 
index f56e5f587e36931b6d34f0de5c40bb8b81c3dbd3..ac0a7bf8d1b86d6ee003b76db55268d00ae8e8d2 100644 (file)
@@ -40,7 +40,7 @@ public class PDFTTFStream extends PDFStream {
 
     public void setData(byte[] data, int size) throws java.io.IOException {
         _data.reset();
-        System.out.println("Writing " + size + " bytes of font data");
+        //System.out.println("Writing " + size + " bytes of font data");
         _data.write(data, 0, size);
     }
 
index 8d670a574331e9dbe52ce79d940a204b04217904..ef859f807c5cea1712fc4d7d8183e89085f2bdef 100644 (file)
@@ -17,7 +17,11 @@ import java.io.OutputStream;
 
 // FOP
 import org.apache.fop.datatypes.ColorSpace;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFICCStream;
 import org.apache.fop.image.FopImage;
+import org.apache.fop.image.EPSImage;
+import org.apache.fop.image.JpegImage;
 import org.apache.fop.image.FopImageException;
 
 /**
@@ -28,21 +32,44 @@ import org.apache.fop.image.FopImageException;
  * the dictionary just provides information like the stream length
  */
 public class PDFXObject extends PDFObject {
+    private boolean isPS;
+    private PDFDocument pdfDoc;
+    private PDFICCStream pdfICCStream;
 
     FopImage fopimage;
     int Xnum;
 
-
     /**
      * create an Xobject with the given number and name and load the
      * image in the object
      */
     public PDFXObject(int number, int Xnumber, FopImage img) {
+        this(number, Xnumber, img, null);
+    }
+
+    public PDFXObject(int number, int Xnumber, FopImage img, PDFDocument pdfdoc) {
         super(number);
+        isPS = false;
         this.Xnum = Xnumber;
         if (img == null)
             MessageHandler.errorln("FISH");
         fopimage = img;
+        this.pdfDoc = pdfdoc;
+        pdfICCStream = null;
+        try {
+            if (fopimage instanceof JpegImage) {
+                fopimage.getBitmaps();
+                JpegImage jpegimage = (JpegImage)fopimage;
+                if (jpegimage.getColorSpace().hasICCProfile()) {
+                        pdfICCStream = pdfDoc.makePDFICCStream();
+                        pdfICCStream.setColorSpace(jpegimage.getColorSpace());
+                        pdfICCStream.addDefaultFilters();
+                    }
+            }
+        } catch (Exception e) {
+            MessageHandler.errorln("Error while reading image " + fopimage.getURL() +
+                            ": " + e.getMessage());
+        }
     }
 
     /**
@@ -58,58 +85,141 @@ public class PDFXObject extends PDFObject {
     protected int output(OutputStream stream) throws IOException {
         int length = 0;
         int i = 0;
-        int x, y;
 
         try {
-            // delegate the stream work to PDFStream
-            PDFStream imgStream = new PDFStream(0);
-
-            imgStream.setData(fopimage.getBitmaps());
-
-            /*
-             * Added by Eric Dalquist
-             * If the DCT filter hasn't been added to the object we add it here
-             */
-            if (fopimage.getPDFFilter() != null) {
-                imgStream.addFilter(fopimage.getPDFFilter());
-            }
-
-            imgStream.addDefaultFilters();
-
-            String dictEntries = imgStream.applyFilters();
-
-            String p = this.number + " " + this.generation + " obj\n";
-            p = p + "<</Type /XObject\n";
-            p = p + "/Subtype /Image\n";
-            p = p + "/Name /Im" + Xnum + "\n";
-            p = p + "/Length " + imgStream.getDataLength() + "\n";
-            p = p + "/Width " + fopimage.getWidth() + "\n";
-            p = p + "/Height " + fopimage.getHeight() + "\n";
-            p = p + "/BitsPerComponent " + fopimage.getBitsPerPixel() + "\n";
-            ColorSpace cs = fopimage.getColorSpace();
-            p = p + "/ColorSpace /" + cs.getColorSpacePDFString() + "\n";
-            if (fopimage.isTransparent()) {
-                PDFColor transp = fopimage.getTransparentColor();
-                p = p + "/Mask [" + transp.red255() + " " + transp.red255()
-                    + " " + transp.green255() + " " + transp.green255() + " "
-                    + transp.blue255() + " " + transp.blue255() + "]\n";
+            if (fopimage instanceof EPSImage) {
+                isPS = true;
+                EPSImage epsImage = (EPSImage)fopimage;
+                int[] bbox = epsImage.getBBox();
+                int bboxw = bbox[2] - bbox[0];
+                int bboxh = bbox[3] - bbox[1];
+
+                // delegate the stream work to PDFStream
+                PDFStream imgStream = new PDFStream(0);
+
+                StringBuffer preamble = new StringBuffer();
+                preamble.append("%%BeginDocument: " + epsImage.getDocName() + "\n");
+
+                preamble.append("userdict begin                 % Push userdict on dict stack\n");
+                preamble.append("/PreEPS_state save def\n");
+                preamble.append("/dict_stack countdictstack def\n");
+                preamble.append("/ops_count count 1 sub def\n");
+                preamble.append("/showpage {} def\n");
+
+
+                preamble.append((double)(1f/(double)bboxw) + " " + (double)(1f/(double)bboxh) + " scale\n");
+                preamble.append(-bbox[0] + " " + (-bbox[1]) + " translate\n");
+                preamble.append(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + " rectclip\n");
+                preamble.append("newpath\n");
+
+                StringBuffer post = new StringBuffer();
+                post.append("%%EndDocument\n");
+                post.append("count ops_count sub {pop} repeat\n");
+                post.append("countdictstack dict_stack sub {end} repeat\n");
+                post.append("PreEPS_state restore\n");
+                post.append("end % userdict\n");
+
+                byte[] preBytes = preamble.toString().getBytes();
+                byte[] postBytes = post.toString().getBytes();
+                byte[] imgData = new byte[preBytes.length + postBytes.length + fopimage.getBitmaps().length];
+
+                System.arraycopy (preBytes, 0, imgData, 0, preBytes.length);
+                System.arraycopy (fopimage.getBitmaps(), 0, imgData, preBytes.length, fopimage.getBitmaps().length);
+                System.arraycopy (postBytes, 0, imgData, preBytes.length + fopimage.getBitmaps().length, postBytes.length);
+
+
+                imgStream.setData(imgData);
+                //imgStream.addFilter(new FlateFilter());
+                imgStream.addDefaultFilters();
+
+                String dictEntries = imgStream.applyFilters();
+
+                String p = this.number + " " + this.generation + " obj\n";
+                p = p + "<</Type /XObject\n";
+                p = p + "/Subtype /PS\n";
+                p = p + "/Length " + imgStream.getDataLength();
+
+                // don't know if it's the good place (other objects can have references to it)
+                fopimage.close();
+                p = p + dictEntries;
+                p = p + ">>\n";
+
+                // push the pdf dictionary on the writer
+                byte[] pdfBytes = p.getBytes();
+                stream.write(pdfBytes);
+                length += pdfBytes.length;
+                // push all the image data on  the writer and takes care of length for trailer
+                length += imgStream.outputStreamData(stream);
+
+                pdfBytes = ("endobj\n").getBytes();
+                stream.write(pdfBytes);
+                length += pdfBytes.length;
+
+            } else {
+
+                // delegate the stream work to PDFStream
+                PDFStream imgStream = new PDFStream(0);
+
+                imgStream.setData(fopimage.getBitmaps());
+
+                /*
+                 * Added by Eric Dalquist
+                 * If the DCT filter hasn't been added to the object we add it here
+                 */
+                if (fopimage.getPDFFilter() != null) {
+                    imgStream.addFilter(fopimage.getPDFFilter());
+                }
+
+                imgStream.addDefaultFilters();
+
+                String dictEntries = imgStream.applyFilters();
+
+                String p = this.number + " " + this.generation + " obj\n";
+                p = p + "<</Type /XObject\n";
+                p = p + "/Subtype /Image\n";
+                p = p + "/Name /Im" + Xnum + "\n";
+                p = p + "/Length " + imgStream.getDataLength() + "\n";
+                p = p + "/Width " + fopimage.getWidth() + "\n";
+                p = p + "/Height " + fopimage.getHeight() + "\n";
+                p = p + "/BitsPerComponent " + fopimage.getBitsPerPixel() + "\n";
+
+                if (pdfICCStream != null ) {
+                    p = p + "/ColorSpace [/ICCBased " + pdfICCStream.referencePDF() + "]\n";
+                } else {
+                    ColorSpace cs = fopimage.getColorSpace();
+                    p = p + "/ColorSpace /" + cs.getColorSpacePDFString() + "\n";
+                }
+
+                    /* PhotoShop generates CMYK values that's inverse,
+                     */
+                if (fopimage.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK &&
+                    fopimage.invertImage()) {
+                    p = p + "/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.1 0.0 ]\n";
+                }
+
+                if (fopimage.isTransparent()) {
+                    PDFColor transp = fopimage.getTransparentColor();
+                    p = p + "/Mask [" + transp.red255() + " " + transp.red255()
+                        + " " + transp.green255() + " " + transp.green255() + " "
+                        + transp.blue255() + " " + transp.blue255() + "]\n";
+                }
+                p = p + dictEntries;
+                p = p + ">>\n";
+
+                // don't know if it's the good place (other objects can have references to it)
+                fopimage.close();
+
+                // push the pdf dictionary on the writer
+                byte[] pdfBytes = p.getBytes();
+                stream.write(pdfBytes);
+                length += pdfBytes.length;
+                // push all the image data on  the writer and takes care of length for trailer
+                length += imgStream.outputStreamData(stream);
+
+                pdfBytes = ("endobj\n").getBytes();
+                stream.write(pdfBytes);
+                length += pdfBytes.length;
             }
-            p = p + dictEntries;
-            p = p + ">>\n";
-
-            // don't know if it's the good place (other objects can have references to it)
-            fopimage.close();
-
-            // push the pdf dictionary on the writer
-            byte[] pdfBytes = p.getBytes();
-            stream.write(pdfBytes);
-            length += pdfBytes.length;
-            // push all the image data on  the writer and takes care of length for trailer
-            length += imgStream.outputStreamData(stream);
-
-            pdfBytes = ("endobj\n").getBytes();
-            stream.write(pdfBytes);
-            length += pdfBytes.length;
         } catch (FopImageException imgex) {
             MessageHandler.errorln("Error in XObject : "
                                    + imgex.getMessage());
index ec9da072539d4045c1f4719f666436fd6eeea72c..6ea1e9c031e98258859789379ae7f1b2b298fced 100644 (file)
@@ -548,6 +548,10 @@ public class PDFRenderer extends PrintRenderer {
             addWordLines(area, rx, bl, size, areaColor);
 
 
+            // Set letterSpacing
+            float ls = area.getFontState().getLetterSpacing() / this.currentFontSize;
+            pdf.append(ls).append(" Tc\n");
+
             if (!textOpen || bl != prevWordY) {
                 closeText();
 
@@ -576,7 +580,6 @@ public class PDFRenderer extends PrintRenderer {
             prevWordWidth = area.getContentWidth();
             prevWordX = rx;
 
-
             String s;
             if (area.getPageNumberID()
                     != null) {    // this text is a page number, so resolve it
@@ -687,6 +690,7 @@ public class PDFRenderer extends PrintRenderer {
         }
     }
 
+
     public void render(Page page, OutputStream outputStream)
     throws FOPException, IOException {
         // log.debug("rendering single page to PDF");
index d380f54ef18c2a6161f0e50da6368eb537fd7b17..372e334dc4be64b9bd264f06398aeb1b54425df1 100644 (file)
@@ -13,6 +13,7 @@ import org.apache.fop.render.AbstractRenderer;
 import org.apache.fop.render.Renderer;
 import org.apache.fop.image.ImageArea;
 import org.apache.fop.image.FopImage;
+import org.apache.fop.image.JpegImage;
 import org.apache.fop.image.FopImageException;
 import org.apache.fop.layout.*;
 import org.apache.fop.layout.inline.*;
@@ -156,6 +157,7 @@ public class PSRenderer extends AbstractRenderer {
         write("/M/moveto ld");
         write("/RM/rmoveto ld");
         write("/t/show ld");
+        write("/A/ashow ld");
 
         write("/ux 0.0 def");
         write("/uy 0.0 def");
@@ -303,11 +305,11 @@ public class PSRenderer extends AbstractRenderer {
         BridgeContext ctx = new BridgeContext(userAgent);
 
         GraphicsNode root;
-        try {        
+        try {
             root = builder.build(ctx, doc);
-        } catch (Exception e) {        
+        } catch (Exception e) {
             log.error("svg graphic could not be built: "
-                                   + e.getMessage(), e);        
+                                   + e.getMessage(), e);
             return;
         }
         // get the 'width' and 'height' attributes of the SVG document
@@ -355,6 +357,34 @@ public class PSRenderer extends AbstractRenderer {
         movetoCurrPosition();
     }
 
+    public void renderEPS(FopImage img, int x, int y, int w, int h) {
+        try {
+            EPSImage eimg = (EPSImage)img;
+            int[] bbox = eimg.getBBox();
+            int bboxw = bbox[2] - bbox[0];
+            int bboxh = bbox[3] - bbox[1];
+
+
+            write("%%BeginDocument: " + eimg.getDocName());
+            write("BeginEPSF");
+
+            write(x + " " + (y - h) + " translate");
+            write("0.0 rotate");
+            write((long)(w/bboxw) + " " + (long)(h/bboxh) + " scale");
+            write(-bbox[0] + " " + (-bbox[1]) + " translate");
+            write(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + " rectclip");
+            write("newpath");
+            out.writeByteArr(img.getBitmaps());
+            write("%%EndDocument");
+            write("EndEPSF");
+            write("");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+                                   + e.getMessage() + ")", e);
+        }
+    }
+
     public void renderBitmap(FopImage img, int x, int y, int w, int h) {
         try {
             boolean iscolor = img.getColorSpace().getColorSpace()
@@ -362,7 +392,11 @@ public class PSRenderer extends AbstractRenderer {
             byte[] imgmap = img.getBitmaps();
 
             write("gsave");
-            write("/DeviceRGB setcolorspace");
+            if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK)
+                write("/DeviceCMYK setcolorspace");
+            else
+                write("/DeviceRGB setcolorspace");
+
             write(x + " " + (y - h) + " translate");
             write(w + " " + h + " scale");
             write("<<");
@@ -370,7 +404,12 @@ public class PSRenderer extends AbstractRenderer {
             write("  /Width " + img.getWidth());
             write("  /Height " + img.getHeight());
             write("  /BitsPerComponent 8");
-            if (iscolor) {
+            if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) {
+                if (img.invertImage())
+                    write("  /Decode [1 0 1 0 1 0 1 0]");
+                else
+                    write("  /Decode [0 1 0 1 0 1 0 1]");
+            } else if (iscolor) {
                 write("  /Decode [0 1 0 1 0 1]");
             } else {
                 write("  /Decode [0 1]");
@@ -378,7 +417,11 @@ public class PSRenderer extends AbstractRenderer {
             // Setup scanning for left-to-right and top-to-bottom
             write("  /ImageMatrix [" + img.getWidth() + " 0 0 -"
                   + img.getHeight() + " 0 " + img.getHeight() + "]");
-            write("  /DataSource currentfile /ASCII85Decode filter /FlateDecode filter");
+
+            if (img instanceof JpegImage)
+                write("  /DataSource currentfile /ASCII85Decode filter /DCTDecode filter");
+            else
+                write("  /DataSource currentfile /ASCII85Decode filter /FlateDecode filter");
             // write("  /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter");
             // write("  /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter");
             // write("  /DataSource currentfile /ASCIIHexDecode filter /RunLengthDecode filter");
@@ -408,7 +451,8 @@ public class PSRenderer extends AbstractRenderer {
                 InputStream bain = new ByteArrayInputStream(imgmap);
                 InputStream in;
                 in = bain;
-                in = FlateEncodeFilter.filter(in);
+                if (!(img instanceof JpegImage))
+                    in = FlateEncodeFilter.filter(in);
                 // in = RunLengthEncodeFilter.filter(in);
                 // in = ASCIIHexEncodeFilter.filter(in);
                 in = ASCII85EncodeFilter.filter(in);
@@ -442,9 +486,11 @@ public class PSRenderer extends AbstractRenderer {
         imagecount++;
         // if (imagecount!=4) return;
 
-        comment("% --- ImageArea");
+                comment("% --- ImageArea");
         if (area.getImage() instanceof SVGImage) {}
-        else {
+        else if (area.getImage() instanceof EPSImage) {
+            renderEPS(area.getImage(), x, y, w, h);
+        } else {
             renderBitmap(area.getImage(), x, y, w, h);
         }
         comment("% --- ImageArea end");
@@ -488,7 +534,7 @@ public class PSRenderer extends AbstractRenderer {
             s = area.getText();
         }
         int l = s.length();
-        
+
         for (int i = 0; i < l; i++) {
             char ch = s.charAt(i);
             char mch = fs.mapChar(ch);
@@ -502,6 +548,17 @@ public class PSRenderer extends AbstractRenderer {
                 sb = sb.append(mch);
             }
         }
+
+        String psString = null;
+        if (area.getFontState().getLetterSpacing() > 0) {
+            float f = area.getFontState().getLetterSpacing() * 1000 / this.currentFontSize;
+            psString = (new StringBuffer().append(f).append(" 0.0 (").append(sb).
+                        append(") A")).toString();
+        } else {
+            psString = (new StringBuffer("(").append(sb).append(") t")).toString();
+        }
+
+
         // System.out.println("["+s+"] --> ["+sb.toString()+"]");
 
         // comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
@@ -510,7 +567,7 @@ public class PSRenderer extends AbstractRenderer {
         if (area.getUnderlined() || area.getLineThrough()
                 || area.getOverlined())
             write("ULS");
-        write("(" + sb.toString() + ") t");
+        write(psString);
         if (area.getUnderlined())
             write("ULE");
         if (area.getLineThrough())
@@ -824,6 +881,35 @@ public class PSRenderer extends AbstractRenderer {
         write("%%EndProlog");
         write("%%BeginSetup");
         writeFontDict(fontInfo);
+
+        /* Write proc for including EPS */
+        write("%%BeginResource: procset EPSprocs");
+        write("%%Title: EPS encapsulation procs");
+
+        write("/BeginEPSF { %def");
+        write("/b4_Inc_state save def         % Save state for cleanup");
+        write("/dict_count countdictstack def % Count objects on dict stack");
+        write("/op_count count 1 sub def      % Count objects on operand stack");
+        write("userdict begin                 % Push userdict on dict stack");
+        write("/showpage { } def              % Redefine showpage, { } = null proc");
+        write("0 setgray 0 setlinecap         % Prepare graphics state");
+        write("1 setlinewidth 0 setlinejoin");
+        write("10 setmiterlimit [ ] 0 setdash newpath");
+        write("/languagelevel where           % If level not equal to 1 then");
+        write("{pop languagelevel             % set strokeadjust and");
+        write("1 ne                           % overprint to their defaults.");
+        write("{false setstrokeadjust false setoverprint");
+        write("} if");
+        write("} if");
+        write("} bind def");
+
+        write("/EndEPSF { %def");
+        write("count op_count sub {pop} repeat            % Clean up stacks");
+        write("countdictstack dict_count sub {end} repeat");
+        write("b4_Inc_state restore");
+        write("} bind def");
+        write("%%EndResource");
+
         write("%%EndSetup");
         write("FOPFonts begin");
     }
index 9b03c11fd8bd04292c55395fe8cca98bbc1e468a..f752b7148d10e3672b4850282441ba35e884d9c3 100644 (file)
@@ -22,4 +22,8 @@ public class PSStream extends FilterOutputStream {
         write('\n');
     }
 
+    public void writeByteArr(byte[] cmd) throws IOException {
+        write(cmd);
+        write('\n');
+    }
 }