blob: a32e1f21525ed5410a2a6bc406c7326fa5e6312a [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.ByteArrayOutputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
// FOP
import org.apache.fop.util.CMYKColorSpace;
/**
* FopImage object for JPEG images, Using Java native classes.
* @author Eric Dalquist
* @see AbstractFopImage
* @see FopImage
*/
public class JpegImage extends AbstractFopImage {
private ICC_Profile iccProfile = null;
private boolean foundICCProfile = false;
private boolean foundDimensions = 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 = new ByteArrayOutputStream();
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);
}
inputStream.close();
inputStream = null;
} catch (java.io.IOException ex) {
log.error("Error while loading image "
+ " : " + ex.getClass()
+ " - " + ex.getMessage(), ex);
return false;
}
this.bitmaps = baos.toByteArray();
this.bitsPerPixel = 8;
this.isTransparent = false;
//Check for SOI (Start of image) marker (FFD8)
if (this.bitmaps.length > (index + 2)
&& uByte(this.bitmaps[index]) == 255 /*0xFF*/
&& uByte(this.bitmaps[index + 1]) == 216 /*0xD8*/) {
index += 2;
while (index < this.bitmaps.length && cont) {
//check to be sure this is the begining of a header
if (this.bitmaps.length > (index + 2)
&& uByte(this.bitmaps[index]) == 255 /*0xFF*/) {
//192 or 194 are the header bytes that contain
// the jpeg width height and color depth.
if (uByte(this.bitmaps[index + 1]) == 192 /*0xC0*/
|| uByte(this.bitmaps[index + 1]) == 194 /*0xC2*/) {
this.height = calcBytes(this.bitmaps[index + 5],
this.bitmaps[index + 6]);
this.width = calcBytes(this.bitmaps[index + 7],
this.bitmaps[index + 8]);
if (this.bitmaps[index + 9] == 1) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_GRAY);
} else if (this.bitmaps[index + 9] == 3) {
this.colorSpace = ColorSpace.getInstance(
ColorSpace.CS_LINEAR_RGB);
} else if (this.bitmaps[index + 9] == 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;
}
foundDimensions = true;
if (foundICCProfile) {
cont = false;
break;
}
index += calcBytes(this.bitmaps[index + 2],
this.bitmaps[index + 3]) + 2;
} else if (uByte(this.bitmaps[index + 1]) == 226 /*0xE2*/
&& this.bitmaps.length > (index + 60)) {
// Check if ICC profile
byte[] iccString = new byte[11];
System.arraycopy(this.bitmaps, index + 4,
iccString, 0, 11);
if ("ICC_PROFILE".equals(new String(iccString))) {
int chunkSize = calcBytes(
this.bitmaps[index + 2],
this.bitmaps[index + 3]) + 2;
iccStream.write(this.bitmaps,
index + 18, chunkSize - 18);
}
index += calcBytes(this.bitmaps[index + 2],
this.bitmaps[index + 3]) + 2;
} else {
index += calcBytes(this.bitmaps[index + 2],
this.bitmaps[index + 3]) + 2;
}
} else {
cont = false;
}
}
} else {
log.error("Error while loading "
+ "JpegImage - Invalid JPEG Header.");
return false;
}
if (iccStream.size() > 0) {
byte[] align = new byte[((iccStream.size()) % 8) + 8];
try {
iccStream.write(align);
} catch (Exception e) {
log.error("Error while loading image "
+ " : "
+ e.getMessage(), e);
return false;
}
try {
iccProfile = ICC_Profile.getInstance(iccStream.toByteArray());
} catch (Exception e) {
log.error("Invalid ICC profile: " + e, e);
return false;
}
} else if (this.colorSpace == null) {
log.error("ColorSpace not specified for JPEG image");
return false;
}
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;
}
}
}