You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-dev@xmlgraphics.apache.org by Eric SCHAEFFER <es...@posterconseil.com> on 2000/02/03 10:08:03 UTC
JIMI files (Re: We should do something)
----- Original Message -----
From: <Gi...@pwr.ch>
To: <fo...@xml.apache.org>
Sent: Tuesday, February 01, 2000 9:18 AM
Subject: RE: We should do something
> This is a multi-part message in MIME format.
>
> ------=_NextPart_000_0000_01BF6C95.4A880BA0
> Content-Type: text/plain;
> charset="iso-8859-1"
> Content-Transfer-Encoding: 7bit
>
> Hi Eric
>
> > My Jimi implementation is ready (but I'd like people to test it).
> > If we do it this way, we could then change for JAI just changing the
> > properties file.
>
> Send it over. I like to test them. I've tested the JAI implementation. But
> the quality of the images when printed doesn't fullfill my expectation.
>
> Giacomo
>
I'm going to change the FopImageFactory class to use a configuration file.
The PDFRenderer.renderImageArea function needs to be changed (I don't use
XObject, just insert the image data inline, encoded in Hexa and
Deflat/ZLib)...
Eric.
=============================================
FopImage
=============================================
package org.apache.fop.image;
public interface FopImage {
public int getPixelWidth();
public int getPixelHeight();
public int getWidth();
public int getHeight();
public void setDimensions(int w, int h);
public int getX();
public int getY();
public String getHRef();
// be carreful : image is compressed with zlib
public byte[] getImageMap();
public int getImageSize();
public boolean isColored();
public int getBitsPerPixel();
}
=============================================
FopImageFactory
=============================================
package org.apache.fop.image;
import java.io.IOException;
import java.net.*;
public class FopImageFactory {
// Image file formats supported
public final static int IMAGE_GIF = 1;
public final static int IMAGE_JPEG = 2;
public final static int IMAGE_PNG = 3;
public final static int IMAGE_TGA = 4;
public final static int IMAGE_DIB = 5;
public final static int IMAGE_DDB = 6;
public final static int IMAGE_BMP = 7;
public final static int IMAGE_PICT = 8;
public final static int IMAGE_PSD = 9;
public final static int IMAGE_CMU_RASTER = 10;
public final static int IMAGE_TIFF = 11;
public final static int IMAGE_XBM = 12;
public final static int IMAGE_XPM = 13;
public final static int IMAGE_ICO = 14;
public final static int IMAGE_CUR = 15;
public final static int IMAGE_PCX = 16;
public static FopImage Make(String ref,int x,int y, int width, int height)
{
URL absoluteURL = null;
try {
absoluteURL = new URL(ref);
}
catch (MalformedURLException e) {
// maybe relative
/* URL context_url = null;
try {
context_url = new URL(); // how to get the context URL ?
try {
absoluteURL = new URL(context_url, ref);
}
catch (MalformedURLException e_abs) {
// not found
System.err.println("Invalid Image URL : " + e_abs.getMessage() + "(base
URL " + context_url.toString() + ")");
return null;
}
}
catch (MalformedURLException e_context) {
// pb context url
System.err.println("Invalid Image URL - error on relative URL : " +
e_context.getMessage());
return null;
}
*/
System.err.println("Invalid Image URL : " + e.getMessage());
return null;
}
int imageType = -1;
// try to get image type by 'Content-Type'
try {
URLConnection url_conn = absoluteURL.openConnection();
String contentType = url_conn.getContentType();
if ( contentType != null ) {
if ( ( contentType.equalsIgnoreCase("image/gif") ) ||
( contentType.equalsIgnoreCase("image/x-gif") ) ) {
imageType = IMAGE_GIF;
} else if ( ( contentType.equalsIgnoreCase("image/jpeg") ) ||
( contentType.equalsIgnoreCase("image/x-jpeg") ) ) {
imageType = IMAGE_JPEG;
} else if ( ( contentType.equalsIgnoreCase("image/png") ) ||
( contentType.equalsIgnoreCase("image/x-png") ) ) {
imageType = IMAGE_PNG;
} else if ( ( contentType.equalsIgnoreCase("image/tga") ) ||
( contentType.equalsIgnoreCase("image/x-tga") ) ) {
imageType = IMAGE_TGA;
} else if ( contentType.equalsIgnoreCase("image/dib") ) {
imageType = IMAGE_DIB;
} else if ( ( contentType.equalsIgnoreCase("image/ddb") ) ||
( contentType.equalsIgnoreCase("image/x-ddb") ) ) {
imageType = IMAGE_DDB;
} else if ( ( contentType.equalsIgnoreCase("image/bmp") ) ||
( contentType.equalsIgnoreCase("image/x-bmp") ) ||
( contentType.equalsIgnoreCase("image/x-ms-bmp") ) ) {
imageType = IMAGE_BMP;
} else if ( ( contentType.equalsIgnoreCase("image/pict") ) ||
( contentType.equalsIgnoreCase("image/x-pict") ) ) {
imageType = IMAGE_PICT;
} else if ( ( contentType.equalsIgnoreCase("image/psd") ) ||
( contentType.equalsIgnoreCase("image/x-psd") ) ) {
imageType = IMAGE_PSD;
} else if ( ( contentType.equalsIgnoreCase("image/cmu-raster") ) ||
( contentType.equalsIgnoreCase("image/x-cmu-raster") ) ) {
imageType = IMAGE_CMU_RASTER;
} else if ( ( contentType.equalsIgnoreCase("image/tiff") ) ||
( contentType.equalsIgnoreCase("image/x-tiff") ) ) {
imageType = IMAGE_TIFF;
} else if ( ( contentType.equalsIgnoreCase("image/xbm") ) ||
( contentType.equalsIgnoreCase("image/x-xbm") ) ||
( contentType.equalsIgnoreCase("image/x-xbitmap") ) ) {
imageType = IMAGE_XBM;
} else if ( ( contentType.equalsIgnoreCase("image/xpm") ) ||
( contentType.equalsIgnoreCase("image/x-xpm") ) ||
( contentType.equalsIgnoreCase("image/x-xbitmap") ) ) {
imageType = IMAGE_XPM;
} else if ( ( contentType.equalsIgnoreCase("image/ico") ) ||
( contentType.equalsIgnoreCase("image/x-ico") ) ) {
imageType = IMAGE_ICO;
} else if ( ( contentType.equalsIgnoreCase("image/cur") ) ||
( contentType.equalsIgnoreCase("image/x-cur") ) ) {
imageType = IMAGE_CUR;
} else if ( ( contentType.equalsIgnoreCase("image/pcx") ) ||
( contentType.equalsIgnoreCase("image/x-pcx") ) ) {
imageType = IMAGE_PCX;
}
}
}
catch (IOException e) {
System.err.println("Error while recovering Image Type : " +
e.getMessage());
return null;
}
// try get image type by extension if the first method failed
if ( imageType < 0 ) {
String stringURL = absoluteURL.toString();
int extensionStart = stringURL.lastIndexOf(".");
String extensionURL = "";
if ( ( extensionStart > 0 ) && ( extensionStart < stringURL.length() -
1 ) ) {
extensionURL = stringURL.substring(extensionStart + 1,
stringURL.length());
}
if ( extensionURL.equalsIgnoreCase("gif") ) {
imageType = IMAGE_GIF;
} else if ( ( extensionURL.equalsIgnoreCase("jpeg") ) ||
( extensionURL.equalsIgnoreCase("jpg") ) ||
( extensionURL.equalsIgnoreCase("jpe") ) ) {
imageType = IMAGE_JPEG;
} else if ( extensionURL.equalsIgnoreCase("png") ) {
imageType = IMAGE_PNG;
} else if ( extensionURL.equalsIgnoreCase("tga") ) {
imageType = IMAGE_TGA;
} else if ( extensionURL.equalsIgnoreCase("dib") ) {
imageType = IMAGE_DIB;
} else if ( extensionURL.equalsIgnoreCase("ddb") ) {
imageType = IMAGE_DDB;
} else if ( extensionURL.equalsIgnoreCase("bmp") ) {
imageType = IMAGE_BMP;
} else if ( extensionURL.equalsIgnoreCase("pict") ) {
// ?
imageType = IMAGE_PICT;
} else if ( extensionURL.equalsIgnoreCase("psd") ) {
imageType = IMAGE_PSD;
} else if ( extensionURL.equalsIgnoreCase("ras") ) {
// ?
imageType = IMAGE_CMU_RASTER;
} else if ( ( extensionURL.equalsIgnoreCase("tiff") ) ||
( extensionURL.equalsIgnoreCase("tif") ) ) {
imageType = IMAGE_TIFF;
} else if ( extensionURL.equalsIgnoreCase("xbm") ) {
imageType = IMAGE_XBM;
} else if ( extensionURL.equalsIgnoreCase("xpm") ) {
imageType = IMAGE_XPM;
} else if ( extensionURL.equalsIgnoreCase("ico") ) {
imageType = IMAGE_ICO;
} else if ( extensionURL.equalsIgnoreCase("cur") ) {
imageType = IMAGE_CUR;
} else if ( extensionURL.equalsIgnoreCase("pcx") ) {
imageType = IMAGE_PCX;
}
}
// if image type not defined
if ( imageType < 0 ) {
System.err.println("Image format not supported (" +
absoluteURL.toString() + ")");
return null;
}
// Load the right class
FopImage image = null;
if ( imageType == IMAGE_GIF ||
imageType == IMAGE_JPEG ) {
try {
image = new GifJpegImage(absoluteURL, x, y, width, height);
} catch (InstantiationException e) {
System.err.println(e.getMessage());
return null;
}
return image;
} else if ( imageType == IMAGE_PNG ||
imageType == IMAGE_TGA ||
imageType == IMAGE_DIB ||
imageType == IMAGE_DDB ||
imageType == IMAGE_BMP ||
imageType == IMAGE_PICT ||
imageType == IMAGE_PSD ||
imageType == IMAGE_CMU_RASTER ||
imageType == IMAGE_TIFF ||
imageType == IMAGE_XBM ||
imageType == IMAGE_XPM ||
imageType == IMAGE_ICO ||
imageType == IMAGE_CUR ||
imageType == IMAGE_PCX ) {
try {
image = new JimiImage(absoluteURL, x, y, width, height);
} catch (InstantiationException e) {
System.err.println(e.getMessage());
return null;
}
return image;
}
/* else if ( ... */
// no Image Producer
System.err.println("Image format not supported (" +
absoluteURL.toString() + ")");
return null;
}
}
=============================================
GifJpegImage
=============================================
package org.apache.fop.image;
import java.util.Hashtable;
import java.net.URL;
import java.io.IOException;
import java.io.PrintWriter;
import java.awt.image.*;
import java.awt.Image;
import java.awt.Toolkit;
import java.lang.Math;
import java.util.zip.Deflater;
public class GifJpegImage implements FopImage {
int X = 0;
int Y = 0;
int width = 0;
int height = 0;
int pixelWidth = 0;
int pixelHeight = 0;
URL HRef = null;
boolean colored = true;
int bitsPerPixel = 8;
byte[] compressedMap;
int compressedSize = 0;
/** synchronization object */
protected Integer imageWait = new Integer(0);
public GifJpegImage(URL href, int x, int y, int w, int h)
throws InstantiationException {
this.HRef = href;
this.X = x;
this.Y = y;
this.width = w;
this.height = h;
this.pixelHeight = -1;
this.pixelWidth = -1;
int[] tempMap;
try {
ImageProducer ip = (ImageProducer)HRef.getContent();
FopImageConsumer consumer = new FopImageConsumer(this);
ip.startProduction(consumer);
while (! consumer.isImageReady() ) {}
this.pixelHeight = consumer.getHeight();
this.pixelWidth = consumer.getWidth();
tempMap = new int[this.pixelWidth * this.pixelHeight];
PixelGrabber pg = new PixelGrabber( ip,
0, 0,
this.pixelWidth, this.pixelHeight,
tempMap,
0, this.pixelWidth
);
try {
pg.grabPixels();
} catch (InterruptedException e) {
// System.err.println("Image grabbing interrupted");
throw new InstantiationException("Image grabbing interrupted");
}
} catch (Exception e) {
// System.err.println("Error loading image " + HRef.toString() + " : " +
e.getClass() + " - " + e.getMessage());
throw new InstantiationException("Error loading image " + HRef.toString()
+ " : " + e.getClass() + " - " + e.getMessage());
}
// try to Deflat the image
Deflater compressor = new Deflater();
compressor.setLevel(Deflater.DEFAULT_COMPRESSION);
compressor.setStrategy(Deflater.DEFAULT_STRATEGY);
byte[] byteTempMap = new byte[this.pixelWidth * this.pixelHeight * 3];
for (int i = 0; i < this.pixelHeight; i++) {
for (int j = 0; j < this.pixelWidth; j++) {
int p = tempMap[i * this.pixelWidth + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p ) & 0xFF;
byteTempMap[3 * (i * this.pixelWidth + j)] = (byte) (r & 0xFF);
byteTempMap[3 * (i * this.pixelWidth + j) + 1] = (byte) (g & 0xFF);
byteTempMap[3 * (i * this.pixelWidth + j) + 2] = (byte) (b & 0xFF);
}
}
compressor.setInput(byteTempMap);
compressor.finish();
compressedMap = new byte[this.pixelWidth * this.pixelHeight * 3];
compressedSize = compressor.deflate(compressedMap);
compressor.end();
tempMap = null;
byteTempMap = null;
double ratio = ((double) pixelWidth) / ((double) pixelHeight);
// found formatting size
if ( ( width == 0 ) && ( height == 0 ) ) {
height = (int) (1000.0 * ((double) pixelHeight) / 2.0);
width = (int) (1000.0 * ((double) pixelWidth) / 2.0);
} else if ( width == 0 ) {
width = (int) (ratio * ((double) height));
} else if ( height == 0 ) {
height = (int) (((double) width) / ratio);
}
}
public void setDimensions(int width, int height) {
this.width = width;
this.height = height;
}
public static class FopImageConsumer implements ImageConsumer {
int width = -1;
int height = -1;
GifJpegImage graphic;
Integer imageStatus = new Integer(-1);
public FopImageConsumer(GifJpegImage graphic) {
this.graphic = graphic;
}
public void imageComplete(int status) {
synchronized (this.imageStatus) {
this.imageStatus = new Integer(status);
}
}
public synchronized boolean isImageReady()
throws Exception {
synchronized (this.imageStatus) {
if ( this.imageStatus.intValue() != -1 ) {
String statusStr = null;
if ( this.imageStatus.intValue() == ImageConsumer.IMAGEABORTED ) {
statusStr = new String("Image Aborted");
} else if ( this.imageStatus.intValue() == ImageConsumer.IMAGEERROR ) {
statusStr = new String("Image Error");
}
if ( statusStr != null ) {
throw new Exception("Error in image consumer (" + statusStr + ")");
}
if ( this.imageStatus.intValue() == ImageConsumer.STATICIMAGEDONE ) {
return true;
}
}
return false;
}
}
public void setColorModel(ColorModel model) {}
public void setDimensions(int width, int height) {
this.width = width;
this.height = height;
}
public void setHints(int hintflags) {}
public void setPixels(int x, int y, int w, int h,
ColorModel model, byte[] pixels,int off,
int scansize) {}
public void setPixels(int x, int y, int w, int h,
ColorModel model, int[] pixels, int off,
int scansize) {}
public void setProperties(Hashtable props) {}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}
public String getHRef() {
// need to be changed (URL everywhere...)
return this.HRef.toString();
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public int getPixelWidth() {
return this.pixelWidth;
}
public int getPixelHeight() {
return this.pixelHeight;
}
public int getX() {
return this.X;
}
public int getY() {
return this.Y;
}
public int getImageSize() {
return this.compressedSize;
}
public byte[] getImageMap() {
return this.compressedMap;
}
public boolean isColored() {
return true;
}
public int getBitsPerPixel() {
return this.bitsPerPixel;
}
}
=============================================
JimiImage
=============================================
package org.apache.fop.image;
// Java
import java.util.Hashtable;
import java.net.URL;
import java.io.IOException;
import java.io.PrintWriter;
import java.awt.image.*;
import java.awt.*;
// png compression
import java.util.zip.Deflater;
// Jimi
import com.sun.jimi.core.*;
public class JimiImage implements FopImage {
int X = 0;
int Y = 0;
int width = 0;
int height = 0;
int pixelWidth = 0;
int pixelHeight = 0;
URL HRef = null;
boolean colored = true;
int bitsPerPixel = 8;
byte[] compressedMap;
int compressedSize = 0;
public JimiImage(URL href, int x, int y, int w, int h)
throws InstantiationException {
this.HRef = href;
this.X = x;
this.Y = y;
this.width = w;
this.height = h;
this.pixelHeight = -1;
this.pixelWidth = -1;
int[] tempMap;
try {
ImageProducer ip = Jimi.getImageProducer(href, Jimi.SYNCHRONOUS |
Jimi.IN_MEMORY);
FopImageConsumer consumer = new FopImageConsumer(this);
ip.startProduction(consumer);
while (! consumer.isImageReady() ) {}
this.pixelHeight = consumer.getHeight();
this.pixelWidth = consumer.getWidth();
tempMap = new int[this.pixelWidth * this.pixelHeight];
PixelGrabber pg = new PixelGrabber( ip,
0, 0,
this.pixelWidth, this.pixelHeight,
tempMap,
0, this.pixelWidth
);
try {
pg.grabPixels();
} catch (InterruptedException e) {
// System.err.println("Image grabbing interrupted");
throw new InstantiationException("Image grabbing interrupted");
}
} catch (Exception e) {
// System.err.println("Error loading image " + HRef.toString() + " : " +
e.getClass() + " - " + e.getMessage());
throw new InstantiationException("Error loading image " + HRef.toString()
+ " : " + e.getClass() + " - " + e.getMessage());
}
// try to Deflat the image
Deflater compressor = new Deflater();
compressor.setLevel(Deflater.DEFAULT_COMPRESSION);
compressor.setStrategy(Deflater.DEFAULT_STRATEGY);
byte[] byteTempMap = new byte[this.pixelWidth * this.pixelHeight * 3];
for (int i = 0; i < this.pixelHeight; i++) {
for (int j = 0; j < this.pixelWidth; j++) {
int p = tempMap[i * this.pixelWidth + j];
int r = (p >> 16) & 0xFF;
int g = (p >> 8) & 0xFF;
int b = (p ) & 0xFF;
byteTempMap[3 * (i * this.pixelWidth + j)] = (byte) (r & 0xFF);
byteTempMap[3 * (i * this.pixelWidth + j) + 1] = (byte) (g & 0xFF);
byteTempMap[3 * (i * this.pixelWidth + j) + 2] = (byte) (b & 0xFF);
}
}
compressor.setInput(byteTempMap);
compressor.finish();
compressedMap = new byte[this.pixelWidth * this.pixelHeight * 3];
compressedSize = compressor.deflate(compressedMap);
compressor.end();
tempMap = null;
byteTempMap = null;
double ratio = ((double) pixelWidth) / ((double) pixelHeight);
// found formatting size
if ( ( width == 0 ) && ( height == 0 ) ) {
height = (int) (1000.0d * ((double) pixelHeight) / 2.0d);
width = (int) (1000.0d * ((double) pixelWidth) / 2.0d);
} else if ( width == 0 ) {
width = (int) (ratio * ((double) height));
} else if ( height == 0 ) {
height = (int) (((double) width) / ratio);
}
}
public void setDimensions(int width, int height) {
this.width = width;
this.height = height;
}
public static class FopImageConsumer implements ImageConsumer {
int width = -1;
int height = -1;
JimiImage graphic;
Integer imageStatus = new Integer(-1);
public FopImageConsumer(JimiImage graphic) {
this.graphic = graphic;
}
public void imageComplete(int status) {
synchronized (this.imageStatus) {
this.imageStatus = new Integer(status);
}
}
public synchronized boolean isImageReady()
throws Exception {
synchronized (this.imageStatus) {
if ( this.imageStatus.intValue() != -1 ) {
String statusStr = null;
if ( this.imageStatus.intValue() == ImageConsumer.IMAGEABORTED ) {
statusStr = new String("Image Aborted");
} else if ( this.imageStatus.intValue() == ImageConsumer.IMAGEERROR ) {
statusStr = new String("Image Error");
}
if ( statusStr != null ) {
throw new Exception("Error in image consumer (" + statusStr + ")");
}
if ( this.imageStatus.intValue() == ImageConsumer.STATICIMAGEDONE ) {
return true;
}
}
return false;
}
}
public void setColorModel(ColorModel model) {}
public void setDimensions(int width, int height) {
this.width = width;
this.height = height;
}
public void setHints(int hintflags) {}
public void setPixels(int x, int y, int w, int h,
ColorModel model, byte[] pixels,int off,
int scansize) {}
public void setPixels(int x, int y, int w, int h,
ColorModel model, int[] pixels, int off,
int scansize) {}
public void setProperties(Hashtable props) {}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}
public String getHRef() {
// need to be changed (URL everywhere...)
return this.HRef.toString();
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public int getPixelWidth() {
return this.pixelWidth;
}
public int getPixelHeight() {
return this.pixelHeight;
}
public int getX() {
return this.X;
}
public int getY() {
return this.Y;
}
public int getImageSize() {
return this.compressedSize;
}
public byte[] getImageMap() {
return this.compressedMap;
}
public boolean isColored() {
return true;
}
public int getBitsPerPixel() {
return this.bitsPerPixel;
}
}
=============================================
PDFRenderer
=============================================
...
public void renderImageArea(ImageArea area) {
// adapted from contribution by BoBoGi
int x = this.currentAreaContainerXPosition +
area.getXOffset();
int y = this.currentYPosition;
int w = area.getContentWidth();
int h = area.getHeight();
this.currentYPosition -= h;
FopImage img = area.getImage();
int pw = img.getPixelWidth();
int ph = img.getPixelHeight();
byte[] pixels = img.getImageMap();
int size = img.getImageSize();
float rx = (x + img.getX())/1000f;
float ry = (y + img.getY())/1000f;
float rh = img.getHeight()/1000f;
float rw = img.getWidth()/1000f;
currentStream.add("ET\nq\n" + rw + " 0 0 " + rh + " " + rx + " " + (ry-rh)
+ " cm\nBI\n/W " + pw + "\n/H " + ph +
"\n/BPC 8\n/CS /RGB\n/F [/ASCIIHexDecode /FlateDecode]\nID\n");
for (int i = 0; i < size; i++) {
int val = (int) (pixels[i] & 0xFF);
if ( val < 16 ) {
this.currentStream.add(Integer.toString(0));
}
this.currentStream.add(Integer.toHexString(val));
}
this.currentStream.add(">\n");
currentStream.add("EI\nQ\nBT\n");
}
...
_______________________________________
Eric SCHAEFFER
eschaeffer@posterconseil.com
POSTER CONSEIL
118 rue de Tocqueville
75017 PARIS
FRANCE
Tel. : 33-140541058
Fax : 33-140541059
----------------------------------------------------------------------------
-----------------------------
Come to the first official Apache Software Foundation Conference!
-----------------------------------
http://ApacheCon.Com ------------------------------------
_______________________________________