diff dwt/internal/image/WinICOFileFormat.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children e831403a80a9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/internal/image/WinICOFileFormat.d	Sat Aug 09 17:00:02 2008 +0200
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.internal.image;
+
+
+import java.io.IOException;
+
+import dwt.DWT;
+import dwt.graphics.ImageData;
+import dwt.graphics.ImageLoader;
+import dwt.graphics.PaletteData;
+
+public final class WinICOFileFormat : FileFormat {
+    
+byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
+    // Destructively bit invert data in the given byte array.
+    for (int i = startIndex; i < endIndex; i++) {
+        data[i] = (byte)(255 - data[i - startIndex]);
+    }
+    return data;
+}
+
+static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
+    if (pad is newPad) return data;
+    int stride = (width * depth + 7) / 8;
+    int bpl = (stride + (pad - 1)) / pad * pad;
+    int newBpl = (stride + (newPad - 1)) / newPad * newPad;
+    byte[] newData = new byte[height * newBpl];
+    int srcIndex = 0, destIndex = 0;
+    for (int y = 0; y < height; y++) {
+        System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
+        srcIndex += bpl;
+        destIndex += newBpl;
+    }
+    return newData;
+}
+/**
+ * Answer the size in bytes of the file representation of the given
+ * icon
+ */
+int iconSize(ImageData i) {
+    int shapeDataStride = (i.width * i.depth + 31) / 32 * 4;
+    int maskDataStride = (i.width + 31) / 32 * 4;
+    int dataSize = (shapeDataStride + maskDataStride) * i.height;
+    int paletteSize = i.palette.colors !is null ? i.palette.colors.length * 4 : 0;
+    return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize;
+}
+bool isFileFormat(LEDataInputStream stream) {
+    try {
+        byte[] header = new byte[4];
+        stream.read(header);
+        stream.unread(header);
+        return header[0] is 0 && header[1] is 0 && header[2] is 1 && header[3] is 0;
+    } catch (Exception e) {
+        return false;
+    }
+}
+bool isValidIcon(ImageData i) {
+    switch (i.depth) {
+        case 1:
+        case 4:
+        case 8:
+            if (i.palette.isDirect) return false;
+            int size = i.palette.colors.length;
+            return size is 2 || size is 16 || size is 32 || size is 256;
+        case 24:
+        case 32:
+            return i.palette.isDirect;
+    }
+    return false;
+}
+int loadFileHeader(LEDataInputStream byteStream) {
+    int[] fileHeader = new int[3];
+    try {
+        fileHeader[0] = byteStream.readShort();
+        fileHeader[1] = byteStream.readShort();
+        fileHeader[2] = byteStream.readShort();
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    if ((fileHeader[0] !is 0) || (fileHeader[1] !is 1))
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    int numIcons = fileHeader[2];
+    if (numIcons <= 0)
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    return numIcons;
+}
+int loadFileHeader(LEDataInputStream byteStream, bool hasHeader) {
+    int[] fileHeader = new int[3];
+    try {
+        if (hasHeader) {
+            fileHeader[0] = byteStream.readShort();
+            fileHeader[1] = byteStream.readShort();
+        } else {
+            fileHeader[0] = 0;
+            fileHeader[1] = 1;
+        }
+        fileHeader[2] = byteStream.readShort();
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    if ((fileHeader[0] !is 0) || (fileHeader[1] !is 1))
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    int numIcons = fileHeader[2];
+    if (numIcons <= 0)
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    return numIcons;
+}
+ImageData[] loadFromByteStream() {
+    int numIcons = loadFileHeader(inputStream);
+    int[][] headers = loadIconHeaders(numIcons);
+    ImageData[] icons = new ImageData[headers.length];
+    for (int i = 0; i < icons.length; i++) {
+        icons[i] = loadIcon(headers[i]);
+    }
+    return icons;
+}
+/**
+ * Load one icon from the byte stream.
+ */
+ImageData loadIcon(int[] iconHeader) {
+    byte[] infoHeader = loadInfoHeader(iconHeader);
+    WinBMPFileFormat bmpFormat = new WinBMPFileFormat();
+    bmpFormat.inputStream = inputStream;
+    PaletteData palette = bmpFormat.loadPalette(infoHeader);
+    byte[] shapeData = bmpFormat.loadData(infoHeader);
+    int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
+    int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
+    if (height < 0) height = -height;
+    int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
+    infoHeader[14] = 1;
+    infoHeader[15] = 0;
+    byte[] maskData = bmpFormat.loadData(infoHeader);
+    maskData = convertPad(maskData, width, height, 1, 4, 2);
+    bitInvertData(maskData, 0, maskData.length);
+    return ImageData.internal_new(
+        width,
+        height,
+        depth,
+        palette,
+        4,
+        shapeData,
+        2,
+        maskData,
+        null,
+        -1,
+        -1,
+        DWT.IMAGE_ICO,
+        0,
+        0,
+        0,
+        0);
+}
+int[][] loadIconHeaders(int numIcons) {
+    int[][] headers = new int[numIcons][7];
+    try {
+        for (int i = 0; i < numIcons; i++) {
+            headers[i][0] = inputStream.read();
+            headers[i][1] = inputStream.read();
+            headers[i][2] = inputStream.readShort();
+            headers[i][3] = inputStream.readShort();
+            headers[i][4] = inputStream.readShort();
+            headers[i][5] = inputStream.readInt();
+            headers[i][6] = inputStream.readInt();
+        }
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    return headers;
+}
+byte[] loadInfoHeader(int[] iconHeader) {
+    int width = iconHeader[0];
+    int height = iconHeader[1];
+    int numColors = iconHeader[2]; // the number of colors is in the low byte, but the high byte must be 0
+    if (numColors is 0) numColors = 256; // this is specified: '00' represents '256' (0x100) colors
+    if ((numColors !is 2) && (numColors !is 8) && (numColors !is 16) &&
+        (numColors !is 32) && (numColors !is 256))
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    if (inputStream.getPosition() < iconHeader[6]) {
+        // Seek to the specified offset
+        try {
+            inputStream.skip(iconHeader[6] - inputStream.getPosition());
+        } catch (IOException e) {
+            DWT.error(DWT.ERROR_IO, e);
+            return null;
+        }
+    }
+    byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize];
+    try {
+        inputStream.read(infoHeader);
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) !is 1)
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
+    int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
+    int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
+    if (height is infoHeight && bitCount is 1) height /= 2;
+    if (!((width is infoWidth) && (height * 2 is infoHeight) &&
+        (bitCount is 1 || bitCount is 4 || bitCount is 8 || bitCount is 24 || bitCount is 32)))
+            DWT.error(DWT.ERROR_INVALID_IMAGE);
+    infoHeader[8] = (byte)(height & 0xFF);
+    infoHeader[9] = (byte)((height >> 8) & 0xFF);
+    infoHeader[10] = (byte)((height >> 16) & 0xFF);
+    infoHeader[11] = (byte)((height >> 24) & 0xFF);
+    return infoHeader;
+}
+/**
+ * Unload a single icon
+ */
+void unloadIcon(ImageData icon) {
+    int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) +
+        ((icon.width + 31) / 32 * 4)) * icon.height;
+    try {
+        outputStream.writeInt(WinBMPFileFormat.BMPHeaderFixedSize);
+        outputStream.writeInt(icon.width);
+        outputStream.writeInt(icon.height * 2);
+        outputStream.writeShort(1);
+        outputStream.writeShort((short)icon.depth);
+        outputStream.writeInt(0);
+        outputStream.writeInt(sizeImage);
+        outputStream.writeInt(0);
+        outputStream.writeInt(0);
+        outputStream.writeInt(icon.palette.colors !is null ? icon.palette.colors.length : 0);
+        outputStream.writeInt(0);
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    
+    byte[] rgbs = WinBMPFileFormat.paletteToBytes(icon.palette);
+    try {
+        outputStream.write(rgbs);
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    unloadShapeData(icon);
+    unloadMaskData(icon);
+}
+/**
+ * Unload the icon header for the given icon, calculating the offset.
+ */
+void unloadIconHeader(ImageData i) {
+    int headerSize = 16;
+    int offset = headerSize + 6;
+    int iconSize = iconSize(i);
+    try {
+        outputStream.write(i.width);
+        outputStream.write(i.height);
+        outputStream.writeShort(i.palette.colors !is null ? i.palette.colors.length : 0);
+        outputStream.writeShort(0);
+        outputStream.writeShort(0);
+        outputStream.writeInt(iconSize);
+        outputStream.writeInt(offset);
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+}
+void unloadIntoByteStream(ImageLoader loader) {
+    /* We do not currently support writing multi-image ico,
+     * so we use the first image data in the loader's array. */
+    ImageData image = loader.data[0];
+    if (!isValidIcon(image))
+        DWT.error(DWT.ERROR_INVALID_IMAGE);
+    try {
+        outputStream.writeShort(0);
+        outputStream.writeShort(1);
+        outputStream.writeShort(1);
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+    unloadIconHeader(image);
+    unloadIcon(image);
+}
+/**
+ * Unload the mask data for an icon. The data is flipped vertically
+ * and inverted.
+ */
+void unloadMaskData(ImageData icon) {
+    ImageData mask = icon.getTransparencyMask();
+    int bpl = (icon.width + 7) / 8;
+    int pad = mask.scanlinePad;
+    int srcBpl = (bpl + pad - 1) / pad * pad;
+    int destBpl = (bpl + 3) / 4 * 4;
+    byte[] buf = new byte[destBpl];
+    int offset = (icon.height - 1) * srcBpl;
+    byte[] data = mask.data;
+    try {
+        for (int i = 0; i < icon.height; i++) {
+            System.arraycopy(data, offset, buf, 0, bpl);
+            bitInvertData(buf, 0, bpl);
+            outputStream.write(buf, 0, destBpl);
+            offset -= srcBpl;
+        }
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+}
+/**
+ * Unload the shape data for an icon. The data is flipped vertically.
+ */
+void unloadShapeData(ImageData icon) {
+    int bpl = (icon.width * icon.depth + 7) / 8;
+    int pad = icon.scanlinePad;
+    int srcBpl = (bpl + pad - 1) / pad * pad;
+    int destBpl = (bpl + 3) / 4 * 4;
+    byte[] buf = new byte[destBpl];
+    int offset = (icon.height - 1) * srcBpl;
+    byte[] data = icon.data;
+    try {
+        for (int i = 0; i < icon.height; i++) {
+            System.arraycopy(data, offset, buf, 0, bpl);
+            outputStream.write(buf, 0, destBpl);
+            offset -= srcBpl;
+        }
+    } catch (IOException e) {
+        DWT.error(DWT.ERROR_IO, e);
+    }
+}
+}