Browse Source

Removed old image adapters.

Removed support for Java 1.3 building as it didn't work anymore anyway.
Added a check to require Java 1.4 for building.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_95@637791 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_95beta
Jeremias Maerki 16 years ago
parent
commit
49c55efd33
44 changed files with 18 additions and 5944 deletions
  1. 2
    2
      build.properties
  2. 4
    76
      build.xml
  3. 0
    31
      src/java-1.3/org/apache/fop/svg/GraphicsConfiguration.java
  4. 0
    237
      src/java-1.4/org/apache/fop/image/ImageIOImage.java
  5. 0
    161
      src/java-1.4/org/apache/fop/image/JpegImageIOImage.java
  6. 0
    10
      src/java/org/apache/fop/apps/FopFactory.java
  7. 6
    0
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  8. 0
    5
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  9. 0
    376
      src/java/org/apache/fop/image/AbstractFopImage.java
  10. 0
    220
      src/java/org/apache/fop/image/BmpImage.java
  11. 0
    122
      src/java/org/apache/fop/image/EPSImage.java
  12. 0
    51
      src/java/org/apache/fop/image/EmfImage.java
  13. 0
    207
      src/java/org/apache/fop/image/FopImage.java
  14. 0
    211
      src/java/org/apache/fop/image/FopImageConsumer.java
  15. 0
    218
      src/java/org/apache/fop/image/GifImage.java
  16. 0
    72
      src/java/org/apache/fop/image/ImageCache.java
  17. 0
    708
      src/java/org/apache/fop/image/ImageFactory.java
  18. 0
    64
      src/java/org/apache/fop/image/ImageLoader.java
  19. 0
    194
      src/java/org/apache/fop/image/JAIImage.java
  20. 0
    186
      src/java/org/apache/fop/image/JimiImage.java
  21. 0
    239
      src/java/org/apache/fop/image/JpegImage.java
  22. 0
    87
      src/java/org/apache/fop/image/PNGImage.java
  23. 0
    49
      src/java/org/apache/fop/image/RegisterableImageProvider.java
  24. 0
    207
      src/java/org/apache/fop/image/TIFFImage.java
  25. 0
    78
      src/java/org/apache/fop/image/XMLImage.java
  26. 0
    239
      src/java/org/apache/fop/image/XmlGraphicsCommonsImage.java
  27. 0
    134
      src/java/org/apache/fop/image/analyser/BMPReader.java
  28. 0
    162
      src/java/org/apache/fop/image/analyser/EMFReader.java
  29. 0
    253
      src/java/org/apache/fop/image/analyser/EPSReader.java
  30. 0
    104
      src/java/org/apache/fop/image/analyser/GIFReader.java
  31. 0
    56
      src/java/org/apache/fop/image/analyser/ImageReader.java
  32. 0
    108
      src/java/org/apache/fop/image/analyser/ImageReaderFactory.java
  33. 0
    264
      src/java/org/apache/fop/image/analyser/JPEGReader.java
  34. 0
    115
      src/java/org/apache/fop/image/analyser/PNGReader.java
  35. 0
    188
      src/java/org/apache/fop/image/analyser/SVGReader.java
  36. 0
    53
      src/java/org/apache/fop/image/analyser/SVGZReader.java
  37. 0
    117
      src/java/org/apache/fop/image/analyser/TIFFReader.java
  38. 0
    167
      src/java/org/apache/fop/image/analyser/XMLReader.java
  39. 0
    23
      src/java/org/apache/fop/image/analyser/package.html
  40. 1
    1
      src/java/org/apache/fop/image/package.html
  41. 0
    73
      src/java/org/apache/fop/render/ps/PSImageUtils.java
  42. 0
    70
      src/java/org/apache/fop/render/rtf/SVGConverter.java
  43. 0
    0
      src/java/org/apache/fop/svg/GraphicsConfiguration.java
  44. 5
    6
      test/java/org/apache/fop/URIResolutionTestCase.java

+ 2
- 2
build.properties View File

@@ -24,8 +24,8 @@
# javac.debug = on
# javac.optimize = off
# javac.deprecation = on
# javac.source = 1.3
# javac.target = 1.3
# javac.source = 1.4
# javac.target = 1.4
# javac.fork = on

## JUnit task switches

+ 4
- 76
build.xml View File

@@ -131,15 +131,6 @@ list of possible build targets.
</fileset>
</path>

<patternset id="exclude-jimi">
<exclude name="org/apache/fop/image/JimiImage.java" unless="jimi.present"/>
</patternset>

<patternset id="exclude-jai">
<exclude name="org/apache/fop/image/JAIImage.java" unless="jai.present"/>
<exclude name="org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java" unless="jai.present"/>
</patternset>

<patternset id="exclude-jce-dependencies">
<exclude name="org/apache/fop/pdf/PDFEncryptionJCE.java" unless="jce.present"/>
</patternset>
@@ -214,7 +205,7 @@ list of possible build targets.
<!-- =================================================================== -->
<!-- Initialization target -->
<!-- =================================================================== -->
<target name="init" depends="init-avail, init-filters-jdk14, init-filters-jdk13">
<target name="init" depends="init-avail">
</target>

<target name="init-avail">
@@ -224,30 +215,6 @@ list of possible build targets.
<echo message="VM: ${java.vm.version}, ${java.vm.vendor}"/>
<echo message="JAVA_HOME: ${env.JAVA_HOME}"/>

<available property="jimi.present" classname="com.sun.jimi.core.Jimi"
classpathref="libs-build-classpath"/>
<condition property="jimi.message" value="Jimi Support PRESENT">
<equals arg1="${jimi.present}" arg2="true"/>
</condition>
<condition property="jimi.message" value="Jimi Support NOT Present">
<not>
<equals arg1="${jimi.present}" arg2="true"/>
</not>
</condition>
<echo message="${jimi.message}"/>

<available property="jai.present" classname="javax.media.jai.JAI"
classpathref="libs-build-classpath"/>
<condition property="jai.message" value="JAI Support PRESENT">
<equals arg1="${jai.present}" arg2="true"/>
</condition>
<condition property="jai.message" value="JAI Support NOT Present">
<not>
<equals arg1="${jai.present}" arg2="true"/>
</not>
</condition>
<echo message="${jai.message}"/>

<available property="jce.present" classname="javax.crypto.Cipher"
classpathref="libs-build-classpath"/>
<condition property="jce.message" value="JCE Support PRESENT">
@@ -261,7 +228,8 @@ list of possible build targets.
<echo message="${jce.message}"/>

<available property="jdk14.present" classname="java.lang.CharSequence"/>

<fail message="${Name} requires at least Java 1.4!" unless="jdk14.present"/>
<available property="junit.present" classname="junit.framework.TestCase"
classpathref="libs-build-classpath"/>
<condition property="junit.message" value="JUnit Support PRESENT">
@@ -292,22 +260,6 @@ list of possible build targets.
</target>

<target name="init-filters-jdk13" depends="init-avail" unless="jdk14.present">
<echo message="Use GraphicsConfiguration adapter for JDK 1.3 or earlier."/>
<path id="graphics-configuration-adapter">
<pathelement location="src/java-1.3"/>
</path>
<property name="src.java.version.dir" value="${basedir}/src/java-1.3"/>
</target>

<target name="init-filters-jdk14" depends="init-avail" if="jdk14.present">
<echo message="Use GraphicsConfiguration adapter for JDK 1.4."/>
<path id="graphics-configuration-adapter">
<pathelement location="src/java-1.4"/>
</path>
<property name="src.java.version.dir" value="${basedir}/src/java-1.4"/>
</target>

<!-- =================================================================== -->
<!-- Help on usage -->
<!-- =================================================================== -->
@@ -401,12 +353,8 @@ list of possible build targets.
source="${javac.source}" target="${javac.target}">
<src path="${build.gensrc.dir}"/>
<src path="${src.java.dir}"/>
<src refid="graphics-configuration-adapter"/>
<patternset includes="**/*.java"/>
<!--patternset includes="org/apache/fop/svg/GraphicsConfiguration.java"/-->
<patternset refid="exclude-jce-dependencies"/>
<patternset refid="exclude-jai"/>
<patternset refid="exclude-jimi"/>
<classpath refid="libs-build-classpath"/>
</javac>
<copy todir="${build.classes.dir}">
@@ -431,7 +379,6 @@ list of possible build targets.
source="${javac.source}" target="${javac.target}">
<src path="${src.sandbox.dir}"/>
<patternset includes="**/*.java"/>
<patternset refid="exclude-jai"/>
<classpath>
<path refid="libs-build-classpath"/>
<pathelement location="${build.classes.dir}"/>
@@ -543,7 +490,6 @@ list of possible build targets.
<uptodate property="jar.sources.uptodate" targetfile="${build.dir}/fop-sources.jar">
<srcfiles dir="${build.gensrc.dir}"/>
<srcfiles dir="${src.java.dir}"/>
<srcfiles refid="graphics-configuration-adapter"/>
</uptodate>
</target>

@@ -1032,7 +978,6 @@ NOTE:
<pathelement path="${src.java.dir}"/>
<pathelement path="${src.sandbox.dir}"/>
<pathelement path="${build.gensrc.dir}"/>
<path refid="graphics-configuration-adapter"/>
</sourcepath>
<tag name="todo" scope="all" description="To do:"/>
<group title="Control and Startup">
@@ -1206,25 +1151,10 @@ NOTE:
-->
<echo message="Make sure you have a proper Forrest installation (see http://forrest.apache.org/)"/>

<!--<antcall target="site"/>-->
<!-- You can provide a JDK 1.4 for a JDK 1.3 build by adding "javahome.jdk14" to build-local.properties -->
<condition property="javahome.jdk14.override" value="${javahome.jdk14}">
<isset property="javahome.jdk14"/>
</condition>
<echo message="java home: ${javahome.jdk14.override}"/>
<condition property="javahome.jdk14.override" value="${env.JAVA_HOME}">
<not>
<isset property="javahome.jdk14.override"/>
</not>
</condition>
<echo message="java home: ${javahome.jdk14.override}"/>
<condition property="forrest.call" value="forrest.bat" else="forrest">
<os family="windows"/>
</condition>
<exec executable="${forrest.call}">
<env key="JAVA_HOME" value="${javahome.jdk14.override}"/>
</exec>
<exec executable="${forrest.call}"/>
</target>
<!-- =================================================================== -->
@@ -1234,8 +1164,6 @@ NOTE:

<target name="dist-bin" depends="all,javadocs,docs">
<echo message="Building the binary distribution files (zip,tar)"/>
<fail message="A complete binary build requires Jimi" unless="jimi.present"/>
<fail message="A complete binary build requires JAI" unless="jai.present"/>
<fail message="A complete binary build requires JCE" unless="jce.present"/>
<mkdir dir="${dist.bin.result.dir}"/>
<copy todir="${dist.bin.result.dir}">

+ 0
- 31
src/java-1.3/org/apache/fop/svg/GraphicsConfiguration.java View File

@@ -1,31 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.svg;
/**
* Adapter to allow subclassing java.awt.GraphicsConfiguration without
* compilation errors.
* The version for JDK 1.3 is just empty.
*
*/
abstract public class GraphicsConfiguration extends java.awt.GraphicsConfiguration {


}

+ 0
- 237
src/java-1.4/org/apache/fop/image/ImageIOImage.java View File

@@ -1,237 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// AWT
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;
import java.util.Iterator;

// ImageIO
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;

import org.apache.commons.io.IOUtils;
import org.apache.fop.util.UnitConv;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* FopImage object using ImageIO.
* @see AbstractFopImage
* @see FopImage
*/
public class ImageIOImage extends AbstractFopImage {

private byte[] softMask = null;

/**
* Creates a new ImageIOImage.
* @param info the image info from the ImageReader
*/
public ImageIOImage(FopImage.ImageInfo info) {
super(info);
if ("image/png".equals(info.mimeType)
|| "image/tiff".equals(info.mimeType)) {
this.loaded = 0; //TODO The PNG and TIFF Readers cannot read the resolution, yet.
}
}

/**
* @see org.apache.fop.image.AbstractFopImage#loadDimensions()
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
return loadBitmap();
}
return true;
}
private Element getChild(Element el, String name) {
NodeList nodes = el.getElementsByTagName(name);
if (nodes.getLength() > 0) {
return (Element)nodes.item(0);
} else {
return null;
}
}
/** @see org.apache.fop.image.AbstractFopImage#loadBitmap() */
protected boolean loadBitmap() {
if (this.bitmaps != null) {
return true;
}
try {
inputStream.reset();
ImageInputStream imgStream = ImageIO.createImageInputStream(inputStream);
Iterator iter = ImageIO.getImageReaders(imgStream);
if (!iter.hasNext()) {
log.error("No ImageReader found.");
return false;
}
ImageReader reader = (ImageReader)iter.next();
ImageReadParam param = reader.getDefaultReadParam();
reader.setInput(imgStream, true, false);
BufferedImage imageData = reader.read(0, param);
//Read image resolution
IIOMetadata iiometa = reader.getImageMetadata(0);
if (iiometa != null && iiometa.isStandardMetadataFormatSupported()) {
Element metanode = (Element)iiometa.getAsTree("javax_imageio_1.0");
Element dim = getChild(metanode, "Dimension");
if (dim != null) {
Element child;
child = getChild(dim, "HorizontalPixelSize");
if (child != null) {
this.dpiHorizontal = UnitConv.IN2MM
/ Float.parseFloat(child.getAttribute("value"));
}
child = getChild(dim, "VerticalPixelSize");
if (child != null) {
this.dpiVertical = UnitConv.IN2MM
/ Float.parseFloat(child.getAttribute("value"));
}
}
}
imgStream.close();
reader.dispose();
this.height = imageData.getHeight();
this.width = imageData.getWidth();

ColorModel cm = imageData.getColorModel();
this.bitsPerPixel = cm.getComponentSize(0); //only use first, we assume all are equal
//this.colorSpace = cm.getColorSpace();
//We currently force the image to sRGB
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);

int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
//TODO Is there another case?
this.isTransparent = false;
}
} else {
// TRANSLUCENT
this.softMask = new byte[width * height];
imageData.getAlphaRaster().getDataElements(
0, 0, width, height, this.softMask);
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)]
= (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1]
= (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2]
= (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}

/** @see org.apache.fop.image.AbstractFopImage#loadOriginalData() */
protected boolean loadOriginalData() {
if (inputStream == null && getBitmaps() != null) {
return false;
} else {
return loadDefaultOriginalData();
}
}
/** @see org.apache.fop.image.FopImage#hasSoftMask() */
public boolean hasSoftMask() {
if (this.bitmaps == null && this.raw == null) {
loadBitmap();
}

return (this.softMask != null);
}

/** @see org.apache.fop.image.FopImage#getSoftMask() */
public byte[] getSoftMask() {
if (this.bitmaps == null) {
loadBitmap();
}

return this.softMask;
}

}


+ 0
- 161
src/java-1.4/org/apache/fop/image/JpegImageIOImage.java View File

@@ -1,161 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// AWT
import java.awt.Color;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;

// ImageIO
import javax.imageio.ImageIO;

import org.apache.commons.io.IOUtils;

/**
* FopImage object using ImageIO.
* Special class to allow the use of JpegImage for those
* renderers which can embed Jpeg directly but for renderers
* which require the decoded data this class delivers it.
* @see AbstractFopImage
* @see JpegImage
*/
public class JpegImageIOImage extends JpegImage {

/**
* Creates a new JpegImageIOImage.
* @param info the image info from the ImageReader
*/
public JpegImageIOImage(FopImage.ImageInfo info) {
super(info);
}

/**
* @see org.apache.fop.image.AbstractFopImage#loadDimensions()
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
return loadBitmap();
}
return true;
}
/** @see org.apache.fop.image.AbstractFopImage#loadBitmap() */
protected boolean loadBitmap() {
try {
inputStream.reset();
BufferedImage imageData = ImageIO.read(inputStream);

this.height = imageData.getHeight();
this.width = imageData.getWidth();

ColorModel cm = imageData.getColorModel();
this.bitsPerPixel = cm.getComponentSize(0); //only use first, we assume all are equal
this.colorSpace = cm.getColorSpace();

int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
* // or use special API...
*/
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)]
= (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1]
= (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2]
= (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}

}


+ 0
- 10
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -46,7 +46,6 @@ import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fonts.FontCache;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
@@ -82,9 +81,6 @@ public class FopFactory implements ImageContext {

private ColorSpaceCache colorSpaceCache = null;
/** Image factory for creating fop image objects */
private ImageFactory imageFactory;

/** Image manager for loading and caching image objects */
private ImageManager imageManager;

@@ -155,7 +151,6 @@ public class FopFactory implements ImageContext {
this.elementMappingRegistry = new ElementMappingRegistry(this);
this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
this.colorSpaceCache = new ColorSpaceCache(foURIResolver);
this.imageFactory = new ImageFactory();
this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry();
@@ -290,11 +285,6 @@ public class FopFactory implements ImageContext {
return this.contentHandlerFactoryRegistry;
}

/** @return the image factory */
public ImageFactory getImageFactory() {
return this.imageFactory;
}

/**
* Returns the image manager.
* @return the image manager

+ 6
- 0
src/java/org/apache/fop/fo/FOPropertyMapping.java View File

@@ -412,6 +412,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_HEIGHT);
addPropertyMaker("top", l);

// right
@@ -419,6 +420,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_WIDTH);
addPropertyMaker("right", l);

// bottom
@@ -426,6 +428,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_HEIGHT);
addPropertyMaker("bottom", l);

// left
@@ -433,6 +436,7 @@ public final class FOPropertyMapping implements Constants {
l.setInherited(false);
l.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
l.setDefault("auto");
l.setPercentBase(LengthBase.CONTAINING_BLOCK_WIDTH);
addPropertyMaker("left", l);
}

@@ -1161,6 +1165,7 @@ public final class FOPropertyMapping implements Constants {
m = new LengthProperty.Maker(PR_START_INDENT);
m.setInherited(true);
m.setDefault("0pt");
m.setPercentBase(LengthBase.CONTAINING_REFAREA_WIDTH);
IndentPropertyMaker sCorr = new IndentPropertyMaker(m);
sCorr.setCorresponding(PR_MARGIN_LEFT, PR_MARGIN_RIGHT, PR_MARGIN_TOP);
sCorr.setUseParent(false);
@@ -1177,6 +1182,7 @@ public final class FOPropertyMapping implements Constants {
m = new LengthProperty.Maker(PR_END_INDENT);
m.setInherited(true);
m.setDefault("0pt");
m.setPercentBase(LengthBase.CONTAINING_REFAREA_WIDTH);
IndentPropertyMaker eCorr = new IndentPropertyMaker(m);
eCorr.setCorresponding(PR_MARGIN_RIGHT, PR_MARGIN_LEFT, PR_MARGIN_BOTTOM);
eCorr.setUseParent(false);

+ 0
- 5
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -38,7 +38,6 @@ import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.ElementMapping.Maker;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
import org.apache.fop.util.ContentHandlerFactory.ObjectSource;
@@ -155,10 +154,6 @@ public class FOTreeBuilder extends DefaultHandler {
log.debug("Parsing of document complete");
}
foEventHandler.endDocument();
//Notify the image factory that this user agent has expired.
ImageFactory imageFactory = userAgent.getFactory().getImageFactory();
imageFactory.removeContext(this.userAgent);
}

/** {@inheritDoc} */

+ 0
- 376
src/java/org/apache/fop/image/AbstractFopImage.java View File

@@ -1,376 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// Java
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.InputStream;
import java.awt.Color;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.datatypes.Length;

/**
* Base class to implement the FopImage interface.
*
* @see FopImage
*/
public abstract class AbstractFopImage implements FopImage {

/**
* logging instance
*/
protected static Log log = LogFactory.getLog(AbstractFopImage.class);

/**
* Keeps track of what has been loaded.
*/
protected int loaded = 0;

/**
* Image width (in pixel).
*/
protected int width = 0;

/**
* Image height (in pixel).
*/
protected int height = 0;
/** Horizontal bitmap resolution (in dpi) */
protected double dpiHorizontal = 72.0f;

/** Vertical bitmap resolution (in dpi) */
protected double dpiVertical = 72.0f;

/**
* Image input stream.
*/
protected InputStream inputStream = null;

/**
* ImageReader object (to obtain image header informations).
*/
protected FopImage.ImageInfo imageInfo = null;

/**
* Image color space (java.awt.color.ColorSpace).
*/
protected ColorSpace colorSpace = null;

/**
* Bits per pixel.
*/
protected int bitsPerPixel = 0;

/**
* Image data (pixels, uncompressed).
*/
protected byte[] bitmaps = null;

/**
* Image data (undecoded, compressed, for image formats that can be embedded without decoding.
*/
protected byte[] raw = null;

/**
* Image transparency.
*/
protected boolean isTransparent = false;

/**
* Transparent color (java.awt.Color).
*/
protected Color transparentColor = null;

/**
* Photoshop generated CMYK JPEGs are inverted.
*/
protected boolean invertImage = false;
/**
* Constructor.
* Construct a new FopImage object and initialize its default properties:
* <UL>
* <LI>image width
* <LI>image height
* </UL>
* The image data isn't kept in memory.
* @param info image information
*/
public AbstractFopImage(FopImage.ImageInfo info) {
this.inputStream = info.inputStream;
this.imageInfo = info;
if (this.imageInfo.width != -1) {
width = imageInfo.width;
height = imageInfo.height;
dpiHorizontal = imageInfo.dpiHorizontal;
dpiVertical = imageInfo.dpiVertical;
loaded = loaded | DIMENSIONS;
}
}

/**
* Get the mime type for this image.
*
* @return the mime type for the image
*/
public String getMimeType() {
return imageInfo.mimeType;
}

/** {@inheritDoc} */
public String getOriginalURI() {
return this.imageInfo.originalURI;
}
/**
* Load image data and initialize its properties.
*
* @param type the type of loading to do
* @return true if the loading was successful
*/
public synchronized boolean load(int type) {
if ((loaded & type) != 0) {
return true;
}
boolean success = true;
if (((type & DIMENSIONS) != 0) && ((loaded & DIMENSIONS) == 0)) {
success = success && loadDimensions();

if (!success) {
return false;
}
loaded = loaded | DIMENSIONS;
}
if (((type & BITMAP) != 0) && ((loaded & BITMAP) == 0)) {
success = success && loadBitmap();
if (success) {
loaded = loaded | BITMAP;
}
}
if (((type & ORIGINAL_DATA) != 0) && ((loaded & ORIGINAL_DATA) == 0)) {
success = success && loadOriginalData();
if (success) {
loaded = loaded | ORIGINAL_DATA;
}
}
return success;
}

/**
* Load the dimensions of the image.
* All implementations should override this to get and
* return the dimensions.
*
* @return true if the loading was successful
*/
protected boolean loadDimensions() {
return false;
}

/**
* Load a bitmap array of the image.
* If the renderer requires a bitmap image then the
* implementations should override this to load the bitmap.
*
* @return true if the loading was successful
*/
protected boolean loadBitmap() {
return false;
}

/**
* Load the original image data.
* In some cases the original data can be used by the renderer.
* This should load the data and any other associated information.
*
* @return true if the loading was successful
*/
protected boolean loadOriginalData() {
return false;
}

/**
* Load the original image data. This is generic code for use by any
* subclass that wants to use this from a loadOriginalData() implementation.
*
* @return true if the loading was successful
*/
protected boolean loadDefaultOriginalData() {
if (inputStream == null) {
throw new IllegalStateException("inputStream is already null or was never set");
}
try {
this.raw = IOUtils.toByteArray(inputStream);
} catch (java.io.IOException ex) {
log.error("Error while reading raw image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}
return true;
}
/**
* @return the image width (in pixels)
*/
public int getWidth() {
return this.width;
}
/**
* @return the image height (in pixels)
*/
public int getHeight() {
return this.height;
}

/** {@inheritDoc} */
public int getIntrinsicWidth() {
return (int)(getWidth() * 72000 / getHorizontalResolution());
}

/** {@inheritDoc} */
public int getIntrinsicHeight() {
return (int)(getHeight() * 72000 / getVerticalResolution());
}
/** {@inheritDoc} */
public Length getIntrinsicAlignmentAdjust() {
return this.imageInfo.alignmentAdjust;
}

/** {@inheritDoc} */
public double getHorizontalResolution() {
return this.dpiHorizontal;
}
/** {@inheritDoc} */
public double getVerticalResolution() {
return this.dpiVertical;
}
/**
* Return the image color space.
* @return the image color space (java.awt.color.ColorSpace)
*/
public ColorSpace getColorSpace() {
return this.colorSpace;
}

/**
* Get ICC profile for this image.
* @return the icc profile or null if not applicable
*/
public ICC_Profile getICCProfile() {
if (this.colorSpace != null && this.colorSpace instanceof ICC_ColorSpace) {
return ((ICC_ColorSpace)this.colorSpace).getProfile();
}
return null;
}

/**
* Return the number of bits per pixel.
* @return number of bits per pixel
*/
public int getBitsPerPixel() {
return this.bitsPerPixel;
}

/**
* Return the image transparency.
* @return true if the image is transparent
*/
public boolean isTransparent() {
return this.isTransparent;
}

/**
* Check if this image has a soft mask.
*
* @return true if the image also has a soft transparency mask
*/
public boolean hasSoftMask() {
return false;
}

/**
* Get the soft mask.
* The soft mask should have the same bitdepth as the image data.
*
* @return the data array of soft mask values
*/
public byte[] getSoftMask() {
return null;
}

/**
* Return the transparent color.
* @return the transparent color (java.awt.Color)
*/
public Color getTransparentColor() {
return this.transparentColor;
}

/** @return true for CMYK images generated by Adobe Photoshop */
public boolean isInverted() {
return this.invertImage;
}
/**
* Return the image data (pixels, uncompressed).
* @return the image data
*/
public byte[] getBitmaps() {
return this.bitmaps;
}

/**
* Return the image data size (number of bytes taken up by the uncompressed pixels).
* @return the image data size
*/
public int getBitmapsSize() {
return (bitmaps != null ? bitmaps.length : 0);
}

/**
* Return the original image data (compressed).
* @return the original image data
*/
public byte[] getRessourceBytes() {
return raw;
}

/**
* Return the original image data size (compressed).
* @return the original image data size
*/
public int getRessourceBytesSize() {
return (raw != null ? raw.length : 0);
}

}


+ 0
- 220
src/java/org/apache/fop/image/BmpImage.java View File

@@ -1,220 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

// Java
import java.io.IOException;
import java.awt.color.ColorSpace;

import org.apache.commons.io.IOUtils;

/**
* Bitmap image.
* This supports loading a bitmap image into bitmap data.
*
* @see AbstractFopImage
* @see FopImage
*/
public class BmpImage extends AbstractFopImage {
/**
* Create a bitmap image with the image data.
*
* @param imgInfo the image information
*/
public BmpImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the bitmap.
* This laods the bitmap data from the bitmap image.
*
* @return true if it was loaded successfully
*/
protected boolean loadBitmap() {
int wpos = 18;
int hpos = 22; // offset positioning for w and height in bmp files
int[] headermap = new int[54];
int filepos = 0;
byte[] palette = null;
try {
boolean eof = false;
while ((!eof) && (filepos < 54)) {
int input = inputStream.read();
if (input == -1) {
eof = true;
} else {
headermap[filepos++] = input;
}
}

if (headermap[28] == 4 || headermap[28] == 8) {
int palettesize = 1 << headermap[28];
palette = new byte[palettesize * 3];
int countr = 0;
while (!eof && countr < palettesize) {
int count2 = 2;
while (!eof && count2 >= -1) {
int input = inputStream.read();
if (input == -1) {
eof = true;
} else if (count2 >= 0) {
palette[countr * 3 + count2] = (byte)(input & 0xFF);
}
count2--;
filepos++;
}
countr++;
}
}
} catch (IOException ex) {
log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
IOUtils.closeQuietly(inputStream);
inputStream = null;
return false;
}
// gets h & w from headermap
this.width = headermap[wpos]
+ headermap[wpos + 1] * 256
+ headermap[wpos + 2] * 256 * 256
+ headermap[wpos + 3] * 256 * 256 * 256;
this.height = headermap[hpos]
+ headermap[hpos + 1] * 256
+ headermap[hpos + 2] * 256 * 256
+ headermap[hpos + 3] * 256 * 256 * 256;

int imagestart = headermap[10]
+ headermap[11] * 256
+ headermap[12] * 256 * 256
+ headermap[13] * 256 * 256 * 256;
this.bitsPerPixel = headermap[28];
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
int bytes = 0;
if (this.bitsPerPixel == 1) {
bytes = (this.width + 7) / 8;
} else if (this.bitsPerPixel == 24) {
bytes = this.width * 3;
} else if (this.bitsPerPixel == 4 || this.bitsPerPixel == 8) {
bytes = this.width / (8 / this.bitsPerPixel);
} else {
log.error("Image (" + ""
+ ") has " + this.bitsPerPixel
+ " which is not a supported BMP format.");
return false;
}
if ((bytes & 0x03) != 0) {
bytes |= 0x03;
bytes++;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];

int[] temp = new int[bytes * this.height];
try {
int input;
int count = 0;
inputStream.skip((long)(imagestart - filepos));
while ((input = inputStream.read()) != -1) {
if (count >= temp.length) {
log.warn("Data longer than expected while loading image");
break;
} else {
temp[count++] = input;
}
}
} catch (IOException ex) {
log.error("Error while loading image (Bmp): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

for (int i = 0; i < this.height; i++) {
int x = 0;
int j = 0;
while (j < bytes) {
int p = temp[(this.height - i - 1) * bytes + j];

if (this.bitsPerPixel == 24 && x < this.width) {
int countr = 2;
do {
this.bitmaps[3 * (i * this.width + x) + countr]
= (byte)(temp[(this.height - i - 1) * bytes + j] & 0xFF);
j++;
} while (--countr >= 0)
;
x++;
} else if (this.bitsPerPixel == 1) {
for (int countr = 0;
countr < 8 && x < this.width; countr++) {
if ((p & 0x80) != 0) {
this.bitmaps[3 * (i * this.width + x)] = (byte) 0xFF;
this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0xFF;
this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0xFF;
} else {
this.bitmaps[3 * (i * this.width + x)] = (byte) 0;
this.bitmaps[3 * (i * this.width + x) + 1] = (byte) 0;
this.bitmaps[3 * (i * this.width + x) + 2] = (byte) 0;
}
p <<= 1;
x++;
}
j++;
} else if (this.bitsPerPixel == 4) {
for (int countr = 0;
countr < 2 && x < this.width; countr++) {
int pal = ((p & 0xF0) >> 4) * 3;
this.bitmaps[3 * (i * this.width + x)] = palette[pal];
this.bitmaps[3 * (i * this.width + x) + 1] = palette[pal + 1];
this.bitmaps[3 * (i * this.width + x) + 2] = palette[pal + 2];
p <<= 4;
x++;
}
j++;
} else if (this.bitsPerPixel == 8) {
if (x < this.width) {
p *= 3;
this.bitmaps[3 * (i * this.width + x)] = palette[p];
this.bitmaps[3 * (i * this.width + x) + 1] = palette[p + 1];
this.bitmaps[3 * (i * this.width + x) + 2] = palette[p + 2];
j++;
x++;
} else {
j = bytes;
}
} else {
j++;
}
}
}

// This seems really strange to me, but I noticed that
// JimiImage hardcodes bitsPerPixel to 8. If I do not
// do this Acrobat is unable to read the resultant PDF,
// so we will hardcode this...
this.bitsPerPixel = 8;

return true;
}

}


+ 0
- 122
src/java/org/apache/fop/image/EPSImage.java View File

@@ -1,122 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;


/**
* EPS image handler.
* This handles the Encapulated PostScript images.
* It gets the dimensions and original data from the analyser.
*
* @see AbstractFopImage
* @see FopImage
*/
public class EPSImage extends AbstractFopImage {
private String docName;
private int[] bbox;

private EPSData epsData = null;

/**
* Create an EPS image with the image information.
*
* @param imgInfo the information containing the data and bounding box
*/
public EPSImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
init("");
if (imgInfo.data instanceof EPSData) {
epsData = (EPSData) imgInfo.data;
bbox = new int[4];
bbox[0] = (int) epsData.bbox[0];
bbox[1] = (int) epsData.bbox[1];
bbox[2] = (int) epsData.bbox[2];
bbox[3] = (int) epsData.bbox[3];

loaded = loaded | ORIGINAL_DATA;
}
}

/**
* Initialize docName and bounding box.
* @param name the document name
*/
private void init(String name) {
bbox = new int[4];
bbox[0] = 0;
bbox[1] = 0;
bbox[2] = 0;
bbox[3] = 0;

docName = name;
}

/**
* Return the name of the eps
* @return the name of the eps
*/
public String getDocName() {
return docName;
}

/**
* Return the bounding box
* @return an int array containing the bounding box
*/
public int[] getBBox() {
return bbox;
}

/**
* Get the eps image.
*
* @return the original eps image data
*/
public byte[] getEPSImage() {
if (epsData.epsFile == null) {
//log.error("ERROR LOADING EXTERNAL EPS");
}
return epsData.epsFile;
}

/**
* Data for EPS image.
*/
public static class EPSData {
public long[] bbox;
public boolean isAscii; // True if plain ascii eps file

// offsets if not ascii
public long psStart = 0;
public long psLength = 0;
public long wmfStart = 0;
public long wmfLength = 0;
public long tiffStart = 0;
public long tiffLength = 0;

/** raw eps file */
public byte[] rawEps;
/** eps part */
public byte[] epsFile;
public byte[] preview = null;
}

}

+ 0
- 51
src/java/org/apache/fop/image/EmfImage.java View File

@@ -1,51 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

/**
* Enhanced metafile image.
* This supports loading a EMF image.
*
* @see AbstractFopImage
* @see FopImage
*/
public class EmfImage extends AbstractFopImage {
/**
* Create a bitmap image with the image data.
*
* @param imgInfo the image information
*/
public EmfImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the original EMF data.
* This loads the original EMF data and reads the color space,
* and icc profile if any.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 207
src/java/org/apache/fop/image/FopImage.java View File

@@ -1,207 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

import java.io.InputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.Color;

import org.apache.fop.datatypes.Length;

/**
* Fop image interface for loading images.
*/
public interface FopImage {
/**
* Flag for loading dimensions.
*/
int DIMENSIONS = 1;

/**
* Flag for loading original data.
*/
int ORIGINAL_DATA = 2;

/**
* Flag for loading bitmap data.
*/
int BITMAP = 4;

/**
* Get the mime type of this image.
* This is used so that when reading from the image it knows
* what type of image it is.
*
* @return the mime type string
*/
String getMimeType();

/** @return the original URI used to access this image. */
String getOriginalURI();
/**
* Load particular inforamtion for this image
* This must be called before attempting to get
* the information.
*
* @param type the type of loading required
* @return boolean true if the information could be loaded
*/
boolean load(int type);

/**
* Returns the image width.
* @return the width in pixels
*/
int getWidth();

/**
* Returns the image height.
* @return the height in pixels
*/
int getHeight();
/**
* @return the intrinsic image width (in millipoints)
*/
int getIntrinsicWidth();

/**
* @return the intrinsic image width (in millipoints)
*/
int getIntrinsicHeight();

/**
* @return the intrinsic alignment-adjust value or NULL if the image does
* not have one.
*/
Length getIntrinsicAlignmentAdjust();
/**
* @return the horizontal bitmap resolution (in dpi)
*/
double getHorizontalResolution();
/**
* @return the vertical bitmap resolution (in dpi)
*/
double getVerticalResolution();

/**
* Returns the color space of the image.
* @return the color space
*/
ColorSpace getColorSpace();

/**
* Returns the ICC profile.
* @return the ICC profile, null if none is available
*/
ICC_Profile getICCProfile();

/**
* Returns the number of bits per pixel for the image.
* @return the number of bits per pixel
*/
int getBitsPerPixel();

/**
* Indicates whether the image is transparent.
* @return True if it is transparent
*/
boolean isTransparent();

/**
* For transparent images. Returns the transparent color.
* @return the transparent color
*/
Color getTransparentColor();

/**
* Indicates whether the image has a Soft Mask (See section 7.5.4 in the
* PDF specs)
* @return True if a Soft Mask exists
*/
boolean hasSoftMask();

/**
* For images with a Soft Mask. Returns the Soft Mask as an array.
* @return the Soft Mask
*/
byte[] getSoftMask();

/** @return true for CMYK images generated by Adobe Photoshop */
boolean isInverted();
/**
* Returns the decoded and uncompressed image as a array of
* width * height * [colorspace-multiplicator] pixels.
* @return the bitmap
*/
byte[] getBitmaps();
/**
* Returns the size of the image.
* width * (bitsPerPixel / 8) * height, no ?
* @return the size
*/
int getBitmapsSize();

/**
* Returns the encoded/compressed image as an array of bytes.
* @return the raw image
*/
byte[] getRessourceBytes();

/**
* Returns the number of bytes of the raw image.
* @return the size in bytes
*/
int getRessourceBytesSize();

/**
* Image info class.
* Information loaded from analyser and passed to image object.
*/
public static class ImageInfo {
/** InputStream to load the image from */
public InputStream inputStream;
/** Original URI the image was accessed with */
public String originalURI;
/** image width (in pixels) */
public int width;
/** image height (in pixels) */
public int height;
/** horizontal bitmap resolution (in dpi) */
public double dpiHorizontal = 72.0f;
/** vertical bitmap resolution (in dpi) */
public double dpiVertical = 72.0f;
/** implementation-specific data object (ex. a SVG DOM for SVG images) */
public Object data;
/** MIME type of the image */
public String mimeType;
/** implementation-specific String (ex. the namespace for XML-based images) */
public String str;
/** intrinsic alignment-adjust or null if there is none */
public Length alignmentAdjust;
}

}


+ 0
- 211
src/java/org/apache/fop/image/FopImageConsumer.java View File

@@ -1,211 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

// Java
import java.util.Hashtable;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.PixelGrabber;

/**
* ImageConsumer implementation for FopImage classes.
*/
public class FopImageConsumer implements ImageConsumer {
/** Image width in pixels */
protected int width = -1;
/** Image height in pixels */
protected int height = -1;
/** Image status */
protected Integer imageStatus = new Integer(-1);
/** hints */
protected int hints = 0;
/** Image properties */
protected Hashtable properties = null;
/** Color model */
protected ColorModel cm = null;
/** Image producer */
protected ImageProducer ip = null;

/**
* Main constructor
* @param iprod ImageProducer to use
*/
public FopImageConsumer(ImageProducer iprod) {
this.ip = iprod;
}

/**
* {@inheritDoc}
*/
public void imageComplete(int status) {
/*
* log.error("Status ");
* if (status == ImageConsumer.COMPLETESCANLINES) {
* log.error("CompleteScanLines");
* } else if (status == ImageConsumer.IMAGEABORTED) {
* log.error("ImageAborted");
* } else if (status == ImageConsumer.IMAGEERROR) {
* log.error("ImageError");
* } else if (status == ImageConsumer.RANDOMPIXELORDER) {
* log.error("RandomPixelOrder");
* } else if (status == ImageConsumer.SINGLEFRAME) {
* log.error("SingleFrame");
* } else if (status == ImageConsumer.SINGLEFRAMEDONE) {
* log.error("SingleFrameDone");
* } else if (status == ImageConsumer.SINGLEPASS) {
* log.error("SinglePass");
* } else if (status == ImageConsumer.STATICIMAGEDONE) {
* log.error("StaticImageDone");
* } else if (status == ImageConsumer.TOPDOWNLEFTRIGHT) {
* log.error("TopDownLeftRight");
* }
*/
synchronized (this.imageStatus) {
// Need to stop status if image done
if (imageStatus.intValue() != ImageConsumer.STATICIMAGEDONE
&& imageStatus.intValue() != ImageConsumer.SINGLEFRAMEDONE) {
this.imageStatus = new Integer(status);
}
}
}

/**
* {@inheritDoc}
*/
public void setColorModel(ColorModel model) {
// log.error("setColorModel: " + model);
this.cm = model;
}

/**
* {@inheritDoc}
*/
public void setDimensions(int width, int height) {
// log.error("setDimension: w=" + width + " h=" + height);
this.width = width;
this.height = height;
}

/**
* {@inheritDoc}
*/
public void setHints(int hintflags) {
// log.error("setHints: " + hintflags);
this.hints = hintflags;
}

/**
* {@inheritDoc}
*/
public void setProperties(Hashtable props) {
// log.error("setProperties: " + props);
this.properties = props;
}

/**
* {@inheritDoc}
*/
public void setPixels(int x, int y, int w, int h, ColorModel model,
byte[] pixels, int off, int scansize) {
}

/**
* {@inheritDoc}
*/
public void setPixels(int x, int y, int w, int h, ColorModel model,
int[] pixels, int off, int scansize) {
}

/**
* Indicates whether the image is ready.
* @return boolean True if the image is ready, false if it's still loading
* @throws Exception If an error happened while loading the image
*/
public boolean isImageReady() throws Exception {
/**@todo Use a better exception than Exception */
synchronized (this.imageStatus) {
if (this.imageStatus.intValue() == ImageConsumer.IMAGEABORTED) {
throw new Exception("Image aborted");
}
if (this.imageStatus.intValue() == ImageConsumer.IMAGEERROR) {
throw new Exception("Image error");
}

if (imageStatus.intValue() == ImageConsumer.STATICIMAGEDONE
|| imageStatus.intValue() == ImageConsumer.SINGLEFRAMEDONE) {
return true;
}

return false;
}
}

/**
* Returns the image width
* @return the width in pixels
*/
public int getWidth() {
return this.width;
}

/**
* Returns the image height
* @return the height in pixels
*/
public int getHeight() {
return this.height;
}

/**
* Returns the color model of the image
* @return the color model
*/
public ColorModel getColorModel() {
return this.cm;
}

/**
* Returns the bitmap as an array.
* @return the bitmap as an array.
* @throws Exception if an error occured while generating the array
*/
public int[] getImage() throws Exception {
int tmpMap[] = new int[this.width * this.height];
PixelGrabber pg = new PixelGrabber(this.ip, 0, 0, this.width,
this.height, tmpMap, 0, this.width);
pg.setDimensions(this.width, this.height);
pg.setColorModel(this.cm);
pg.setHints(this.hints);
pg.setProperties(this.properties);
try {
pg.grabPixels();
} catch (InterruptedException intex) {
/**@todo Use a better exception than Exception */
throw new Exception("Image grabbing interrupted : "
+ intex.getMessage());
}
return tmpMap;
}

}


+ 0
- 218
src/java/org/apache/fop/image/GifImage.java View File

@@ -1,218 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// Java
import java.awt.image.ImageProducer;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.color.ColorSpace;
import java.awt.Color;
import java.io.InputStream;
import java.io.IOException;
import java.net.URLConnection;

import org.apache.commons.io.IOUtils;

/**
* FopImage object for GIF images, using Java native classes.
*
* @see AbstractFopImage
* @see FopImage
*/
public class GifImage extends AbstractFopImage {

/**
* Create a new gif image.
*
* @param imgInfo the image info for this gif image
*/
public GifImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the bitmap for this gif image.
* This loads the data and creates a bitmap byte array
* of the image data.
* To decode the image a dummy URLConnection is used that
* will do the conversion.
*
* @return True if the load process succeeded
*/
protected boolean loadBitmap() {
int[] tmpMap = null;
try {
URLConnection con = new DummyConnection(inputStream);

ImageProducer ip = (ImageProducer) con.getContent();
if (ip == null) {
return false;
}
FopImageConsumer consumer = new FopImageConsumer(ip);
ip.startProduction(consumer);

//Load the image into memory
while (!consumer.isImageReady()) {
Thread.sleep(500);
}

this.height = consumer.getHeight();
this.width = consumer.getWidth();

try {
tmpMap = consumer.getImage();
} catch (Exception ex) {
log.error("Image grabbing interrupted : "
+ ex.getMessage(), ex);
return false;
}

ColorModel cm = consumer.getColorModel();
this.bitsPerPixel = 8;
// this.bitsPerPixel = cm.getPixelSize();
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();

if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
IndexColorModel indexcm = (IndexColorModel) cm;
this.isTransparent = false;
byte[] alphas = new byte[indexcm.getMapSize()];
byte[] reds = new byte[indexcm.getMapSize()];
byte[] greens = new byte[indexcm.getMapSize()];
byte[] blues = new byte[indexcm.getMapSize()];
indexcm.getAlphas(alphas);
indexcm.getReds(reds);
indexcm.getGreens(greens);
indexcm.getBlues(blues);
for (int i = 0;
i < indexcm.getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
*/
// use special API...
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} catch (Exception ex) {
log.error("Error while loading image (Gif): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}
return true;
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
/**
* A dummy url connection for a gif image in an input stream.
*/
protected static class DummyConnection extends URLConnection {
private InputStream inputStream;

DummyConnection(InputStream is) {
super(null);
inputStream = is;
}

/**
* {@inheritDoc}
*/
public InputStream getInputStream() throws IOException {
return inputStream;
}

/**
* {@inheritDoc}
*/
public void connect() throws IOException {
// do nothing
}

/**
* {@inheritDoc}
*/
public String getContentType() {
return "image/gif";
}

/**
* {@inheritDoc}
*/
public int getContentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return -1;
}
}

}
}


+ 0
- 72
src/java/org/apache/fop/image/ImageCache.java View File

@@ -1,72 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

// FOP
import org.apache.fop.apps.FOUserAgent;

/**
* Image cache holder.
* This interface is used for caching images.
*/
public interface ImageCache {
/**
* Get an image from the cache.
*
* @param url the url and key for the image
* @param context the user agent context
* @return the requested image
*/
FopImage getImage(String url, FOUserAgent context);

/**
* Release an image in the current context.
*
* @param url the url and key for the image
* @param context the user agent context
*/
void releaseImage(String url, FOUserAgent context);

/**
* Invalidate image.
* If during loading this image is found to be invalid
* it will be invalidated to prevent further attempts at
* loading the image.
*
* @param url the url and key for the image
* @param context the user agent context
*/
void invalidateImage(String url, FOUserAgent context);

/**
* Remove a context and handle all images in the context.
*
* @param context the user agent context
*/
void removeContext(FOUserAgent context);
/**
* Forces the cache to fully cleared.
*/
void clearAll();
}


+ 0
- 708
src/java/org/apache/fop/image/ImageFactory.java View File

@@ -1,708 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// Java
import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.image.analyser.ImageReaderFactory;
import org.apache.xmlgraphics.util.Service;

/**
* Create FopImage objects (with a configuration file - not yet implemented).
* @author Eric SCHAEFFER
*/
public final class ImageFactory {

/**
* logging instance
*/
protected static Log log = LogFactory.getLog(FopImage.class);
private HashMap imageMimeTypes = new HashMap();
private ImageCache cache = new ContextImageCache(true);

/**
* Main constructor for the ImageFactory.
*/
public ImageFactory() {
/* @todo The mappings set up below of image mime types to implementing
* classes should be made externally configurable
*/
ImageProvider jaiImage = new ImageProvider("JAIImage", "org.apache.fop.image.JAIImage");
ImageProvider jimiImage = new ImageProvider("JIMIImage", "org.apache.fop.image.JimiImage");
ImageProvider imageIoImage = new ImageProvider(
"ImageIOImage", "org.apache.fop.image.ImageIOImage");
ImageProvider gifImage = new ImageProvider("GIFImage", "org.apache.fop.image.GifImage");
ImageProvider jpegImage = new ImageProvider("JPEGImage", "org.apache.fop.image.JpegImage");
ImageProvider jpegImageIOImage = new ImageProvider(
"JPEGImage", "org.apache.fop.image.JpegImageIOImage");
ImageProvider bmpImage = new ImageProvider("BMPImage", "org.apache.fop.image.BmpImage");
ImageProvider epsImage = new ImageProvider("EPSImage", "org.apache.fop.image.EPSImage");
ImageProvider pngImage = new ImageProvider("PNGImage", "org.apache.fop.image.PNGImage");
ImageProvider tiffImage = new ImageProvider("TIFFImage", "org.apache.fop.image.TIFFImage");
ImageProvider xmlImage = new ImageProvider("XMLImage", "org.apache.fop.image.XMLImage");
ImageProvider emfImage = new ImageProvider("EMFImage", "org.apache.fop.image.EmfImage");
ImageMimeType imt = new ImageMimeType("image/gif");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(imageIoImage);
imt.addProvider(jaiImage);
imt.addProvider(jimiImage);
imt.addProvider(gifImage);

imt = new ImageMimeType("image/jpeg");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(jpegImageIOImage);
imt.addProvider(jpegImage);

imt = new ImageMimeType("image/bmp");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(bmpImage);

imt = new ImageMimeType("image/eps");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(epsImage);

imt = new ImageMimeType("image/png");
imageMimeTypes.put(imt.getMimeType(), imt);
//Image I/O is faster and more memory-efficient than own codec for PNG
imt.addProvider(imageIoImage);
imt.addProvider(pngImage);

imt = new ImageMimeType("image/tga");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(jaiImage);
imt.addProvider(imageIoImage);
imt.addProvider(jimiImage);

imt = new ImageMimeType("image/tiff");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(tiffImage); //Slower but supports CCITT embedding
imt.addProvider(imageIoImage); //Fast but doesn't support CCITT embedding
imt.addProvider(jaiImage); //Fast but doesn't support CCITT embedding

imt = new ImageMimeType("image/svg+xml");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(xmlImage);

imt = new ImageMimeType("text/xml");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(xmlImage);
imt = new ImageMimeType("image/emf");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(emfImage);

Iterator iter = Service.providers(RegisterableImageProvider.class, true);
while (iter.hasNext()) {
RegisterableImageProvider impl = (RegisterableImageProvider)iter.next();
imt = new ImageMimeType(impl.getSupportedMimeType());
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(new ImageProvider(impl.getName(), impl.getClassName()));
}
}

/**
* Get the url string from a wrapped url.
*
* @param href the input wrapped url
* @return the raw url
*/
public static String getURL(String href) {
return URISpecification.getURL(href);
}

/**
* Get the image from the cache or load.
* If this returns null then the image could not be loaded
* due to an error. Messages should be logged.
* Before calling this the getURL(url) must be used.
*
* @param url the url for the image
* @param context the user agent context
* @return the fop image instance
*/
public FopImage getImage(String url, FOUserAgent context) {
return cache.getImage(url, context);
}

/**
* Release an image from the cache.
* This can be used if the renderer has its own cache of
* the image.
* The image should then be put into the weak cache.
*
* @param url the url for the image
* @param context the user agent context
*/
public void releaseImage(String url, FOUserAgent context) {
cache.releaseImage(url, context);
}

/**
* Release the context and all images in the context.
*
* @param context the context to remove
*/
public void removeContext(FOUserAgent context) {
cache.removeContext(context);
}

/**
* Create an FopImage objects.
* @param href the url for the image
* @param ua the user agent context
* @return the fop image instance
*/
public FopImage loadImage(String href, FOUserAgent ua) {

Source source = ua.resolveURI(href);
if (source == null) {
return null;
}
// Got a valid source, obtain an InputStream from it
InputStream in = null;
if (source instanceof StreamSource) {
in = ((StreamSource)source).getInputStream();
}
if (in == null) {
try {
in = new java.net.URL(source.getSystemId()).openStream();
} catch (Exception ex) {
log.error("Unable to obtain stream from id '"
+ source.getSystemId() + "'");
}
}
if (in == null) {
return null;
}

//Make sure the InputStream is decorated with a BufferedInputStream
if (!(in instanceof java.io.BufferedInputStream)) {
in = new java.io.BufferedInputStream(in);
}

// Check image type
FopImage.ImageInfo imgInfo = null;
try {
imgInfo = ImageReaderFactory.make(source.getSystemId(), in, ua);
} catch (Exception e) {
log.error("Error while recovering image information ("
+ href + ") : " + e.getMessage(), e);
return null;
}
if (imgInfo == null) {
try {
in.close();
in = null;
} catch (Exception e) {
log.debug("Error closing the InputStream for the image", e);
}
log.error("No ImageReader for this type of image (" + href + ")");
return null;
}
// Associate mime-type to FopImage class
String imgMimeType = imgInfo.mimeType;
Class imageClass = getImageClass(imgMimeType);
if (imageClass == null) {
log.error("Unsupported image type (" + href + "): " + imgMimeType);
return null;
} else {
if (log.isDebugEnabled()) {
log.debug("Loading " + imgMimeType + " with " + imageClass.getName()
+ ": " + href);
}
}

// load the right image class
// return new <FopImage implementing class>
Object imageInstance = null;
try {
Class[] imageConstructorParameters = new Class[1];
imageConstructorParameters[0] = org.apache.fop.image.FopImage.ImageInfo.class;
Constructor imageConstructor = imageClass.getDeclaredConstructor(
imageConstructorParameters);
Object[] initArgs = new Object[1];
initArgs[0] = imgInfo;
imageInstance = imageConstructor.newInstance(initArgs);
} catch (java.lang.reflect.InvocationTargetException ex) {
Throwable t = ex.getTargetException();
String msg;
if (t != null) {
msg = t.getMessage();
} else {
msg = ex.getMessage();
}
log.error("Error creating FopImage object ("
+ href + "): " + msg, (t == null) ? ex : t);
return null;
} catch (InstantiationException ie) {
log.error("Error creating FopImage object ("
+ href + "): Could not instantiate " + imageClass.getName() + " instance");
return null;
} catch (Exception ex) {
log.error("Error creating FopImage object ("
+ href + "): " + ex.getMessage(), ex);
return null;
}
if (!(imageInstance instanceof org.apache.fop.image.FopImage)) {
log.error("Error creating FopImage object (" + href + "): " + "class "
+ imageClass.getName()
+ " doesn't implement org.apache.fop.image.FopImage interface");
return null;
}
return (FopImage) imageInstance;
}

private Class getImageClass(String imgMimeType) {
ImageMimeType imt = (ImageMimeType)imageMimeTypes.get(imgMimeType);
if (imt == null) {
return null;
}
return imt.getFirstImplementingClass();
}
/**
* Forces all the image caches to be cleared. This should normally only be used in
* testing environments. If you happen to think that you need to call this yourself
* in a production environment, please notify the development team so we can look
* into the issue. A call like this shouldn't be necessary anymore like it may have
* been with FOP 0.20.5.
*/
public void clearCaches() {
cache.clearAll();
}
}

/**
* Basic image cache.
* This keeps track of invalid images.
*/
class BasicImageCache implements ImageCache {

private Set invalid = Collections.synchronizedSet(new java.util.HashSet());
//private Map contextStore = Collections.synchronizedMap(new java.util.HashMap());

public FopImage getImage(String url, FOUserAgent context) {
if (invalid.contains(url)) {
return null;
}
//TODO Doesn't seem to be fully implemented. Do we need it at all? Not referenced.
return null;
}

public void releaseImage(String url, FOUserAgent context) {
// do nothing
}

public void invalidateImage(String url, FOUserAgent context) {
// cap size of invalid list
if (invalid.size() > 100) {
invalid.clear();
}
invalid.add(url);
}

public void removeContext(FOUserAgent context) {
// do nothing
}

/** {@inheritDoc} */
public void clearAll() {
invalid.clear();
}
}

/**
* This is the context image cache.
* This caches images on the basis of the given context.
* Common images in different contexts are currently not handled.
* There are two possiblities, each context handles its own images
* and renderers can cache information or images are shared and
* all information is retained.
* Once a context is removed then all images are placed into a
* weak hashmap so they may be garbage collected.
*/
class ContextImageCache implements ImageCache {

// if this cache is collective then images can be shared
// among contexts, this implies that the base directory
// is either the same or does not effect the images being
// loaded
private boolean collective;
private Map contextStore = Collections.synchronizedMap(new java.util.HashMap());
private Set invalid = null;
private Map refStore = null;
private ReferenceQueue refQueue = new ReferenceQueue();

public ContextImageCache(boolean col) {
collective = col;
if (collective) {
refStore = Collections.synchronizedMap(new java.util.HashMap());
invalid = Collections.synchronizedSet(new java.util.HashSet());
}
}

// sync around lookups and puts
// another sync around load for a particular image
public FopImage getImage(String url, FOUserAgent context) {
ImageLoader im = null;
// this protects the finding or creating of a new
// ImageLoader for multi threads
synchronized (this) {
if (collective && invalid.contains(url)) {
return null;
}
Context con = (Context) contextStore.get(context);
if (con == null) {
con = new Context(context, collective);
contextStore.put(context, con);
} else {
if (con.invalid(url)) {
return null;
}
im = con.getImage(url);
}
if (im == null && collective) {
Iterator i = contextStore.values().iterator();
while (i.hasNext()) {
Context c = (Context)i.next();
if (c != con) {
im = c.getImage(url);
if (im != null) {
break;
}
}
}
if (im == null) {
Reference ref = (Reference)refStore.get(url);
if (ref != null) {
im = (ImageLoader) ref.get();
if (im == null) {
//Remove key if its value has been garbage collected
refStore.remove(url);
}
}
}
}

if (im != null) {
con.putImage(url, im);
} else {
im = con.getImage(url, this);
}
}

// the ImageLoader is synchronized so images with the
// same url will not be loaded at the same time
if (im != null) {
return im.loadImage();
}
return null;
}

public void releaseImage(String url, FOUserAgent context) {
Context con = (Context) contextStore.get(context);
if (con != null) {
if (collective) {
ImageLoader im = con.getImage(url);
refStore.put(url, wrapInReference(im, url));
}
con.releaseImage(url);
}
}

public void invalidateImage(String url, FOUserAgent context) {
if (collective) {
// cap size of invalid list
if (invalid.size() > 100) {
invalid.clear();
}
invalid.add(url);
}
Context con = (Context) contextStore.get(context);
if (con != null) {
con.invalidateImage(url);
}
}

private Reference wrapInReference(Object obj, Object key) {
return new SoftReferenceWithKey(obj, key, refQueue);
}
private static class SoftReferenceWithKey extends SoftReference {
private Object key;
public SoftReferenceWithKey(Object referent, Object key, ReferenceQueue q) {
super(referent, q);
this.key = key;
}
}
public void removeContext(FOUserAgent context) {
Context con = (Context) contextStore.get(context);
if (con != null) {
if (collective) {
Map images = con.getImages();
Iterator iter = images.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = (Entry)iter.next();
refStore.put(entry.getKey(),
wrapInReference(entry.getValue(), entry.getKey()));
}
}
contextStore.remove(context);
}
//House-keeping (remove cleared references)
checkReferenceQueue();
}
/**
* Checks the reference queue if any references have been cleared and removes them from the
* cache.
*/
private void checkReferenceQueue() {
SoftReferenceWithKey ref;
while ((ref = (SoftReferenceWithKey)refQueue.poll()) != null) {
refStore.remove(ref.key);
}
}

class Context {
private Map images = Collections.synchronizedMap(new java.util.HashMap());
private Set invalid = null;
private FOUserAgent userAgent;

public Context(FOUserAgent ua, boolean inv) {
userAgent = ua;
if (inv) {
invalid = Collections.synchronizedSet(new java.util.HashSet());
}
}

public ImageLoader getImage(String url, ImageCache c) {
if (images.containsKey(url)) {
return (ImageLoader) images.get(url);
}
ImageLoader loader = new ImageLoader(url, c, userAgent);
images.put(url, loader);
return loader;
}

public void putImage(String url, ImageLoader image) {
images.put(url, image);
}

public ImageLoader getImage(String url) {
return (ImageLoader) images.get(url);
}

public void releaseImage(String url) {
images.remove(url);
}

public Map getImages() {
return images;
}

public void invalidateImage(String url) {
invalid.add(url);
}

public boolean invalid(String url) {
return invalid.contains(url);
}

}

/** {@inheritDoc} */
public void clearAll() {
this.refStore.clear();
this.invalid.clear();
//The context-sensitive caches are not cleared so there are no negative side-effects
//in a multi-threaded environment. Not that it's a good idea to use this method at
//all except in testing environments. If such a calls is necessary in normal environments
//we need to check on memory leaks!
}

}

/**
* Encapsulates a class of type FopImage by holding its class name.
* This allows dynamic loading of the class at runtime.
*/
class ImageProvider {

private String name = null;

private String className = null;

private boolean checked = false;

private Class clazz = null;

/**
* Creates an ImageProvider with a given name and implementing class.
* The class name should refer to a class of type {@link FopImage}.
* However, this is not checked on construction.
* @param name The name of the provider
* @param className The full class name of the class implementing this provider
*/
public ImageProvider(String name, String className) {
setName(name);
setClassName(className);
}

/**
* Returns the provider name.
* @return The provider name
*/
public String getName() {
return name;
}

private void setName(String name) {
this.name = name;
}

/**
* Returns the implementing class name.
* @return The implementing class name
*/
public String getClassName() {
return className;
}

private void setClassName(String className) {
this.className = className;
}

/**
* Returns the implementing class as a {@link Class} object.
* @return The implementing class or null if it couldn't be loaded.
*/
public Class getImplementingClass() {
if (!checked) {
try {
clazz = Class.forName(getClassName());
} catch (ClassNotFoundException cnfe) {
//nop
} catch (LinkageError le) {
// This can happen if fop was build with support for a
// particular provider (e.g. a binary fop distribution)
// but the required support files (e.g. jai, jimi) are not
// available in the current runtime environment.
ImageFactory.log.debug("Image support provider " + getName()
+ " could not be loaded. If " + getName() + " should be"
+ " available please make sure all required external libraries"
+ " are on the classpath.");
}
checked = true;
}
return clazz;
}
}

/**
* Holds a mime type for a particular image format plus a list of
* {@link ImageProvider} objects which support the particular image format.
*/
class ImageMimeType {

private String mimeType = null;

private List providers = null;

/**
* Constructor for a particular mime type.
* @param mimeType The mime type
*/
public ImageMimeType(String mimeType) {
setMimeType(mimeType);
}

/**
* Returns the mime type.
* @return The mime type
*/
public String getMimeType() {
return mimeType;
}

private void setMimeType(String mimeType) {
this.mimeType = mimeType;
}

/**
* Returns the class from the first available provider.
* @return The first available class or null if none can be found
*/
public Class getFirstImplementingClass() {
if (providers == null) {
return null;
}
for (Iterator it = providers.iterator(); it.hasNext();) {
ImageProvider ip = (ImageProvider)it.next();
Class clazz = ip.getImplementingClass();
if (clazz != null) {
return clazz;
}
}
return null;
}

/**
* Adds a new provider.
* The provider is added to the end of the current provider list.
* @param The new provider to add
*/
public void addProvider(ImageProvider provider) {
if (providers == null) {
providers = new ArrayList(4); // Assume we only have a few providers
}
if (!providers.contains(provider)) {
providers.add(provider);
}
}
}

+ 0
- 64
src/java/org/apache/fop/image/ImageLoader.java View File

@@ -1,64 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

import org.apache.fop.apps.FOUserAgent;

/**
* Class to load images.
*/
class ImageLoader {
private String url;
private ImageCache cache;
private boolean valid = true;
private FOUserAgent userAgent;
private FopImage image = null;

/**
* Main constructor.
* @param url URL to the image
* @param cache Image cache
* @param ua User agent
*/
public ImageLoader(String url, ImageCache cache, FOUserAgent ua) {
this.url = url;
this.cache = cache;
this.userAgent = ua;
}

/**
* Loads the image.
* @return the loaded image
*/
public synchronized FopImage loadImage() {
if (!valid || image != null) {
return image;
}
ImageFactory imageFactory = userAgent.getFactory().getImageFactory();
image = imageFactory.loadImage(url, userAgent);
if (image == null) {
cache.invalidateImage(url, userAgent);
valid = false;
}
return image;
}

}

+ 0
- 194
src/java/org/apache/fop/image/JAIImage.java View File

@@ -1,194 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// AWT
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;
import java.awt.Color;

// JAI
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;

import org.apache.commons.io.IOUtils;
// Sun codec
import com.sun.media.jai.codec.FileCacheSeekableStream;

/**
* FopImage object using JAI.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JAIImage extends AbstractFopImage {

/**
* Create a new JAI image.
*
* @param imgInfo the image info for this JAI image
*/
public JAIImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
loadImage();
}
return this.bitmaps != null;
}
/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* Loads the image from the inputstream
*/
protected void loadImage() {
com.sun.media.jai.codec.FileCacheSeekableStream seekableInput = null;
RenderedOp imageOp = null;
try {
seekableInput = new FileCacheSeekableStream(inputStream);
imageOp = JAI.create("stream", seekableInput);

this.height = imageOp.getHeight();
this.width = imageOp.getWidth();

ColorModel cm = imageOp.getColorModel();
//this.bitsPerPixel = 8;
this.bitsPerPixel = cm.getPixelSize();
// TODO: the getRGB() function converts the image into the RGB
// colorspace. However, here we assume the image colorspace is kept.
// It should be either one of them, but not both. Unfortunately
// there are other hacks for images in the CMYK colorspace (e.g. in
// the PDF output) that would need to be changed as well.
//this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
this.colorSpace = cm.getColorSpace();
BufferedImage imageData = imageOp.getAsBufferedImage();
int[] tmpMap = imageData.getRGB(0, 0, this.width,
this.height, null, 0, this.width);

if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();

if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
* // or use special API...
*/
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}

// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}

} catch (Exception ex) {
log.error("Error while loading image (JAI): " + ex.getMessage(), ex);
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
if (imageOp != null) {
imageOp.dispose();
}
if (seekableInput != null) {
IOUtils.closeQuietly(seekableInput);
}
}
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 186
src/java/org/apache/fop/image/JimiImage.java View File

@@ -1,186 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// Java
import java.awt.image.ImageProducer;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.color.ColorSpace;
import java.awt.Color;

import org.apache.commons.io.IOUtils;

// Jimi
import com.sun.jimi.core.Jimi;

/**
* FopImage object for several images types, using Jimi.
* See Jimi documentation for supported image types.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JimiImage extends AbstractFopImage {

/**
* Create a new Jimi image.
*
* @param imgInfo the image info for this Jimi image
*/
public JimiImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* Loads the image from the inputstream
*/
protected void loadImage() {
int[] tmpMap = null;
try {
ImageProducer ip = Jimi.getImageProducer(inputStream,
Jimi.SYNCHRONOUS | Jimi.IN_MEMORY);
FopImageConsumer consumer = new FopImageConsumer(ip);
ip.startProduction(consumer);

while (!consumer.isImageReady()) {
Thread.sleep(500);
}
this.height = consumer.getHeight();
this.width = consumer.getWidth();

try {
tmpMap = consumer.getImage();
} catch (Exception ex) {
log.error("Image grabbing interrupted", ex);
return;
}

ColorModel cm = consumer.getColorModel();
this.bitsPerPixel = 8;
// this.bitsPerPixel = cm.getPixelSize();
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
if (cm.hasAlpha()) {
// java.awt.Transparency. BITMASK or OPAQUE or TRANSLUCENT
int transparencyType = cm.getTransparency();
if (transparencyType == java.awt.Transparency.OPAQUE) {
this.isTransparent = false;
} else if (transparencyType == java.awt.Transparency.BITMASK) {
if (cm instanceof IndexColorModel) {
this.isTransparent = false;
byte[] alphas = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] reds = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] greens = new byte[
((IndexColorModel) cm).getMapSize()];
byte[] blues = new byte[
((IndexColorModel) cm).getMapSize()];
((IndexColorModel) cm).getAlphas(alphas);
((IndexColorModel) cm).getReds(reds);
((IndexColorModel) cm).getGreens(greens);
((IndexColorModel) cm).getBlues(blues);
for (int i = 0;
i < ((IndexColorModel) cm).getMapSize();
i++) {
if ((alphas[i] & 0xFF) == 0) {
this.isTransparent = true;
this.transparentColor = new Color(
(int)(reds[i] & 0xFF),
(int)(greens[i] & 0xFF),
(int)(blues[i] & 0xFF));
break;
}
}
} else {
// TRANSLUCENT
/*
* this.isTransparent = false;
* for (int i = 0; i < this.width * this.height; i++) {
* if (cm.getAlpha(tmpMap[i]) == 0) {
* this.isTransparent = true;
* this.transparentColor = new PDFColor(cm.getRed(tmpMap[i]),
* cm.getGreen(tmpMap[i]), cm.getBlue(tmpMap[i]));
* break;
* }
* }
*/
// use special API...
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} else {
this.isTransparent = false;
}
} catch (Throwable ex) {
log.error("Error while loading image (Jimi): " + ex.getMessage(), ex);
return;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}


// Should take care of the ColorSpace and bitsPerPixel
this.bitmaps = new byte[this.width * this.height * 3];
for (int i = 0; i < this.height; i++) {
for (int j = 0; j < this.width; j++) {
int p = tmpMap[i * this.width + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p) & 0xFF;
this.bitmaps[3 * (i * this.width + j)] = (byte)(r & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 1] = (byte)(g & 0xFF);
this.bitmaps[3 * (i * this.width + j) + 2] = (byte)(b & 0xFF);
}
}
}

/** {@inheritDoc} */
protected boolean loadOriginalData() {
return loadDefaultOriginalData();
}
}


+ 0
- 239
src/java/org/apache/fop/image/JpegImage.java View File

@@ -1,239 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.fop.util.CMYKColorSpace;

/**
* FopImage object for JPEG images, Using Java native classes.
*
* @see AbstractFopImage
* @see FopImage
*/
public class JpegImage extends AbstractFopImage {
private ICC_Profile iccProfile = null;
private boolean foundICCProfile = false;
private boolean hasAPPEMarker = false;

/**
* Create a jpeg image with the info.
*
* @param imgInfo the image info for this jpeg
*/
public JpegImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
}

/**
* Load the original jpeg data.
* This loads the original jpeg data and reads the color space,
* and icc profile if any.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayOutputStream iccStream = null;
int index = 0;
boolean cont = true;

try {
byte[] readBuf = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(readBuf)) != -1) {
baos.write(readBuf, 0, bytesRead);
}
} catch (java.io.IOException ex) {
log.error("Error while loading image (Jpeg): " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

this.raw = baos.toByteArray();
this.bitsPerPixel = 8;
this.isTransparent = false;

//Check for SOI (Start of image) marker (FFD8)
if (this.raw.length > (index + 2)
&& uByte(this.raw[index]) == 255 /*0xFF*/
&& uByte(this.raw[index + 1]) == 216 /*0xD8*/) {
index += 2;

while (index < this.raw.length && cont) {
//check to be sure this is the begining of a header
if (this.raw.length > (index + 2)
&& uByte(this.raw[index]) == 255 /*0xFF*/) {

//192 or 194 are the header bytes that contain
// the jpeg width height and color depth.
if (uByte(this.raw[index + 1]) == 192 /*0xC0*/
|| uByte(this.raw[index + 1]) == 194 /*0xC2*/) {

this.height = calcBytes(this.raw[index + 5],
this.raw[index + 6]);
this.width = calcBytes(this.raw[index + 7],
this.raw[index + 8]);

int numComponents = this.raw[index + 9];
if (numComponents == 1) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_GRAY);
} else if (numComponents == 3) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_LINEAR_RGB);
} else if (numComponents == 4) {
// howto create CMYK color space
/*
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_CIEXYZ);
*/
this.colorSpace = CMYKColorSpace.getInstance();
} else {
log.error("Unknown ColorSpace for image: "
+ "");
return false;
}

if (foundICCProfile) {
cont = false;
break;
}
index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;

} else if (uByte(this.raw[index + 1]) == 226 /*0xE2*/
&& this.raw.length > (index + 60)) {
// Check if ICC profile
byte[] iccString = new byte[11];
System.arraycopy(this.raw, index + 4,
iccString, 0, 11);

if ("ICC_PROFILE".equals(new String(iccString))) {
int chunkSize = calcBytes(
this.raw[index + 2],
this.raw[index + 3]) + 2;

if (iccStream == null) {
iccStream = new ByteArrayOutputStream();
}
iccStream.write(this.raw,
index + 18, chunkSize - 18);

}

index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;
// Check for Adobe APPE Marker
} else if ((uByte(this.raw[index]) == 0xff
&& uByte(this.raw[index + 1]) == 0xee
&& uByte(this.raw[index + 2]) == 0
&& uByte(this.raw[index + 3]) == 14
&& "Adobe".equals(new String(this.raw, index + 4, 5)))) {
// The reason for reading the APPE marker is that Adobe Photoshop
// generates CMYK JPEGs 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.raw[index + 2],
this.raw[index + 3]) + 2;
} else {
index += calcBytes(this.raw[index + 2],
this.raw[index + 3]) + 2;
}

} else {
cont = false;
}
}
} else {
log.error("Error while loading "
+ "JpegImage - Invalid JPEG Header.");
return false;
}
if (iccStream != null && iccStream.size() > 0) {
int padding = (8 - (iccStream.size() % 8)) % 8;
if (padding != 0) {
try {
iccStream.write(new byte[padding]);
} catch (Exception ex) {
log.error("Error while aligning ICC stream: " + ex.getMessage(), ex);
return false;
}
}
try {
iccProfile = ICC_Profile.getInstance(iccStream.toByteArray());
} catch (IllegalArgumentException iae) {
log.warn("An ICC profile is present but it is invalid ("
+ iae.getMessage() + "). The color profile will be ignored. ("
+ this.getOriginalURI() + ")");
}
if (iccProfile.getNumComponents() != this.colorSpace.getNumComponents()) {
log.warn("The number of components of the ICC profile ("
+ iccProfile.getNumComponents()
+ ") doesn't match the image ("
+ this.colorSpace.getNumComponents()
+ "). Ignoring the ICC color profile.");
this.iccProfile = null;
}
} else if (this.colorSpace == null) {
log.error("ColorSpace not specified for JPEG image");
return false;
}
if (hasAPPEMarker && this.colorSpace.getType() == ColorSpace.TYPE_CMYK) {
if (log.isDebugEnabled()) {
log.debug("JPEG has an Adobe APPE marker. Note: CMYK Image will be inverted. ("
+ this.getOriginalURI() + ")");
}
this.invertImage = true;
}
return true;
}

/**
* Get the ICC profile for this Jpeg image.
*
* @return the icc profile or null if not found
*/
public ICC_Profile getICCProfile() {
return iccProfile;
}

private int calcBytes(byte bOne, byte bTwo) {
return (uByte(bOne) * 256) + uByte(bTwo);
}

private int uByte(byte bIn) {
if (bIn < 0) {
return 256 + bIn;
} else {
return bIn;
}
}
}


+ 0
- 87
src/java/org/apache/fop/image/PNGImage.java View File

@@ -1,87 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

import java.io.IOException;

import org.apache.xmlgraphics.image.codec.png.PNGRed;
import org.apache.xmlgraphics.image.codec.png.PNGDecodeParam;
import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.commons.io.IOUtils;

/**
* FopImage object using PNG
*
* @see AbstractFopImage
* @see FopImage
*/
public class PNGImage extends XmlGraphicsCommonsImage {

/**
* Constructs a new PNGImage instance.
* @param imgReader basic metadata for the image
*/
public PNGImage(FopImage.ImageInfo imgReader) {
super(imgReader);
this.loaded = 0; //TODO The PNGReader cannot read the resolution, yet.
}

/**
* {@inheritDoc}
*/
protected CachableRed decodeImage(SeekableStream stream) throws IOException {
PNGDecodeParam param = new PNGDecodeParam();
param.setPerformGammaCorrection(true);
param.setDisplayExponent(2.2f); // sRGB gamma
PNGRed red = new PNGRed(stream, param);
String unit = (String)red.getProperty("pixel_units");
if ("Meters".equals(unit)) {
this.dpiHorizontal = ((Integer)red.getProperty("x_pixels_per_unit")).intValue()
* 25.4f / 1000f;
this.dpiVertical = ((Integer)red.getProperty("y_pixels_per_unit")).intValue()
* 25.4f / 1000f;
}
return red;
}
/**
* Load the original PNG data.
* This loads the original PNG data as is into memory.
*
* @return true if loaded false for any error
*/
protected boolean loadOriginalData() {
try {
seekableInput.seek(0);
this.raw = IOUtils.toByteArray(seekableInput);
} catch (java.io.IOException ex) {
log.error("Error while loading raw image: " + ex.getMessage(), ex);
return false;
} finally {
IOUtils.closeQuietly(inputStream);
inputStream = null;
}

return true;
}
}

+ 0
- 49
src/java/org/apache/fop/image/RegisterableImageProvider.java View File

@@ -1,49 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image;

/**
* This interface is used to dynamically register FopImage implementations.
* <p>
* NOTE: Please don't rely on this interface too much. It is a temporary measure
* until the whole image package can be redesigned. The redesign will likely
* provide a different mechanism to dynamically register new implementations.
*/
public interface RegisterableImageProvider {

/**
* Returns the MIME type the implementation supports.
* @return the MIME type
*/
String getSupportedMimeType();
/**
* Returns the name of the implementation.
* @return the name
*/
String getName();
/**
* Returns the fully qualified class name for the implementing class.
* @return the class name
*/
String getClassName();

}

+ 0
- 207
src/java/org/apache/fop/image/TIFFImage.java View File

@@ -1,207 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

import java.awt.color.ColorSpace;
import java.io.IOException;

import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.codec.tiff.TIFFDirectory;
import org.apache.xmlgraphics.image.codec.tiff.TIFFField;
import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
import org.apache.xmlgraphics.image.rendered.CachableRed;
import org.apache.commons.io.IOUtils;

/**
* TIFF implementation using the Batik codecs.
*/
public class TIFFImage extends XmlGraphicsCommonsImage {

private int compression = 0;
private int stripCount = 0;
private long stripOffset = 0;
private long stripLength = 0;
private int fillOrder = 1;

/**
* Constructs a new BatikImage instance.
* @param imgReader basic metadata for the image
*/
public TIFFImage(FopImage.ImageInfo imgReader) {
super(imgReader);
}

/**
* The compression type set in the TIFF directory
* @return the TIFF compression type
*/
public int getCompression() {
return compression;
}

/**
* The number of strips in the image
* @return the number of strips in the image
*/
public int getStripCount() {
return stripCount;
}

/**
* {@inheritDoc}
* org.apache.xmlgraphics.image.codec.util.SeekableStream)
*/
protected CachableRed decodeImage(SeekableStream stream) throws IOException {
org.apache.xmlgraphics.image.codec.tiff.TIFFImage img
= new org.apache.xmlgraphics.image.codec.tiff.TIFFImage
(stream, null, 0);
TIFFDirectory dir = (TIFFDirectory)img.getProperty("tiff_directory");
TIFFField fld = dir.getField(TIFFImageDecoder.TIFF_RESOLUTION_UNIT);
int resUnit = fld.getAsInt(0);
fld = dir.getField(TIFFImageDecoder.TIFF_X_RESOLUTION);
double xRes = fld.getAsDouble(0);
fld = dir.getField(TIFFImageDecoder.TIFF_Y_RESOLUTION);
double yRes = fld.getAsDouble(0);
switch (resUnit) {
case 2: //inch
this.dpiHorizontal = xRes;
this.dpiVertical = yRes;
break;
case 3: //cm
this.dpiHorizontal = xRes * 2.54f;
this.dpiVertical = yRes * 2.54f;
break;
default:
//ignored
log.warn("Cannot determine bitmap resolution."
+ " Unimplemented resolution unit: " + resUnit);
}
fld = dir.getField(TIFFImageDecoder.TIFF_COMPRESSION);
if (fld != null) {
compression = fld.getAsInt(0);
}
fld = dir.getField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE);
if (fld != null) {
bitsPerPixel = fld.getAsInt(0);
}
fld = dir.getField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP);
if (fld == null) {
stripCount = 1;
} else {
stripCount = (int)(dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_LENGTH)
/ fld.getAsLong(0));
}

fld = dir.getField(TIFFImageDecoder.TIFF_FILL_ORDER);
if (fld != null) {
fillOrder = fld.getAsInt(0);
}

stripOffset = dir.getField(TIFFImageDecoder.TIFF_STRIP_OFFSETS).getAsLong(0);
stripLength = dir.getField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS).getAsLong(0);
if (this.bitsPerPixel == 1) {
this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
}
return img;
}

/**
* Load the original TIFF data.
* This loads only strip 1 of the original TIFF data.
*
* @return true if loaded false for any error
* {@inheritDoc}
*/
protected boolean loadOriginalData() {
if (loadDimensions()) {
byte[] readBuf = new byte[(int)stripLength];
int bytesRead;

try {
this.seekableInput.reset();
this.seekableInput.skip(stripOffset);
bytesRead = seekableInput.read(readBuf);
if (bytesRead != stripLength) {
log.error("Error while loading image: length mismatch on read");
return false;
}

// need to invert bytes if fill order = 2
if (fillOrder == 2) {
for (int i = 0; i < (int)stripLength; i++) {
readBuf[i] = flipTable[readBuf[i] & 0xff];
}
}
this.raw = readBuf;

return true;
} catch (IOException ioe) {
log.error("Error while loading image strip 1 (TIFF): ", ioe);
return false;
} finally {
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
this.seekableInput = null;
this.inputStream = null;
this.cr = null;
}
}
return false;
}

// Table to be used when fillOrder = 2, for flipping bytes.
// Copied from XML Graphics Commons' TIFFFaxDecoder class
private static byte[] flipTable = {
0, -128, 64, -64, 32, -96, 96, -32,
16, -112, 80, -48, 48, -80, 112, -16,
8, -120, 72, -56, 40, -88, 104, -24,
24, -104, 88, -40, 56, -72, 120, -8,
4, -124, 68, -60, 36, -92, 100, -28,
20, -108, 84, -44, 52, -76, 116, -12,
12, -116, 76, -52, 44, -84, 108, -20,
28, -100, 92, -36, 60, -68, 124, -4,
2, -126, 66, -62, 34, -94, 98, -30,
18, -110, 82, -46, 50, -78, 114, -14,
10, -118, 74, -54, 42, -86, 106, -22,
26, -102, 90, -38, 58, -70, 122, -6,
6, -122, 70, -58, 38, -90, 102, -26,
22, -106, 86, -42, 54, -74, 118, -10,
14, -114, 78, -50, 46, -82, 110, -18,
30, -98, 94, -34, 62, -66, 126, -2,
1, -127, 65, -63, 33, -95, 97, -31,
17, -111, 81, -47, 49, -79, 113, -15,
9, -119, 73, -55, 41, -87, 105, -23,
25, -103, 89, -39, 57, -71, 121, -7,
5, -123, 69, -59, 37, -91, 101, -27,
21, -107, 85, -43, 53, -75, 117, -11,
13, -115, 77, -51, 45, -83, 109, -19,
29, -99, 93, -35, 61, -67, 125, -3,
3, -125, 67, -61, 35, -93, 99, -29,
19, -109, 83, -45, 51, -77, 115, -13,
11, -117, 75, -53, 43, -85, 107, -21,
27, -101, 91, -37, 59, -69, 123, -5,
7, -121, 71, -57, 39, -89, 103, -25,
23, -105, 87, -41, 55, -73, 119, -9,
15, -113, 79, -49, 47, -81, 111, -17,
31, -97, 95, -33, 63, -65, 127, -1,
};
// end
}

+ 0
- 78
src/java/org/apache/fop/image/XMLImage.java View File

@@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

// Java
import org.w3c.dom.Document;
import javax.xml.parsers.SAXParserFactory;

/**
* This is an implementation for XML-based images such as SVG.
*
* @see AbstractFopImage
* @see FopImage
*/
public class XMLImage extends AbstractFopImage {

private Document doc;
private String namespace = "";

/**
* @see org.apache.fop.image.AbstractFopImage#AbstractFopImage(FopImage.ImageInfo)
*/
public XMLImage(FopImage.ImageInfo imgInfo) {
super(imgInfo);
if (imgInfo.data instanceof Document) {
doc = (Document)imgInfo.data;
loaded = loaded | ORIGINAL_DATA;
}
namespace = imgInfo.str;
}

/**
* Returns the fully qualified classname of an XML parser for
* Batik classes that apparently need it (error messages, perhaps)
* @return an XML parser classname
*/
public static String getParserName() {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
return factory.newSAXParser().getXMLReader().getClass().getName();
} catch (Exception e) {
return null;
}
}

/**
* Returns the XML document as a DOM document.
* @return the DOM document
*/
public Document getDocument() {
return this.doc;
}

/**
* Returns the namespace of the XML document.
* @return the namespace
*/
public String getNameSpace() {
return this.namespace;
}
}

+ 0
- 239
src/java/org/apache/fop/image/XmlGraphicsCommonsImage.java View File

@@ -1,239 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image;

import java.awt.Color;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.BufferedImage;
import java.io.IOException;

import org.apache.xmlgraphics.image.GraphicsUtil;
import org.apache.xmlgraphics.image.codec.util.SeekableStream;
import org.apache.xmlgraphics.image.codec.util.MemoryCacheSeekableStream;
import org.apache.xmlgraphics.image.codec.util.FileCacheSeekableStream;
import org.apache.xmlgraphics.image.rendered.CachableRed;

import org.apache.commons.io.IOUtils;

/**
* Abstract FopImage implementation which uses the internal codecs from XML Graphics Commons.
*
* @see AbstractFopImage
* @see FopImage
*/
public abstract class XmlGraphicsCommonsImage extends AbstractFopImage {

private byte[] softMask = null;

/**
* The InputStream wrapped into a SeekableStream for decoding.
*/
protected SeekableStream seekableInput = null;

/**
* The Batik representation of the image
*/
protected CachableRed cr = null;
/**
* Constructs a new BatikImage instance.
* @param imgReader basic metadata for the image
*/
public XmlGraphicsCommonsImage(FopImage.ImageInfo imgReader) {
super(imgReader);
}

/**
* {@inheritDoc}
*/
protected boolean loadDimensions() {
if (seekableInput == null && inputStream != null) {
try {
seekableInput = new FileCacheSeekableStream(inputStream);
} catch (IOException ioe) {
seekableInput = new MemoryCacheSeekableStream(inputStream);
}
try {
this.bitsPerPixel = 8;
cr = decodeImage(seekableInput);
this.height = cr.getHeight();
this.width = cr.getWidth();
this.isTransparent = false;
this.softMask = null;
ColorModel cm = cr.getColorModel();

this.height = cr.getHeight();
this.width = cr.getWidth();
this.isTransparent = false;
this.softMask = null;

int transparencyType = cm.getTransparency();
if (cm instanceof IndexColorModel) {
if (transparencyType == Transparency.BITMASK) {
// Use 'transparent color'.
IndexColorModel icm = (IndexColorModel)cm;
int numColor = icm.getMapSize();
byte [] alpha = new byte[numColor];
icm.getAlphas(alpha);
for (int i = 0; i < numColor; i++) {
if ((alpha[i] & 0xFF) == 0) {
this.isTransparent = true;
int red = (icm.getRed (i)) & 0xFF;
int grn = (icm.getGreen(i)) & 0xFF;
int blu = (icm.getBlue (i)) & 0xFF;
this.transparentColor = new Color(red, grn, blu);
break;
}
}
}
} else {
cr = GraphicsUtil.convertTosRGB(cr);
}

// Get our current ColorModel
cm = cr.getColorModel();
if (this.colorSpace == null) {
this.colorSpace = cm.getColorSpace();
}
} catch (IOException ioe) {
log.error("Error while loading image (Batik): " + ioe.getMessage(), ioe);
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
seekableInput = null;
inputStream = null;
return false;
}
}
return this.height != -1;
}

/**
* {@inheritDoc}
*/
protected boolean loadBitmap() {
if (this.bitmaps == null) {
loadImage();
}

return this.bitmaps != null;
}

/**
* {@inheritDoc}
*/
public boolean hasSoftMask() {
if (this.bitmaps == null && this.raw == null) {
loadImage();
}

return (this.softMask != null);
}

/**
* {@inheritDoc}
*/
public byte[] getSoftMask() {
if (this.bitmaps == null) {
loadImage();
}

return this.softMask;
}

/**
* Decodes the image from the stream.
* @param stream the stream to read the image from
* @return the decoded image
* @throws IOException in case an I/O problem occurs
*/
protected abstract CachableRed decodeImage(SeekableStream stream) throws IOException;
/**
* Loads the image from the InputStream.
*/
protected void loadImage() {
if (loadDimensions()) {
try {
if (cr == null) {
throw new IllegalStateException(
"Can't load the bitmaps data without the CachableRed instance");
}
// Get our current ColorModel
ColorModel cm = cr.getColorModel();

// It has an alpha channel so generate a soft mask.
if (!this.isTransparent && cm.hasAlpha()) {
this.softMask = new byte[this.width * this.height];
}

this.bitmaps = new byte[this.width * this.height * 3];

constructBitmaps(cr, this.bitmaps, this.softMask);
} catch (Exception ex) {
log.error("Error while loading image (Batik): " + ex.getMessage(), ex);
} finally {
// Make sure we clean up
IOUtils.closeQuietly(seekableInput);
IOUtils.closeQuietly(inputStream);
seekableInput = null;
inputStream = null;
cr = null;
}
}
}

private static void constructBitmaps(RenderedImage red, byte[] bitmaps, byte[] softMask) {
WritableRaster wr = (WritableRaster)red.getData();
ColorModel cm = red.getColorModel();
BufferedImage bi = new BufferedImage
(cm, wr.createWritableTranslatedChild(0, 0),
cm.isAlphaPremultiplied(), null);
int width = red.getWidth();
int height = red.getHeight();
int [] tmpMap = new int[width];
int idx = 0;
int sfIdx = 0;
for (int y = 0; y < height; y++) {
tmpMap = bi.getRGB(0, y, width, 1, tmpMap, 0, width);
if (softMask != null) {
for (int x = 0; x < width; x++) {
int pix = tmpMap[x];
softMask[sfIdx++] = (byte)(pix >>> 24);
bitmaps[idx++] = (byte)((pix >>> 16) & 0xFF);
bitmaps[idx++] = (byte)((pix >>> 8) & 0xFF);
bitmaps[idx++] = (byte)((pix) & 0xFF);
}
} else {
for (int x = 0; x < width; x++) {
int pix = tmpMap[x];
bitmaps[idx++] = (byte)((pix >> 16) & 0xFF);
bitmaps[idx++] = (byte)((pix >> 8) & 0xFF);
bitmaps[idx++] = (byte)((pix) & 0xFF);
}
}
}
}
}

+ 0
- 134
src/java/org/apache/fop/image/analyser/BMPReader.java View File

@@ -1,134 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for BMP image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class BMPReader implements ImageReader {

/** Length of the BMP header */
protected static final int BMP_SIG_LENGTH = 46;
/** offset to width */
private static final int WIDTH_OFFSET = 18;
/** offset to height */
private static final int HEIGHT_OFFSET = 22;
/** offset to horizontal res */
private static final int HRES_OFFSET = 38;
/** offset to vertical res */
private static final int VRES_OFFSET = 42;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == (byte) 0x42)
&& (header[1] == (byte) 0x4d));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/bmp";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// little endian notation
int byte1 = header[WIDTH_OFFSET] & 0xff;
int byte2 = header[WIDTH_OFFSET + 1] & 0xff;
int byte3 = header[WIDTH_OFFSET + 2] & 0xff;
int byte4 = header[WIDTH_OFFSET + 3] & 0xff;
long l = (long) ((byte4 << 24) | (byte3 << 16)
| (byte2 << 8) | byte1);
info.width = (int) (l & 0xffffffff);

byte1 = header[HEIGHT_OFFSET] & 0xff;
byte2 = header[HEIGHT_OFFSET + 1] & 0xff;
byte3 = header[HEIGHT_OFFSET + 2] & 0xff;
byte4 = header[HEIGHT_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
info.height = (int) (l & 0xffffffff);

byte1 = header[HRES_OFFSET] & 0xff;
byte2 = header[HRES_OFFSET + 1] & 0xff;
byte3 = header[HRES_OFFSET + 2] & 0xff;
byte4 = header[HRES_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
if (l > 0) {
info.dpiHorizontal = l / 39.37d;
}

byte1 = header[VRES_OFFSET] & 0xff;
byte2 = header[VRES_OFFSET + 1] & 0xff;
byte3 = header[VRES_OFFSET + 2] & 0xff;
byte4 = header[VRES_OFFSET + 3] & 0xff;
l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
if (l > 0) {
info.dpiVertical = l / 39.37d;
}
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[BMP_SIG_LENGTH];
try {
imageStream.mark(BMP_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}

+ 0
- 162
src/java/org/apache/fop/image/analyser/EMFReader.java View File

@@ -1,162 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for EMF image type.
*
* @author Peter Herweg
*/
public class EMFReader implements ImageReader {

/** Length of the EMF header */
protected static final int EMF_SIG_LENGTH = 88;
/** offset to signature */
private static final int SIGNATURE_OFFSET = 40;
/** offset to width */
private static final int WIDTH_OFFSET = 32;
/** offset to height */
private static final int HEIGHT_OFFSET = 36;
/** offset to horizontal resolution in pixel */
private static final int HRES_PIXEL_OFFSET = 72;
/** offset to vertical resolution in pixel */
private static final int VRES_PIXEL_OFFSET = 76;
/** offset to horizontal resolution in mm */
private static final int HRES_MM_OFFSET = 80;
/** offset to vertical resolution in mm */
private static final int VRES_MM_OFFSET = 84;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported
= ( (header[SIGNATURE_OFFSET + 0] == (byte) 0x20)
&& (header[SIGNATURE_OFFSET + 1] == (byte) 0x45)
&& (header[SIGNATURE_OFFSET + 2] == (byte) 0x4D)
&& (header[SIGNATURE_OFFSET + 3] == (byte) 0x46) );
if (supported) {
FopImage.ImageInfo info = getDimension(header);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/emf";
}

private FopImage.ImageInfo getDimension(byte[] header) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
long value = 0;
int byte1;
int byte2;
int byte3;
int byte4;
// little endian notation

//resolution
byte1 = header[HRES_MM_OFFSET] & 0xff;
byte2 = header[HRES_MM_OFFSET + 1] & 0xff;
byte3 = header[HRES_MM_OFFSET + 2] & 0xff;
byte4 = header[HRES_MM_OFFSET + 3] & 0xff;
long hresMM = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[VRES_MM_OFFSET] & 0xff;
byte2 = header[VRES_MM_OFFSET + 1] & 0xff;
byte3 = header[VRES_MM_OFFSET + 2] & 0xff;
byte4 = header[VRES_MM_OFFSET + 3] & 0xff;
long vresMM = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[HRES_PIXEL_OFFSET] & 0xff;
byte2 = header[HRES_PIXEL_OFFSET + 1] & 0xff;
byte3 = header[HRES_PIXEL_OFFSET + 2] & 0xff;
byte4 = header[HRES_PIXEL_OFFSET + 3] & 0xff;
long hresPixel = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
byte1 = header[VRES_PIXEL_OFFSET] & 0xff;
byte2 = header[VRES_PIXEL_OFFSET + 1] & 0xff;
byte3 = header[VRES_PIXEL_OFFSET + 2] & 0xff;
byte4 = header[VRES_PIXEL_OFFSET + 3] & 0xff;
long vresPixel = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
info.dpiHorizontal = hresPixel / (hresMM / 25.4f);
info.dpiVertical = vresPixel / (vresMM / 25.4f);
//width
byte1 = header[WIDTH_OFFSET] & 0xff;
byte2 = header[WIDTH_OFFSET + 1] & 0xff;
byte3 = header[WIDTH_OFFSET + 2] & 0xff;
byte4 = header[WIDTH_OFFSET + 3] & 0xff;
value = (long) ((byte4 << 24) | (byte3 << 16)
| (byte2 << 8) | byte1);
value = Math.round(value / 100f / 25.4f * info.dpiHorizontal);
info.width = (int) (value & 0xffffffff);

//height
byte1 = header[HEIGHT_OFFSET] & 0xff;
byte2 = header[HEIGHT_OFFSET + 1] & 0xff;
byte3 = header[HEIGHT_OFFSET + 2] & 0xff;
byte4 = header[HEIGHT_OFFSET + 3] & 0xff;
value = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1);
value = Math.round(value / 100f / 25.4f * info.dpiVertical);
info.height = (int) (value & 0xffffffff);

return info;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[EMF_SIG_LENGTH];
try {
imageStream.mark(EMF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}
}

+ 0
- 253
src/java/org/apache/fop/image/analyser/EPSReader.java View File

@@ -1,253 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

// FOP
import org.apache.commons.io.IOUtils;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.EPSImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for EPS document image type.
*
* @version $Id$
*/
public class EPSReader implements ImageReader {

private static final byte[] EPS_HEADER_ASCII = "%!PS".getBytes();
private static final byte[] BOUNDINGBOX = "%%BoundingBox: ".getBytes();
//private static final byte[] HIRESBOUNDINGBOX = "%%HiResBoundingBox: ".getBytes();
//TODO Implement HiResBoundingBox, ImageInfo probably needs some changes for that

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {

boolean isEPS = false;

bis.mark(32);
byte[] header = new byte[30];
bis.read(header, 0, 30);
bis.reset();

EPSImage.EPSData data = new EPSImage.EPSData();

// Check if binary header
if (getLong(header, 0) == 0xC6D3D0C5) {
data.isAscii = false;
isEPS = true;

data.psStart = getLong(header, 4);
data.psLength = getLong(header, 8);
data.wmfStart = getLong(header, 12);
data.wmfLength = getLong(header, 16);
data.tiffStart = getLong(header, 20);
data.tiffLength = getLong(header, 24);

} else {
// Check if plain ascii
byte[] epsh = "%!PS".getBytes();
if (EPS_HEADER_ASCII[0] == header[0]
&& EPS_HEADER_ASCII[1] == header[1]
&& EPS_HEADER_ASCII[2] == header[2]
&& EPS_HEADER_ASCII[3] == header[3]) {
data.isAscii = true;
isEPS = true;
}
}

if (isEPS) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.originalURI = uri;
info.mimeType = getMimeType();
info.data = data;
readEPSImage(bis, data);
data.bbox = readBBox(data);

if (data.bbox != null) {
info.width = (int) (data.bbox[2] - data.bbox[0]);
info.height = (int) (data.bbox[3] - data.bbox[1]);

// image data read
IOUtils.closeQuietly(bis);
info.inputStream = null;

return info;
} else {
// Ain't eps if no BoundingBox
isEPS = false;
}
}

return null;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/eps";
}

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) ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
}

/**
* Read the eps file and extract eps part.
*
* @param bis The InputStream
* @param data EPSData object to write the results to
* @exception IOException If an I/O error occurs
*/
private void readEPSImage(InputStream bis, EPSImage.EPSData data)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] file;
byte[] readBuf = new byte[20480];
int bytesRead;
int index = 0;
boolean cont = true;

try {
while ((bytesRead = bis.read(readBuf)) != -1) {
baos.write(readBuf, 0, bytesRead);
}
} catch (java.io.IOException ex) {
throw new IOException("Error while loading EPS image: "
+ ex.getMessage());
}

file = baos.toByteArray();

if (data.isAscii) {
data.rawEps = null;
data.epsFile = new byte[file.length];
System.arraycopy(file, 0, data.epsFile, 0, data.epsFile.length);
} else {
data.rawEps = new byte[file.length];
data.epsFile = new byte[(int) data.psLength];
System.arraycopy(file, 0, data.rawEps, 0, data.rawEps.length);
System.arraycopy(data.rawEps, (int) data.psStart, data.epsFile, 0,
(int) data.psLength);
}
}

/**
* Get embedded TIFF preview or null.
*
* @param data The EPS payload
* @return The embedded preview
*/
public byte[] getPreview(EPSImage.EPSData data) {
if (data.preview == null) {
if (data.tiffLength > 0) {
data.preview = new byte[(int) data.tiffLength];
System.arraycopy(data.rawEps, (int) data.tiffStart, data.preview, 0,
(int) data.tiffLength);
}
}
return data.preview;
}

/**
* Extract bounding box from eps part.
*
* @param data The EPS payload
* @return An Array of four coordinates making up the bounding box
*/
private long[] readBBox(EPSImage.EPSData data) {
long[] mbbox = null;
int idx = 0;
boolean found = false;

while (!found && (data.epsFile.length > (idx + BOUNDINGBOX.length))) {
boolean sfound = true;
int i = idx;
for (i = idx; sfound && (i - idx) < BOUNDINGBOX.length; i++) {
if (BOUNDINGBOX[i - idx] != data.epsFile[i]) {
sfound = false;
}
}
if (sfound) {
found = true;
idx = i;
} else {
idx++;
}
}

if (!found) {
return mbbox;
}

mbbox = new long[4];
idx += readLongString(data, mbbox, 0, idx);
idx += readLongString(data, mbbox, 1, idx);
idx += readLongString(data, mbbox, 2, idx);
idx += readLongString(data, mbbox, 3, idx);

return mbbox;
}

private int readLongString(EPSImage.EPSData data, long[] mbbox, int i, int idx) {
while (idx < data.epsFile.length && (data.epsFile[idx] == 32)) {
idx++;
}

int nidx = idx;

// check also for ANSI46(".") to identify floating point values
while (nidx < data.epsFile.length
&& ((data.epsFile[nidx] >= 48 && data.epsFile[nidx] <= 57)
|| (data.epsFile[nidx] == 45)
|| (data.epsFile[nidx] == 46))) {
nidx++;
}

byte[] num = new byte[nidx - idx];
System.arraycopy(data.epsFile, idx, num, 0, nidx - idx);
String ns = new String(num);

//if( ns.indexOf(".") != -1 ) {
// do something like logging a warning
//}

// then parse the double and round off to the next math. Integer
mbbox[i] = (long) Math.ceil(Double.parseDouble(ns));

return (1 + nidx - idx);
}

}


+ 0
- 104
src/java/org/apache/fop/image/analyser/GIFReader.java View File

@@ -1,104 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for GIF image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class GIFReader implements ImageReader {

private static final int GIF_SIG_LENGTH = 10;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == 'G')
&& (header[1] == 'I')
&& (header[2] == 'F')
&& (header[3] == '8')
&& (header[4] == '7' || header[4] == '9')
&& (header[5] == 'a'));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/gif";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// little endian notation
int byte1 = header[6] & 0xff;
int byte2 = header[7] & 0xff;
info.width = ((byte2 << 8) | byte1) & 0xffff;

byte1 = header[8] & 0xff;
byte2 = header[9] & 0xff;
info.height = ((byte2 << 8) | byte1) & 0xffff;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[GIF_SIG_LENGTH];
try {
imageStream.mark(GIF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}


+ 0
- 56
src/java/org/apache/fop/image/analyser/ImageReader.java View File

@@ -1,56 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader objects read image headers to determine the image size.
*
* @author Pankaj Narula
* @version $Id$
*/
public interface ImageReader {

/**
* Verify image type. If the stream does not contain image data expected by
* the reader it must reset the stream to the start. This is so that the
* next reader can start reading from the start. The reader must not close
* the stream unless it can handle the image and it has read the
* information.
*
* @param bis Image buffered input stream
* @param uri URI to the image
* @param ua The user agent
* @return <code>true</code> if image type is the handled one
* @exception IOException if an I/O error occurs
*/
FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua)
throws IOException;

}


+ 0
- 108
src/java/org/apache/fop/image/analyser/ImageReaderFactory.java View File

@@ -1,108 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.FopImage;
import org.apache.xmlgraphics.util.Service;

/**
* Factory for ImageReader objects.
*
* @author Pankaj Narula
* @version $Id$
*/
public class ImageReaderFactory {

private static List formats = new java.util.ArrayList();

/** logger */
protected static Log log = LogFactory.getLog(ImageReaderFactory.class);

static {
registerFormat(new JPEGReader());
registerFormat(new BMPReader());
registerFormat(new GIFReader());
registerFormat(new PNGReader());
registerFormat(new TIFFReader());
registerFormat(new EPSReader());
registerFormat(new EMFReader());

//Dynamic registration of ImageReaders
Iterator iter = Service.providers(ImageReader.class, true);
while (iter.hasNext()) {
registerFormat((ImageReader)iter.next());
}
// the xml parser through batik closes the stream when finished
// so there is a workaround in the SVGReader
registerFormat(new SVGReader());
registerFormat(new SVGZReader());
registerFormat(new XMLReader());
}

/**
* Registers a new ImageReader.
*
* @param reader An ImageReader instance
*/
public static void registerFormat(ImageReader reader) {
formats.add(reader);
}

/**
* ImageReader maker.
*
* @param uri URI to the image
* @param in image input stream
* @param ua user agent
* @return An ImageInfo object describing the image
*/
public static FopImage.ImageInfo make(String uri, InputStream in,
FOUserAgent ua) {

ImageReader reader;
try {
for (int count = 0; count < formats.size(); count++) {
reader = (ImageReader) formats.get(count);
FopImage.ImageInfo info = reader.verifySignature(uri, in, ua);
if (info != null) {
return info;
}
}
log.warn("No ImageReader found for " + uri);
in.close();
} catch (IOException ex) {
log.error("Error while recovering Image Informations ("
+ uri + ")", ex);
}
return null;
}

}


+ 0
- 264
src/java/org/apache/fop/image/analyser/JPEGReader.java View File

@@ -1,264 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for JPEG image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class JPEGReader implements ImageReader {

/**
* Only SOFn and APPn markers are defined as SOFn is needed for the height and
* width search. APPn is also defined because if the JPEG contains thumbnails
* the dimensions of the thumnail would also be after the SOFn marker enclosed
* inside the APPn marker. And we don't want to confuse those dimensions with
* the image dimensions.
*/
private static final int MARK = 0xff; // Beginning of a Marker
private static final int NULL = 0x00; // Special case for 0xff00
private static final int SOF1 = 0xc0; // Baseline DCT
private static final int SOF2 = 0xc1; // Extended Sequential DCT
private static final int SOF3 = 0xc2; // Progrssive DCT only PDF 1.3
private static final int SOFA = 0xca; // Progressice DCT only PDF 1.3
private static final int APP0 = 0xe0; // Application marker, JFIF
private static final int APPF = 0xef; // Application marker
private static final int SOS = 0xda; // Start of Scan
private static final int SOI = 0xd8; // start of Image
private static final int JPG_SIG_LENGTH = 2;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(fis);
boolean supported = ((header[0] == (byte) 0xff)
&& (header[1] == (byte) 0xd8));
if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(fis, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = fis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/jpeg";
}

private byte[] getDefaultHeader(InputStream imageStream) throws IOException {
byte[] header = new byte[JPG_SIG_LENGTH];
try {
imageStream.mark(JPG_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

private void getDimension(InputStream imageStream,
FopImage.ImageInfo info)
throws IOException {
try {
int pos=0, avail = imageStream.available();
imageStream.mark(avail);
int marker = NULL;
long length, skipped;
outer:
while (true) {
do {
if (avail == 0) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
//Marker first byte (FF)
marker = imageStream.read();
pos++; avail--;
} while (marker != MARK);

do {
if (avail == 0) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
//Marker second byte
marker = imageStream.read();
pos++; avail--;
} while (marker == MARK);

switch (marker) {
case SOI:
break;
case NULL:
break;
case APP0:
if (avail < 14) {
imageStream.reset();
avail = 2 * pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
int reclen = this.read2bytes(imageStream);
pos += 2; avail -= 2;
this.skip(imageStream, 7);
pos += 7; avail -= 7;
int densityUnits = imageStream.read();
pos++; avail--;
int xdensity = this.read2bytes(imageStream);
pos += 2; avail -= 2;
int ydensity = this.read2bytes(imageStream);
pos += 2; avail -= 2;
if (densityUnits == 2) {
info.dpiHorizontal = xdensity * 28.3464567 / 72; //dpi
info.dpiVertical = ydensity * 28.3464567 / 72; //dpi
} else if (densityUnits == 1) {
info.dpiHorizontal = xdensity;
info.dpiVertical = ydensity;
} else {
// Use resolution specified in
// FOUserAgent.getFactory() (default 72dpi).
}
int restlen = reclen - 12;
if (avail < restlen) {
imageStream.reset();
avail = 2 * pos;
if (avail < pos + restlen + 10) {
avail = (int)(pos + restlen + 10);
}
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
skipped = this.skip(imageStream, restlen - 2);
pos += skipped; avail -= skipped;
if (skipped != restlen - 2) {
throw new IOException("Skipping Error");
}
break;
case SOF1:
case SOF2:
case SOF3: // SOF3 and SOFA are only supported by PDF 1.3
case SOFA:
while (avail < 7) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
this.skip(imageStream, 3);
pos+=3; avail-=3;
info.height = this.read2bytes(imageStream);
pos+=2; avail-=2;
info.width = this.read2bytes(imageStream);
pos+=2; avail-=2;
break outer;
default:
while (avail < 2) {
imageStream.reset();
avail = 2*pos;
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
length = this.read2bytes(imageStream);
pos+=2; avail-=2;
if (avail < length) {
imageStream.reset();
avail = 2*pos;
if (avail < pos+length+10) {
avail = (int)(pos+length+10);
}
imageStream.mark(avail);
pos = (int)this.skip(imageStream, pos);
avail -= pos;
}
skipped = this.skip(imageStream, length - 2);
pos += skipped; avail -= skipped;
if (skipped != length - 2) {
throw new IOException("Skipping Error");
}
}
}
imageStream.reset();
} catch (IOException ioe) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ioe;
}
}

private int read2bytes(InputStream imageStream) throws IOException {
int byte1 = imageStream.read();
int byte2 = imageStream.read();
return (int) ((byte1 << 8) | byte2);
}

private long skip(InputStream imageStream, long n) throws IOException {
long discarded = 0;
while (discarded != n) {
imageStream.read();
discarded++;
}
return discarded; // scope for exception
}

}


+ 0
- 115
src/java/org/apache/fop/image/analyser/PNGReader.java View File

@@ -1,115 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for PNG image type.
*
* @author Pankaj Narula
* @version $Id$
*/
public class PNGReader implements ImageReader {

private static final int PNG_SIG_LENGTH = 24;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = ((header[0] == (byte) 0x89)
&& (header[1] == (byte) 0x50)
&& (header[2] == (byte) 0x4e)
&& (header[3] == (byte) 0x47)
&& (header[4] == (byte) 0x0d)
&& (header[5] == (byte) 0x0a)
&& (header[6] == (byte) 0x1a)
&& (header[7] == (byte) 0x0a));

if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/png";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// png is always big endian
int byte1 = header[16] & 0xff;
int byte2 = header[17] & 0xff;
int byte3 = header[18] & 0xff;
int byte4 = header[19] & 0xff;
long l = (long) ((byte1 << 24)
| (byte2 << 16)
| (byte3 << 8)
| (byte4));
info.width = (int) l;

byte1 = header[20] & 0xff;
byte2 = header[21] & 0xff;
byte3 = header[22] & 0xff;
byte4 = header[23] & 0xff;
l = (long) ((byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4);
info.height = (int) l;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[PNG_SIG_LENGTH];
try {
imageStream.mark(PNG_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}

+ 0
- 188
src/java/org/apache/fop/image/analyser/SVGReader.java View File

@@ -1,188 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;
import java.awt.geom.AffineTransform;

// XML
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;

// Batik
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.UnitProcessor;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

// FOP
import org.apache.fop.image.XMLImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.svg.SVGUserAgent;
import org.apache.fop.util.UnclosableInputStream;

/**
* ImageReader object for SVG document image type.
*/
public class SVGReader implements ImageReader {

/** Logger instance */
protected static Log log = LogFactory.getLog(SVGReader.class);
/** SVG's MIME type */
public static final String SVG_MIME_TYPE = "image/svg+xml";

private boolean batik = true;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua) throws IOException {
FopImage.ImageInfo info = loadImage(uri, fis, ua);
if (info != null) {
IOUtils.closeQuietly(fis);
}
return info;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return SVG_MIME_TYPE;
}

/**
* This means the external svg document will be loaded twice. Possibly need
* a slightly different design for the image stuff.
*
* @param uri @todo Description of the Parameter
* @param fis @todo Description of the Parameter
* @param ua @todo Description of the Parameter
* @return @todo Description of the Return Value
*/
private FopImage.ImageInfo loadImage(String uri, InputStream bis,
FOUserAgent ua) {
if (batik) {
try {
Loader loader = new Loader();
return loader.getImage(uri, bis,
ua.getSourcePixelUnitToMillimeter());
} catch (NoClassDefFoundError e) {
batik = false;
log.warn("Batik not in class path", e);
return null;
}
}
return null;
}

/**
* This method is put in another class so that the classloader does not
* attempt to load batik related classes when constructing the SVGReader
* class.
*/
class Loader {
private FopImage.ImageInfo getImage(String uri, InputStream fis,
float pixelUnitToMM) {
// parse document and get the size attributes of the svg element

try {
fis = new UnclosableInputStream(fis);

FopImage.ImageInfo info = new FopImage.ImageInfo();

//Set the resolution to that of the FOUserAgent
info.dpiHorizontal = 25.4f / pixelUnitToMM;
info.dpiVertical = info.dpiHorizontal;
info.originalURI = uri;
info.mimeType = getMimeType();
info.str = SVGDOMImplementation.SVG_NAMESPACE_URI;

int length = fis.available();
fis.mark(length + 1);
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(
XMLImage.getParserName());
SVGDocument doc = (SVGDocument) factory.createSVGDocument(uri, fis);
info.data = doc;

Element e = doc.getRootElement();
String s;
SVGUserAgent userAg = new SVGUserAgent(pixelUnitToMM,
new AffineTransform());
BridgeContext ctx = new BridgeContext(userAg);
UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);

// 'width' attribute - default is 100%
s = e.getAttributeNS(null,
SVGOMDocument.SVG_WIDTH_ATTRIBUTE);
if (s.length() == 0) {
s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE;
}
info.width = Math.round(UnitProcessor.svgHorizontalLengthToUserSpace(
s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx));

// 'height' attribute - default is 100%
s = e.getAttributeNS(null,
SVGOMDocument.SVG_HEIGHT_ATTRIBUTE);
if (s.length() == 0) {
s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE;
}
info.height = Math.round(UnitProcessor.svgVerticalLengthToUserSpace(
s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx));

return info;
} catch (NoClassDefFoundError ncdfe) {
try {
fis.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
batik = false;
log.warn("Batik not in class path", ncdfe);
return null;
} catch (IOException e) {
// If the svg is invalid then it throws an IOException
// so there is no way of knowing if it is an svg document

log.debug("Error while trying to load stream as an SVG file: "
+ e.getMessage());
// assuming any exception means this document is not svg
// or could not be loaded for some reason
try {
fis.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
return null;
}
}
}

}

+ 0
- 53
src/java/org/apache/fop/image/analyser/SVGZReader.java View File

@@ -1,53 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image.analyser;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.FopImage;

/**
* Implements a reader for gzipped XMLFiles.
*
* <p>
* The current implementation is limited to SVG files only.
*/
public class SVGZReader extends XMLReader {
/**
* Default constructor.
*/
public SVGZReader() {
}

/** {@inheritDoc} */
protected FopImage.ImageInfo loadImage(final String uri,
final InputStream bis, final FOUserAgent ua) {
try {
return new SVGReader().verifySignature(uri,
new GZIPInputStream(bis), ua);
} catch (final IOException e) {
// ignore
}
return null;
}
}

+ 0
- 117
src/java/org/apache/fop/image/analyser/TIFFReader.java View File

@@ -1,117 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;

/**
* ImageReader object for TIFF image type.
*
* @author Pankaj Narula, Michael Lee
* @version $Id$
*/
public class TIFFReader implements ImageReader {

private static final int TIFF_SIG_LENGTH = 8;

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream bis,
FOUserAgent ua) throws IOException {
byte[] header = getDefaultHeader(bis);
boolean supported = false;

// first 2 bytes = II (little endian encoding)
if (header[0] == (byte) 0x49 && header[1] == (byte) 0x49) {

// look for '42' in byte 3 and '0' in byte 4
if (header[2] == 42 && header[3] == 0) {
supported = true;
}
}

// first 2 bytes == MM (big endian encoding)
if (header[0] == (byte) 0x4D && header[1] == (byte) 0x4D) {

// look for '42' in byte 4 and '0' in byte 3
if (header[2] == 0 && header[3] == 42) {
supported = true;
}
}

if (supported) {
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.dpiHorizontal = ua.getFactory().getSourceResolution();
info.dpiVertical = info.dpiHorizontal;

getDimension(header, info);
info.originalURI = uri;
info.mimeType = getMimeType();
info.inputStream = bis;
return info;
} else {
return null;
}
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "image/tiff";
}

private void getDimension(byte[] header, FopImage.ImageInfo info) {
// currently not setting the width and height
// these are set again by the Jimi image reader.
// I suppose I'll do it one day to be complete. Or
// someone else will.
// Note: bytes 4,5,6,7 contain the byte offset in the stream of the first IFD block
info.width = -1;
info.height = -1;
}

private byte[] getDefaultHeader(InputStream imageStream)
throws IOException {
byte[] header = new byte[TIFF_SIG_LENGTH];
try {
imageStream.mark(TIFF_SIG_LENGTH + 1);
imageStream.read(header);
imageStream.reset();
} catch (IOException ex) {
try {
imageStream.reset();
} catch (IOException exbis) {
// throw the original exception, not this one
}
throw ex;
}
return header;
}

}


+ 0
- 167
src/java/org/apache/fop/image/analyser/XMLReader.java View File

@@ -1,167 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;
import java.util.Map;

// XML
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.util.UnclosableInputStream;
import org.apache.fop.apps.FOUserAgent;

// Commons-Logging
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** ImageReader object for XML document image type. */
public class XMLReader implements ImageReader {

/**
* logging instance
*/
private Log log = LogFactory.getLog(XMLReader.class);

private static Map converters = new java.util.HashMap();

/**
* Registers a Converter implementation with XMLReader.
*
* @param ns The namespace to associate with this converter
* @param conv The actual Converter implementation
*/
public static void setConverter(String ns, Converter conv) {
converters.put(ns, conv);
}

/** {@inheritDoc} */
public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
FOUserAgent ua)
throws IOException {
FopImage.ImageInfo info = loadImage(uri, fis, ua);
if (info != null) {
info.originalURI = uri;
IOUtils.closeQuietly(fis);
}
return info;
}

/**
* Returns the MIME type supported by this implementation.
*
* @return The MIME type
*/
public String getMimeType() {
return "text/xml";
}

/**
* Creates an ImageInfo object from an XML image read from a stream.
*
* (todo) This means the external svg document will be loaded twice. Possibly need
* a slightly different design for the image stuff.
*
* @param uri The URI to the image
* @param bis The InputStream
* @param ua The user agent
* @return An ImageInfo object describing the image
*/
protected FopImage.ImageInfo loadImage(String uri, InputStream bis,
FOUserAgent ua) {
return createDocument(bis, ua);
}

/**
* Creates an ImageInfo object from an XML image read from a stream.
*
* @param input The InputStream
* @param ua The user agent
* @return An ImageInfo object describing the image
*/
public FopImage.ImageInfo createDocument(final InputStream input, final FOUserAgent ua) {
Document doc = null;
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.mimeType = getMimeType();

try {
final InputStream is = new UnclosableInputStream(input);
int length = is.available();
is.mark(length);

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
doc = dbf.newDocumentBuilder().parse(is);
info.data = doc;

Element root = doc.getDocumentElement();
log.debug("XML image namespace: " + root.getAttribute("xmlns"));
String ns = root.getAttribute("xmlns");
info.str = ns;

Converter conv = (Converter) converters.get(ns);
if (conv != null) {
FopImage.ImageInfo i = conv.convert(doc);
if (i != null) {
info = i;
}
}
} catch (Exception e) {
log.debug("Error while constructing image from XML", e);
try {
input.reset();
} catch (IOException ioe) {
// throw the original exception, not this one
}
return null;
}
if (info != null) {
try {
input.close();
} catch (IOException io) {
// ignore
}
}
return info;
}

/**
* This interface is to be implemented for XML to image converters.
*/
public static interface Converter {

/**
* This method is called for a DOM document to be converted into an
* ImageInfo object.
*
* @param doc The DOM document to convert
* @return An ImageInfo object describing the image
*/
FopImage.ImageInfo convert(Document doc);
}

}


+ 0
- 23
src/java/org/apache/fop/image/analyser/package.html View File

@@ -1,23 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<HTML>
<TITLE>org.apache.fop.image.analyser Package</TITLE>
<BODY>
<P>Image analyzers for determining the format of an image and to preload its intrinsic size.</P>
</BODY>
</HTML>

+ 1
- 1
src/java/org/apache/fop/image/package.html View File

@@ -18,6 +18,6 @@
<HTML>
<TITLE>org.apache.fop.image Package</TITLE>
<BODY>
<P>Contains image loading adapters for various image sources and the image cache.</P>
<P>Contains image loading adapters for various image sources.</P>
</BODY>
</HTML>

+ 0
- 73
src/java/org/apache/fop/render/ps/PSImageUtils.java View File

@@ -1,73 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.render.ps;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.ps.PSGenerator;

import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;

/**
* Utility code for rendering images in PostScript.
*/
public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {

/** logging instance */
protected static Log log = LogFactory.getLog(PSImageUtils.class);

/**
* Renders an EPS image to PostScript.
* @param img EPS image to render
* @param x x position
* @param y y position
* @param w width
* @param h height
* @param gen PS generator
* @deprecated Use {@link #renderEPS(java.io.InputStream, String, java.awt.geom.Rectangle2D,
* java.awt.geom.Rectangle2D, PSGenerator)} instead
*/
public static void renderEPS(EPSImage img,
float x, float y, float w, float h,
PSGenerator gen) {
try {
if (!img.load(FopImage.ORIGINAL_DATA)) {
gen.commentln("%EPS image could not be processed: " + img);
return;
}
int[] bbox = img.getBBox();
int bboxw = bbox[2] - bbox[0];
int bboxh = bbox[3] - bbox[1];
String name = img.getDocName();
if (name == null || name.length() == 0) {
name = img.getOriginalURI();
}
renderEPS(img.getEPSImage(), name,
x, y, w, h,
bbox[0], bbox[1], bboxw, bboxh, gen);

} catch (Exception e) {
log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+ e.getMessage() + ")", e);
}
}

}

+ 0
- 70
src/java/org/apache/fop/render/rtf/SVGConverter.java View File

@@ -1,70 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.render.rtf;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.image.XMLImage;

/**
* Helper class for converting SVG to bitmap images.
*/
public final class SVGConverter {

/** logger instance */
private static Log log = LogFactory.getLog(SVGConverter.class);

/**
* Constructor is private, because it's just a utility class.
*/
private SVGConverter() {
}
/**
* Converts a SVG image to a JPEG bitmap.
* @param image the SVG image
* @return a byte array containing the JPEG image
*/
public static byte[] convertToJPEG(XMLImage image) {
JPEGTranscoder transcoder = new JPEGTranscoder();
/* TODO Disabled to avoid side-effect due to the mixing of source and target resolutions
* This should be reenabled when it has been determined how exactly to handle this
transcoder.addTranscodingHint(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER,
new Float(25.4f / 300)); //300dpi should be enough for now.
*/
transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(0.9f));
TranscoderInput input = new TranscoderInput(image.getDocument());
ByteArrayOutputStream baout = new ByteArrayOutputStream(16384);
TranscoderOutput output = new TranscoderOutput(baout);
try {
transcoder.transcode(input, output);
return baout.toByteArray();
} catch (TranscoderException e) {
log.error(e);
return null;
}
}
}

src/java-1.4/org/apache/fop/svg/GraphicsConfiguration.java → src/java/org/apache/fop/svg/GraphicsConfiguration.java View File


+ 5
- 6
test/java/org/apache/fop/URIResolutionTestCase.java View File

@@ -36,17 +36,19 @@ import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Document;

/**
* Tests URI resolution facilities.
@@ -85,9 +87,6 @@ public class URIResolutionTestCase extends AbstractFOPTestCase {
private void innerTestFO1(boolean withStream) throws Exception {
FOUserAgent ua = fopFactory.newFOUserAgent();

//Reset the image caches to force URI resolution!
ua.getFactory().getImageFactory().clearCaches();
File foFile = new File(getBaseDir(), "test/xml/uri-resolution1.fo");
MyURIResolver resolver = new MyURIResolver(withStream);

Loading…
Cancel
Save