/* * Copyright © 2009-2011 Rebecca G. Bettencourt / Kreative Software * <p> * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a> * <p> * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * <p> * Alternatively, the contents of this file may be used under the terms * of the GNU Lesser General Public License (the "LGPL License"), in which * case the provisions of LGPL License are applicable instead of those * above. If you wish to allow use of your version of this file only * under the terms of the LGPL License and not to allow others to use * your version of this file under the MPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the LGPL License. If you do not delete * the provisions above, a recipient may use your version of this file * under either the MPL or the LGPL License. * @since PowerPaint 1.0 * @author Rebecca G. Bettencourt, Kreative Software */ package com.kreative.paint.pict; import java.io.*; // NOTE: Both BitMap and PixMap are represented by this structure. public class PixMap { public static final int PACK_TYPE_PACKBITS = 0; public static final int PACK_TYPE_UNPACKED = 1; public static final int PACK_TYPE_UNPACKED_NO_PADDING = 2; public static final int PACK_TYPE_BY_PIXEL = 3; public static final int PACK_TYPE_BY_COMPONENT = 4; public static final int PIXEL_TYPE_INDEXED = 0; public static final int PIXEL_TYPE_RGBDIRECT = 16; public static final int PIXEL_SIZE_1BIT = 1; public static final int PIXEL_SIZE_2BIT = 2; public static final int PIXEL_SIZE_4BIT = 4; public static final int PIXEL_SIZE_8BIT = 8; public static final int PIXEL_SIZE_16BIT = 16; public static final int PIXEL_SIZE_32BIT = 32; public static final int COMPONENT_COUNT_INDEXED = 1; public static final int COMPONENT_COUNT_RGB = 3; public static final int COMPONENT_COUNT_ARGB = 4; public static final int COMPONENT_SIZE_1BIT = 1; public static final int COMPONENT_SIZE_2BIT = 2; public static final int COMPONENT_SIZE_4BIT = 4; public static final int COMPONENT_SIZE_8BIT = 8; public static final int COMPONENT_SIZE_16BIT = 5; public static final int COMPONENT_SIZE_32BIT = 8; public int baseAddr; // pixel image public int rowBytes; // flags and row width public Rect bounds; // boundary rectangle public int pmVersion; // PixMap record version number public int packType; // packing format public int packSize; // size of data in packed state public float hRes; // horizontal resolution public float vRes; // vertical resolution public int pixelType; // format of pixel image public int pixelSize; // physical bits per pixel public int cmpCount; // logical components per pixel public int cmpSize; // logical bits per component public int planeBytes; // offset to next plane public int pmTable; // handle to the ColorTable record for this image public int pmReserved; // reserved for future expansion public static PixMap read(DataInputStream in, boolean withBaseAddr) throws IOException { PixMap p = new PixMap(); p.baseAddr = withBaseAddr ? in.readInt() : 0; p.rowBytes = in.readUnsignedShort(); p.bounds = Rect.read(in); if ((p.rowBytes & 0x8000) != 0) { // pixmap p.pmVersion = in.readShort(); p.packType = in.readShort(); p.packSize = in.readInt(); p.hRes = in.readInt() / 65536.0f; p.vRes = in.readInt() / 65536.0f; p.pixelType = in.readShort(); p.pixelSize = in.readShort(); p.cmpCount = in.readShort(); p.cmpSize = in.readShort(); p.planeBytes = in.readInt(); p.pmTable = in.readInt(); p.pmReserved = in.readInt(); } else { // bitmap p.pmVersion = 0; p.packType = PACK_TYPE_PACKBITS; p.packSize = 0; p.hRes = 72; p.vRes = 72; p.pixelType = PIXEL_TYPE_INDEXED; p.pixelSize = PIXEL_SIZE_1BIT; p.cmpCount = COMPONENT_COUNT_INDEXED; p.cmpSize = COMPONENT_SIZE_1BIT; p.planeBytes = 0; p.pmTable = 0; p.pmReserved = 0; } return p; } public PixMap() { this.baseAddr = 0; this.rowBytes = 0; this.bounds = new Rect(); this.pmVersion = 0; this.packType = PACK_TYPE_PACKBITS; this.packSize = 0; this.hRes = 72; this.vRes = 72; this.pixelType = PIXEL_TYPE_INDEXED; this.pixelSize = PIXEL_SIZE_1BIT; this.cmpCount = COMPONENT_COUNT_INDEXED; this.cmpSize = COMPONENT_SIZE_1BIT; this.planeBytes = 0; this.pmTable = 0; this.pmReserved = 0; } public void write(DataOutputStream out, boolean withBaseAddr) throws IOException { if ((rowBytes & 0x8000) == 0) { // Is it really a bitmap? if (pmVersion != 0 || packType != PACK_TYPE_PACKBITS || packSize != 0 || hRes != 72 || vRes != 72 || pixelType != PIXEL_TYPE_INDEXED || pixelSize != PIXEL_SIZE_1BIT || cmpCount != COMPONENT_COUNT_INDEXED || cmpSize != COMPONENT_SIZE_1BIT || planeBytes != 0 || pmTable != 0 || pmReserved != 0) { // No, so mark it as a pixmap. rowBytes |= 0x8000; } } if (withBaseAddr) out.writeInt(baseAddr); out.writeShort(rowBytes); bounds.write(out); if ((rowBytes & 0x8000) != 0) { out.writeShort(pmVersion); out.writeShort(packType); out.writeInt(packSize); out.writeInt((int)(hRes*65536.0f)); out.writeInt((int)(vRes*65536.0f)); out.writeShort(pixelType); out.writeShort(pixelSize); out.writeShort(cmpCount); out.writeShort(cmpSize); out.writeInt(planeBytes); out.writeInt(pmTable); out.writeInt(pmReserved); } } public String toString() { return (((rowBytes & 0x8000) == 0) ? "Bitmap" : "Pixmap")+"["+bounds.toString()+"]"; } public boolean hasColorTable() { return ((pixelType == PIXEL_TYPE_INDEXED) && ((rowBytes & 0x8000) != 0)); } public byte[] readPixData(DataInputStream in, boolean packed) throws IOException { if (((packType == PixMap.PACK_TYPE_PACKBITS) && !packed) || (packType == PACK_TYPE_UNPACKED) || ((rowBytes & 0x7FFF) < 8)) { byte[] data = new byte[(rowBytes & 0x7FFF) * (bounds.bottom-bounds.top)]; in.readFully(data); return data; } else if (packType == PACK_TYPE_UNPACKED_NO_PADDING) { byte[] data = new byte[(rowBytes & 0x7FFF) * (bounds.bottom-bounds.top) * 3 / 4]; in.readFully(data); return data; } else if ((rowBytes & 0x7FFF) > 250) { ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(bout); for (int y = bounds.top; y < bounds.bottom; y++) { byte[] scanline = new byte[in.readUnsignedShort()]; in.readFully(scanline); dout.writeShort(scanline.length); dout.write(scanline); } dout.close(); bout.close(); return bout.toByteArray(); } else { ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(bout); for (int y = bounds.top; y < bounds.bottom; y++) { byte[] scanline = new byte[in.readUnsignedByte()]; in.readFully(scanline); dout.writeByte(scanline.length); dout.write(scanline); } dout.close(); bout.close(); return bout.toByteArray(); } } public void writePixData(DataOutputStream out, byte[] data) throws IOException { out.write(data); } }