1 11 package org.eclipse.swt.tools.internal; 12 13 import java.io.*; 14 import java.util.*; 15 16 24 public class IconExe { 25 26 51 public static void main(String [] args) throws Exception { 52 if (args.length < 2) { 53 System.err.println("Usage: IconExe <windows executable> <ico file>"); 54 return; 55 } 56 ImageLoader loader = new ImageLoader(); 57 58 List images = new ArrayList(); 59 for (int i = 1; i < args.length; i++) { 60 try { 61 ImageData[] current = loader.load(args[i]); 63 for (int j = 0; j < current.length; j++) { 64 images.add(current[j]); 65 } 66 } catch (RuntimeException e) { 67 } 69 } 70 ImageData[] data = new ImageData[images.size()]; 71 data = (ImageData[]) images.toArray(data); 72 73 int nMissing = unloadIcons(args[0], data); 74 if (nMissing != 0) 75 System.err.println("Error - " + nMissing + " icon(s) not replaced in " + args[0] + " using " + args[1]); 76 } 77 78 79 80 94 static ImageData[] loadIcons(String program) throws FileNotFoundException, IOException { 95 RandomAccessFile raf = new RandomAccessFile(program, "r"); 96 IconExe iconExe = new IconExe(); 97 IconResInfo[] iconInfo = iconExe.getIcons(raf); 98 ImageData[] data = new ImageData[iconInfo.length]; 99 for (int i = 0; i < data.length; i++) data[i] = iconInfo[i].data; 100 raf.close(); 101 return data; 102 } 103 104 134 static int unloadIcons(String program, ImageData[] icons) throws FileNotFoundException, IOException { 135 RandomAccessFile raf = new RandomAccessFile(program, "rw"); 136 IconExe iconExe = new IconExe(); 137 IconResInfo[] iconInfo = iconExe.getIcons(raf); 138 int cnt = 0; 139 for (int i = 0; i < iconInfo.length; i++) { 140 for (int j = 0; j < icons.length; j++) { 141 if (icons[j] == null) 142 continue; 143 if (iconInfo[i].data.width == icons[j].width && iconInfo[i].data.height == icons[j].height && iconInfo[i].data.depth == icons[j].depth) { 144 raf.seek(iconInfo[i].offset); 145 unloadIcon(raf, icons[j]); 146 cnt++; 147 break; 148 } 149 } 150 } 151 raf.close(); 152 return iconInfo.length - cnt; 153 } 154 155 public static final String VERSION = "20050124"; 156 157 static final boolean DEBUG = false; 158 public static class IconResInfo { 159 ImageData data; 160 int offset; 161 int size; 162 } 163 164 IconResInfo[] iconInfo = null; 165 int iconCnt; 166 167 IconResInfo[] getIcons(RandomAccessFile raf) throws IOException { 168 iconInfo = new IconResInfo[4]; 169 iconCnt = 0; 170 IMAGE_DOS_HEADER imageDosHeader = new IMAGE_DOS_HEADER(); 171 read(raf, imageDosHeader); 172 if (imageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) return null; 173 int imageNtHeadersOffset = imageDosHeader.e_lfanew; 174 raf.seek(imageNtHeadersOffset); 175 IMAGE_NT_HEADERS imageNtHeaders = new IMAGE_NT_HEADERS(); 176 read(raf, imageNtHeaders); 177 if (imageNtHeaders.Signature != IMAGE_NT_SIGNATURE) return null; 178 179 int resourcesRVA = imageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; 181 if (resourcesRVA == 0) return null; 182 if (DEBUG) System.out.println("* Resources (RVA= "+resourcesRVA+")"); 183 IMAGE_SECTION_HEADER imageSectionHeader = new IMAGE_SECTION_HEADER(); 184 int firstSectionOffset = imageNtHeadersOffset + IMAGE_NT_HEADERS.FIELD_OFFSET_OptionalHeader + imageNtHeaders.FileHeader.SizeOfOptionalHeader; 185 raf.seek(firstSectionOffset); 186 boolean found = false; 187 for (int i = 0; i < imageNtHeaders.FileHeader.NumberOfSections; i++) { 188 read(raf, imageSectionHeader); 189 if (resourcesRVA >= imageSectionHeader.VirtualAddress && resourcesRVA < imageSectionHeader.VirtualAddress + imageSectionHeader.Misc_VirtualSize) { 190 found = true; 192 break; 193 } 194 } 195 if (!found) return null; 196 int delta = imageSectionHeader.VirtualAddress - imageSectionHeader.PointerToRawData; 197 int imageResourceDirectoryOffset = resourcesRVA - delta; 198 dumpResourceDirectory(raf, imageResourceDirectoryOffset, imageResourceDirectoryOffset, delta, 0, 0, false); 199 if (iconCnt < iconInfo.length) { 200 IconResInfo[] newArray = new IconResInfo[iconCnt]; 201 System.arraycopy(iconInfo, 0, newArray, 0, iconCnt); 202 iconInfo = newArray; 203 } 204 return iconInfo; 205 } 206 207 void dumpResourceDirectory(RandomAccessFile raf, int imageResourceDirectoryOffset, int resourceBase, int delta, int type, int level, boolean rt_icon_root) throws IOException { 208 if (DEBUG) System.out.println("** LEVEL "+level); 209 210 IMAGE_RESOURCE_DIRECTORY imageResourceDirectory = new IMAGE_RESOURCE_DIRECTORY(); 211 raf.seek(imageResourceDirectoryOffset); 212 read(raf, imageResourceDirectory); 213 214 if (DEBUG) { 215 String sType = ""+type; 216 if (level == 1) { 218 System.out.println("___________________________"); 219 if (type == RT_ICON) sType = "RT_ICON"; 220 if (type == RT_GROUP_ICON) sType = "RT_GROUP_ICON"; 221 } 222 System.out.println("Resource Directory ["+sType+"]"+" (Named "+imageResourceDirectory.NumberOfNamedEntries+", ID "+imageResourceDirectory.NumberOfIdEntries+")"); 223 } 224 int IRDE_StartOffset = imageResourceDirectoryOffset + IMAGE_RESOURCE_DIRECTORY.SIZEOF; 225 IMAGE_RESOURCE_DIRECTORY_ENTRY[] imageResourceDirectoryEntries = new IMAGE_RESOURCE_DIRECTORY_ENTRY[imageResourceDirectory.NumberOfIdEntries]; 226 for (int i = 0; i < imageResourceDirectoryEntries.length; i++) { 227 imageResourceDirectoryEntries[i] = new IMAGE_RESOURCE_DIRECTORY_ENTRY(); 228 read(raf, imageResourceDirectoryEntries[i]); 229 } 230 for (int i = 0; i < imageResourceDirectoryEntries.length; i++) { 231 if (imageResourceDirectoryEntries[i].DataIsDirectory) { 232 dumpResourceDirectory(raf, imageResourceDirectoryEntries[i].OffsetToDirectory + resourceBase, resourceBase, delta, imageResourceDirectoryEntries[i].Id, level + 1, rt_icon_root ? true : type == RT_ICON); 233 } else { 234 IMAGE_RESOURCE_DIRECTORY_ENTRY irde = imageResourceDirectoryEntries[i]; 237 IMAGE_RESOURCE_DATA_ENTRY data = new IMAGE_RESOURCE_DATA_ENTRY(); 238 raf.seek(imageResourceDirectoryEntries[i].OffsetToData + resourceBase); 239 read(raf, data); 240 if (DEBUG) System.out.println("Resource Id "+irde.Id+" Data Offset RVA "+data.OffsetToData+", Size "+data.Size); 241 if (rt_icon_root) { 242 if (DEBUG) System.out.println("iconcnt "+iconCnt+" |"+iconInfo.length); 243 iconInfo[iconCnt] = new IconResInfo(); 244 iconInfo[iconCnt].data = parseIcon(raf, data.OffsetToData - delta, data.Size); 245 iconInfo[iconCnt].offset = data.OffsetToData - delta; 246 iconInfo[iconCnt].size = data.Size; 247 iconCnt++; 248 if (iconCnt == iconInfo.length) { 249 IconResInfo[] newArray = new IconResInfo[iconInfo.length + 4]; 250 System.arraycopy(iconInfo, 0, newArray, 0, iconInfo.length); 251 iconInfo = newArray; 252 } 253 } 254 } 255 } 256 } 257 258 static ImageData parseIcon(RandomAccessFile raf, int offset, int size) throws IOException { 259 raf.seek(offset); 260 BITMAPINFO bitmapInfo = new BITMAPINFO(); 261 read(raf, bitmapInfo); 262 bitmapInfo.bmiHeader.biHeight /= 2; 263 int width = bitmapInfo.bmiHeader.biWidth; 264 int height = bitmapInfo.bmiHeader.biHeight; 265 int depth = bitmapInfo.bmiHeader.biBitCount; 266 267 PaletteData palette = loadPalette(bitmapInfo.bmiHeader, raf); 268 byte[] shapeData = loadData(bitmapInfo.bmiHeader, raf); 269 bitmapInfo.bmiHeader.biBitCount = 1; 270 byte[] maskData = loadData(bitmapInfo.bmiHeader, raf); 271 maskData = convertPad(maskData, width, height, 1, 4, 2); 272 bitInvertData(maskData, 0, maskData.length); 273 return ImageData.internal_new( 274 width, 275 height, 276 depth, 277 palette, 278 4, 279 shapeData, 280 2, 281 maskData, 282 null, 283 -1, 284 -1, 285 SWT.IMAGE_ICO, 286 0, 287 0, 288 0, 289 0); 290 } 291 292 static byte[] bitInvertData(byte[] data, int startIndex, int endIndex) { 293 for (int i = startIndex; i < endIndex; i++) { 295 data[i] = (byte)(255 - data[i - startIndex]); 296 } 297 return data; 298 } 299 300 static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { 301 if (pad == newPad) return data; 302 int stride = (width * depth + 7) / 8; 303 int bpl = (stride + (pad - 1)) / pad * pad; 304 int newBpl = (stride + (newPad - 1)) / newPad * newPad; 305 byte[] newData = new byte[height * newBpl]; 306 int srcIndex = 0, destIndex = 0; 307 for (int y = 0; y < height; y++) { 308 System.arraycopy(data, srcIndex, newData, destIndex, newBpl); 309 srcIndex += bpl; 310 destIndex += newBpl; 311 } 312 return newData; 313 } 314 static PaletteData loadPalette(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException { 315 int depth = bih.biBitCount; 316 if (depth <= 8) { 317 int numColors = bih.biClrUsed; 318 if (numColors == 0) { 319 numColors = 1 << depth; 320 } else { 321 if (numColors > 256) 322 numColors = 256; 323 } 324 byte[] buf = new byte[numColors * 4]; 325 raf.read(buf); 326 return paletteFromBytes(buf, numColors); 327 } 328 if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F); 329 if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000); 330 return new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 331 } 332 static PaletteData paletteFromBytes(byte[] bytes, int numColors) { 333 int bytesOffset = 0; 334 RGB[] colors = new RGB[numColors]; 335 for (int i = 0; i < numColors; i++) { 336 colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF, 337 bytes[bytesOffset + 1] & 0xFF, 338 bytes[bytesOffset] & 0xFF); 339 bytesOffset += 4; 340 } 341 return new PaletteData(colors); 342 } 343 static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException { 344 int stride = (bih.biWidth * bih.biBitCount + 7) / 8; 345 stride = (stride + 3) / 4 * 4; byte[] data = loadData(bih, raf, stride); 347 flipScanLines(data, stride, bih.biHeight); 348 return data; 349 } 350 static void flipScanLines(byte[] data, int stride, int height) { 351 int i1 = 0; 352 int i2 = (height - 1) * stride; 353 for (int i = 0; i < height / 2; i++) { 354 for (int index = 0; index < stride; index++) { 355 byte b = data[index + i1]; 356 data[index + i1] = data[index + i2]; 357 data[index + i2] = b; 358 } 359 i1 += stride; 360 i2 -= stride; 361 } 362 } 363 static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf, int stride) throws IOException { 364 int dataSize = bih.biHeight * stride; 365 byte[] data = new byte[dataSize]; 366 int cmp = bih.biCompression; 367 if (cmp == 0) { raf.read(data); 369 } else { 370 if (DEBUG) System.out.println("ICO cannot be compressed?"); 371 } 372 return data; 373 } 374 375 static void unloadIcon(RandomAccessFile raf, ImageData icon) throws IOException { 376 int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) + 377 ((icon.width + 31) / 32 * 4)) * icon.height; 378 write4(raf, BMPHeaderFixedSize); 379 write4(raf, icon.width); 380 write4(raf, icon.height * 2); 381 writeU2(raf, 1); 382 writeU2(raf, icon.depth); 383 write4(raf, 0); 384 write4(raf, sizeImage); 385 write4(raf, 0); 386 write4(raf, 0); 387 write4(raf, icon.palette.colors != null ? icon.palette.colors.length : 0); 388 write4(raf, 0); 389 390 byte[] rgbs = paletteToBytes(icon.palette); 391 raf.write(rgbs); 392 unloadShapeData(raf, icon); 393 unloadMaskData(raf, icon); 394 } 395 static byte[] paletteToBytes(PaletteData pal) { 396 int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256); 397 byte[] bytes = new byte[n * 4]; 398 int offset = 0; 399 for (int i = 0; i < n; i++) { 400 RGB col = pal.colors[i]; 401 bytes[offset] = (byte)col.blue; 402 bytes[offset + 1] = (byte)col.green; 403 bytes[offset + 2] = (byte)col.red; 404 offset += 4; 405 } 406 return bytes; 407 } 408 static void unloadMaskData(RandomAccessFile raf, ImageData icon) { 409 ImageData mask = icon.getTransparencyMask(); 410 int bpl = (icon.width + 7) / 8; 411 int pad = mask.scanlinePad; 412 int srcBpl = (bpl + pad - 1) / pad * pad; 413 int destBpl = (bpl + 3) / 4 * 4; 414 byte[] buf = new byte[destBpl]; 415 int offset = (icon.height - 1) * srcBpl; 416 byte[] data = mask.data; 417 try { 418 for (int i = 0; i < icon.height; i++) { 419 System.arraycopy(data, offset, buf, 0, bpl); 420 bitInvertData(buf, 0, bpl); 421 raf.write(buf, 0, destBpl); 422 offset -= srcBpl; 423 } 424 } catch (IOException e) { 425 SWT.error(SWT.ERROR_IO, e); 426 } 427 } 428 static void unloadShapeData(RandomAccessFile raf, ImageData icon) { 429 int bpl = (icon.width * icon.depth + 7) / 8; 430 int pad = icon.scanlinePad; 431 int srcBpl = (bpl + pad - 1) / pad * pad; 432 int destBpl = (bpl + 3) / 4 * 4; 433 byte[] buf = new byte[destBpl]; 434 int offset = (icon.height - 1) * srcBpl; 435 byte[] data = icon.data; 436 try { 437 for (int i = 0; i < icon.height; i++) { 438 System.arraycopy(data, offset, buf, 0, bpl); 439 raf.write(buf, 0, destBpl); 440 offset -= srcBpl; 441 } 442 } catch (IOException e) { 443 SWT.error(SWT.ERROR_IO, e); 444 } 445 } 446 static boolean readIconGroup(RandomAccessFile raf, int offset, int size) throws IOException { 447 raf.seek(offset); 448 NEWHEADER newHeader = new NEWHEADER(); 449 read(raf, newHeader); 450 if (newHeader.ResType != RES_ICON) return false; 451 RESDIR[] resDir = new RESDIR[newHeader.ResCount]; 452 for (int i = 0; i < newHeader.ResCount; i++) { 453 resDir[i] = new RESDIR(); 454 read(raf, resDir[i]); 455 } 456 return true; 457 } 458 459 static void copyFile(String src, String dst) throws FileNotFoundException, IOException { 460 File srcFile = new File(src); 461 File dstFile = new File(dst); 462 FileInputStream in = new FileInputStream(srcFile); 463 FileOutputStream out = new FileOutputStream(dstFile); 464 int c; 465 while ((c = in.read()) != -1) out.write(c); 466 in.close(); 467 out.close(); 468 } 469 470 471 static final int IMAGE_DOS_SIGNATURE = 0x5a4d; 472 static final int IMAGE_NT_SIGNATURE = 0x00004550; 473 static final int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; 474 static final int RES_ICON = 1; 475 static final int RT_ICON = 3; 476 static final int RT_GROUP_ICON = 14; 477 static final int BMPHeaderFixedSize = 40; 478 479 public static class IMAGE_DOS_HEADER { 480 int e_magic; int e_cblp; int e_cp; int e_crlc; int e_cparhdr; int e_minalloc; int e_maxalloc; int e_ss; int e_sp; int e_csum; int e_ip; int e_cs; int e_lfarlc; int e_ovno; int[] e_res = new int[4]; int e_oemid; int e_oeminfo; int[] e_res2 = new int[10]; int e_lfanew; } 500 501 public static class IMAGE_FILE_HEADER { 502 int Machine; int NumberOfSections; int TimeDateStamp; int PointerToSymbolTable; int NumberOfSymbols; int SizeOfOptionalHeader; int Characteristics; } 510 511 public static class IMAGE_DATA_DIRECTORY { 512 int VirtualAddress; int Size; } 515 516 public static class IMAGE_OPTIONAL_HEADER { 517 int Magic; int MajorLinkerVersion; int MinorLinkerVersion; int SizeOfCode; int SizeOfInitializedData; int SizeOfUninitializedData; int AddressOfEntryPoint; int BaseOfCode; int BaseOfData; int ImageBase; int SectionAlignment; int FileAlignment; int MajorOperatingSystemVersion; int MinorOperatingSystemVersion; int MajorImageVersion; int MinorImageVersion; int MajorSubsystemVersion; int MinorSubsystemVersion; int Win32VersionValue; int SizeOfImage; int SizeOfHeaders; int CheckSum; int Subsystem; int DllCharacteristics; int SizeOfStackReserve; int SizeOfStackCommit; int SizeOfHeapReserve; int SizeOfHeapCommit; int LoaderFlags; int NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16]; 548 } 549 public static class IMAGE_NT_HEADERS { 550 int Signature; IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER(); 552 IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER(); 553 final static int FIELD_OFFSET_OptionalHeader = 24; 554 } 555 556 public static class IMAGE_SECTION_HEADER { 557 int[] Name = new int[8]; int Misc_VirtualSize; int VirtualAddress; int SizeOfRawData; int PointerToRawData; int PointerToRelocations; int PointerToLinenumbers; int NumberOfRelocations; int NumberOfLinenumbers; int Characteristics; } 568 569 public static class IMAGE_RESOURCE_DIRECTORY { 570 int Characteristics; int TimeDateStamp; int MajorVersion; int MinorVersion; int NumberOfNamedEntries; int NumberOfIdEntries; final static int SIZEOF = 16; 577 } 578 579 public static class IMAGE_RESOURCE_DIRECTORY_ENTRY { 580 int NameOffset; boolean NameIsString; int Name; int Id; int OffsetToData; int OffsetToDirectory; boolean DataIsDirectory; } 590 591 public static class IMAGE_RESOURCE_DATA_ENTRY { 592 int OffsetToData; int Size; int CodePage; int Reserved; } 597 598 public static class NEWHEADER { 599 int Reserved; int ResType; int ResCount; } 603 604 public static class ICONRESDIR { 605 int Width; int Height; int ColorCount; int reserved; } 610 611 public static class CURSORDIR { 612 int Width; int Height; } 615 616 public static class RESDIR { 617 ICONRESDIR Icon = new ICONRESDIR(); 619 CURSORDIR Cursor = new CURSORDIR(); 620 int Planes; int BitCount; int BytesInRes; int IconCursorId; } 625 626 public static class BITMAPINFOHEADER { 627 int biSize; int biWidth; int biHeight; int biPlanes; int biBitCount; int biCompression; int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; int biClrUsed; int biClrImportant; } 639 640 static class RGBQUAD { 641 int rgBlue; int rgbGreen; int rgbRed; int rgbReserved; } 646 static class BITMAPINFO { 647 BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER(); 648 RGBQUAD[] bmiColors = null; 649 } 650 static void read(RandomAccessFile raf, BITMAPINFOHEADER bih) throws IOException { 651 bih.biSize = read4(raf); 652 bih.biWidth = read4(raf); 653 bih.biHeight = read4(raf); 654 bih.biPlanes = readU2(raf); 655 bih.biBitCount = readU2(raf); 656 bih.biCompression = read4(raf); 657 bih.biSizeImage = read4(raf); 658 bih.biXPelsPerMeter = read4(raf); 659 bih.biYPelsPerMeter = read4(raf); 660 bih.biClrUsed = read4(raf); 661 bih.biClrImportant = read4(raf); 662 } 663 static void read(RandomAccessFile raf, BITMAPINFO bi) throws IOException { 664 read(raf, bi.bmiHeader); 665 } 666 667 static int readU2(RandomAccessFile raf) throws IOException { 668 int b0 = raf.readByte() & 0xFF; 669 int b1 = raf.readByte() & 0xFF; 670 return (b1 << 8 | b0); 671 } 672 static int read4(RandomAccessFile raf) throws IOException { 673 int b0 = raf.readByte() & 0xFF; 674 int b1 = raf.readByte() & 0xFF; 675 int b2 = raf.readByte() & 0xFF; 676 int b3 = raf.readByte() & 0xFF; 677 return b3 << 24 | b2 << 16 | b1 << 8 | b0; 678 } 679 static void write4(RandomAccessFile raf, int value) throws IOException { 680 raf.write(value & 0xFF); 681 raf.write((value >> 8) & 0xFF); 682 raf.write((value >> 16) & 0xFF); 683 raf.write((value >> 24) & 0xFF); 684 } 685 static void writeU2(RandomAccessFile raf, int value) throws IOException { 686 raf.write(value & 0xFF); 687 raf.write((value >> 8) & 0xFF); 688 } 689 static void read(RandomAccessFile raf, IMAGE_DOS_HEADER idh) throws IOException { 690 idh.e_magic = readU2(raf); 691 idh.e_cblp = readU2(raf); 692 idh.e_cp = readU2(raf); 693 idh.e_crlc = readU2(raf); 694 idh.e_cparhdr = readU2(raf); 695 idh.e_minalloc = readU2(raf); 696 idh.e_maxalloc = readU2(raf); 697 idh.e_ss = readU2(raf); 698 idh.e_sp = readU2(raf); 699 idh.e_csum = readU2(raf); 700 idh.e_ip = readU2(raf); 701 idh.e_cs = readU2(raf); 702 idh.e_lfarlc = readU2(raf); 703 idh.e_ovno = readU2(raf); 704 for (int i = 0; i < idh.e_res.length; i++) idh.e_res[i] = readU2(raf); 705 idh.e_oemid = readU2(raf); 706 idh.e_oeminfo = readU2(raf); 707 for (int i = 0; i < idh.e_res2.length; i++) idh.e_res2[i] = readU2(raf); 708 idh.e_lfanew = read4(raf); 709 } 710 static void read(RandomAccessFile raf, IMAGE_FILE_HEADER ifh) throws IOException { 711 ifh.Machine = readU2(raf); 712 ifh.NumberOfSections = readU2(raf); 713 ifh.TimeDateStamp = read4(raf); 714 ifh.PointerToSymbolTable = read4(raf); 715 ifh.NumberOfSymbols = read4(raf); 716 ifh.SizeOfOptionalHeader = readU2(raf); 717 ifh.Characteristics = readU2(raf); 718 } 719 static void read(RandomAccessFile raf, IMAGE_DATA_DIRECTORY idd) throws IOException { 720 idd.VirtualAddress = read4(raf); 721 idd.Size = read4(raf); 722 } 723 static void read(RandomAccessFile raf, IMAGE_OPTIONAL_HEADER ioh) throws IOException { 724 ioh.Magic = readU2(raf); 725 ioh.MajorLinkerVersion = raf.read(); 726 ioh.MinorLinkerVersion = raf.read(); 727 ioh.SizeOfCode = read4(raf); 728 ioh.SizeOfInitializedData = read4(raf); 729 ioh.SizeOfUninitializedData = read4(raf); 730 ioh.AddressOfEntryPoint = read4(raf); 731 ioh.BaseOfCode = read4(raf); 732 ioh.BaseOfData = read4(raf); 733 ioh.ImageBase = read4(raf); 734 ioh.SectionAlignment = read4(raf); 735 ioh.FileAlignment = read4(raf); 736 ioh.MajorOperatingSystemVersion = readU2(raf); 737 ioh.MinorOperatingSystemVersion = readU2(raf); 738 ioh.MajorImageVersion = readU2(raf); 739 ioh.MinorImageVersion = readU2(raf); 740 ioh.MajorSubsystemVersion = readU2(raf); 741 ioh.MinorSubsystemVersion = readU2(raf); 742 ioh.Win32VersionValue = read4(raf); 743 ioh.SizeOfImage = read4(raf); 744 ioh.SizeOfHeaders = read4(raf); 745 ioh.CheckSum = read4(raf); 746 ioh.Subsystem = readU2(raf); 747 ioh.DllCharacteristics = readU2(raf); 748 ioh.SizeOfStackReserve = read4(raf); 749 ioh.SizeOfStackCommit = read4(raf); 750 ioh.SizeOfHeapReserve = read4(raf); 751 ioh.SizeOfHeapCommit = read4(raf); 752 ioh.LoaderFlags = read4(raf); 753 ioh.NumberOfRvaAndSizes = read4(raf); 754 for (int i = 0 ; i < ioh.DataDirectory.length; i++) { 755 ioh.DataDirectory[i] = new IMAGE_DATA_DIRECTORY(); 756 read(raf, ioh.DataDirectory[i]); 757 } 758 } 759 static void read(RandomAccessFile raf, IMAGE_NT_HEADERS inh) throws IOException { 760 inh.Signature = read4(raf); 761 read(raf, inh.FileHeader); 762 read(raf, inh.OptionalHeader); 763 } 764 static void read(RandomAccessFile raf, IMAGE_SECTION_HEADER ish) throws IOException { 765 for (int i = 0 ; i < ish.Name.length; i++) ish.Name[i] = raf.read(); 766 ish.Misc_VirtualSize = read4(raf); 767 ish.VirtualAddress = read4(raf); 768 ish.SizeOfRawData = read4(raf); 769 ish.PointerToRawData = read4(raf); 770 ish.PointerToRelocations = read4(raf); 771 ish.PointerToLinenumbers = read4(raf); 772 ish.NumberOfRelocations = readU2(raf); 773 ish.NumberOfLinenumbers = readU2(raf); 774 ish.Characteristics = read4(raf); 775 } 776 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY ird) throws IOException { 777 ird.Characteristics = read4(raf); 778 ird.TimeDateStamp = read4(raf); 779 ird.MajorVersion = readU2(raf); 780 ird.MinorVersion = readU2(raf); 781 ird.NumberOfNamedEntries = readU2(raf); 782 ird.NumberOfIdEntries = readU2(raf); 783 } 784 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY_ENTRY irde) throws IOException { 785 irde.Name = read4(raf); 786 irde.OffsetToData = read4(raf); 787 irde.NameOffset = irde.Name & ~ (1 << 31); 789 irde.NameIsString = (irde.Name & (1 << 31)) != 0; 790 irde.Id = irde.Name & 0xFFFF; 791 irde.OffsetToDirectory = irde.OffsetToData & ~ (1 << 31); 792 irde.DataIsDirectory = (irde.OffsetToData & (1 << 31)) != 0; 793 } 794 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DATA_ENTRY irde) throws IOException { 795 irde.OffsetToData = read4(raf); 796 irde.Size = read4(raf); 797 irde.CodePage = read4(raf); 798 irde.Reserved = read4(raf); 799 } 800 static void read(RandomAccessFile raf, NEWHEADER nh) throws IOException { 801 nh.Reserved = readU2(raf); 802 nh.ResType = readU2(raf); 803 nh.ResCount = readU2(raf); 804 } 805 static void read(RandomAccessFile raf, ICONRESDIR i) throws IOException { 806 i.Width = raf.read(); 807 i.Height = raf.read(); 808 i.ColorCount = raf.read(); 809 i.reserved = raf.read(); 810 } 811 static void read(RandomAccessFile raf, CURSORDIR c) throws IOException { 812 c.Width = readU2(raf); 813 c.Height = readU2(raf); 814 } 815 static void read(RandomAccessFile raf, RESDIR rs) throws IOException { 816 long start = raf.getFilePointer(); 817 read(raf, rs.Icon); 818 raf.seek(start); 819 read(raf, rs.Cursor); 820 rs.Planes = readU2(raf); 821 rs.BitCount = readU2(raf); 822 rs.BytesInRes = read4(raf); 823 rs.IconCursorId = readU2(raf); 824 } 825 826 829 830 static class RGB { 831 832 835 public int red; 836 837 840 public int green; 841 842 845 public int blue; 846 847 static final long serialVersionUID = 3258415023461249074L; 848 849 861 public RGB(int red, int green, int blue) { 862 if ((red > 255) || (red < 0) || 863 (green > 255) || (green < 0) || 864 (blue > 255) || (blue < 0)) 865 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 866 this.red = red; 867 this.green = green; 868 this.blue = blue; 869 } 870 871 881 public boolean equals (Object object) { 882 if (object == this) return true; 883 if (!(object instanceof RGB)) return false; 884 RGB rgb = (RGB)object; 885 return (rgb.red == this.red) && (rgb.green == this.green) && (rgb.blue == this.blue); 886 } 887 888 898 public int hashCode () { 899 return (blue << 16) | (green << 8) | red; 900 } 901 902 908 public String toString () { 909 return "RGB {" + red + ", " + green + ", " + blue + "}"; 911 } 913 914 } 915 static class PaletteData { 916 917 921 public boolean isDirect; 922 923 927 public RGB[] colors; 928 929 932 public int redMask; 933 934 937 public int greenMask; 938 939 942 public int blueMask; 943 944 947 public int redShift; 948 949 952 public int greenShift; 953 954 957 public int blueShift; 958 959 968 public PaletteData(RGB[] colors) { 969 if (colors == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 970 this.colors = colors; 971 this.isDirect = false; 972 } 973 974 981 public PaletteData(int redMask, int greenMask, int blueMask) { 982 this.redMask = redMask; 983 this.greenMask = greenMask; 984 this.blueMask = blueMask; 985 this.isDirect = true; 986 this.redShift = shiftForMask(redMask); 987 this.greenShift = shiftForMask(greenMask); 988 this.blueShift = shiftForMask(blueMask); 989 } 990 991 1002public int getPixel(RGB rgb) { 1003 if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1004 if (isDirect) { 1005 int pixel = 0; 1006 pixel |= (redShift < 0 ? rgb.red << -redShift : rgb.red >>> redShift) & redMask; 1007 pixel |= (greenShift < 0 ? rgb.green << -greenShift : rgb.green >>> greenShift) & greenMask; 1008 pixel |= (blueShift < 0 ? rgb.blue << -blueShift : rgb.blue >>> blueShift) & blueMask; 1009 return pixel; 1010 } else { 1011 for (int i = 0; i < colors.length; i++) { 1012 if (colors[i].equals(rgb)) return i; 1013 } 1014 1015 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1016 return 0; 1017 } 1018} 1019 1020 1031public RGB getRGB(int pixel) { 1032 if (isDirect) { 1033 int r = pixel & redMask; 1034 r = (redShift < 0) ? r >>> -redShift : r << redShift; 1035 int g = pixel & greenMask; 1036 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift; 1037 int b = pixel & blueMask; 1038 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift; 1039 return new RGB(r, g, b); 1040 } else { 1041 if (pixel < 0 || pixel >= colors.length) { 1042 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1043 } 1044 return colors[pixel]; 1045 } 1046} 1047 1048 1054public RGB[] getRGBs() { 1055 return colors; 1056} 1057 1058 1066int shiftForMask(int mask) { 1067 for (int i = 31; i >= 0; i--) { 1068 if (((mask >> i) & 0x1) != 0) return 7 - i; 1069 } 1070 return 32; 1071} 1072 1073} 1074static class ImageLoader { 1075 1076 1081 public ImageData[] data; 1082 1083 1088 public int logicalScreenWidth; 1089 1090 1095 public int logicalScreenHeight; 1096 1097 1103 public int backgroundPixel; 1104 1105 1110 public int repeatCount; 1111 1112 1115 Vector imageLoaderListeners; 1116 1117 1120public ImageLoader() { 1121 reset(); 1122} 1123 1124 1128void reset() { 1129 data = null; 1130 logicalScreenWidth = 0; 1131 logicalScreenHeight = 0; 1132 backgroundPixel = -1; 1133 repeatCount = 1; 1134} 1135 1136 1154public ImageData[] load(InputStream stream) { 1155 if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1156 reset(); 1157 data = FileFormat.load(stream, this); 1158 return data; 1159} 1160 1161 1179public ImageData[] load(String filename) { 1180 if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1181 InputStream stream = null; 1182 try { 1183 stream = new FileInputStream(filename); 1184 return load(stream); 1185 } catch (IOException e) { 1186 SWT.error(SWT.ERROR_IO, e); 1187 } finally { 1188 try { 1189 if (stream != null) stream.close(); 1190 } catch (IOException e) { 1191 } 1193 } 1194 return null; 1195} 1196} 1197static class ImageData { 1198 1199 1202 public int width; 1203 1204 1207 public int height; 1208 1209 1218 public int depth; 1219 1220 1227 public int scanlinePad; 1228 1229 1235 public int bytesPerLine; 1236 1237 1246 public byte[] data; 1247 1248 1251 public PaletteData palette; 1252 1253 1261 public int transparentPixel; 1262 1263 1273 public byte[] maskData; 1274 1275 1283 public int maskPad; 1284 1285 1294 public byte[] alphaData; 1295 1296 1307 public int alpha; 1308 1309 1328 public int type; 1329 1330 1335 public int x; 1336 1337 1342 public int y; 1343 1344 1361 public int disposalMethod; 1362 1363 1368 public int delayTime; 1369 1370 1373 static final byte[][] ANY_TO_EIGHT = new byte[9][]; 1374 static { 1375 for (int b = 0; b < 9; ++b) { 1376 byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b]; 1377 if (b == 0) continue; 1378 int inc = 0; 1379 for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit; 1380 for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8); 1381 } 1382 } 1383 static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8]; 1384 1385 1388 static final int[][] DITHER_MATRIX = { 1389 { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 }, 1390 { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 }, 1391 { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 }, 1392 { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 }, 1393 { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 }, 1394 { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 }, 1395 { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 }, 1396 { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 } 1397 }; 1398 1399 1415public ImageData(int width, int height, int depth, PaletteData palette) { 1416 this(width, height, depth, palette, 1417 4, null, 0, null, 1418 null, -1, -1, SWT.IMAGE_UNDEFINED, 1419 0, 0, 0, 0); 1420} 1421 1422 1440public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) { 1441 this(width, height, depth, palette, 1442 scanlinePad, checkData(data), 0, null, 1443 null, -1, -1, SWT.IMAGE_UNDEFINED, 1444 0, 0, 0, 0); 1445} 1446 1447 1469public ImageData(String filename) { 1470 ImageData[] data = new ImageLoader().load(filename); 1471 if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); 1472 ImageData i = data[0]; 1473 setAllFields( 1474 i.width, 1475 i.height, 1476 i.depth, 1477 i.scanlinePad, 1478 i.bytesPerLine, 1479 i.data, 1480 i.palette, 1481 i.transparentPixel, 1482 i.maskData, 1483 i.maskPad, 1484 i.alphaData, 1485 i.alpha, 1486 i.type, 1487 i.x, 1488 i.y, 1489 i.disposalMethod, 1490 i.delayTime); 1491} 1492 1493 1496ImageData() { 1497} 1498 1499 1505ImageData( 1506 int width, int height, int depth, PaletteData palette, 1507 int scanlinePad, byte[] data, int maskPad, byte[] maskData, 1508 byte[] alphaData, int alpha, int transparentPixel, int type, 1509 int x, int y, int disposalMethod, int delayTime) 1510{ 1511 1512 if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1513 if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8 1514 || depth == 16 || depth == 24 || depth == 32)) { 1515 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1516 } 1517 if (width <= 0 || height <= 0) { 1518 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1519 } 1520 if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO); 1521 1522 int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) 1523 / scanlinePad * scanlinePad; 1524 setAllFields( 1525 width, 1526 height, 1527 depth, 1528 scanlinePad, 1529 bytesPerLine, 1530 data != null ? data : new byte[bytesPerLine * height], 1531 palette, 1532 transparentPixel, 1533 maskData, 1534 maskPad, 1535 alphaData, 1536 alpha, 1537 type, 1538 x, 1539 y, 1540 disposalMethod, 1541 delayTime); 1542} 1543 1544 1553void setAllFields(int width, int height, int depth, int scanlinePad, 1554 int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel, 1555 byte[] maskData, int maskPad, byte[] alphaData, int alpha, 1556 int type, int x, int y, int disposalMethod, int delayTime) { 1557 1558 this.width = width; 1559 this.height = height; 1560 this.depth = depth; 1561 this.scanlinePad = scanlinePad; 1562 this.bytesPerLine = bytesPerLine; 1563 this.data = data; 1564 this.palette = palette; 1565 this.transparentPixel = transparentPixel; 1566 this.maskData = maskData; 1567 this.maskPad = maskPad; 1568 this.alphaData = alphaData; 1569 this.alpha = alpha; 1570 this.type = type; 1571 this.x = x; 1572 this.y = y; 1573 this.disposalMethod = disposalMethod; 1574 this.delayTime = delayTime; 1575} 1576 1577 1591public static ImageData internal_new( 1592 int width, int height, int depth, PaletteData palette, 1593 int scanlinePad, byte[] data, int maskPad, byte[] maskData, 1594 byte[] alphaData, int alpha, int transparentPixel, int type, 1595 int x, int y, int disposalMethod, int delayTime) 1596{ 1597 return new ImageData( 1598 width, height, depth, palette, scanlinePad, data, maskPad, maskData, 1599 alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime); 1600} 1601 1602ImageData colorMaskImage(int pixel) { 1603 ImageData mask = new ImageData(width, height, 1, bwPalette(), 1604 2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED, 1605 0, 0, 0, 0); 1606 int[] row = new int[width]; 1607 for (int y = 0; y < height; y++) { 1608 getPixels(0, y, width, row, 0); 1609 for (int i = 0; i < width; i++) { 1610 if (pixel != -1 && row[i] == pixel) { 1611 row[i] = 0; 1612 } else { 1613 row[i] = 1; 1614 } 1615 } 1616 mask.setPixels(0, y, width, row, 0); 1617 } 1618 return mask; 1619} 1620 1621static byte[] checkData(byte [] data) { 1622 if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1623 return data; 1624} 1625 1626 1648public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) { 1649 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1650 if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error 1651 1652(SWT.ERROR_INVALID_ARGUMENT); 1653 if (getWidth == 0) return; 1654 int index; 1655 int theByte; 1656 int mask = 0; 1657 int n = getWidth; 1658 int i = startIndex; 1659 int srcX = x, srcY = y; 1660 if (depth == 1) { 1661 index = (y * bytesPerLine) + (x >> 3); 1662 theByte = data[index] & 0xFF; 1663 while (n > 0) { 1664 mask = 1 << (7 - (srcX & 0x7)); 1665 if ((theByte & mask) == 0) { 1666 pixels[i] = 0; 1667 } else { 1668 pixels[i] = 1; 1669 } 1670 i++; 1671 n--; 1672 srcX++; 1673 if (srcX >= width) { 1674 srcY++; 1675 index = srcY * bytesPerLine; 1676 if (n > 0) theByte = data[index] & 0xFF; 1677 srcX = 0; 1678 } else { 1679 if (mask == 1) { 1680 index++; 1681 if (n > 0) theByte = data[index] & 0xFF; 1682 } 1683 } 1684 } 1685 return; 1686 } 1687 if (depth == 2) { 1688 index = (y * bytesPerLine) + (x >> 2); 1689 theByte = data[index] & 0xFF; 1690 int offset; 1691 while (n > 0) { 1692 offset = 3 - (srcX % 4); 1693 mask = 3 << (offset * 2); 1694 pixels[i] = (byte)((theByte & mask) >> (offset * 2)); 1695 i++; 1696 n--; 1697 srcX++; 1698 if (srcX >= width) { 1699 srcY++; 1700 index = srcY * bytesPerLine; 1701 if (n > 0) theByte = data[index] & 0xFF; 1702 srcX = 0; 1703 } else { 1704 if (offset == 0) { 1705 index++; 1706 theByte = data[index] & 0xFF; 1707 } 1708 } 1709 } 1710 return; 1711 } 1712 if (depth == 4) { 1713 index = (y * bytesPerLine) + (x >> 1); 1714 if ((x & 0x1) == 1) { 1715 theByte = data[index] & 0xFF; 1716 pixels[i] = (byte)(theByte & 0x0F); 1717 i++; 1718 n--; 1719 srcX++; 1720 if (srcX >= width) { 1721 srcY++; 1722 index = srcY * bytesPerLine; 1723 srcX = 0; 1724 } else { 1725 index++; 1726 } 1727 } 1728 while (n > 1) { 1729 theByte = data[index] & 0xFF; 1730 pixels[i] = (byte)(theByte >> 4); 1731 i++; 1732 n--; 1733 srcX++; 1734 if (srcX >= width) { 1735 srcY++; 1736 index = srcY * bytesPerLine; 1737 srcX = 0; 1738 } else { 1739 pixels[i] = (byte)(theByte & 0x0F); 1740 i++; 1741 n--; 1742 srcX++; 1743 if (srcX >= width) { 1744 srcY++; 1745 index = srcY * bytesPerLine; 1746 srcX = 0; 1747 } else { 1748 index++; 1749 } 1750 } 1751 } 1752 if (n > 0) { 1753 theByte = data[index] & 0xFF; 1754 pixels[i] = (byte)(theByte >> 4); 1755 } 1756 return; 1757 } 1758 if (depth == 8) { 1759 index = (y * bytesPerLine) + x; 1760 for (int j = 0; j < getWidth; j++) { 1761 pixels[i] = data[index]; 1762 i++; 1763 srcX++; 1764 if (srcX >= width) { 1765 srcY++; 1766 index = srcY * bytesPerLine; 1767 srcX = 0; 1768 } else { 1769 index++; 1770 } 1771 } 1772 return; 1773 } 1774 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 1775} 1776 1777 1798public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) { 1799 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1800 if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error 1801 1802(SWT.ERROR_INVALID_ARGUMENT); 1803 if (getWidth == 0) return; 1804 int index; 1805 int theByte; 1806 int mask; 1807 int n = getWidth; 1808 int i = startIndex; 1809 int srcX = x, srcY = y; 1810 if (depth == 1) { 1811 index = (y * bytesPerLine) + (x >> 3); 1812 theByte = data[index] & 0xFF; 1813 while (n > 0) { 1814 mask = 1 << (7 - (srcX & 0x7)); 1815 if ((theByte & mask) == 0) { 1816 pixels[i] = 0; 1817 } else { 1818 pixels[i] = 1; 1819 } 1820 i++; 1821 n--; 1822 srcX++; 1823 if (srcX >= width) { 1824 srcY++; 1825 index = srcY * bytesPerLine; 1826 if (n > 0) theByte = data[index] & 0xFF; 1827 srcX = 0; 1828 } else { 1829 if (mask == 1) { 1830 index++; 1831 if (n > 0) theByte = data[index] & 0xFF; 1832 } 1833 } 1834 } 1835 return; 1836 } 1837 if (depth == 2) { 1838 index = (y * bytesPerLine) + (x >> 2); 1839 theByte = data[index] & 0xFF; 1840 int offset; 1841 while (n > 0) { 1842 offset = 3 - (srcX % 4); 1843 mask = 3 << (offset * 2); 1844 pixels[i] = (byte)((theByte & mask) >> (offset * 2)); 1845 i++; 1846 n--; 1847 srcX++; 1848 if (srcX >= width) { 1849 srcY++; 1850 index = srcY * bytesPerLine; 1851 if (n > 0) theByte = data[index] & 0xFF; 1852 srcX = 0; 1853 } else { 1854 if (offset == 0) { 1855 index++; 1856 theByte = data[index] & 0xFF; 1857 } 1858 } 1859 } 1860 return; 1861 } 1862 if (depth == 4) { 1863 index = (y * bytesPerLine) + (x >> 1); 1864 if ((x & 0x1) == 1) { 1865 theByte = data[index] & 0xFF; 1866 pixels[i] = theByte & 0x0F; 1867 i++; 1868 n--; 1869 srcX++; 1870 if (srcX >= width) { 1871 srcY++; 1872 index = srcY * bytesPerLine; 1873 srcX = 0; 1874 } else { 1875 index++; 1876 } 1877 } 1878 while (n > 1) { 1879 theByte = data[index] & 0xFF; 1880 pixels[i] = theByte >> 4; 1881 i++; 1882 n--; 1883 srcX++; 1884 if (srcX >= width) { 1885 srcY++; 1886 index = srcY * bytesPerLine; 1887 srcX = 0; 1888 } else { 1889 pixels[i] = theByte & 0x0F; 1890 i++; 1891 n--; 1892 srcX++; 1893 if (srcX >= width) { 1894 srcY++; 1895 index = srcY * bytesPerLine; 1896 srcX = 0; 1897 } else { 1898 index++; 1899 } 1900 } 1901 } 1902 if (n > 0) { 1903 theByte = data[index] & 0xFF; 1904 pixels[i] = theByte >> 4; 1905 } 1906 return; 1907 } 1908 if (depth == 8) { 1909 index = (y * bytesPerLine) + x; 1910 for (int j = 0; j < getWidth; j++) { 1911 pixels[i] = data[index] & 0xFF; 1912 i++; 1913 srcX++; 1914 if (srcX >= width) { 1915 srcY++; 1916 index = srcY * bytesPerLine; 1917 srcX = 0; 1918 } else { 1919 index++; 1920 } 1921 } 1922 return; 1923 } 1924 if (depth == 16) { 1925 index = (y * bytesPerLine) + (x * 2); 1926 for (int j = 0; j < getWidth; j++) { 1927 pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF); 1928 i++; 1929 srcX++; 1930 if (srcX >= width) { 1931 srcY++; 1932 index = srcY * bytesPerLine; 1933 srcX = 0; 1934 } else { 1935 index += 2; 1936 } 1937 } 1938 return; 1939 } 1940 if (depth == 24) { 1941 index = (y * bytesPerLine) + (x * 3); 1942 for (int j = 0; j < getWidth; j++) { 1943 pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8) 1944 | (data[index+2] & 0xFF); 1945 i++; 1946 srcX++; 1947 if (srcX >= width) { 1948 srcY++; 1949 index = srcY * bytesPerLine; 1950 srcX = 0; 1951 } else { 1952 index += 3; 1953 } 1954 } 1955 return; 1956 } 1957 if (depth == 32) { 1958 index = (y * bytesPerLine) + (x * 4); 1959 i = startIndex; 1960 for (int j = 0; j < getWidth; j++) { 1961 pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16) 1962 | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF); 1963 i++; 1964 srcX++; 1965 if (srcX >= width) { 1966 srcY++; 1967 index = srcY * bytesPerLine; 1968 srcX = 0; 1969 } else { 1970 index += 4; 1971 } 1972 } 1973 return; 1974 } 1975 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 1976} 1977 1978 1987public RGB[] getRGBs() { 1988 return palette.getRGBs(); 1989} 1990 1991 1998public ImageData getTransparencyMask() { 1999 if (getTransparencyType() == SWT.TRANSPARENCY_MASK) { 2000 return new ImageData(width, height, 1, bwPalette(), maskPad, maskData); 2001 } else { 2002 return colorMaskImage(transparentPixel); 2003 } 2004} 2005 2006 2011public int getTransparencyType() { 2012 if (maskData != null) return SWT.TRANSPARENCY_MASK; 2013 if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL; 2014 if (alphaData != null) return SWT.TRANSPARENCY_ALPHA; 2015 return SWT.TRANSPARENCY_NONE; 2016} 2017 2018 2023int getByteOrder() { 2024 return depth != 16 ? MSB_FIRST : LSB_FIRST; 2025} 2026 2027 2050public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) { 2051 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 2052 if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2053 if (putWidth == 0) return; 2054 int index; 2055 int theByte; 2056 int mask; 2057 int n = putWidth; 2058 int i = startIndex; 2059 int srcX = x, srcY = y; 2060 if (depth == 1) { 2061 index = (y * bytesPerLine) + (x >> 3); 2062 while (n > 0) { 2063 mask = 1 << (7 - (srcX & 0x7)); 2064 if ((pixels[i] & 0x1) == 1) { 2065 data[index] = (byte)((data[index] & 0xFF) | mask); 2066 } else { 2067 data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); 2068 } 2069 i++; 2070 n--; 2071 srcX++; 2072 if (srcX >= width) { 2073 srcY++; 2074 index = srcY * bytesPerLine; 2075 srcX = 0; 2076 } else { 2077 if (mask == 1) { 2078 index++; 2079 } 2080 } 2081 } 2082 return; 2083 } 2084 if (depth == 2) { 2085 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; 2086 index = (y * bytesPerLine) + (x >> 2); 2087 int offset = 3 - (x % 4); 2088 while (n > 0) { 2089 theByte = pixels[i] & 0x3; 2090 data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); 2091 i++; 2092 n--; 2093 srcX++; 2094 if (srcX >= width) { 2095 srcY++; 2096 index = srcY * bytesPerLine; 2097 offset = 0; 2098 srcX = 0; 2099 } else { 2100 if (offset == 0) { 2101 index++; 2102 offset = 3; 2103 } else { 2104 offset--; 2105 } 2106 } 2107 } 2108 return; 2109 } 2110 if (depth == 4) { 2111 index = (y * bytesPerLine) + (x >> 1); 2112 boolean high = (x & 0x1) == 0; 2113 while (n > 0) { 2114 theByte = pixels[i] & 0x0F; 2115 if (high) { 2116 data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); 2117 } else { 2118 data[index] = (byte)((data[index] & 0xF0) | theByte); 2119 } 2120 i++; 2121 n--; 2122 srcX++; 2123 if (srcX >= width) { 2124 srcY++; 2125 index = srcY * bytesPerLine; 2126 high = true; 2127 srcX = 0; 2128 } else { 2129 if (!high) index++; 2130 high = !high; 2131 } 2132 } 2133 return; 2134 } 2135 if (depth == 8) { 2136 index = (y * bytesPerLine) + x; 2137 for (int j = 0; j < putWidth; j++) { 2138 data[index] = (byte)(pixels[i] & 0xFF); 2139 i++; 2140 srcX++; 2141 if (srcX >= width) { 2142 srcY++; 2143 index = srcY * bytesPerLine; 2144 srcX = 0; 2145 } else { 2146 index++; 2147 } 2148 } 2149 return; 2150 } 2151 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 2152} 2153 2154 2176public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) { 2177 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 2178 if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2179 if (putWidth == 0) return; 2180 int index; 2181 int theByte; 2182 int mask; 2183 int n = putWidth; 2184 int i = startIndex; 2185 int pixel; 2186 int srcX = x, srcY = y; 2187 if (depth == 1) { 2188 index = (y * bytesPerLine) + (x >> 3); 2189 while (n > 0) { 2190 mask = 1 << (7 - (srcX & 0x7)); 2191 if ((pixels[i] & 0x1) == 1) { 2192 data[index] = (byte)((data[index] & 0xFF) | mask); 2193 } else { 2194 data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); 2195 } 2196 i++; 2197 n--; 2198 srcX++; 2199 if (srcX >= width) { 2200 srcY++; 2201 index = srcY * bytesPerLine; 2202 srcX = 0; 2203 } else { 2204 if (mask == 1) { 2205 index++; 2206 } 2207 } 2208 } 2209 return; 2210 } 2211 if (depth == 2) { 2212 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; 2213 index = (y * bytesPerLine) + (x >> 2); 2214 int offset = 3 - (x % 4); 2215 while (n > 0) { 2216 theByte = pixels[i] & 0x3; 2217 data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); 2218 i++; 2219 n--; 2220 srcX++; 2221 if (srcX >= width) { 2222 srcY++; 2223 index = srcY * bytesPerLine; 2224 offset = 3; 2225 srcX = 0; 2226 } else { 2227 if (offset == 0) { 2228 index++; 2229 offset = 3; 2230 } else { 2231 offset--; 2232 } 2233 } 2234 } 2235 return; 2236 } 2237 if (depth == 4) { 2238 index = (y * bytesPerLine) + (x >> 1); 2239 boolean high = (x & 0x1) == 0; 2240 while (n > 0) { 2241 theByte = pixels[i] & 0x0F; 2242 if (high) { 2243 data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); 2244 } else { 2245 data[index] = (byte)((data[index] & 0xF0) | theByte); 2246 } 2247 i++; 2248 n--; 2249 srcX++; 2250 if (srcX >= width) { 2251 srcY++; 2252 index = srcY * bytesPerLine; 2253 high = true; 2254 srcX = 0; 2255 } else { 2256 if (!high) index++; 2257 high = !high; 2258 } 2259 } 2260 return; 2261 } 2262 if (depth == 8) { 2263 index = (y * bytesPerLine) + x; 2264 for (int j = 0; j < putWidth; j++) { 2265 data[index] = (byte)(pixels[i] & 0xFF); 2266 i++; 2267 srcX++; 2268 if (srcX >= width) { 2269 srcY++; 2270 index = srcY * bytesPerLine; 2271 srcX = 0; 2272 } else { 2273 index++; 2274 } 2275 } 2276 return; 2277 2278 } 2279 if (depth == 16) { 2280 index = (y * bytesPerLine) + (x * 2); 2281 for (int j = 0; j < putWidth; j++) { 2282 pixel = pixels[i]; 2283 data[index] = (byte)(pixel & 0xFF); 2284 data[index + 1] = (byte)((pixel >> 8) & 0xFF); 2285 i++; 2286 srcX++; 2287 if (srcX >= width) { 2288 srcY++; 2289 index = srcY * bytesPerLine; 2290 srcX = 0; 2291 } else { 2292 index += 2; 2293 } 2294 } 2295 return; 2296 } 2297 if (depth == 24) { 2298 index = (y * bytesPerLine) + (x * 3); 2299 for (int j = 0; j < putWidth; j++) { 2300 pixel = pixels[i]; 2301 data[index] = (byte)((pixel >> 16) & 0xFF); 2302 data[index + 1] = (byte)((pixel >> 8) & 0xFF); 2303 data[index + 2] = (byte)(pixel & 0xFF); 2304 i++; 2305 srcX++; 2306 if (srcX >= width) { 2307 srcY++; 2308 index = srcY * bytesPerLine; 2309 srcX = 0; 2310 } else { 2311 index += 3; 2312 } 2313 } 2314 return; 2315 } 2316 if (depth == 32) { 2317 index = (y * bytesPerLine) + (x * 4); 2318 for (int j = 0; j < putWidth; j++) { 2319 pixel = pixels[i]; 2320 data[index] = (byte)((pixel >> 24) & 0xFF); 2321 data[index + 1] = (byte)((pixel >> 16) & 0xFF); 2322 data[index + 2] = (byte)((pixel >> 8) & 0xFF); 2323 data[index + 3] = (byte)(pixel & 0xFF); 2324 i++; 2325 srcX++; 2326 if (srcX >= width) { 2327 srcY++; 2328 index = srcY * bytesPerLine; 2329 srcX = 0; 2330 } else { 2331 index += 4; 2332 } 2333 } 2334 return; 2335 } 2336 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 2337} 2338 2339 2342static PaletteData bwPalette() { 2343 return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)}); 2344} 2345 2346 2350static int getMSBOffset(int mask) { 2351 for (int i = 31; i >= 0; i--) { 2352 if (((mask >> i) & 0x1) != 0) return i + 1; 2353 } 2354 return 0; 2355} 2356 2357 2360static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) { 2361 if (depth > 8) { 2362 int rshift = 32 - getMSBOffset(redMask); 2363 int gshift = 32 - getMSBOffset(greenMask); 2364 int bshift = 32 - getMSBOffset(blueMask); 2365 return (((red << 24) >>> rshift) & redMask) | 2366 (((green << 24) >>> gshift) & greenMask) | 2367 (((blue << 24) >>> bshift) & blueMask); 2368 } 2369 int r, g, b; 2370 int minDistance = 0x7fffffff; 2371 int nearestPixel = 0; 2372 int n = reds.length; 2373 for (int j = 0; j < n; j++) { 2374 r = (reds[j] & 0xFF) - (red & 0xFF); 2375 g = (greens[j] & 0xFF) - (green & 0xFF); 2376 b = (blues[j] & 0xFF) - (blue & 0xFF); 2377 int distance = r*r + g*g + b*b; 2378 if (distance < minDistance) { 2379 nearestPixel = j; 2380 if (distance == 0) break; 2381 minDistance = distance; 2382 } 2383 } 2384 return nearestPixel; 2385} 2386 2387static final ImageData convertMask(ImageData mask) { 2388 if (mask.depth == 1) return mask; 2389 PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); 2390 ImageData newMask = new ImageData(mask.width, mask.height, 1, palette); 2391 2392 int blackIndex = 0; 2393 RGB[] rgbs = mask.getRGBs(); 2394 if (rgbs != null) { 2395 while (blackIndex < rgbs.length) { 2396 if (rgbs[blackIndex].equals(palette.colors[0])) break; 2397 blackIndex++; 2398 } 2399 } 2400 int[] pixels = new int[mask.width]; 2401 for (int y = 0; y < mask.height; y++) { 2402 mask.getPixels(0, y, mask.width, pixels, 0); 2403 for (int i = 0; i < pixels.length; i++) { 2404 if (pixels[i] == blackIndex) { 2405 pixels[i] = 0; 2406 } else { 2407 pixels[i] = 1; 2408 } 2409 } 2410 newMask.setPixels(0, y, mask.width, pixels, 0); 2411 } 2412 return newMask; 2413} 2414 2415static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { 2416 if (pad == newPad) return data; 2417 int stride = (width * depth + 7) / 8; 2418 int bpl = (stride + (pad - 1)) / pad * pad; 2419 int newBpl = (stride + (newPad - 1)) / newPad * newPad; 2420 byte[] newData = new byte[height * newBpl]; 2421 int srcIndex = 0, destIndex = 0; 2422 for (int y = 0; y < height; y++) { 2423 System.arraycopy(data, srcIndex, newData, destIndex, stride); 2424 srcIndex += bpl; 2425 destIndex += newBpl; 2426 } 2427 return newData; 2428} 2429 2430 2433static final int 2434 BLIT_SRC = 1, BLIT_ALPHA = 2, BLIT_DITHER = 4; 2438 2441static final int 2442 ALPHA_OPAQUE = 255, ALPHA_TRANSPARENT = 0, ALPHA_CHANNEL_SEPARATE = -1, ALPHA_CHANNEL_SOURCE = -2, ALPHA_MASK_UNPACKED = -3, ALPHA_MASK_PACKED = -4, ALPHA_MASK_INDEX = -5, ALPHA_MASK_RGB = -6; 2451 2454static final int LSB_FIRST = 0; 2455static final int MSB_FIRST = 1; 2456 2457 2460private static final int 2461 TYPE_GENERIC_8 = 0, 2463 TYPE_GENERIC_16_MSB = 1, 2464 TYPE_GENERIC_16_LSB = 2, 2465 TYPE_GENERIC_24 = 3, 2466 TYPE_GENERIC_32_MSB = 4, 2467 TYPE_GENERIC_32_LSB = 5, 2468 TYPE_INDEX_8 = 6, 2470 TYPE_INDEX_4 = 7, 2471 TYPE_INDEX_2 = 8, 2472 TYPE_INDEX_1_MSB = 9, 2473 TYPE_INDEX_1_LSB = 10; 2474 2475 2478static int getChannelShift(int mask) { 2479 if (mask == 0) return 0; 2480 int i; 2481 for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) { 2482 mask >>>= 1; 2483 } 2484 return i; 2485} 2486 2487 2490static int getChannelWidth(int mask, int shift) { 2491 if (mask == 0) return 0; 2492 int i; 2493 mask >>>= shift; 2494 for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) { 2495 mask >>>= 1; 2496 } 2497 return i - shift; 2498} 2499 2500 2503static byte getChannelField(int data, int mask) { 2504 final int shift = getChannelShift(mask); 2505 return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift]; 2506} 2507 2508 2511static final void buildDitheredGradientChannel(int from, int to, int steps, 2512 int bandWidth, int bandHeight, boolean vertical, 2513 byte[] bitmapData, int dp, int bytesPerLine, int bits) { 2514 final int mask = 0xff00 >>> bits; 2515 int val = from << 16; 2516 final int inc = ((to << 16) - val) / steps + 1; 2517 if (vertical) { 2518 for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) { 2519 for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) { 2520 final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits; 2521 int temp = val + thresh; 2522 if (temp > 0xffffff) bitmapData[dptr] = -1; 2523 else bitmapData[dptr] = (byte)((temp >>> 16) & mask); 2524 } 2525 val += inc; 2526 } 2527 } else { 2528 for (int dx = 0; dx < bandWidth; ++dx, dp += 4) { 2529 for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) { 2530 final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits; 2531 int temp = val + thresh; 2532 if (temp > 0xffffff) bitmapData[dptr] = -1; 2533 else bitmapData[dptr] = (byte)((temp >>> 16) & mask); 2534 } 2535 val += inc; 2536 } 2537 } 2538} 2539} 2540 2541static class LEDataInputStream extends InputStream { 2542 int position; 2543 InputStream in; 2544 2545 2548 protected byte[] buf; 2549 2550 2555 protected int pos; 2556 2557 2558 public LEDataInputStream(InputStream input) { 2559 this(input, 512); 2560 } 2561 2562 public LEDataInputStream(InputStream input, int bufferSize) { 2563 this.in = input; 2564 if (bufferSize > 0) { 2565 buf = new byte[bufferSize]; 2566 pos = bufferSize; 2567 } 2568 else throw new IllegalArgumentException (); 2569 } 2570 2571 public void close() throws IOException { 2572 buf = null; 2573 if (in != null) { 2574 in.close(); 2575 in = null; 2576 } 2577 } 2578 2579 2582 public int getPosition() { 2583 return position; 2584 } 2585 2586 2589 public int available() throws IOException { 2590 if (buf == null) throw new IOException(); 2591 return (buf.length - pos) + in.available(); 2592 } 2593 2594 2597 public int read() throws IOException { 2598 if (buf == null) throw new IOException(); 2599 position++; 2600 if (pos < buf.length) return (buf[pos++] & 0xFF); 2601 return in.read(); 2602 } 2603 2604 2608 public int read(byte b[], int off, int len) throws IOException { 2609 int result; 2610 int left = len; 2611 result = readData(b, off, len); 2612 while (true) { 2613 if (result == -1) return -1; 2614 position += result; 2615 if (result == left) return len; 2616 left -= result; 2617 off += result; 2618 result = readData(b, off, left); 2619 } 2620 } 2621 2622 2639 private int readData(byte[] buffer, int offset, int length) throws IOException { 2640 if (buf == null) throw new IOException(); 2641 if (offset < 0 || offset > buffer.length || 2642 length < 0 || (length > buffer.length - offset)) { 2643 throw new ArrayIndexOutOfBoundsException (); 2644 } 2645 2646 int cacheCopied = 0; 2647 int newOffset = offset; 2648 2649 int available = buf.length - pos; 2651 if (available > 0) { 2652 cacheCopied = (available >= length) ? length : available; 2653 System.arraycopy(buf, pos, buffer, newOffset, cacheCopied); 2654 newOffset += cacheCopied; 2655 pos += cacheCopied; 2656 } 2657 2658 if (cacheCopied == length) return length; 2660 2661 int inCopied = in.read(buffer, newOffset, length - cacheCopied); 2662 2663 if (inCopied > 0) return inCopied + cacheCopied; 2664 if (cacheCopied == 0) return inCopied; 2665 return cacheCopied; 2666 } 2667 2668 2672 public int readInt() throws IOException { 2673 byte[] buf = new byte[4]; 2674 read(buf); 2675 return ((((((buf[3] & 0xFF) << 8) | 2676 (buf[2] & 0xFF)) << 8) | 2677 (buf[1] & 0xFF)) << 8) | 2678 (buf[0] & 0xFF); 2679 } 2680 2681 2685 public short readShort() throws IOException { 2686 byte[] buf = new byte[2]; 2687 read(buf); 2688 return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF)); 2689 } 2690 2691 2703 public void unread(byte[] b) throws IOException { 2704 int length = b.length; 2705 if (length > pos) throw new IOException(); 2706 position -= length; 2707 pos -= length; 2708 System.arraycopy(b, 0, buf, pos, length); 2709 } 2710} 2711public static abstract class FileFormat { 2712 LEDataInputStream inputStream; 2713 ImageLoader loader; 2714 int compression; 2715 2716byte[] bitInvertData(byte[] data, int startIndex, int endIndex) { 2717 for (int i = startIndex; i < endIndex; i++) { 2719 data[i] = (byte)(255 - data[i - startIndex]); 2720 } 2721 return data; 2722} 2723 2724 2728abstract boolean isFileFormat(LEDataInputStream stream); 2729 2730abstract ImageData[] loadFromByteStream(); 2731 2732public ImageData[] loadFromStream(LEDataInputStream stream) { 2733 try { 2734 inputStream = stream; 2735 return loadFromByteStream(); 2736 } catch (Exception e) { 2737 SWT.error(SWT.ERROR_IO, e); 2738 return null; 2739 } 2740} 2741 2742public static ImageData[] load(InputStream is, ImageLoader loader) { 2743 LEDataInputStream stream = new LEDataInputStream(is); 2744 boolean isSupported = false; 2745 FileFormat fileFormat = new WinICOFileFormat(); 2746 if (fileFormat.isFileFormat(stream)) isSupported = true; 2747 else { 2748 fileFormat = new WinBMPFileFormat(); 2749 if (fileFormat.isFileFormat(stream)) isSupported = true; 2750 } 2751 if (!isSupported) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); 2752 fileFormat.loader = loader; 2753 return fileFormat.loadFromStream(stream); 2754} 2755} 2756static class WinBMPFileFormat extends FileFormat { 2757 static final int BMPFileHeaderSize = 14; 2758 static final int BMPHeaderFixedSize = 40; 2759 int importantColors; 2760 2761void decompressData(byte[] src, byte[] dest, int stride, int cmp) { 2762 if (cmp == 1) { if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0) 2764 SWT.error(SWT.ERROR_INVALID_IMAGE); 2765 return; 2766 } 2767 if (cmp == 2) { if (decompressRLE4Data(src, src.length, stride, dest, dest.length) <= 0) 2769 SWT.error(SWT.ERROR_INVALID_IMAGE); 2770 return; 2771 } 2772 SWT.error(SWT.ERROR_INVALID_IMAGE); 2773} 2774int decompressRLE4Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) { 2775 int sp = 0; 2776 int se = numBytes; 2777 int dp = 0; 2778 int de = destSize; 2779 int x = 0, y = 0; 2780 while (sp < se) { 2781 int len = src[sp] & 0xFF; 2782 sp++; 2783 if (len == 0) { 2784 len = src[sp] & 0xFF; 2785 sp++; 2786 switch (len) { 2787 case 0: 2788 y++; 2789 x = 0; 2790 dp = y * stride; 2791 if (dp >= de) 2792 return -1; 2793 break; 2794 case 1: 2795 return 1; 2796 case 2: 2797 x += src[sp] & 0xFF; 2798 sp++; 2799 y += src[sp] & 0xFF; 2800 sp++; 2801 dp = y * stride + x / 2; 2802 if (dp >= de) 2803 return -1; 2804 break; 2805 default: 2806 if ((len & 1) != 0) 2807 return -1; 2808 x += len; 2809 len = len / 2; 2810 if (len > (se - sp)) 2811 return -1; 2812 if (len > (de - dp)) 2813 return -1; 2814 for (int i = 0; i < len; i++) { 2815 dest[dp] = src[sp]; 2816 dp++; 2817 sp++; 2818 } 2819 if ((sp & 1) != 0) 2820 sp++; 2821 break; 2822 } 2823 } else { 2824 if ((len & 1) != 0) 2825 return -1; 2826 x += len; 2827 len = len / 2; 2828 byte theByte = src[sp]; 2829 sp++; 2830 if (len > (de - dp)) 2831 return -1; 2832 for (int i = 0; i < len; i++) { 2833 dest[dp] = theByte; 2834 dp++; 2835 } 2836 } 2837 } 2838 return 1; 2839} 2840int decompressRLE8Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) { 2841 int sp = 0; 2842 int se = numBytes; 2843 int dp = 0; 2844 int de = destSize; 2845 int x = 0, y = 0; 2846 while (sp < se) { 2847 int len = src[sp] & 0xFF; 2848 sp++; 2849 if (len == 0) { 2850 len = src[sp] & 0xFF; 2851 sp++; 2852 switch (len) { 2853 case 0: 2854 y++; 2855 x = 0; 2856 dp = y * stride; 2857 if (dp >= de) 2858 return -1; 2859 break; 2860 case 1: 2861 return 1; 2862 case 2: 2863 x += src[sp] & 0xFF; 2864 sp++; 2865 y += src[sp] & 0xFF; 2866 sp++; 2867 dp = y * stride + x; 2868 if (dp >= de) 2869 return -1; 2870 break; 2871 default: 2872 if (len > (se - sp)) 2873 return -1; 2874 if (len > (de - dp)) 2875 return -1; 2876 for (int i = 0; i < len; i++) { 2877 dest[dp] = src[sp]; 2878 dp++; 2879 sp++; 2880 } 2881 if ((sp & 1) != 0) 2882 sp++; 2883 x += len; 2884 break; 2885 } 2886 } else { 2887 byte theByte = src[sp]; 2888 sp++; 2889 if (len > (de - dp)) 2890 return -1; 2891 for (int i = 0; i < len; i++) { 2892 dest[dp] = theByte; 2893 dp++; 2894 } 2895 x += len; 2896 } 2897 } 2898 return 1; 2899} 2900boolean isFileFormat(LEDataInputStream stream) { 2901 try { 2902 byte[] header = new byte[18]; 2903 stream.read(header); 2904 stream.unread(header); 2905 int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24); 2906 return header[0] == 0x42 && header[1] == 0x4D && infoHeaderSize >= BMPHeaderFixedSize; 2907 } catch (Exception e) { 2908 return false; 2909 } 2910} 2911byte[] loadData(byte[] infoHeader) { 2912 int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 2913 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 2914 int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 2915 int stride = (width * bitCount + 7) / 8; 2916 stride = (stride + 3) / 4 * 4; byte[] data = loadData(infoHeader, stride); 2918 flipScanLines(data, stride, height); 2919 return data; 2920} 2921byte[] loadData(byte[] infoHeader, int stride) { 2922 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 2923 int dataSize = height * stride; 2924 byte[] data = new byte[dataSize]; 2925 int cmp = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24); 2926 if (cmp == 0) { try { 2928 if (inputStream.read(data) != dataSize) 2929 SWT.error(SWT.ERROR_INVALID_IMAGE); 2930 } catch (IOException e) { 2931 SWT.error(SWT.ERROR_IO, e); 2932 } 2933 } else { 2934 int compressedSize = (infoHeader[20] & 0xFF) | ((infoHeader[21] & 0xFF) << 8) | ((infoHeader[22] & 0xFF) << 16) | ((infoHeader[23] & 0xFF) << 24); 2935 byte[] compressed = new byte[compressedSize]; 2936 try { 2937 if (inputStream.read(compressed) != compressedSize) 2938 SWT.error(SWT.ERROR_INVALID_IMAGE); 2939 } catch (IOException e) { 2940 SWT.error(SWT.ERROR_IO, e); 2941 } 2942 decompressData(compressed, data, stride, cmp); 2943 } 2944 return data; 2945} 2946int[] loadFileHeader() { 2947 int[] header = new int[5]; 2948 try { 2949 header[0] = inputStream.readShort(); 2950 header[1] = inputStream.readInt(); 2951 header[2] = inputStream.readShort(); 2952 header[3] = inputStream.readShort(); 2953 header[4] = inputStream.readInt(); 2954 } catch (IOException e) { 2955 SWT.error(SWT.ERROR_IO, e); 2956 } 2957 if (header[0] != 0x4D42) 2958 SWT.error(SWT.ERROR_INVALID_IMAGE); 2959 return header; 2960} 2961ImageData[] loadFromByteStream() { 2962 int[] fileHeader = loadFileHeader(); 2963 byte[] infoHeader = new byte[BMPHeaderFixedSize]; 2964 try { 2965 inputStream.read(infoHeader); 2966 } catch (Exception e) { 2967 SWT.error(SWT.ERROR_IO, e); 2968 } 2969 int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 2970 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 2971 int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 2972 PaletteData palette = loadPalette(infoHeader); 2973 if (inputStream.getPosition() < fileHeader[4]) { 2974 try { 2976 inputStream.skip(fileHeader[4] - inputStream.getPosition()); 2977 } catch (IOException e) { 2978 SWT.error(SWT.ERROR_IO, e); 2979 } 2980 } 2981 byte[] data = loadData(infoHeader); 2982 this.compression = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24); 2983 this.importantColors = (infoHeader[36] & 0xFF) | ((infoHeader[37] & 0xFF) << 8) | ((infoHeader[38] & 0xFF) << 16) | ((infoHeader[39] & 0xFF) << 24); 2984 int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24); 2985 int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24); 2986 int type = (this.compression == 1 ) || (this.compression == 2 2987 2988) ? SWT.IMAGE_BMP_RLE : SWT.IMAGE_BMP; 2989 return new ImageData[] { 2990 ImageData.internal_new( 2991 width, 2992 height, 2993 bitCount, 2994 palette, 2995 4, 2996 data, 2997 0, 2998 null, 2999 null, 3000 -1, 3001 -1, 3002 type, 3003 0, 3004 0, 3005 0, 3006 0) 3007 }; 3008} 3009PaletteData loadPalette(byte[] infoHeader) { 3010 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3011 if (depth <= 8) { 3012 int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24); 3013 if (numColors == 0) { 3014 numColors = 1 << depth; 3015 } else { 3016 if (numColors > 256) 3017 numColors = 256; 3018 } 3019 byte[] buf = new byte[numColors * 4]; 3020 try { 3021 if (inputStream.read(buf) != buf.length) 3022 SWT.error(SWT.ERROR_INVALID_IMAGE); 3023 } catch (IOException e) { 3024 SWT.error(SWT.ERROR_IO, e); 3025 } 3026 return paletteFromBytes(buf, numColors); 3027 } 3028 if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F); 3029 if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000); 3030 return new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 3031} 3032PaletteData paletteFromBytes(byte[] bytes, int numColors) { 3033 int bytesOffset = 0; 3034 RGB[] colors = new RGB[numColors]; 3035 for (int i = 0; i < numColors; i++) { 3036 colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF, 3037 bytes[bytesOffset + 1] & 0xFF, 3038 bytes[bytesOffset] & 0xFF); 3039 bytesOffset += 4; 3040 } 3041 return new PaletteData(colors); 3042} 3043 3047static byte[] paletteToBytes(PaletteData pal) { 3048 int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256); 3049 byte[] bytes = new byte[n * 4]; 3050 int offset = 0; 3051 for (int i = 0; i < n; i++) { 3052 RGB col = pal.colors[i]; 3053 bytes[offset] = (byte)col.blue; 3054 bytes[offset + 1] = (byte)col.green; 3055 bytes[offset + 2] = (byte)col.red; 3056 offset += 4; 3057 } 3058 return bytes; 3059} 3060 3061void flipScanLines(byte[] data, int stride, int height) { 3062 int i1 = 0; 3063 int i2 = (height - 1) * stride; 3064 for (int i = 0; i < height / 2; i++) { 3065 for (int index = 0; index < stride; index++) { 3066 byte b = data[index + i1]; 3067 data[index + i1] = data[index + i2]; 3068 data[index + i2] = b; 3069 } 3070 i1 += stride; 3071 i2 -= stride; 3072 } 3073} 3074 3075} 3076 3077static class WinICOFileFormat extends FileFormat { 3078 3079static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { 3080 if (pad == newPad) return data; 3081 int stride = (width * depth + 7) / 8; 3082 int bpl = (stride + (pad - 1)) / pad * pad; 3083 int newBpl = (stride + (newPad - 1)) / newPad * newPad; 3084 byte[] newData = new byte[height * newBpl]; 3085 int srcIndex = 0, destIndex = 0; 3086 for (int y = 0; y < height; y++) { 3087 System.arraycopy(data, srcIndex, newData, destIndex, newBpl); 3088 srcIndex += bpl; 3089 destIndex += newBpl; 3090 } 3091 return newData; 3092} 3093 3097int iconSize(ImageData i) { 3098 int shapeDataStride = (i.width * i.depth + 31) / 32 * 4; 3099 int maskDataStride = (i.width + 31) / 32 * 4; 3100 int dataSize = (shapeDataStride + maskDataStride) * i.height; 3101 int paletteSize = i.palette.colors != null ? i.palette.colors.length * 4 : 0; 3102 return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize; 3103} 3104boolean isFileFormat(LEDataInputStream stream) { 3105 try { 3106 byte[] header = new byte[4]; 3107 stream.read(header); 3108 stream.unread(header); 3109 return header[0] == 0 && header[1] == 0 && header[2] == 1 && header[3] == 0; 3110 } catch (Exception e) { 3111 return false; 3112 } 3113} 3114boolean isValidIcon(ImageData i) { 3115 switch (i.depth) { 3116 case 1: 3117 case 4: 3118 case 8: 3119 if (i.palette.isDirect) return false; 3120 int size = i.palette.colors.length; 3121 return size == 2 || size == 16 || size == 32 || size == 256; 3122 case 24: 3123 case 32: 3124 return i.palette.isDirect; 3125 } 3126 return false; 3127} 3128int loadFileHeader(LEDataInputStream byteStream) { 3129 int[] fileHeader = new int[3]; 3130 try { 3131 fileHeader[0] = byteStream.readShort(); 3132 fileHeader[1] = byteStream.readShort(); 3133 fileHeader[2] = byteStream.readShort(); 3134 } catch (IOException e) { 3135 SWT.error(SWT.ERROR_IO, e); 3136 } 3137 if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) 3138 SWT.error(SWT.ERROR_INVALID_IMAGE); 3139 int numIcons = fileHeader[2]; 3140 if (numIcons <= 0) 3141 SWT.error(SWT.ERROR_INVALID_IMAGE); 3142 return numIcons; 3143} 3144int loadFileHeader(LEDataInputStream byteStream, boolean hasHeader) { 3145 int[] fileHeader = new int[3]; 3146 try { 3147 if (hasHeader) { 3148 fileHeader[0] = byteStream.readShort(); 3149 fileHeader[1] = byteStream.readShort(); 3150 } else { 3151 fileHeader[0] = 0; 3152 fileHeader[1] = 1; 3153 } 3154 fileHeader[2] = byteStream.readShort(); 3155 } catch (IOException e) { 3156 SWT.error(SWT.ERROR_IO, e); 3157 } 3158 if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) 3159 SWT.error(SWT.ERROR_INVALID_IMAGE); 3160 int numIcons = fileHeader[2]; 3161 if (numIcons <= 0) 3162 SWT.error(SWT.ERROR_INVALID_IMAGE); 3163 return numIcons; 3164} 3165ImageData[] loadFromByteStream() { 3166 int numIcons = loadFileHeader(inputStream); 3167 int[][] headers = loadIconHeaders(numIcons); 3168 ImageData[] icons = new ImageData[headers.length]; 3169 for (int i = 0; i < icons.length; i++) { 3170 icons[i] = loadIcon(headers[i]); 3171 } 3172 return icons; 3173} 3174 3177ImageData loadIcon(int[] iconHeader) { 3178 byte[] infoHeader = loadInfoHeader(iconHeader); 3179 WinBMPFileFormat bmpFormat = new WinBMPFileFormat(); 3180 bmpFormat.inputStream = inputStream; 3181 PaletteData palette = bmpFormat.loadPalette(infoHeader); 3182 byte[] shapeData = bmpFormat.loadData(infoHeader); 3183 int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 3184 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 3185 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3186 infoHeader[14] = 1; 3187 infoHeader[15] = 0; 3188 byte[] maskData = bmpFormat.loadData(infoHeader); 3189 maskData = convertPad(maskData, width, height, 1, 4, 2); 3190 bitInvertData(maskData, 0, maskData.length); 3191 return ImageData.internal_new( 3192 width, 3193 height, 3194 depth, 3195 palette, 3196 4, 3197 shapeData, 3198 2, 3199 maskData, 3200 null, 3201 -1, 3202 -1, 3203 SWT.IMAGE_ICO, 3204 0, 3205 0, 3206 0, 3207 0); 3208} 3209int[][] loadIconHeaders(int numIcons) { 3210 int[][] headers = new int[numIcons][7]; 3211 try { 3212 for (int i = 0; i < numIcons; i++) { 3213 headers[i][0] = inputStream.read(); 3214 headers[i][1] = inputStream.read(); 3215 headers[i][2] = inputStream.readShort(); 3216 headers[i][3] = inputStream.readShort(); 3217 headers[i][4] = inputStream.readShort(); 3218 headers[i][5] = inputStream.readInt(); 3219 headers[i][6] = inputStream.readInt(); 3220 } 3221 } catch (IOException e) { 3222 SWT.error(SWT.ERROR_IO, e); 3223 } 3224 return headers; 3225} 3226byte[] loadInfoHeader(int[] iconHeader) { 3227 int width = iconHeader[0]; 3228 int height = iconHeader[1]; 3229 int numColors = iconHeader[2]; if (numColors == 0) numColors = 256; if ((numColors != 2) && (numColors != 8) && (numColors != 16) && 3232 (numColors != 32) && (numColors != 256)) 3233 SWT.error(SWT.ERROR_INVALID_IMAGE); 3234 if (inputStream.getPosition() < iconHeader[6]) { 3235 try { 3237 inputStream.skip(iconHeader[6] - inputStream.getPosition()); 3238 } catch (IOException e) { 3239 SWT.error(SWT.ERROR_IO, e); 3240 return null; 3241 } 3242 } 3243 byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize]; 3244 try { 3245 inputStream.read(infoHeader); 3246 } catch (IOException e) { 3247 SWT.error(SWT.ERROR_IO, e); 3248 } 3249 if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) != 1) 3250 SWT.error(SWT.ERROR_INVALID_IMAGE); 3251 int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 3252 int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 3253 int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3254 if (height == infoHeight && bitCount == 1) height /= 2; 3255 if (!((width == infoWidth) && (height * 2 == infoHeight) && 3256 (bitCount == 1 || bitCount == 4 || bitCount == 8 || bitCount == 24 || bitCount == 32))) 3257 SWT.error(SWT.ERROR_INVALID_IMAGE); 3258 infoHeader[8] = (byte)(height & 0xFF); 3259 infoHeader[9] = (byte)((height >> 8) & 0xFF); 3260 infoHeader[10] = (byte)((height >> 16) & 0xFF); 3261 infoHeader[11] = (byte)((height >> 24) & 0xFF); 3262 return infoHeader; 3263} 3264} 3265static class SWT { 3266 public static final int IMAGE_ICO = 3; 3267 public static final int ERROR_IO = 39; 3268 public static final int ERROR_INVALID_IMAGE = 40; 3269 public static final int ERROR_NULL_ARGUMENT = 4; 3270 public static final int ERROR_INVALID_ARGUMENT = 5; 3271 public static final int ERROR_CANNOT_BE_ZERO = 7; 3272 public static final int IMAGE_UNDEFINED = -1; 3273 public static final int ERROR_UNSUPPORTED_DEPTH = 38; 3274 public static final int TRANSPARENCY_MASK = 1 << 1; 3275 public static final int ERROR_UNSUPPORTED_FORMAT = 42; 3276 public static final int TRANSPARENCY_ALPHA = 1 << 0; 3277 public static final int TRANSPARENCY_NONE = 0x0; 3278 public static final int TRANSPARENCY_PIXEL = 1 << 2; 3279 public static final int IMAGE_BMP = 0; 3280 public static final int IMAGE_BMP_RLE = 1; 3281 3282 public static void error(int code) { 3283 throw new RuntimeException ("Error "+code); 3284 } 3285 public static void error(int code, Throwable t) { 3286 throw new RuntimeException (t); 3287 } 3288} 3289} 3290 | Popular Tags |