/* * 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.IOException; import java.awt.color.ColorSpace; // FOP import org.apache.commons.logging.Log; /** * Bitmap image. * This supports loading a bitmap image into bitmap data. * * @author Art WELCH * @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. * * @param ua the user agent * @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 e) { log.error("Error while loading image " + "" + " : " + e.getClass() + " - " + e.getMessage(), e); 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.bitmapsSize = this.width * this.height * 3; this.bitmaps = new byte[this.bitmapsSize]; int[] temp = new int[bytes * this.height]; try { int input; int count = 0; inputStream.skip((long)(imagestart - filepos)); while ((input = inputStream.read()) != -1) { temp[count++] = input; } inputStream.close(); inputStream = null; } catch (IOException e) { log.error("Error while loading image " + "" + " : " + e.getClass() + " - " + e.getMessage(), e); return false; } 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; } }