diff options
Diffstat (limited to 'bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java')
-rw-r--r-- | bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java | 3290 |
1 files changed, 0 insertions, 3290 deletions
diff --git a/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java b/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java deleted file mode 100644 index 26226a38b7..0000000000 --- a/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java +++ /dev/null @@ -1,3290 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2005 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 - *******************************************************************************/ -package org.eclipse.swt.tools.internal; - -import java.io.*; -import java.util.Vector; - -/** - * Customize the icon of a Windows exe - * - * WARNING! This class is not part of SWT API. It is NOT API. It is an internal - * tool that may be changed or removed at anytime. - * - * Based on MSDN "An In-Depth Look into the Win32 Portable Executable File Format" - */ -public class IconExe { - - /** - * Replace the Desktop icons provided in the Windows executable program - * with matching icons provided by the user. - * - * Takes 2 arguments - * argument 0: the Windows executable e.g c:/eclipse/eclipse.exe - * argument 1: The .ico file to write to the given executable e.g. c:/myApp.ico - * - * Note 1. Write access to the executable program is required. As a result, that - * program must not be currently running or edited elsewhere. - * - * Note 2. The Eclipse 3.1 launcher requires a .ico file with the following 6 images - * 1. 32x32, 4 bit (Windows 16 colors palette) - * 2. 16x16, 4 bit (Windows 16 colors palette) - * 3. 16x16, 8 bit (256 colors) - * 4. 32x32, 8 bit (256 colors) - * 5. 48x48, 4 bit (Windows 16 colors palette) - * 6. 48x48, 8 bit (256 colors) - * A user icon matching exactly the width/height/depth of an executable icon will be written - * to the executable and will replace that executable icon. If an executable icon - * does not match a user icon, it is silently left as is. - * - * Note 3. This function modifies the content of the executable program and may cause - * its corruption. - */ - public static void main(String[] args) { - if (args.length < 2) { - System.err.println("Usage: IconExe <windows executable> <ico file>"); - return; - } - ImageLoader loader = new ImageLoader(); - try { - ImageData[] data = null; - - if (args.length == 2) { - /* ICO case */ - data = loader.load(args[1]); - } else { - /* BMP case - each following argument is a single BMP file - * BMP is handled for testing purpose only. The ICO file is the - * official Microsoft format for image resources. - */ - data = new ImageData[args.length - 1]; - for (int i = 1; i < args.length; i++) { - ImageData[] current = loader.load(args[i]); - data[i - 1] = current[0]; - } - } - int nMissing = unloadIcons(args[0], data); - if (nMissing != 0) System.err.println("Error - "+nMissing+" icon(s) not replaced in "+args[0]+" using "+args[1]); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /* Implementation */ - - /** - * Retrieve the Desktop icons provided in the Windows executable program. - * These icons are typically shown in various places of the Windows desktop. - * - * Note. The Eclipse 3.1 launcher returns the following 6 images - * 1. 32x32, 4 bit (Windows 16 colors palette) - * 2. 16x16, 4 bit (Windows 16 colors palette) - * 3. 16x16, 8 bit (256 colors) - * 4. 32x32, 8 bit (256 colors) - * 5. 48x48, 4 bit (Windows 16 colors palette) - * 6. 48x48, 8 bit (256 colors) - * - * @param program the Windows executable e.g c:/eclipse/eclipse.exe - */ - static ImageData[] loadIcons(String program) throws FileNotFoundException, IOException { - RandomAccessFile raf = new RandomAccessFile(program, "r"); - IconExe iconExe = new IconExe(); - IconResInfo[] iconInfo = iconExe.getIcons(raf); - ImageData[] data = new ImageData[iconInfo.length]; - for (int i = 0; i < data.length; i++) data[i] = iconInfo[i].data; - raf.close(); - return data; - } - - /** - * Replace the Desktop icons provided in the Windows executable program - * with icons provided by the user. - * - * Note 1. Write access to the executable program is required. As a result, that - * program must not be currently running or edited elsewhere. - * - * Note 2. Use loadIcons to determine which set of icons (width, height, depth) - * is required to replace the icons in the executable program. A user icon - * matching exactly the width/height/depth of an executable icon will be written - * to the executable and will replace that executable icon. If an executable icon - * does not match a user icon, it is left as is. Verify the return value matches - * the number of icons to write. Finally, use loadIcons after this operation - * to verify the icons have changed as expected. - * - * Note 3. The Eclipse 3.1 launcher requires the following 6 images (in any order). - * 1. 32x32, 4 bit (Windows 16 colors palette) - * 2. 16x16, 4 bit (Windows 16 colors palette) - * 3. 16x16, 8 bit (256 colors) - * 4. 32x32, 8 bit (256 colors) - * 5. 48x48, 4 bit (Windows 16 colors palette) - * 6. 48x48, 8 bit (256 colors) - * - * Note 4. This function modifies the content of the executable program and may cause - * its corruption. - * - * @param program the Windows executable e.g c:/eclipse/eclipse.exe - * @param icons to write to the given executable - * @return the number of icons from the original program that were not successfully replaced (0 if success) - */ - static int unloadIcons(String program, ImageData[] icons) throws FileNotFoundException, IOException { - RandomAccessFile raf = new RandomAccessFile(program, "rw"); - IconExe iconExe = new IconExe(); - IconResInfo[] iconInfo = iconExe.getIcons(raf); - int cnt = 0; - for (int i = 0; i < iconInfo.length; i++) { - for (int j = 0; j < icons.length; j++) - if (iconInfo[i].data.width == icons[j].width && - iconInfo[i].data.height == icons[j].height && - iconInfo[i].data.depth == icons[j].depth) { - raf.seek(iconInfo[i].offset); - unloadIcon(raf, icons[j]); - cnt++; - } - } - raf.close(); - return iconInfo.length - cnt; - } - - public static final String VERSION = "20050124"; - - static final boolean DEBUG = false; - public static class IconResInfo { - ImageData data; - int offset; - int size; - } - - IconResInfo[] iconInfo = null; - int iconCnt; - - IconResInfo[] getIcons(RandomAccessFile raf) throws IOException { - iconInfo = new IconResInfo[4]; - iconCnt = 0; - IMAGE_DOS_HEADER imageDosHeader = new IMAGE_DOS_HEADER(); - read(raf, imageDosHeader); - if (imageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) return null; - int imageNtHeadersOffset = imageDosHeader.e_lfanew; - raf.seek(imageNtHeadersOffset); - IMAGE_NT_HEADERS imageNtHeaders = new IMAGE_NT_HEADERS(); - read(raf, imageNtHeaders); - if (imageNtHeaders.Signature != IMAGE_NT_SIGNATURE) return null; - - // DumpResources - int resourcesRVA = imageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; - if (resourcesRVA == 0) return null; - if (DEBUG) System.out.println("* Resources (RVA= "+resourcesRVA+")"); - IMAGE_SECTION_HEADER imageSectionHeader = new IMAGE_SECTION_HEADER(); - int firstSectionOffset = imageNtHeadersOffset + IMAGE_NT_HEADERS.FIELD_OFFSET_OptionalHeader + imageNtHeaders.FileHeader.SizeOfOptionalHeader; - raf.seek(firstSectionOffset); - boolean found = false; - for (int i = 0; i < imageNtHeaders.FileHeader.NumberOfSections; i++) { - read(raf, imageSectionHeader); - if (resourcesRVA >= imageSectionHeader.VirtualAddress && resourcesRVA < imageSectionHeader.VirtualAddress + imageSectionHeader.Misc_VirtualSize) { - // could check the imageSectionHeader name is .rsrc - found = true; - break; - } - } - if (!found) return null; - int delta = imageSectionHeader.VirtualAddress - imageSectionHeader.PointerToRawData; - int imageResourceDirectoryOffset = resourcesRVA - delta; - dumpResourceDirectory(raf, imageResourceDirectoryOffset, imageResourceDirectoryOffset, delta, 0, 0, false); - if (iconCnt < iconInfo.length) { - IconResInfo[] newArray = new IconResInfo[iconCnt]; - System.arraycopy(iconInfo, 0, newArray, 0, iconCnt); - iconInfo = newArray; - } - return iconInfo; - } - -void dumpResourceDirectory(RandomAccessFile raf, int imageResourceDirectoryOffset, int resourceBase, int delta, int type, int level, boolean rt_icon_root) throws IOException { - if (DEBUG) System.out.println("** LEVEL "+level); - - IMAGE_RESOURCE_DIRECTORY imageResourceDirectory = new IMAGE_RESOURCE_DIRECTORY(); - raf.seek(imageResourceDirectoryOffset); - read(raf, imageResourceDirectory); - - if (DEBUG) { - String sType = ""+type; - // level 1 resources are resource types - if (level == 1) { - System.out.println("___________________________"); - if (type == RT_ICON) sType = "RT_ICON"; - if (type == RT_GROUP_ICON) sType = "RT_GROUP_ICON"; - } - System.out.println("Resource Directory ["+sType+"]"+" (Named "+imageResourceDirectory.NumberOfNamedEntries+", ID "+imageResourceDirectory.NumberOfIdEntries+")"); - } - int IRDE_StartOffset = imageResourceDirectoryOffset + IMAGE_RESOURCE_DIRECTORY.SIZEOF; - IMAGE_RESOURCE_DIRECTORY_ENTRY[] imageResourceDirectoryEntries = new IMAGE_RESOURCE_DIRECTORY_ENTRY[imageResourceDirectory.NumberOfIdEntries]; - for (int i = 0; i < imageResourceDirectoryEntries.length; i++) { - imageResourceDirectoryEntries[i] = new IMAGE_RESOURCE_DIRECTORY_ENTRY(); - read(raf, imageResourceDirectoryEntries[i]); - } - for (int i = 0; i < imageResourceDirectoryEntries.length; i++) { - if (imageResourceDirectoryEntries[i].DataIsDirectory) { - dumpResourceDirectory(raf, imageResourceDirectoryEntries[i].OffsetToDirectory + resourceBase, resourceBase, delta, imageResourceDirectoryEntries[i].Id, level + 1, rt_icon_root ? true : type == RT_ICON); - } else { - // Resource found - /// pResDirEntry->Name - IMAGE_RESOURCE_DIRECTORY_ENTRY irde = imageResourceDirectoryEntries[i]; - IMAGE_RESOURCE_DATA_ENTRY data = new IMAGE_RESOURCE_DATA_ENTRY(); - raf.seek(imageResourceDirectoryEntries[i].OffsetToData + resourceBase); - read(raf, data); - if (DEBUG) System.out.println("Resource Id "+irde.Id+" Data Offset RVA "+data.OffsetToData+", Size "+data.Size); - if (rt_icon_root) { - if (DEBUG) System.out.println("iconcnt "+iconCnt+" |"+iconInfo.length); - iconInfo[iconCnt] = new IconResInfo(); - iconInfo[iconCnt].data = parseIcon(raf, data.OffsetToData - delta, data.Size); - iconInfo[iconCnt].offset = data.OffsetToData - delta; - iconInfo[iconCnt].size = data.Size; - iconCnt++; - if (iconCnt == iconInfo.length) { - IconResInfo[] newArray = new IconResInfo[iconInfo.length + 4]; - System.arraycopy(iconInfo, 0, newArray, 0, iconInfo.length); - iconInfo = newArray; - } - } - } - } -} - -static ImageData parseIcon(RandomAccessFile raf, int offset, int size) throws IOException { - raf.seek(offset); - BITMAPINFO bitmapInfo = new BITMAPINFO(); - read(raf, bitmapInfo); - bitmapInfo.bmiHeader.biHeight /= 2; - int width = bitmapInfo.bmiHeader.biWidth; - int height = bitmapInfo.bmiHeader.biHeight; - int depth = bitmapInfo.bmiHeader.biBitCount; - - PaletteData palette = loadPalette(bitmapInfo.bmiHeader, raf); - byte[] shapeData = loadData(bitmapInfo.bmiHeader, raf); - bitmapInfo.bmiHeader.biBitCount = 1; - byte[] maskData = loadData(bitmapInfo.bmiHeader, raf); - 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, - SWT.IMAGE_ICO, - 0, - 0, - 0, - 0); -} - -static 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 == 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; -} -static PaletteData loadPalette(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException { - int depth = bih.biBitCount; - if (depth <= 8) { - int numColors = bih.biClrUsed; - if (numColors == 0) { - numColors = 1 << depth; - } else { - if (numColors > 256) - numColors = 256; - } - byte[] buf = new byte[numColors * 4]; - raf.read(buf); - return paletteFromBytes(buf, numColors); - } - if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F); - if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000); - return new PaletteData(0xFF00, 0xFF0000, 0xFF000000); -} -static PaletteData paletteFromBytes(byte[] bytes, int numColors) { - int bytesOffset = 0; - RGB[] colors = new RGB[numColors]; - for (int i = 0; i < numColors; i++) { - colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF, - bytes[bytesOffset + 1] & 0xFF, - bytes[bytesOffset] & 0xFF); - bytesOffset += 4; - } - return new PaletteData(colors); -} -static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException { - int stride = (bih.biWidth * bih.biBitCount + 7) / 8; - stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple - byte[] data = loadData(bih, raf, stride); - flipScanLines(data, stride, bih.biHeight); - return data; -} -static void flipScanLines(byte[] data, int stride, int height) { - int i1 = 0; - int i2 = (height - 1) * stride; - for (int i = 0; i < height / 2; i++) { - for (int index = 0; index < stride; index++) { - byte b = data[index + i1]; - data[index + i1] = data[index + i2]; - data[index + i2] = b; - } - i1 += stride; - i2 -= stride; - } -} -static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf, int stride) throws IOException { - int dataSize = bih.biHeight * stride; - byte[] data = new byte[dataSize]; - int cmp = bih.biCompression; - if (cmp == 0) { // BMP_NO_COMPRESSION - raf.read(data); - } else { - if (DEBUG) System.out.println("ICO cannot be compressed?"); - } - return data; -} - -static void unloadIcon(RandomAccessFile raf, ImageData icon) throws IOException { - int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) + - ((icon.width + 31) / 32 * 4)) * icon.height; - write4(raf, BMPHeaderFixedSize); - write4(raf, icon.width); - write4(raf, icon.height * 2); - writeU2(raf, 1); - writeU2(raf, icon.depth); - write4(raf, 0); - write4(raf, sizeImage); - write4(raf, 0); - write4(raf, 0); - write4(raf, icon.palette.colors != null ? icon.palette.colors.length : 0); - write4(raf, 0); - - byte[] rgbs = paletteToBytes(icon.palette); - raf.write(rgbs); - unloadShapeData(raf, icon); - unloadMaskData(raf, icon); -} -static byte[] paletteToBytes(PaletteData pal) { - int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256); - byte[] bytes = new byte[n * 4]; - int offset = 0; - for (int i = 0; i < n; i++) { - RGB col = pal.colors[i]; - bytes[offset] = (byte)col.blue; - bytes[offset + 1] = (byte)col.green; - bytes[offset + 2] = (byte)col.red; - offset += 4; - } - return bytes; -} -static void unloadMaskData(RandomAccessFile raf, 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); - raf.write(buf, 0, destBpl); - offset -= srcBpl; - } - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } -} -static void unloadShapeData(RandomAccessFile raf, 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); - raf.write(buf, 0, destBpl); - offset -= srcBpl; - } - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } -} -static boolean readIconGroup(RandomAccessFile raf, int offset, int size) throws IOException { - raf.seek(offset); - NEWHEADER newHeader = new NEWHEADER(); - read(raf, newHeader); - if (newHeader.ResType != RES_ICON) return false; - RESDIR[] resDir = new RESDIR[newHeader.ResCount]; - for (int i = 0; i < newHeader.ResCount; i++) { - resDir[i] = new RESDIR(); - read(raf, resDir[i]); - } - return true; -} - -static void copyFile(String src, String dst) throws FileNotFoundException, IOException { - File srcFile = new File(src); - File dstFile = new File(dst); - FileInputStream in = new FileInputStream(srcFile); - FileOutputStream out = new FileOutputStream(dstFile); - int c; - while ((c = in.read()) != -1) out.write(c); - in.close(); - out.close(); -} - -/* IO utilities to parse Windows executable */ -static final int IMAGE_DOS_SIGNATURE = 0x5a4d; -static final int IMAGE_NT_SIGNATURE = 0x00004550; -static final int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; -static final int RES_ICON = 1; -static final int RT_ICON = 3; -static final int RT_GROUP_ICON = 14; -static final int BMPHeaderFixedSize = 40; - -public static class IMAGE_DOS_HEADER { - int e_magic; // WORD - int e_cblp; // WORD - int e_cp; // WORD - int e_crlc; // WORD - int e_cparhdr; // WORD - int e_minalloc; // WORD - int e_maxalloc; // WORD - int e_ss; // WORD - int e_sp; // WORD - int e_csum; // WORD - int e_ip; // WORD - int e_cs; // WORD - int e_lfarlc; // WORD - int e_ovno; // WORD - int[] e_res = new int[4]; // WORD[4] - int e_oemid; // WORD - int e_oeminfo; // WORD - int[] e_res2 = new int[10]; // WORD[10] - int e_lfanew; // LONG -} - -public static class IMAGE_FILE_HEADER { - int Machine; // WORD - int NumberOfSections; // WORD - int TimeDateStamp; // DWORD - int PointerToSymbolTable; // DWORD - int NumberOfSymbols; // DWORD - int SizeOfOptionalHeader; // WORD - int Characteristics; // WORD -}; - -public static class IMAGE_DATA_DIRECTORY { - int VirtualAddress; // DWORD - int Size; // DWORD -} - -public static class IMAGE_OPTIONAL_HEADER { - int Magic; // WORD - int MajorLinkerVersion; // BYTE - int MinorLinkerVersion; // BYTE - int SizeOfCode; // DWORD - int SizeOfInitializedData; // DWORD - int SizeOfUninitializedData; // DWORD - int AddressOfEntryPoint; // DWORD - int BaseOfCode; // DWORD - int BaseOfData; // DWORD - int ImageBase; // DWORD - int SectionAlignment; // DWORD - int FileAlignment; // DWORD - int MajorOperatingSystemVersion; // WORD - int MinorOperatingSystemVersion; // WORD - int MajorImageVersion; // WORD - int MinorImageVersion; // WORD - int MajorSubsystemVersion; // WORD - int MinorSubsystemVersion; // WORD - int Win32VersionValue; // DWORD - int SizeOfImage; // DWORD - int SizeOfHeaders; // DWORD - int CheckSum; // DWORD - int Subsystem; // WORD - int DllCharacteristics; // WORD - int SizeOfStackReserve; // DWORD - int SizeOfStackCommit; // DWORD - int SizeOfHeapReserve; // DWORD - int SizeOfHeapCommit; // DWORD - int LoaderFlags; // DWORD - int NumberOfRvaAndSizes; // DWORD - IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16]; -} -public static class IMAGE_NT_HEADERS { - int Signature; // DWORD - IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER(); - IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER(); - final static int FIELD_OFFSET_OptionalHeader = 24; -} - -public static class IMAGE_SECTION_HEADER { - int[] Name = new int[8]; // BYTE[8] - int Misc_VirtualSize; // DWORD (union Misc { DWORD PhysicalAddress; DWORD VirtualSize } - int VirtualAddress; // DWORD - int SizeOfRawData; // DWORD - int PointerToRawData; // DWORD - int PointerToRelocations; // DWORD - int PointerToLinenumbers; // DWORD - int NumberOfRelocations; // WORD - int NumberOfLinenumbers; // WORD - int Characteristics; // DWORD -}; - -public static class IMAGE_RESOURCE_DIRECTORY { - int Characteristics; // DWORD - int TimeDateStamp; // DWORD - int MajorVersion; // WORD - int MinorVersion; // WORD - int NumberOfNamedEntries; // WORD - used - int NumberOfIdEntries; // WORD - used - final static int SIZEOF = 16; -} - -public static class IMAGE_RESOURCE_DIRECTORY_ENTRY { - // union - int NameOffset; // DWORD 31 bits - boolean NameIsString; // DWORD 1 bit - int Name; // DWORD - int Id; // WORD - // union - int OffsetToData; // DWORD - int OffsetToDirectory; // DWORD 31 bits - boolean DataIsDirectory; // DWORD 1 bit -} - -public static class IMAGE_RESOURCE_DATA_ENTRY { - int OffsetToData; // DWORD - int Size; // DWORD - int CodePage; // DWORD - int Reserved; // DWORD -} - -public static class NEWHEADER { - int Reserved; // WORD - int ResType; // WORD - int ResCount; // WORD -} - -public static class ICONRESDIR { - int Width; // BYTE - int Height; // BYTE - int ColorCount; // BYTE - int reserved; // BYTE -} - -public static class CURSORDIR { - int Width; // WORD - int Height; // WORD -} - -public static class RESDIR { - // union - ICONRESDIR Icon = new ICONRESDIR(); - CURSORDIR Cursor = new CURSORDIR(); - int Planes; // WORD - int BitCount; // WORD - int BytesInRes; // DWORD - int IconCursorId; // WORD -} - -public static class BITMAPINFOHEADER { - int biSize; // DWORD - int biWidth; // LONG - int biHeight; // LONG - int biPlanes; // WORD - int biBitCount; // WORD - int biCompression; // DWORD - int biSizeImage; // DWORD - int biXPelsPerMeter; // LONG - int biYPelsPerMeter; // LONG - int biClrUsed; // DWORD - int biClrImportant; // DWORD -} - -static class RGBQUAD { - int rgBlue; // BYTE - int rgbGreen; // BYTE - int rgbRed; // BYTE - int rgbReserved; // BYTE -} -static class BITMAPINFO { - BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); - RGBQUAD[] bmiColors = null; -} -static void read(RandomAccessFile raf, BITMAPINFOHEADER bih) throws IOException { - bih.biSize = read4(raf); - bih.biWidth = read4(raf); - bih.biHeight = read4(raf); - bih.biPlanes = readU2(raf); - bih.biBitCount = readU2(raf); - bih.biCompression = read4(raf); - bih.biSizeImage = read4(raf); - bih.biXPelsPerMeter = read4(raf); - bih.biYPelsPerMeter = read4(raf); - bih.biClrUsed = read4(raf); - bih.biClrImportant = read4(raf); -} -static void read(RandomAccessFile raf, BITMAPINFO bi) throws IOException { - read(raf, bi.bmiHeader); -} -/* Little Endian helpers */ -static int readU2(RandomAccessFile raf) throws IOException { - int b0 = raf.readByte() & 0xFF; - int b1 = raf.readByte() & 0xFF; - return (b1 << 8 | b0); -} -static int read4(RandomAccessFile raf) throws IOException { - int b0 = raf.readByte() & 0xFF;; - int b1 = raf.readByte() & 0xFF;; - int b2 = raf.readByte() & 0xFF;; - int b3 = raf.readByte() & 0xFF;; - return b3 << 24 | b2 << 16 | b1 << 8 | b0; -} -static void write4(RandomAccessFile raf, int value) throws IOException { - raf.write(value & 0xFF); - raf.write((value >> 8) & 0xFF); - raf.write((value >> 16) & 0xFF); - raf.write((value >> 24) & 0xFF); -} -static void writeU2(RandomAccessFile raf, int value) throws IOException { - raf.write(value & 0xFF); - raf.write((value >> 8) & 0xFF); -} -static void read(RandomAccessFile raf, IMAGE_DOS_HEADER idh) throws IOException { - idh.e_magic = readU2(raf); - idh.e_cblp = readU2(raf); - idh.e_cp = readU2(raf); - idh.e_crlc = readU2(raf); - idh.e_cparhdr = readU2(raf); - idh.e_minalloc = readU2(raf); - idh.e_maxalloc = readU2(raf); - idh.e_ss = readU2(raf); - idh.e_sp = readU2(raf); - idh.e_csum = readU2(raf); - idh.e_ip = readU2(raf); - idh.e_cs = readU2(raf); - idh.e_lfarlc = readU2(raf); - idh.e_ovno = readU2(raf); - for (int i = 0; i < idh.e_res.length; i++) idh.e_res[i] = readU2(raf); - idh.e_oemid = readU2(raf); - idh.e_oeminfo = readU2(raf); - for (int i = 0; i < idh.e_res2.length; i++) idh.e_res2[i] = readU2(raf); - idh.e_lfanew = read4(raf); -} -static void read(RandomAccessFile raf, IMAGE_FILE_HEADER ifh) throws IOException { - ifh.Machine = readU2(raf); - ifh.NumberOfSections = readU2(raf); - ifh.TimeDateStamp = read4(raf); - ifh.PointerToSymbolTable = read4(raf); - ifh.NumberOfSymbols = read4(raf); - ifh.SizeOfOptionalHeader = readU2(raf); - ifh.Characteristics = readU2(raf); -} -static void read(RandomAccessFile raf, IMAGE_DATA_DIRECTORY idd) throws IOException { - idd.VirtualAddress = read4(raf); - idd.Size = read4(raf); -} -static void read(RandomAccessFile raf, IMAGE_OPTIONAL_HEADER ioh) throws IOException { - ioh.Magic = readU2(raf); - ioh.MajorLinkerVersion = raf.read(); - ioh.MinorLinkerVersion = raf.read(); - ioh.SizeOfCode = read4(raf); - ioh.SizeOfInitializedData = read4(raf); - ioh.SizeOfUninitializedData = read4(raf); - ioh.AddressOfEntryPoint = read4(raf); - ioh.BaseOfCode = read4(raf); - ioh.BaseOfData = read4(raf); - ioh.ImageBase = read4(raf); - ioh.SectionAlignment = read4(raf); - ioh.FileAlignment = read4(raf); - ioh.MajorOperatingSystemVersion = readU2(raf); - ioh.MinorOperatingSystemVersion = readU2(raf); - ioh.MajorImageVersion = readU2(raf); - ioh.MinorImageVersion = readU2(raf); - ioh.MajorSubsystemVersion = readU2(raf); - ioh.MinorSubsystemVersion = readU2(raf); - ioh.Win32VersionValue = read4(raf); - ioh.SizeOfImage = read4(raf); - ioh.SizeOfHeaders = read4(raf); - ioh.CheckSum = read4(raf); - ioh.Subsystem = readU2(raf); - ioh.DllCharacteristics = readU2(raf); - ioh.SizeOfStackReserve = read4(raf); - ioh.SizeOfStackCommit = read4(raf); - ioh.SizeOfHeapReserve = read4(raf); - ioh.SizeOfHeapCommit = read4(raf); - ioh.LoaderFlags = read4(raf); - ioh.NumberOfRvaAndSizes = read4(raf); - for (int i = 0 ; i < ioh.DataDirectory.length; i++) { - ioh.DataDirectory[i] = new IMAGE_DATA_DIRECTORY(); - read(raf, ioh.DataDirectory[i]); - } -} -static void read(RandomAccessFile raf, IMAGE_NT_HEADERS inh) throws IOException { - inh.Signature = read4(raf); - read(raf, inh.FileHeader); - read(raf, inh.OptionalHeader); -} -static void read(RandomAccessFile raf, IMAGE_SECTION_HEADER ish) throws IOException { - for (int i = 0 ; i < ish.Name.length; i++) ish.Name[i] = raf.read(); - ish.Misc_VirtualSize = read4(raf); - ish.VirtualAddress = read4(raf); - ish.SizeOfRawData = read4(raf); - ish.PointerToRawData = read4(raf); - ish.PointerToRelocations = read4(raf); - ish.PointerToLinenumbers = read4(raf); - ish.NumberOfRelocations = readU2(raf); - ish.NumberOfLinenumbers = readU2(raf); - ish.Characteristics = read4(raf); -} -static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY ird) throws IOException { - ird.Characteristics = read4(raf); - ird.TimeDateStamp = read4(raf); - ird.MajorVersion = readU2(raf); - ird.MinorVersion = readU2(raf); - ird.NumberOfNamedEntries = readU2(raf); - ird.NumberOfIdEntries = readU2(raf); -}; -static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY_ENTRY irde) throws IOException { - irde.Name = read4(raf); - irde.OffsetToData = read4(raf); - // construct other union members - irde.NameOffset = irde.Name & ~ (1 << 31); - irde.NameIsString = (irde.Name & (1 << 31)) != 0; - irde.Id = irde.Name & 0xFFFF; - irde.OffsetToDirectory = irde.OffsetToData & ~ (1 << 31); - irde.DataIsDirectory = (irde.OffsetToData & (1 << 31)) != 0; -} -static void read(RandomAccessFile raf, IMAGE_RESOURCE_DATA_ENTRY irde) throws IOException { - irde.OffsetToData = read4(raf); - irde.Size = read4(raf); - irde.CodePage = read4(raf); - irde.Reserved = read4(raf); -} -static void read(RandomAccessFile raf, NEWHEADER nh) throws IOException { - nh.Reserved = readU2(raf); - nh.ResType = readU2(raf); - nh.ResCount = readU2(raf); -} -static void read(RandomAccessFile raf, ICONRESDIR i) throws IOException { - i.Width = raf.read(); - i.Height = raf.read(); - i.ColorCount = raf.read(); - i.reserved = raf.read(); -} -static void read(RandomAccessFile raf, CURSORDIR c) throws IOException { - c.Width = readU2(raf); - c.Height = readU2(raf); -} -static void read(RandomAccessFile raf, RESDIR rs) throws IOException { - long start = raf.getFilePointer(); - read(raf, rs.Icon); - raf.seek(start); - read(raf, rs.Cursor); - rs.Planes = readU2(raf); - rs.BitCount = readU2(raf); - rs.BytesInRes = read4(raf); - rs.IconCursorId = readU2(raf); -} - -/* ImageData and Image Decoder inlining to avoid dependency on SWT - * The following section can be entirely removed if SWT can be used. - */ - -static class RGB { - - /** - * the red component of the RGB - */ - public int red; - - /** - * the green component of the RGB - */ - public int green; - - /** - * the blue component of the RGB - */ - public int blue; - - static final long serialVersionUID = 3258415023461249074L; - -/** - * Constructs an instance of this class with the given - * red, green and blue values. - * - * @param red the red component of the new instance - * @param green the green component of the new instance - * @param blue the blue component of the new instance - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li> - * </ul> - */ -public RGB(int red, int green, int blue) { - if ((red > 255) || (red < 0) || - (green > 255) || (green < 0) || - (blue > 255) || (blue < 0)) - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - this.red = red; - this.green = green; - this.blue = blue; -} - -/** - * Compares the argument to the receiver, and returns true - * if they represent the <em>same</em> object using a class - * specific comparison. - * - * @param object the object to compare with this object - * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise - * - * @see #hashCode() - */ -public boolean equals (Object object) { - if (object == this) return true; - if (!(object instanceof RGB)) return false; - RGB rgb = (RGB)object; - return (rgb.red == this.red) && (rgb.green == this.green) && (rgb.blue == this.blue); -} - -/** - * Returns an integer hash code for the receiver. Any two - * objects which return <code>true</code> when passed to - * <code>equals</code> must return the same value for this - * method. - * - * @return the receiver's hash - * - * @see #equals(Object) - */ -public int hashCode () { - return (blue << 16) | (green << 8) | red; -} - -/** - * Returns a string containing a concise, human-readable - * description of the receiver. - * - * @return a string representation of the <code>RGB</code> - */ -public String toString () { - return "RGB {" + red + ", " + green + ", " + blue + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - -//$NON-NLS-4$ -} - -} -static class PaletteData { - - /** - * true if the receiver is a direct palette, - * and false otherwise - */ - public boolean isDirect; - - /** - * the RGB values for an indexed palette, where the - * indices of the array correspond to pixel values - */ - public RGB[] colors; - - /** - * the red mask for a direct palette - */ - public int redMask; - - /** - * the green mask for a direct palette - */ - public int greenMask; - - /** - * the blue mask for a direct palette - */ - public int blueMask; - - /** - * the red shift for a direct palette - */ - public int redShift; - - /** - * the green shift for a direct palette - */ - public int greenShift; - - /** - * the blue shift for a direct palette - */ - public int blueShift; - -/** - * Constructs a new indexed palette given an array of RGB values. - * - * @param colors the array of <code>RGB</code>s for the palette - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> - * </ul> - */ -public PaletteData(RGB[] colors) { - if (colors == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - this.colors = colors; - this.isDirect = false; -} - -/** - * Constructs a new direct palette given the red, green and blue masks. - * - * @param redMask the red mask - * @param greenMask the green mask - * @param blueMask the blue mask - */ -public PaletteData(int redMask, int greenMask, int blueMask) { - this.redMask = redMask; - this.greenMask = greenMask; - this.blueMask = blueMask; - this.isDirect = true; - this.redShift = shiftForMask(redMask); - this.greenShift = shiftForMask(greenMask); - this.blueShift = shiftForMask(blueMask); -} - -/** - * Returns the pixel value corresponding to the given <code>RBG</code>. - * - * @param rgb the RGB to get the pixel value for - * @return the pixel value for the given RGB - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> - * <li>ERROR_INVALID_ARGUMENT - if the RGB is not found in the palette</li> - * </ul> - */ -public int getPixel(RGB rgb) { - if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (isDirect) { - int pixel = 0; - pixel |= (redShift < 0 ? rgb.red << -redShift : rgb.red >>> redShift) & redMask; - pixel |= (greenShift < 0 ? rgb.green << -greenShift : rgb.green >>> greenShift) & greenMask; - pixel |= (blueShift < 0 ? rgb.blue << -blueShift : rgb.blue >>> blueShift) & blueMask; - return pixel; - } else { - for (int i = 0; i < colors.length; i++) { - if (colors[i].equals(rgb)) return i; - } - /* The RGB did not exist in the palette */ - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - return 0; - } -} - -/** - * Returns an <code>RGB</code> corresponding to the given pixel value. - * - * @param pixel the pixel to get the RGB value for - * @return the RGB value for the given pixel - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> - * <li>ERROR_INVALID_ARGUMENT - if the pixel does not exist in the palette</li> - * </ul> - */ -public RGB getRGB(int pixel) { - if (isDirect) { - int r = pixel & redMask; - r = (redShift < 0) ? r >>> -redShift : r << redShift; - int g = pixel & greenMask; - g = (greenShift < 0) ? g >>> -greenShift : g << greenShift; - int b = pixel & blueMask; - b = (blueShift < 0) ? b >>> -blueShift : b << blueShift; - return new RGB(r, g, b); - } else { - if (pixel < 0 || pixel >= colors.length) { - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - } - return colors[pixel]; - } -} - -/** - * Returns all the RGB values in the receiver if it is an - * indexed palette, or null if it is a direct palette. - * - * @return the <code>RGB</code>s for the receiver or null - */ -public RGB[] getRGBs() { - return colors; -} - -/** - * Computes the shift value for a given mask. - * - * @param mask the mask to compute the shift for - * @return the shift amount - * - * @see PaletteData - */ -int shiftForMask(int mask) { - for (int i = 31; i >= 0; i--) { - if (((mask >> i) & 0x1) != 0) return 7 - i; - } - return 32; -} - -} -static class ImageLoader { - - /** - * the array of ImageData objects in this ImageLoader. - * This array is read in when the load method is called, - * and it is written out when the save method is called - */ - public ImageData[] data; - - /** - * the width of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Width value) - */ - public int logicalScreenWidth; - - /** - * the height of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Height value) - */ - public int logicalScreenHeight; - - /** - * the background pixel for the logical screen (this - * corresponds to the GIF89a Background Color Index value). - * The default is -1 which means 'unspecified background' - * - */ - public int backgroundPixel; - - /** - * the number of times to repeat the display of a sequence - * of animated images (this corresponds to the commonly-used - * GIF application extension for "NETSCAPE 2.0 01") - */ - public int repeatCount; - - /* - * the set of ImageLoader event listeners, created on demand - */ - Vector imageLoaderListeners; - -/** - * Construct a new empty ImageLoader. - */ -public ImageLoader() { - reset(); -} - -/** - * Resets the fields of the ImageLoader, except for the - * <code>imageLoaderListeners</code> field. - */ -void reset() { - data = null; - logicalScreenWidth = 0; - logicalScreenHeight = 0; - backgroundPixel = -1; - repeatCount = 1; -} - -/** - * Loads an array of <code>ImageData</code> objects from the - * specified input stream. Throws an error if either an error - * occurs while loading the images, or if the images are not - * of a supported type. Returns the loaded image data array. - * - * @param stream the input stream to load the images from - * @return an array of <code>ImageData</code> objects loaded from the specified input stream - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the stream is null</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> - * <li>ERROR_IO - if an input/output error occurs while reading data</li> - * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> - * </ul> - */ -public ImageData[] load(InputStream stream) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - reset(); - data = FileFormat.load(stream, this); - return data; -} - -/** - * Loads an array of <code>ImageData</code> objects from the - * file with the specified name. Throws an error if either - * an error occurs while loading the images, or if the images are - * not of a supported type. Returns the loaded image data array. - * - * @param filename the name of the file to load the images from - * @return an array of <code>ImageData</code> objects loaded from the specified file - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the file name is null</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> - * <li>ERROR_IO - if an IO error occurs while reading data</li> - * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> - * </ul> - */ -public ImageData[] load(String filename) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - InputStream stream = null; - try { - stream = new FileInputStream(filename); - return load(stream); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } finally { - try { - if (stream != null) stream.close(); - } catch (IOException e) { - // Ignore error - } - } - return null; -} -} -static class ImageData { - - /** - * The width of the image, in pixels. - */ - public int width; - - /** - * The height of the image, in pixels. - */ - public int height; - - /** - * The color depth of the image, in bits per pixel. - * <p> - * Note that a depth of 8 or less does not necessarily - * mean that the image is palette indexed, or - * conversely that a depth greater than 8 means that - * the image is direct color. Check the associated - * PaletteData's isDirect field for such determinations. - */ - public int depth; - - /** - * The scanline padding. - * <p> - * If one scanline of the image is not a multiple of - * this number, it will be padded with zeros until it is. - * </p> - */ - public int scanlinePad; - - /** - * The number of bytes per scanline. - * <p> - * This is a multiple of the scanline padding. - * </p> - */ - public int bytesPerLine; - - /** - * The pixel data of the image. - * <p> - * Note that for 16 bit depth images the pixel data is stored - * in least significant byte order; however, for 24bit and - * 32bit depth images the pixel data is stored in most - * significant byte order. - * </p> - */ - public byte[] data; - - /** - * The color table for the image. - */ - public PaletteData palette; - - /** - * The transparent pixel. - * <p> - * Pixels with this value are transparent. - * </p><p> - * The default is -1 which means 'no transparent pixel'. - * </p> - */ - public int transparentPixel; - - /** - * An icon-specific field containing the data from the icon mask. - * <p> - * This is a 1 bit bitmap stored with the most significant - * bit first. The number of bytes per scanline is - * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'. - * </p><p> - * The default is null which means 'no transparency mask'. - * </p> - */ - public byte[] maskData; - - /** - * An icon-specific field containing the scanline pad of the mask. - * <p> - * If one scanline of the transparency mask is not a - * multiple of this number, it will be padded with zeros until - * it is. - * </p> - */ - public int maskPad; - - /** - * The alpha data of the image. - * <p> - * Every pixel can have an <em>alpha blending</em> value that - * varies from 0, meaning fully transparent, to 255 meaning - * fully opaque. The number of bytes per scanline is - * 'width'. - * </p> - */ - public byte[] alphaData; - - /** - * The global alpha value to be used for every pixel. - * <p> - * If this value is set, the <code>alphaData</code> field - * is ignored and when the image is rendered each pixel - * will be blended with the background an amount - * proportional to this value. - * </p><p> - * The default is -1 which means 'no global alpha value' - * </p> - */ - public int alpha; - - /** - * The type of file from which the image was read. - * - * It is expressed as one of the following values: - * <dl> - * <dt><code>IMAGE_BMP</code></dt> - * <dd>Windows BMP file format, no compression</dd> - * <dt><code>IMAGE_BMP_RLE</code></dt> - * <dd>Windows BMP file format, RLE compression if appropriate</dd> - * <dt><code>IMAGE_GIF</code></dt> - * <dd>GIF file format</dd> - * <dt><code>IMAGE_ICO</code></dt> - * <dd>Windows ICO file format</dd> - * <dt><code>IMAGE_JPEG</code></dt> - * <dd>JPEG file format</dd> - * <dt><code>IMAGE_PNG</code></dt> - * <dd>PNG file format</dd> - * </dl> - */ - public int type; - - /** - * The x coordinate of the top left corner of the image - * within the logical screen (this field corresponds to - * the GIF89a Image Left Position value). - */ - public int x; - - /** - * The y coordinate of the top left corner of the image - * within the logical screen (this field corresponds to - * the GIF89a Image Top Position value). - */ - public int y; - - /** - * A description of how to dispose of the current image - * before displaying the next. - * - * It is expressed as one of the following values: - * <dl> - * <dt><code>DM_UNSPECIFIED</code></dt> - * <dd>disposal method not specified</dd> - * <dt><code>DM_FILL_NONE</code></dt> - * <dd>do nothing - leave the image in place</dd> - * <dt><code>DM_FILL_BACKGROUND</code></dt> - * <dd>fill with the background color</dd> - * <dt><code>DM_FILL_PREVIOUS</code></dt> - * <dd>restore the previous picture</dd> - * </dl> - * (this field corresponds to the GIF89a Disposal Method value) - */ - public int disposalMethod; - - /** - * The time to delay before displaying the next image - * in an animation (this field corresponds to the GIF89a - * Delay Time value). - */ - public int delayTime; - - /** - * Arbitrary channel width data to 8-bit conversion table. - */ - static final byte[][] ANY_TO_EIGHT = new byte[9][]; - static { - for (int b = 0; b < 9; ++b) { - byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b]; - if (b == 0) continue; - int inc = 0; - for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit; - for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8); - } - } - static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8]; - - /** - * Scaled 8x8 Bayer dither matrix. - */ - static final int[][] DITHER_MATRIX = { - { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 }, - { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 }, - { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 }, - { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 }, - { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 }, - { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 }, - { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 }, - { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 } - }; - -/** - * Constructs a new, empty ImageData with the given width, height, - * depth and palette. The data will be initialized to an (all zero) - * array of the appropriate size. - * - * @param width the width of the image - * @param height the height of the image - * @param depth the depth of the image - * @param palette the palette of the image (must not be null) - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not - * one of 1, 2, 4, 8, 16, 24 or 32</li> - * <li>ERROR_NULL_ARGUMENT - if the palette is null</li> - * </ul> - */ -public ImageData(int width, int height, int depth, PaletteData palette) { - this(width, height, depth, palette, - 4, null, 0, null, - null, -1, -1, SWT.IMAGE_UNDEFINED, - 0, 0, 0, 0); -} - -/** - * Constructs a new, empty ImageData with the given width, height, - * depth, palette, scanlinePad and data. - * - * @param width the width of the image - * @param height the height of the image - * @param depth the depth of the image - * @param palette the palette of the image - * @param scanlinePad the padding of each line, in bytes - * @param data the data of the image - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not - * one of 1, 2, 4, 8, 16, 24 or 32</li> - * <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li> - * <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li> - * </ul> - */ -public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) { - this(width, height, depth, palette, - scanlinePad, checkData(data), 0, null, - null, -1, -1, SWT.IMAGE_UNDEFINED, - 0, 0, 0, 0); -} - -/** - * Constructs an <code>ImageData</code> loaded from a file with the - * specified name. Throws an error if an error occurs loading the - * image, or if the image has an unsupported type. - * <p> - * This constructor is provided for convenience when loading a single - * image only. If the file contains multiple images, only the first - * one will be loaded. To load multiple images, use - * <code>ImageLoader.load()</code>. - * </p> - * - * @param filename the name of the file to load the image from (must not be null) - * - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if the file name is null</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> - * <li>ERROR_IO if an IO error occurs while reading data</li> - * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> - * </ul> - */ -public ImageData(String filename) { - ImageData[] data = new ImageLoader().load(filename); - if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); - ImageData i = data[0]; - setAllFields( - i.width, - i.height, - i.depth, - i.scanlinePad, - i.bytesPerLine, - i.data, - i.palette, - i.transparentPixel, - i.maskData, - i.maskPad, - i.alphaData, - i.alpha, - i.type, - i.x, - i.y, - i.disposalMethod, - i.delayTime); -} - -/** - * Prevents uninitialized instances from being created outside the package. - */ -ImageData() { -} - -/** - * Constructs an image data by giving values for all non-computable fields. - * <p> - * This method is for internal use, and is not described further. - * </p> - */ -ImageData( - int width, int height, int depth, PaletteData palette, - int scanlinePad, byte[] data, int maskPad, byte[] maskData, - byte[] alphaData, int alpha, int transparentPixel, int type, - int x, int y, int disposalMethod, int delayTime) -{ - - if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8 - || depth == 16 || depth == 24 || depth == 32)) { - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - } - if (width <= 0 || height <= 0) { - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - } - if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO); - - int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) - / scanlinePad * scanlinePad; - setAllFields( - width, - height, - depth, - scanlinePad, - bytesPerLine, - data != null ? data : new byte[bytesPerLine * height], - palette, - transparentPixel, - maskData, - maskPad, - alphaData, - alpha, - type, - x, - y, - disposalMethod, - delayTime); -} - -/** - * Initializes all fields in the receiver. This method must be called - * by all public constructors to ensure that all fields are initialized - * for a new ImageData object. If a new field is added to the class, - * then it must be added to this method. - * <p> - * This method is for internal use, and is not described further. - * </p> - */ -void setAllFields(int width, int height, int depth, int scanlinePad, - int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel, - byte[] maskData, int maskPad, byte[] alphaData, int alpha, - int type, int x, int y, int disposalMethod, int delayTime) { - - this.width = width; - this.height = height; - this.depth = depth; - this.scanlinePad = scanlinePad; - this.bytesPerLine = bytesPerLine; - this.data = data; - this.palette = palette; - this.transparentPixel = transparentPixel; - this.maskData = maskData; - this.maskPad = maskPad; - this.alphaData = alphaData; - this.alpha = alpha; - this.type = type; - this.x = x; - this.y = y; - this.disposalMethod = disposalMethod; - this.delayTime = delayTime; -} - -/** - * Invokes internal SWT functionality to create a new instance of - * this class. - * <p> - * <b>IMPORTANT:</b> This method is <em>not</em> part of the public - * API for <code>ImageData</code>. It is marked public only so that it - * can be shared within the packages provided by SWT. It is subject - * to change without notice, and should never be called from - * application code. - * </p> - * <p> - * This method is for internal use, and is not described further. - * </p> - */ -public static ImageData internal_new( - int width, int height, int depth, PaletteData palette, - int scanlinePad, byte[] data, int maskPad, byte[] maskData, - byte[] alphaData, int alpha, int transparentPixel, int type, - int x, int y, int disposalMethod, int delayTime) -{ - return new ImageData( - width, height, depth, palette, scanlinePad, data, maskPad, maskData, - alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime); -} - -ImageData colorMaskImage(int pixel) { - ImageData mask = new ImageData(width, height, 1, bwPalette(), - 2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED, - 0, 0, 0, 0); - int[] row = new int[width]; - for (int y = 0; y < height; y++) { - getPixels(0, y, width, row, 0); - for (int i = 0; i < width; i++) { - if (pixel != -1 && row[i] == pixel) { - row[i] = 0; - } else { - row[i] = 1; - } - } - mask.setPixels(0, y, width, row, 0); - } - return mask; -} - -static byte[] checkData(byte [] data) { - if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - return data; -} - -/** - * Returns <code>getWidth</code> pixel values starting at offset - * <code>x</code> in scanline <code>y</code> in the receiver's - * data starting at <code>startIndex</code>. - * - * @param x the x position of the first pixel to get - * @param y the y position of the first pixel to get - * @param getWidth the width of the data to get - * @param pixels the buffer in which to put the pixels - * @param startIndex the offset into the byte array to begin storing pixels - * - * @exception IndexOutOfBoundsException if getWidth is too large - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> - * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> - * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8 - * (For higher depths, use the int[] version of this method.)</li> - * </ul> - */ -public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) { - if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error - -(SWT.ERROR_INVALID_ARGUMENT); - if (getWidth == 0) return; - int index; - int theByte; - int mask = 0; - int n = getWidth; - int i = startIndex; - int srcX = x, srcY = y; - if (depth == 1) { - index = (y * bytesPerLine) + (x >> 3); - theByte = data[index] & 0xFF; - while (n > 0) { - mask = 1 << (7 - (srcX & 0x7)); - if ((theByte & mask) == 0) { - pixels[i] = 0; - } else { - pixels[i] = 1; - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - if (n > 0) theByte = data[index] & 0xFF; - srcX = 0; - } else { - if (mask == 1) { - index++; - if (n > 0) theByte = data[index] & 0xFF; - } - } - } - return; - } - if (depth == 2) { - index = (y * bytesPerLine) + (x >> 2); - theByte = data[index] & 0xFF; - int offset; - while (n > 0) { - offset = 3 - (srcX % 4); - mask = 3 << (offset * 2); - pixels[i] = (byte)((theByte & mask) >> (offset * 2)); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - if (n > 0) theByte = data[index] & 0xFF; - srcX = 0; - } else { - if (offset == 0) { - index++; - theByte = data[index] & 0xFF; - } - } - } - return; - } - if (depth == 4) { - index = (y * bytesPerLine) + (x >> 1); - if ((x & 0x1) == 1) { - theByte = data[index] & 0xFF; - pixels[i] = (byte)(theByte & 0x0F); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - while (n > 1) { - theByte = data[index] & 0xFF; - pixels[i] = (byte)(theByte >> 4); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - pixels[i] = (byte)(theByte & 0x0F); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - } - if (n > 0) { - theByte = data[index] & 0xFF; - pixels[i] = (byte)(theByte >> 4); - } - return; - } - if (depth == 8) { - index = (y * bytesPerLine) + x; - for (int j = 0; j < getWidth; j++) { - pixels[i] = data[index]; - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - return; - } - SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); -} - -/** - * Returns <code>getWidth</code> pixel values starting at offset - * <code>x</code> in scanline <code>y</code> in the receiver's - * data starting at <code>startIndex</code>. - * - * @param x the x position of the first pixel to get - * @param y the y position of the first pixel to get - * @param getWidth the width of the data to get - * @param pixels the buffer in which to put the pixels - * @param startIndex the offset into the buffer to begin storing pixels - * - * @exception IndexOutOfBoundsException if getWidth is too large - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> - * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> - * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> - * </ul> - */ -public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) { - if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error - -(SWT.ERROR_INVALID_ARGUMENT); - if (getWidth == 0) return; - int index; - int theByte; - int mask; - int n = getWidth; - int i = startIndex; - int srcX = x, srcY = y; - if (depth == 1) { - index = (y * bytesPerLine) + (x >> 3); - theByte = data[index] & 0xFF; - while (n > 0) { - mask = 1 << (7 - (srcX & 0x7)); - if ((theByte & mask) == 0) { - pixels[i] = 0; - } else { - pixels[i] = 1; - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - if (n > 0) theByte = data[index] & 0xFF; - srcX = 0; - } else { - if (mask == 1) { - index++; - if (n > 0) theByte = data[index] & 0xFF; - } - } - } - return; - } - if (depth == 2) { - index = (y * bytesPerLine) + (x >> 2); - theByte = data[index] & 0xFF; - int offset; - while (n > 0) { - offset = 3 - (srcX % 4); - mask = 3 << (offset * 2); - pixels[i] = (byte)((theByte & mask) >> (offset * 2)); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - if (n > 0) theByte = data[index] & 0xFF; - srcX = 0; - } else { - if (offset == 0) { - index++; - theByte = data[index] & 0xFF; - } - } - } - return; - } - if (depth == 4) { - index = (y * bytesPerLine) + (x >> 1); - if ((x & 0x1) == 1) { - theByte = data[index] & 0xFF; - pixels[i] = theByte & 0x0F; - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - while (n > 1) { - theByte = data[index] & 0xFF; - pixels[i] = theByte >> 4; - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - pixels[i] = theByte & 0x0F; - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - } - if (n > 0) { - theByte = data[index] & 0xFF; - pixels[i] = theByte >> 4; - } - return; - } - if (depth == 8) { - index = (y * bytesPerLine) + x; - for (int j = 0; j < getWidth; j++) { - pixels[i] = data[index] & 0xFF; - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - return; - } - if (depth == 16) { - index = (y * bytesPerLine) + (x * 2); - for (int j = 0; j < getWidth; j++) { - pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 2; - } - } - return; - } - if (depth == 24) { - index = (y * bytesPerLine) + (x * 3); - for (int j = 0; j < getWidth; j++) { - pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8) - | (data[index+2] & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 3; - } - } - return; - } - if (depth == 32) { - index = (y * bytesPerLine) + (x * 4); - i = startIndex; - for (int j = 0; j < getWidth; j++) { - pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16) - | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 4; - } - } - return; - } - SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); -} - -/** - * Returns an array of <code>RGB</code>s which comprise the - * indexed color table of the receiver, or null if the receiver - * has a direct color model. - * - * @return the RGB values for the image or null if direct color - * - * @see PaletteData#getRGBs() - */ -public RGB[] getRGBs() { - return palette.getRGBs(); -} - -/** - * Returns an <code>ImageData</code> which specifies the - * transparency mask information for the receiver, or null if the - * receiver has no transparency and is not an icon. - * - * @return the transparency mask or null if none exists - */ -public ImageData getTransparencyMask() { - if (getTransparencyType() == SWT.TRANSPARENCY_MASK) { - return new ImageData(width, height, 1, bwPalette(), maskPad, maskData); - } else { - return colorMaskImage(transparentPixel); - } -} - -/** - * Returns the image transparency type. - * - * @return the receiver's transparency type - */ -public int getTransparencyType() { - if (maskData != null) return SWT.TRANSPARENCY_MASK; - if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL; - if (alphaData != null) return SWT.TRANSPARENCY_ALPHA; - return SWT.TRANSPARENCY_NONE; -} - -/** - * Returns the byte order of the receiver. - * - * @return MSB_FIRST or LSB_FIRST - */ -int getByteOrder() { - return depth != 16 ? MSB_FIRST : LSB_FIRST; -} - -/** - * Sets the pixel values starting at offset <code>x</code> in - * scanline <code>y</code> in the receiver's data to the - * values from the array <code>pixels</code> starting at - * <code>startIndex</code>. - * - * @param x the x position of the pixel to set - * @param y the y position of the pixel to set - * @param putWidth the width of the pixels to set - * @param pixels the pixels to set - * @param startIndex the index at which to begin setting - * - * @exception IndexOutOfBoundsException if putWidth is too large - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> - * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> - * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8 - * (For higher depths, use the int[] version of this method.)</li> - * </ul> - */ -public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) { - if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - if (putWidth == 0) return; - int index; - int theByte; - int mask; - int n = putWidth; - int i = startIndex; - int srcX = x, srcY = y; - if (depth == 1) { - index = (y * bytesPerLine) + (x >> 3); - while (n > 0) { - mask = 1 << (7 - (srcX & 0x7)); - if ((pixels[i] & 0x1) == 1) { - data[index] = (byte)((data[index] & 0xFF) | mask); - } else { - data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - if (mask == 1) { - index++; - } - } - } - return; - } - if (depth == 2) { - byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; - index = (y * bytesPerLine) + (x >> 2); - int offset = 3 - (x % 4); - while (n > 0) { - theByte = pixels[i] & 0x3; - data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - offset = 0; - srcX = 0; - } else { - if (offset == 0) { - index++; - offset = 3; - } else { - offset--; - } - } - } - return; - } - if (depth == 4) { - index = (y * bytesPerLine) + (x >> 1); - boolean high = (x & 0x1) == 0; - while (n > 0) { - theByte = pixels[i] & 0x0F; - if (high) { - data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); - } else { - data[index] = (byte)((data[index] & 0xF0) | theByte); - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - high = true; - srcX = 0; - } else { - if (!high) index++; - high = !high; - } - } - return; - } - if (depth == 8) { - index = (y * bytesPerLine) + x; - for (int j = 0; j < putWidth; j++) { - data[index] = (byte)(pixels[i] & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - return; - } - SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); -} - -/** - * Sets the pixel values starting at offset <code>x</code> in - * scanline <code>y</code> in the receiver's data to the - * values from the array <code>pixels</code> starting at - * <code>startIndex</code>. - * - * @param x the x position of the pixel to set - * @param y the y position of the pixel to set - * @param putWidth the width of the pixels to set - * @param pixels the pixels to set - * @param startIndex the index at which to begin setting - * - * @exception IndexOutOfBoundsException if putWidth is too large - * @exception IllegalArgumentException <ul> - * <li>ERROR_NULL_ARGUMENT - if pixels is null</li> - * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> - * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li> - * </ul> - * @exception SWTException <ul> - * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> - * </ul> - */ -public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) { - if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - if (putWidth == 0) return; - int index; - int theByte; - int mask; - int n = putWidth; - int i = startIndex; - int pixel; - int srcX = x, srcY = y; - if (depth == 1) { - index = (y * bytesPerLine) + (x >> 3); - while (n > 0) { - mask = 1 << (7 - (srcX & 0x7)); - if ((pixels[i] & 0x1) == 1) { - data[index] = (byte)((data[index] & 0xFF) | mask); - } else { - data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - if (mask == 1) { - index++; - } - } - } - return; - } - if (depth == 2) { - byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; - index = (y * bytesPerLine) + (x >> 2); - int offset = 3 - (x % 4); - while (n > 0) { - theByte = pixels[i] & 0x3; - data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - offset = 3; - srcX = 0; - } else { - if (offset == 0) { - index++; - offset = 3; - } else { - offset--; - } - } - } - return; - } - if (depth == 4) { - index = (y * bytesPerLine) + (x >> 1); - boolean high = (x & 0x1) == 0; - while (n > 0) { - theByte = pixels[i] & 0x0F; - if (high) { - data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); - } else { - data[index] = (byte)((data[index] & 0xF0) | theByte); - } - i++; - n--; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - high = true; - srcX = 0; - } else { - if (!high) index++; - high = !high; - } - } - return; - } - if (depth == 8) { - index = (y * bytesPerLine) + x; - for (int j = 0; j < putWidth; j++) { - data[index] = (byte)(pixels[i] & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index++; - } - } - return; - - } - if (depth == 16) { - index = (y * bytesPerLine) + (x * 2); - for (int j = 0; j < putWidth; j++) { - pixel = pixels[i]; - data[index] = (byte)(pixel & 0xFF); - data[index + 1] = (byte)((pixel >> 8) & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 2; - } - } - return; - } - if (depth == 24) { - index = (y * bytesPerLine) + (x * 3); - for (int j = 0; j < putWidth; j++) { - pixel = pixels[i]; - data[index] = (byte)((pixel >> 16) & 0xFF); - data[index + 1] = (byte)((pixel >> 8) & 0xFF); - data[index + 2] = (byte)(pixel & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 3; - } - } - return; - } - if (depth == 32) { - index = (y * bytesPerLine) + (x * 4); - for (int j = 0; j < putWidth; j++) { - pixel = pixels[i]; - data[index] = (byte)((pixel >> 24) & 0xFF); - data[index + 1] = (byte)((pixel >> 16) & 0xFF); - data[index + 2] = (byte)((pixel >> 8) & 0xFF); - data[index + 3] = (byte)(pixel & 0xFF); - i++; - srcX++; - if (srcX >= width) { - srcY++; - index = srcY * bytesPerLine; - srcX = 0; - } else { - index += 4; - } - } - return; - } - SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); -} - -/** - * Returns a palette with 2 colors: black & white. - */ -static PaletteData bwPalette() { - return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)}); -} - -/** - * Gets the offset of the most significant bit for - * the given mask. - */ -static int getMSBOffset(int mask) { - for (int i = 31; i >= 0; i--) { - if (((mask >> i) & 0x1) != 0) return i + 1; - } - return 0; -} - -/** - * Finds the closest match. - */ -static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) { - if (depth > 8) { - int rshift = 32 - getMSBOffset(redMask); - int gshift = 32 - getMSBOffset(greenMask); - int bshift = 32 - getMSBOffset(blueMask); - return (((red << 24) >>> rshift) & redMask) | - (((green << 24) >>> gshift) & greenMask) | - (((blue << 24) >>> bshift) & blueMask); - } - int r, g, b; - int minDistance = 0x7fffffff; - int nearestPixel = 0; - int n = reds.length; - for (int j = 0; j < n; j++) { - r = (reds[j] & 0xFF) - (red & 0xFF); - g = (greens[j] & 0xFF) - (green & 0xFF); - b = (blues[j] & 0xFF) - (blue & 0xFF); - int distance = r*r + g*g + b*b; - if (distance < minDistance) { - nearestPixel = j; - if (distance == 0) break; - minDistance = distance; - } - } - return nearestPixel; -} - -static final ImageData convertMask(ImageData mask) { - if (mask.depth == 1) return mask; - PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); - ImageData newMask = new ImageData(mask.width, mask.height, 1, palette); - /* Find index of black in mask palette */ - int blackIndex = 0; - RGB[] rgbs = mask.getRGBs(); - if (rgbs != null) { - while (blackIndex < rgbs.length) { - if (rgbs[blackIndex].equals(palette.colors[0])) break; - blackIndex++; - } - } - int[] pixels = new int[mask.width]; - for (int y = 0; y < mask.height; y++) { - mask.getPixels(0, y, mask.width, pixels, 0); - for (int i = 0; i < pixels.length; i++) { - if (pixels[i] == blackIndex) { - pixels[i] = 0; - } else { - pixels[i] = 1; - } - } - newMask.setPixels(0, y, mask.width, pixels, 0); - } - return newMask; -} - -static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { - if (pad == 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, stride); - srcIndex += bpl; - destIndex += newBpl; - } - return newData; -} - -/** - * Blit operation bits to be OR'ed together to specify the desired operation. - */ -static final int - BLIT_SRC = 1, // copy source directly, else applies logic operations - BLIT_ALPHA = 2, // enable alpha blending - BLIT_DITHER = 4; // enable dithering in low color modes - -/** - * Alpha mode, values 0 - 255 specify global alpha level - */ -static final int - ALPHA_OPAQUE = 255, // Fully opaque (ignores any alpha data) - ALPHA_TRANSPARENT = 0, // Fully transparent (ignores any alpha data) - ALPHA_CHANNEL_SEPARATE = -1, // Use alpha channel from separate alphaData - ALPHA_CHANNEL_SOURCE = -2, // Use alpha channel embedded in sourceData - ALPHA_MASK_UNPACKED = -3, // Use transparency mask formed by bytes in alphaData (non-zero is opaque) - ALPHA_MASK_PACKED = -4, // Use transparency mask formed by packed bits in alphaData - ALPHA_MASK_INDEX = -5, // Consider source palette indices transparent if in alphaData array - ALPHA_MASK_RGB = -6; // Consider source RGBs transparent if in RGB888 format alphaData array - -/** - * Byte and bit order constants. - */ -static final int LSB_FIRST = 0; -static final int MSB_FIRST = 1; - -/** - * Data types (internal) - */ -private static final int - // direct / true color formats with arbitrary masks & shifts - TYPE_GENERIC_8 = 0, - TYPE_GENERIC_16_MSB = 1, - TYPE_GENERIC_16_LSB = 2, - TYPE_GENERIC_24 = 3, - TYPE_GENERIC_32_MSB = 4, - TYPE_GENERIC_32_LSB = 5, - // palette indexed color formats - TYPE_INDEX_8 = 6, - TYPE_INDEX_4 = 7, - TYPE_INDEX_2 = 8, - TYPE_INDEX_1_MSB = 9, - TYPE_INDEX_1_LSB = 10; - -/** - * Computes the required channel shift from a mask. - */ -static int getChannelShift(int mask) { - if (mask == 0) return 0; - int i; - for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) { - mask >>>= 1; - } - return i; -} - -/** - * Computes the required channel width (depth) from a mask. - */ -static int getChannelWidth(int mask, int shift) { - if (mask == 0) return 0; - int i; - mask >>>= shift; - for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) { - mask >>>= 1; - } - return i - shift; -} - -/** - * Extracts a field from packed RGB data given a mask for that field. - */ -static byte getChannelField(int data, int mask) { - final int shift = getChannelShift(mask); - return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift]; -} - -/* - * Fill in dithered gradated values for a color channel - */ -static final void buildDitheredGradientChannel(int from, int to, int steps, - int bandWidth, int bandHeight, boolean vertical, - byte[] bitmapData, int dp, int bytesPerLine, int bits) { - final int mask = 0xff00 >>> bits; - int val = from << 16; - final int inc = ((to << 16) - val) / steps + 1; - if (vertical) { - for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) { - for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) { - final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits; - int temp = val + thresh; - if (temp > 0xffffff) bitmapData[dptr] = -1; - else bitmapData[dptr] = (byte)((temp >>> 16) & mask); - } - val += inc; - } - } else { - for (int dx = 0; dx < bandWidth; ++dx, dp += 4) { - for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) { - final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits; - int temp = val + thresh; - if (temp > 0xffffff) bitmapData[dptr] = -1; - else bitmapData[dptr] = (byte)((temp >>> 16) & mask); - } - val += inc; - } - } -} -} - -static class LEDataInputStream extends InputStream { - int position; - InputStream in; - - /** - * The byte array containing the bytes to read. - */ - protected byte[] buf; - - /** - * The current position within the byte array <code>buf</code>. A value - * equal to buf.length indicates no bytes available. A value of - * 0 indicates the buffer is full. - */ - protected int pos; - - - public LEDataInputStream(InputStream input) { - this(input, 512); - } - - public LEDataInputStream(InputStream input, int bufferSize) { - this.in = input; - if (bufferSize > 0) { - buf = new byte[bufferSize]; - pos = bufferSize; - } - else throw new IllegalArgumentException(); - } - - public void close() throws IOException { - buf = null; - if (in != null) { - in.close(); - in = null; - } - } - - /** - * Answer how many bytes were read. - */ - public int getPosition() { - return position; - } - - /** - * Answers how many bytes are available for reading without blocking - */ - public int available() throws IOException { - if (buf == null) throw new IOException(); - return (buf.length - pos) + in.available(); - } - - /** - * Answer the next byte of the input stream. - */ - public int read() throws IOException { - if (buf == null) throw new IOException(); - position++; - if (pos < buf.length) return (buf[pos++] & 0xFF); - return in.read(); - } - - /** - * Don't imitate the JDK behaviour of reading a random number - * of bytes when you can actually read them all. - */ - public int read(byte b[], int off, int len) throws IOException { - int result; - int left = len; - result = readData(b, off, len); - while (true) { - if (result == -1) return -1; - position += result; - if (result == left) return len; - left -= result; - off += result; - result = readData(b, off, left); - } - } - - /** - * Reads at most <code>length</code> bytes from this LEDataInputStream and - * stores them in byte array <code>buffer</code> starting at <code>offset</code>. - * <p> - * Answer the number of bytes actually read or -1 if no bytes were read and - * end of stream was encountered. This implementation reads bytes from - * the pushback buffer first, then the target stream if more bytes are required - * to satisfy <code>count</code>. - * </p> - * @param buffer the byte array in which to store the read bytes. - * @param offset the offset in <code>buffer</code> to store the read bytes. - * @param length the maximum number of bytes to store in <code>buffer</code>. - * - * @return int the number of bytes actually read or -1 if end of stream. - * - * @exception java.io.IOException if an IOException occurs. - */ - private int readData(byte[] buffer, int offset, int length) throws IOException { - if (buf == null) throw new IOException(); - if (offset < 0 || offset > buffer.length || - length < 0 || (length > buffer.length - offset)) { - throw new ArrayIndexOutOfBoundsException(); - } - - int cacheCopied = 0; - int newOffset = offset; - - // Are there pushback bytes available? - int available = buf.length - pos; - if (available > 0) { - cacheCopied = (available >= length) ? length : available; - System.arraycopy(buf, pos, buffer, newOffset, cacheCopied); - newOffset += cacheCopied; - pos += cacheCopied; - } - - // Have we copied enough? - if (cacheCopied == length) return length; - - int inCopied = in.read(buffer, newOffset, length - cacheCopied); - - if (inCopied > 0) return inCopied + cacheCopied; - if (cacheCopied == 0) return inCopied; - return cacheCopied; - } - - /** - * Answer an integer comprised of the next - * four bytes of the input stream. - */ - public int readInt() throws IOException { - byte[] buf = new byte[4]; - read(buf); - return ((((((buf[3] & 0xFF) << 8) | - (buf[2] & 0xFF)) << 8) | - (buf[1] & 0xFF)) << 8) | - (buf[0] & 0xFF); - } - - /** - * Answer a short comprised of the next - * two bytes of the input stream. - */ - public short readShort() throws IOException { - byte[] buf = new byte[2]; - read(buf); - return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF)); - } - - /** - * Push back the entire content of the given buffer <code>b</code>. - * <p> - * The bytes are pushed so that they would be read back b[0], b[1], etc. - * If the push back buffer cannot handle the bytes copied from <code>b</code>, - * an IOException will be thrown and no byte will be pushed back. - * </p> - * - * @param b the byte array containing bytes to push back into the stream - * - * @exception java.io.IOException if the pushback buffer is too small - */ - public void unread(byte[] b) throws IOException { - int length = b.length; - if (length > pos) throw new IOException(); - position -= length; - pos -= length; - System.arraycopy(b, 0, buf, pos, length); - } -} -public static abstract class FileFormat { - LEDataInputStream inputStream; - ImageLoader loader; - int compression; - -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; -} - -/** - * Return whether or not the specified input stream - * represents a supported file format. - */ -abstract boolean isFileFormat(LEDataInputStream stream); - -abstract ImageData[] loadFromByteStream(); - -public ImageData[] loadFromStream(LEDataInputStream stream) { - try { - inputStream = stream; - return loadFromByteStream(); - } catch (Exception e) { - SWT.error(SWT.ERROR_IO, e); - return null; - } -} - -public static ImageData[] load(InputStream is, ImageLoader loader) { - LEDataInputStream stream = new LEDataInputStream(is); - boolean isSupported = false; - FileFormat fileFormat = new WinICOFileFormat(); - if (fileFormat.isFileFormat(stream)) isSupported = true; - else { - fileFormat = new WinBMPFileFormat(); - if (fileFormat.isFileFormat(stream)) isSupported = true; - } - if (!isSupported) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); - fileFormat.loader = loader; - return fileFormat.loadFromStream(stream); -} -} -static class WinBMPFileFormat extends FileFormat { - static final int BMPFileHeaderSize = 14; - static final int BMPHeaderFixedSize = 40; - int importantColors; - -void decompressData(byte[] src, byte[] dest, int stride, int cmp) { - if (cmp == 1) { // BMP_RLE8_COMPRESSION - if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0) - SWT.error(SWT.ERROR_INVALID_IMAGE); - return; - } - if (cmp == 2) { // BMP_RLE4_COMPRESSION - if (decompressRLE4Data(src, src.length, stride, dest, dest.length) <= 0) - SWT.error(SWT.ERROR_INVALID_IMAGE); - return; - } - SWT.error(SWT.ERROR_INVALID_IMAGE); -} -int decompressRLE4Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) { - int sp = 0; - int se = numBytes; - int dp = 0; - int de = destSize; - int x = 0, y = 0; - while (sp < se) { - int len = src[sp] & 0xFF; - sp++; - if (len == 0) { - len = src[sp] & 0xFF; - sp++; - switch (len) { - case 0: /* end of line */ - y++; - x = 0; - dp = y * stride; - if (dp >= de) - return -1; - break; - case 1: /* end of bitmap */ - return 1; - case 2: /* delta */ - x += src[sp] & 0xFF; - sp++; - y += src[sp] & 0xFF; - sp++; - dp = y * stride + x / 2; - if (dp >= de) - return -1; - break; - default: /* absolute mode run */ - if ((len & 1) != 0) /* odd run lengths not currently supported */ - return -1; - x += len; - len = len / 2; - if (len > (se - sp)) - return -1; - if (len > (de - dp)) - return -1; - for (int i = 0; i < len; i++) { - dest[dp] = src[sp]; - dp++; - sp++; - } - if ((sp & 1) != 0) - sp++; /* word align sp? */ - break; - } - } else { - if ((len & 1) != 0) - return -1; - x += len; - len = len / 2; - byte theByte = src[sp]; - sp++; - if (len > (de - dp)) - return -1; - for (int i = 0; i < len; i++) { - dest[dp] = theByte; - dp++; - } - } - } - return 1; -} -int decompressRLE8Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) { - int sp = 0; - int se = numBytes; - int dp = 0; - int de = destSize; - int x = 0, y = 0; - while (sp < se) { - int len = src[sp] & 0xFF; - sp++; - if (len == 0) { - len = src[sp] & 0xFF; - sp++; - switch (len) { - case 0: /* end of line */ - y++; - x = 0; - dp = y * stride; - if (dp >= de) - return -1; - break; - case 1: /* end of bitmap */ - return 1; - case 2: /* delta */ - x += src[sp] & 0xFF; - sp++; - y += src[sp] & 0xFF; - sp++; - dp = y * stride + x; - if (dp >= de) - return -1; - break; - default: /* absolute mode run */ - if (len > (se - sp)) - return -1; - if (len > (de - dp)) - return -1; - for (int i = 0; i < len; i++) { - dest[dp] = src[sp]; - dp++; - sp++; - } - if ((sp & 1) != 0) - sp++; /* word align sp? */ - x += len; - break; - } - } else { - byte theByte = src[sp]; - sp++; - if (len > (de - dp)) - return -1; - for (int i = 0; i < len; i++) { - dest[dp] = theByte; - dp++; - } - x += len; - } - } - return 1; -} -boolean isFileFormat(LEDataInputStream stream) { - try { - byte[] header = new byte[18]; - stream.read(header); - stream.unread(header); - int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24); - return header[0] == 0x42 && header[1] == 0x4D && infoHeaderSize >= BMPHeaderFixedSize; - } catch (Exception e) { - return false; - } -} -byte[] loadData(byte[] 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); - int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); - int stride = (width * bitCount + 7) / 8; - stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple - byte[] data = loadData(infoHeader, stride); - flipScanLines(data, stride, height); - return data; -} -byte[] loadData(byte[] infoHeader, int stride) { - int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); - int dataSize = height * stride; - byte[] data = new byte[dataSize]; - int cmp = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24); - if (cmp == 0) { // BMP_NO_COMPRESSION - try { - if (inputStream.read(data) != dataSize) - SWT.error(SWT.ERROR_INVALID_IMAGE); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - } else { - int compressedSize = (infoHeader[20] & 0xFF) | ((infoHeader[21] & 0xFF) << 8) | ((infoHeader[22] & 0xFF) << 16) | ((infoHeader[23] & 0xFF) << 24); - byte[] compressed = new byte[compressedSize]; - try { - if (inputStream.read(compressed) != compressedSize) - SWT.error(SWT.ERROR_INVALID_IMAGE); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - decompressData(compressed, data, stride, cmp); - } - return data; -} -int[] loadFileHeader() { - int[] header = new int[5]; - try { - header[0] = inputStream.readShort(); - header[1] = inputStream.readInt(); - header[2] = inputStream.readShort(); - header[3] = inputStream.readShort(); - header[4] = inputStream.readInt(); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - if (header[0] != 0x4D42) - SWT.error(SWT.ERROR_INVALID_IMAGE); - return header; -} -ImageData[] loadFromByteStream() { - int[] fileHeader = loadFileHeader(); - byte[] infoHeader = new byte[BMPHeaderFixedSize]; - try { - inputStream.read(infoHeader); - } catch (Exception e) { - SWT.error(SWT.ERROR_IO, e); - } - 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); - int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); - PaletteData palette = loadPalette(infoHeader); - if (inputStream.getPosition() < fileHeader[4]) { - // Seek to the specified offset - try { - inputStream.skip(fileHeader[4] - inputStream.getPosition()); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - } - byte[] data = loadData(infoHeader); - this.compression = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24); - this.importantColors = (infoHeader[36] & 0xFF) | ((infoHeader[37] & 0xFF) << 8) | ((infoHeader[38] & 0xFF) << 16) | ((infoHeader[39] & 0xFF) << 24); - int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24); - int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24); - int type = (this.compression == 1 /*BMP_RLE8_COMPRESSION*/) || (this.compression == 2 - -/*BMP_RLE4_COMPRESSION*/) ? SWT.IMAGE_BMP_RLE : SWT.IMAGE_BMP; - return new ImageData[] { - ImageData.internal_new( - width, - height, - bitCount, - palette, - 4, - data, - 0, - null, - null, - -1, - -1, - type, - 0, - 0, - 0, - 0) - }; -} -PaletteData loadPalette(byte[] infoHeader) { - int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); - if (depth <= 8) { - int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24); - if (numColors == 0) { - numColors = 1 << depth; - } else { - if (numColors > 256) - numColors = 256; - } - byte[] buf = new byte[numColors * 4]; - try { - if (inputStream.read(buf) != buf.length) - SWT.error(SWT.ERROR_INVALID_IMAGE); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - return paletteFromBytes(buf, numColors); - } - if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F); - if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000); - return new PaletteData(0xFF00, 0xFF0000, 0xFF000000); -} -PaletteData paletteFromBytes(byte[] bytes, int numColors) { - int bytesOffset = 0; - RGB[] colors = new RGB[numColors]; - for (int i = 0; i < numColors; i++) { - colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF, - bytes[bytesOffset + 1] & 0xFF, - bytes[bytesOffset] & 0xFF); - bytesOffset += 4; - } - return new PaletteData(colors); -} -/** - * Answer a byte array containing the BMP representation of - * the given device independent palette. - */ -static byte[] paletteToBytes(PaletteData pal) { - int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256); - byte[] bytes = new byte[n * 4]; - int offset = 0; - for (int i = 0; i < n; i++) { - RGB col = pal.colors[i]; - bytes[offset] = (byte)col.blue; - bytes[offset + 1] = (byte)col.green; - bytes[offset + 2] = (byte)col.red; - offset += 4; - } - return bytes; -} - -void flipScanLines(byte[] data, int stride, int height) { - int i1 = 0; - int i2 = (height - 1) * stride; - for (int i = 0; i < height / 2; i++) { - for (int index = 0; index < stride; index++) { - byte b = data[index + i1]; - data[index + i1] = data[index + i2]; - data[index + i2] = b; - } - i1 += stride; - i2 -= stride; - } -} - -} - -static class WinICOFileFormat extends FileFormat { - -static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { - if (pad == 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 != null ? i.palette.colors.length * 4 : 0; - return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize; -} -boolean isFileFormat(LEDataInputStream stream) { - try { - byte[] header = new byte[4]; - stream.read(header); - stream.unread(header); - return header[0] == 0 && header[1] == 0 && header[2] == 1 && header[3] == 0; - } catch (Exception e) { - return false; - } -} -boolean 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 == 2 || size == 16 || size == 32 || size == 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) { - SWT.error(SWT.ERROR_IO, e); - } - if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) - SWT.error(SWT.ERROR_INVALID_IMAGE); - int numIcons = fileHeader[2]; - if (numIcons <= 0) - SWT.error(SWT.ERROR_INVALID_IMAGE); - return numIcons; -} -int loadFileHeader(LEDataInputStream byteStream, boolean 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) { - SWT.error(SWT.ERROR_IO, e); - } - if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) - SWT.error(SWT.ERROR_INVALID_IMAGE); - int numIcons = fileHeader[2]; - if (numIcons <= 0) - SWT.error(SWT.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); - 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, - SWT.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) { - SWT.error(SWT.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 == 0) numColors = 256; // this is specified: '00' represents '256' (0x100) colors - if ((numColors != 2) && (numColors != 8) && (numColors != 16) && - (numColors != 32) && (numColors != 256)) - SWT.error(SWT.ERROR_INVALID_IMAGE); - if (inputStream.getPosition() < iconHeader[6]) { - // Seek to the specified offset - try { - inputStream.skip(iconHeader[6] - inputStream.getPosition()); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - return null; - } - } - byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize]; - try { - inputStream.read(infoHeader); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) != 1) - SWT.error(SWT.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 == infoHeight && bitCount == 1) height /= 2; - if (!((width == infoWidth) && (height * 2 == infoHeight) && - (bitCount == 1 || bitCount == 4 || bitCount == 8 || bitCount == 24 || bitCount == 32))) - SWT.error(SWT.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; -} -} -static class SWT { - public static final int IMAGE_ICO = 3; - public static final int ERROR_IO = 39; - public static final int ERROR_INVALID_IMAGE = 40; - public static final int ERROR_NULL_ARGUMENT = 4; - public static final int ERROR_INVALID_ARGUMENT = 5; - public static final int ERROR_CANNOT_BE_ZERO = 7; - public static final int IMAGE_UNDEFINED = -1; - public static final int ERROR_UNSUPPORTED_DEPTH = 38; - public static final int TRANSPARENCY_MASK = 1 << 1; - public static final int ERROR_UNSUPPORTED_FORMAT = 42; - public static final int TRANSPARENCY_ALPHA = 1 << 0; - public static final int TRANSPARENCY_NONE = 0x0; - public static final int TRANSPARENCY_PIXEL = 1 << 2; - public static final int IMAGE_BMP = 0; - public static final int IMAGE_BMP_RLE = 1; - - public static void error(int code) { - throw new RuntimeException("Error "+code); - } - public static void error(int code, Throwable t) { - throw new RuntimeException(t); - } -} -} |