diff options
author | Carolyn MacLeod <carolyn> | 2005-09-01 21:31:15 +0000 |
---|---|---|
committer | Carolyn MacLeod <carolyn> | 2005-09-01 21:31:15 +0000 |
commit | ff32f7578b312ab2cf7bee31c19161e45b3b344c (patch) | |
tree | 9fb601ce6e9ce8617db17bb9e6ace9a7c6b9063f /bundles/org.eclipse.swt/Eclipse SWT | |
parent | 553d7364f85189cde07e065aaa5ba7380f0c1418 (diff) | |
download | eclipse.platform.swt-ff32f7578b312ab2cf7bee31c19161e45b3b344c.tar.gz eclipse.platform.swt-ff32f7578b312ab2cf7bee31c19161e45b3b344c.tar.xz eclipse.platform.swt-ff32f7578b312ab2cf7bee31c19161e45b3b344c.zip |
bug 46387
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT')
9 files changed, 160 insertions, 72 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java index 15b4d79e96..d3677ff3ba 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java @@ -23,16 +23,17 @@ import org.eclipse.swt.internal.image.*; * <p> * Currently supported image formats are: * </p><ul> - * <li>BMP (Windows Bitmap)</li> + * <li>BMP (Windows or OS/2 Bitmap)</li> * <li>ICO (Windows Icon)</li> * <li>JPEG</li> * <li>GIF</li> * <li>PNG</li> + * <li>TIFF</li> * </ul> * <code>ImageLoaders</code> can be used to: * <ul> * <li>load/save single images in all formats</li> - * <li>load/save multiple images (GIF/ICO)</li> + * <li>load/save multiple images (GIF/ICO/TIFF)</li> * <li>load/save animated GIF images</li> * <li>load interlaced GIF/PNG images</li> * <li>load progressive JPEG images</li> diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java index ed93f2b414..792bf2755c 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java @@ -25,14 +25,6 @@ public abstract class FileFormat { 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. @@ -51,6 +43,10 @@ public ImageData[] loadFromStream(LEDataInputStream stream) { } } +/** + * Read the specified input stream using the specified loader, and + * return the device independent image array represented by the stream. + */ public static ImageData[] load(InputStream is, ImageLoader loader) { FileFormat fileFormat = null; LEDataInputStream stream = new LEDataInputStream(is); @@ -75,13 +71,15 @@ public static ImageData[] load(InputStream is, ImageLoader loader) { return fileFormat.loadFromStream(stream); } +/** + * Write the device independent image array stored in the specified loader + * to the specified output stream using the specified file format. + */ public static void save(OutputStream os, int format, ImageLoader loader) { if (format < 0 || format >= FORMATS.length) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); if (FORMATS[format] == null) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); + if (loader.data == null || loader.data.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - /* We do not currently support writing multi-image files, - * so we use the first image data in the loader's array. */ - ImageData data = loader.data[0]; LEDataOutputStream stream = new LEDataOutputStream(os); FileFormat fileFormat = null; try { @@ -91,20 +89,20 @@ public static void save(OutputStream os, int format, ImageLoader loader) { SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); } if (format == SWT.IMAGE_BMP_RLE) { - switch (data.depth) { + switch (loader.data[0].depth) { case 8: fileFormat.compression = 1; break; case 4: fileFormat.compression = 2; break; } } - fileFormat.unloadIntoStream(data, stream); + fileFormat.unloadIntoStream(loader, stream); } -abstract void unloadIntoByteStream(ImageData image); +abstract void unloadIntoByteStream(ImageLoader loader); -public void unloadIntoStream(ImageData image, LEDataOutputStream stream) { +public void unloadIntoStream(ImageLoader loader, LEDataOutputStream stream) { try { outputStream = stream; - unloadIntoByteStream(image); + unloadIntoByteStream(loader); outputStream.flush(); } catch (Exception e) { try {outputStream.flush();} catch (Exception f) {} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java index 3523c61b3f..d303a6353c 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java @@ -420,31 +420,129 @@ final class GIFFileFormat extends FileFormat { return new PaletteData(colors); } - /** - * Write the specified device independent image - * to the output stream. - */ - void unloadIntoByteStream(ImageData image) { - if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8))) { + void unloadIntoByteStream(ImageLoader loader) { + + /* Step 1: Acquire GIF parameters */ + ImageData[] data = loader.data; + int frameCount = data.length; + boolean multi = frameCount > 1; + ImageData firstImage = data[0]; + int logicalScreenWidth = multi ? loader.logicalScreenWidth : firstImage.width; + int logicalScreenHeight = multi ? loader.logicalScreenHeight : firstImage.height; + int backgroundPixel = loader.backgroundPixel; + int depth = firstImage.depth; + PaletteData palette = firstImage.palette; + RGB[] colors = palette.getRGBs(); + short globalTable = 1; + + /* Step 2: Check for validity and global/local color map */ + if (!(depth == 1 || depth == 4 || depth == 8)) { SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); } - byte bitField = (byte)((0x80 & 0xF8 & 0xF7 & 0x8F) + (image.depth - 1) + ((image.depth - 1) * 16)); + for (int i=0; i<frameCount; i++) { + if (data[i].palette.isDirect) { + SWT.error(SWT.ERROR_INVALID_IMAGE); + } + if (multi) { + if (!(data[i].height <= logicalScreenHeight && data[i].width <= logicalScreenWidth && data[i].depth == depth)) { + SWT.error(SWT.ERROR_INVALID_IMAGE); + } + if (globalTable == 1) { + RGB rgbs[] = data[i].palette.getRGBs(); + if (rgbs.length != colors.length) { + globalTable = 0; + } else { + for (int j=0; j<colors.length; j++) { + if (!(rgbs[j].red == colors[j].red && + rgbs[j].green == colors[j].green && + rgbs[j].blue == colors[j].blue)) + globalTable = 0; + } + } + } + } + } + try { - outputStream.write(new byte[] { (byte)'G', (byte)'I', (byte)'F' }); - outputStream.write(new byte[] { (byte)'8', (byte)'9', (byte)'a' }); - outputStream.writeShort((short)image.width); - outputStream.writeShort((short)image.height); - outputStream.writeByte(bitField); - outputStream.writeByte((byte)0); + /* Step 3: Write the GIF89a Header and Logical Screen Descriptor */ + int bits = globalTable*128 + (depth-1)*16 + depth-1; + outputStream.write("GIF89a".getBytes()); + outputStream.writeShort((short)logicalScreenWidth); + outputStream.writeShort((short)logicalScreenHeight); + outputStream.writeByte((byte)bits); + outputStream.writeByte((byte)backgroundPixel); outputStream.writeByte((byte)0); } catch (IOException e) { SWT.error(SWT.ERROR_IO, e); } - writePalette(image.palette, image.depth); - if (image.transparentPixel != -1 || image.disposalMethod != 0 || image.delayTime != 0) { - writeGraphicsControlBlock(image); + + /* Step 4: Write Global Color Table if applicable */ + if (globalTable == 1) { + writePalette(palette, depth); } - writeImageBlock(image); + + /* Step 5: Write Application Extension if applicable */ + if (multi) { + int repeatCount = loader.repeatCount; + try { + outputStream.write(GIF_EXTENSION_BLOCK_ID); + outputStream.write(GIF_APPLICATION_EXTENSION_BLOCK_ID); + outputStream.write((byte)11); // Eleven bytes following + outputStream.write("NETSCAPE2.0".getBytes()); + outputStream.write((byte)3); // Three bytes following + outputStream.writeByte((byte)1); + outputStream.write((byte) repeatCount & 0xFF); + outputStream.write((byte) (repeatCount >> 8) & 0xFF); + outputStream.writeByte((byte)0); + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } + } + + for (int frame=0; frame<frameCount; frame++) { + + /* Step 6: Write Graphics Control Block for each frame if applicable */ + if (multi || data[frame].transparentPixel != -1) { + writeGraphicsControlBlock(data[frame]); + } + + /* Step 7: Write Image Header for each frame */ + int x = data[frame].x; + int y = data[frame].y; + int width = data[frame].width; + int height = data[frame].height; + try { + outputStream.write(GIF_IMAGE_BLOCK_ID); // 0x2C + byte[] block = new byte[9]; + block[0] = (byte)(x & 0xFF); + block[1] = (byte)((x >> 8) & 0xFF); + block[2] = (byte)(y & 0xFF); + block[3] = (byte)((y >> 8) & 0xFF); + block[4] = (byte)(width & 0xFF); + block[5] = (byte)((width >> 8) & 0xFF); + block[6] = (byte)(height & 0xFF); + block[7] = (byte)((height >> 8) & 0xFF); + block[8] = (byte)(globalTable == 0 ? (depth-1) | 0x80 : 0x00); + outputStream.write(block); + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } + + /* Step 8: Write Local Color Table for each frame if applicable */ + if (globalTable == 0) { + writePalette(data[frame].palette, depth); + } + + /* Step 9: Write the actual data for each frame */ + try { + outputStream.write(depth); // minimum LZW Code size: 3 for 1 bit per pixel images and usually the number of bits per pixel plus 1 for other images. + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } + new LZWCodec().encode(outputStream, data[frame]); + } + + /* Step 10: Write GIF terminator */ try { outputStream.write(0x3B); } catch (IOException e) { @@ -462,18 +560,16 @@ final class GIFFileFormat extends FileFormat { outputStream.write(GIF_GRAPHICS_CONTROL_BLOCK_ID); outputStream.write(0x04); // size of block byte[] gcBlock = new byte[4]; - gcBlock[0] = (byte)0xFD; + gcBlock[0] = 0; gcBlock[1] = 0; gcBlock[2] = 0; gcBlock[3] = 0; - if (image.transparentPixel == -1) { - gcBlock[0] = (byte)(gcBlock[0] & 0xFE); - } else { - gcBlock[0] = (byte)(gcBlock[0] | 0x01); + if (image.transparentPixel != -1) { + gcBlock[0] = (byte)0x01; gcBlock[3] = (byte)image.transparentPixel; } if (image.disposalMethod != 0) { - gcBlock[0] = (byte)(gcBlock[0] | ((image.disposalMethod & 0x07) << 2)); + gcBlock[0] |= (byte)((image.disposalMethod & 0x07) << 2); } if (image.delayTime != 0) { gcBlock[1] = (byte)(image.delayTime & 0xFF); @@ -487,31 +583,6 @@ final class GIFFileFormat extends FileFormat { } /** - * Write the specified device independent image - * to the current position in the output stream. - */ - void writeImageBlock(ImageData image) { - try { - outputStream.write(GIF_IMAGE_BLOCK_ID); - byte[] block = new byte[9]; - block[0] = (byte)(image.x & 0xFF); - block[1] = (byte)((image.x >> 8) & 0xFF); - block[2] = (byte)(image.y & 0xFF); - block[3] = (byte)((image.y >> 8) & 0xFF); - block[4] = (byte)(image.width & 0xFF); - block[5] = (byte)((image.width >> 8) & 0xFF); - block[6] = (byte)(image.height & 0xFF); - block[7] = (byte)((image.height >> 8) & 0xFF); - block[8] = 0; // no interlace, no sort, no local palette - outputStream.write(block); - outputStream.write(image.depth); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - new LZWCodec().encode(outputStream, image); - } - - /** * Write the specified palette to the output stream. */ void writePalette(PaletteData palette, int depth) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java index c3fa2bd47c..3c2c5a18b7 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java @@ -1771,7 +1771,8 @@ void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, i destIndex += compWidth; } } -void unloadIntoByteStream(ImageData image) { +void unloadIntoByteStream(ImageLoader loader) { + ImageData image = loader.data[0]; if (!new JPEGStartOfImage().writeToStream(outputStream)) { SWT.error(SWT.ERROR_IO); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java index a7123c0145..ade4460aa2 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java @@ -201,7 +201,8 @@ int unloadData(ImageData image, OutputStream out) { * Unload a DeviceIndependentImage using Windows .BMP format into the given * byte stream. */ -void unloadIntoByteStream(ImageData image) { +void unloadIntoByteStream(ImageLoader loader) { + ImageData image = loader.data[0]; byte[] rgbs; int numCols; if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8) || diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java index 6973c56745..dc49c29908 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java @@ -135,7 +135,8 @@ void readNextChunk(PngChunkReader chunkReader) { } } } -void unloadIntoByteStream(ImageData p1) { +void unloadIntoByteStream(ImageLoader loader) { + /* We do not currently support writing png. */ SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); } boolean isFileFormat(LEDataInputStream stream) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java index dd48276e5f..21ef7a43d0 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java @@ -64,7 +64,10 @@ ImageData[] loadFromByteStream() { return images; } -void unloadIntoByteStream(ImageData image) { +void unloadIntoByteStream(ImageLoader loader) { + /* We do not currently support writing multi-page tiff, + * so we use the first image data in the loader's array. */ + ImageData image = loader.data[0]; TIFFDirectory directory = new TIFFDirectory(image); try { directory.writeToStream(outputStream); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java index df0261df5c..63cc665694 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java @@ -569,7 +569,8 @@ int unloadDataNoCompression(ImageData image, OutputStream out) { * Unload a DeviceIndependentImage using Windows .BMP format into the given * byte stream. */ -void unloadIntoByteStream(ImageData image) { +void unloadIntoByteStream(ImageLoader loader) { + ImageData image = loader.data[0]; byte[] rgbs; int numCols; if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8) || diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java index b19aaa2f06..1fd3d62eba 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java @@ -17,6 +17,14 @@ import java.io.*; final class WinICOFileFormat extends FileFormat { +byte[] bitInvertData(byte[] data, int startIndex, int endIndex) { + // Destructively bit invert data in the given byte array. + for (int i = startIndex; i < endIndex; i++) { + data[i] = (byte)(255 - data[i - startIndex]); + } + return data; +} + static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { if (pad == newPad) return data; int stride = (width * depth + 7) / 8; @@ -252,7 +260,10 @@ void unloadIconHeader(ImageData i) { SWT.error(SWT.ERROR_IO, e); } } -void unloadIntoByteStream(ImageData image) { +void unloadIntoByteStream(ImageLoader loader) { + /* We do not currently support writing multi-image ico, + * so we use the first image data in the loader's array. */ + ImageData image = loader.data[0]; if (!isValidIcon(image)) SWT.error(SWT.ERROR_INVALID_IMAGE); try { |