ugly hacks to accomodate Apple's buggy AWT implementation
[org.ibex.core.git] / src / org / ibex / graphics / JPEG.java
1 package org.ibex.graphics;
2 import org.eclipse.swt.*;
3 import org.eclipse.swt.graphics.*;
4 import org.eclipse.swt.*;
5 import java.io.*;
6 import java.util.*;
7
8 // Big thanks to the SWT project for this!
9
10 // The code below was badly butchered by Adam Megacz in order to make
11 // it work outside SWT.
12
13
14 public class JPEG {
15
16     private static class SWT {
17         public static final int ERROR_INVALID_ARGUMENT = 0;
18         public static final int ERROR_NULL_ARGUMENT = 1;
19         public static final int ERROR_CANNOT_BE_ZERO = 2;
20         public static final int ERROR_INVALID_IMAGE = 3;
21         public static final int IMAGE_UNDEFINED = 4;
22         public static final int TRANSPARENCY_PIXEL = 5;
23         public static final int TRANSPARENCY_ALPHA = 6;
24         public static final int ERROR_UNSUPPORTED_DEPTH = 7;
25         public static final int ERROR_IO = 8;
26         public static final int TRANSPARENCY_MASK = 9;
27         public static final int TRANSPARENCY_NONE = 10;
28         public static final int ERROR_UNSUPPORTED_FORMAT = 11;
29         public static final int IMAGE_BMP_RLE = 12;
30         public static final int IMAGE_JPEG = 13;
31         public static void error(int i) { }
32         public static void error(int i, Throwable t) { }
33     }
34
35     /*******************************************************************************
36      * Copyright (c) 2000, 2003 IBM Corporation and others.
37      * All rights reserved. This program and the accompanying materials 
38      * are made available under the terms of the Common Public License v1.0
39      * which accompanies this distribution, and is available at
40      * http://www.eclipse.org/legal/cpl-v10.html
41      * 
42      * Contributors:
43      *     IBM Corporation - initial API and implementation
44      *******************************************************************************/
45
46     static final class LEDataOutputStream extends OutputStream {
47         OutputStream out;
48         public LEDataOutputStream(OutputStream output) {
49             this.out = output;
50         }
51         public void close() throws IOException {
52             out.close();
53         }
54         public void write(byte b[], int off, int len) throws IOException {
55             out.write(b, off, len);
56         }
57         /**
58          * Write the given byte to the output stream.
59          */
60         public void write(int b) throws IOException {
61             out.write(b);
62         }
63         /**
64          * Write the given byte to the output stream.
65          */
66         public void writeByte(byte b) throws IOException {
67             out.write(b & 0xFF);
68         }
69         /**
70          * Write the four bytes of the given integer
71          * to the output stream.
72          */
73         public void writeInt(int theInt) throws IOException {
74             out.write(theInt & 0xFF);
75             out.write((theInt >> 8) & 0xFF);
76             out.write((theInt >> 16) & 0xFF);
77             out.write((theInt >> 24) & 0xFF);
78         }
79         /**
80          * Write the two bytes of the given short
81          * to the output stream.
82          */
83         public void writeShort(int theShort) throws IOException {
84             out.write(theShort & 0xFF);
85             out.write((theShort >> 8) & 0xFF);
86         }
87     }
88     /*******************************************************************************
89      * Copyright (c) 2000, 2003 IBM Corporation and others.
90      * All rights reserved. This program and the accompanying materials 
91      * are made available under the terms of the Common Public License v1.0
92      * which accompanies this distribution, and is available at
93      * http://www.eclipse.org/legal/cpl-v10.html
94      * 
95      * Contributors:
96      *     IBM Corporation - initial API and implementation
97      *******************************************************************************/
98
99     public static abstract class FileFormat {
100         static final String FORMAT_PACKAGE = "org.eclipse.swt.internal.image"; //$NON-NLS-1$
101         static final String FORMAT_SUFFIX = "FileFormat"; //$NON-NLS-1$
102         static final String[] FORMATS = {"WinBMP", "WinBMP", "GIF", "WinICO", "JPEG", "PNG", "TIFF", "OS2BMP"}; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ //$NON-NLS-6$//$NON-NLS-7$//$NON-NLS-8$
103         
104         LEDataInputStream inputStream;
105         LEDataOutputStream outputStream;
106         ImageLoader loader;
107         int compression;
108
109         byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
110             // Destructively bit invert data in the given byte array.
111             for (int i = startIndex; i < endIndex; i++) {
112                 data[i] = (byte)(255 - data[i - startIndex]);
113             }
114             return data;
115         }
116
117         /**
118          * Return whether or not the specified input stream
119          * represents a supported file format.
120          */
121         abstract boolean isFileFormat(LEDataInputStream stream);
122
123         abstract ImageData[] loadFromByteStream();
124
125         public ImageData[] loadFromStream(LEDataInputStream stream) {
126             try {
127                 inputStream = stream;
128                 return loadFromByteStream();
129             } catch (Exception e) {
130                 SWT.error(SWT.ERROR_IO, e);
131                 return null;
132             }
133         }
134
135         public static ImageData[] load(InputStream is, ImageLoader loader) {
136             FileFormat fileFormat = null;
137             LEDataInputStream stream = new LEDataInputStream(is);
138             boolean isSupported = false;        
139             for (int i = 1; i < FORMATS.length; i++) {
140                 if (FORMATS[i] != null) {
141                     try {
142                         Class clazz = Class.forName(FORMAT_PACKAGE + '.' + FORMATS[i] + FORMAT_SUFFIX);
143                         fileFormat = (FileFormat) clazz.newInstance();
144                         if (fileFormat.isFileFormat(stream)) {
145                             isSupported = true;
146                             break;
147                         }
148                     } catch (ClassNotFoundException e) {
149                         FORMATS[i] = null;
150                     } catch (Exception e) {
151                     }
152                 }
153             }
154             if (!isSupported) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
155             fileFormat.loader = loader;
156             return fileFormat.loadFromStream(stream);
157         }
158
159         public static void save(OutputStream os, int format, ImageLoader loader) {
160             if (format < 0 || format >= FORMATS.length) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
161             if (FORMATS[format] == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
162
163             /* We do not currently support writing multi-image files,
164              * so we use the first image data in the loader's array. */
165             ImageData data = loader.data[0];
166             LEDataOutputStream stream = new LEDataOutputStream(os);
167             FileFormat fileFormat = null;
168             try {
169                 Class clazz = Class.forName(FORMAT_PACKAGE + '.' + FORMATS[format] + FORMAT_SUFFIX);
170                 fileFormat = (FileFormat) clazz.newInstance();
171             } catch (Exception e) {
172                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
173             }
174             if (format == SWT.IMAGE_BMP_RLE) {
175                 switch (data.depth) {
176                     case 8: fileFormat.compression = 1; break;
177                     case 4: fileFormat.compression = 2; break;
178                 }
179             }
180             fileFormat.unloadIntoStream(data, stream);
181         }
182
183         abstract void unloadIntoByteStream(ImageData image);
184
185         public void unloadIntoStream(ImageData image, LEDataOutputStream stream) {
186             try {
187                 outputStream = stream;
188                 unloadIntoByteStream(image);
189                 outputStream.close();
190             } catch (Exception e) {
191                 try {outputStream.close();} catch (Exception f) {}
192                 SWT.error(SWT.ERROR_IO, e);
193             }
194         }
195     }
196
197
198     /*******************************************************************************
199      * Copyright (c) 2000, 2003 IBM Corporation and others.
200      * All rights reserved. This program and the accompanying materials 
201      * are made available under the terms of the Common Public License v1.0
202      * which accompanies this distribution, and is available at
203      * http://www.eclipse.org/legal/cpl-v10.html
204      * 
205      * Contributors:
206      *     IBM Corporation - initial API and implementation
207      *******************************************************************************/
208
209     /**
210      * Classes which implement this interface provide methods
211      * that deal with the incremental loading of image data. 
212      * <p>
213      * After creating an instance of a class that implements
214      * this interface it can be added to an image loader using the
215      * <code>addImageLoaderListener</code> method and removed using
216      * the <code>removeImageLoaderListener</code> method. When
217      * image data is either partially or completely loaded, this
218      * method will be invoked.
219      * </p>
220      *
221      * @see ImageLoader
222      * @see ImageLoaderEvent
223      */
224
225     public static interface ImageLoaderListener {
226
227         /**
228          * Sent when image data is either partially or completely loaded.
229          * <p>
230          * The timing of when this method is called varies depending on
231          * the format of the image being loaded.
232          * </p>
233          *
234          * @param e an event containing information about the image loading operation
235          */
236         public void imageDataLoaded(ImageLoaderEvent e);
237
238     }
239     /*******************************************************************************
240      * Copyright (c) 2000, 2003 IBM Corporation and others.
241      * All rights reserved. This program and the accompanying materials 
242      * are made available under the terms of the Common Public License v1.0
243      * which accompanies this distribution, and is available at
244      * http://www.eclipse.org/legal/cpl-v10.html
245      * 
246      * Contributors:
247      *     IBM Corporation - initial API and implementation
248      *******************************************************************************/
249
250     /**
251      * Instances of this class are sent as a result of the incremental
252      * loading of image data.
253      * <p>
254      * <b>Notes:</b>
255      * </p><ul>
256      * <li>The number of events which will be sent when loading images
257      * is not constant. It varies by image type, and for JPEG images it 
258      * varies from image to image.</li>
259      * <li>For image sources which contain multiple images, the 
260      * <code>endOfImage</code> flag in the event will be set to true
261      * after each individual image is loaded.</li>
262      * </ul>
263      * 
264      * @see ImageLoader
265      * @see ImageLoaderListener
266      */
267
268     public static class ImageLoaderEvent  {
269         
270         /**
271          * if the <code>endOfImage</code> flag is false, then this is a
272          * partially complete copy of the current <code>ImageData</code>,
273          * otherwise this is a completely loaded <code>ImageData</code>
274          */
275         public ImageData imageData;
276
277         /**
278          * the zero-based count of image data increments -- this is
279          * equivalent to the number of events that have been generated
280          * while loading a particular image
281          */
282         public int incrementCount;
283
284         /**
285          * If this flag is true, then the current image data has been
286          * completely loaded, otherwise the image data is only partially
287          * loaded, and further ImageLoader events will occur unless an
288          * exception is thrown
289          */
290         public boolean endOfImage;
291         
292         /**
293          * Constructs a new instance of this class given the event source and
294          * the values to store in its fields.
295          *
296          * @param source the ImageLoader that was loading when the event occurred
297          * @param imageData the image data for the event
298          * @param incrementCount the image data increment for the event
299          * @param endOfImage the end of image flag for the event
300          */
301         public ImageLoaderEvent(ImageLoader source, ImageData imageData, int incrementCount, boolean endOfImage) {
302             //super(source);
303             this.imageData = imageData;
304             this.incrementCount = incrementCount;
305             this.endOfImage = endOfImage;
306         }
307
308         /**
309          * Returns a string containing a concise, human-readable
310          * description of the receiver.
311          *
312          * @return a string representation of the event
313          */
314         /*
315           public String toString () {
316           return "ImageLoaderEvent {source=" + source + " imageData=" + imageData + " incrementCount=" + incrementCount + " endOfImage=" + endOfImage + "}";
317           }
318         */
319     }
320
321
322     /*******************************************************************************
323      * Copyright (c) 2000, 2004 IBM Corporation and others.
324      * All rights reserved. This program and the accompanying materials
325      * are made available under the terms of the Common Public License v1.0
326      * which accompanies this distribution, and is available at
327      * http://www.eclipse.org/legal/cpl-v10.html
328      * 
329      * Contributors:
330      *     IBM Corporation - initial API and implementation
331      *******************************************************************************/
332
333     /**
334      * Instances of this class are used to load images from,
335      * and save images to, a file or stream.
336      * <p>
337      * Currently supported image formats are:
338      * </p><ul>
339      * <li>BMP (Windows Bitmap)</li>
340      * <li>ICO (Windows Icon)</li>
341      * <li>JPEG</li>
342      * <li>GIF</li>
343      * <li>PNG</li>
344      * </ul>
345      * <code>ImageLoaders</code> can be used to:
346      * <ul>
347      * <li>load/save single images in all formats</li>
348      * <li>load/save multiple images (GIF/ICO)</li>
349      * <li>load/save animated GIF images</li>
350      * <li>load interlaced GIF/PNG images</li>
351      * <li>load progressive JPEG images</li>
352      * </ul>
353      */
354  
355     public static class ImageLoader {
356
357         /**
358          * the array of ImageData objects in this ImageLoader.
359          * This array is read in when the load method is called,
360          * and it is written out when the save method is called
361          */
362         public ImageData[] data;
363         
364         /**
365          * the width of the logical screen on which the images
366          * reside, in pixels (this corresponds to the GIF89a
367          * Logical Screen Width value)
368          */
369         public int logicalScreenWidth;
370
371         /**
372          * the height of the logical screen on which the images
373          * reside, in pixels (this corresponds to the GIF89a
374          * Logical Screen Height value)
375          */
376         public int logicalScreenHeight;
377
378         /**
379          * the background pixel for the logical screen (this 
380          * corresponds to the GIF89a Background Color Index value).
381          * The default is -1 which means 'unspecified background'
382          * 
383          */
384         public int backgroundPixel;
385
386         /**
387          * the number of times to repeat the display of a sequence
388          * of animated images (this corresponds to the commonly-used
389          * GIF application extension for "NETSCAPE 2.0 01")
390          */
391         public int repeatCount;
392                 
393         /*
394          * the set of ImageLoader event listeners, created on demand
395          */
396         Vector imageLoaderListeners;
397
398         /**
399          * Construct a new empty ImageLoader.
400          */
401         public ImageLoader() {
402             reset();
403         }
404
405         /**
406          * Resets the fields of the ImageLoader, except for the
407          * <code>imageLoaderListeners</code> field.
408          */
409         void reset() {
410             data = null;
411             logicalScreenWidth = 0;
412             logicalScreenHeight = 0;
413             backgroundPixel = -1;
414             repeatCount = 1;
415         }
416
417         /**
418          * Loads an array of <code>ImageData</code> objects from the
419          * specified input stream. Throws an error if either an error
420          * occurs while loading the images, or if the images are not
421          * of a supported type. Returns the loaded image data array.
422          *
423          * @param stream the input stream to load the images from
424          * @return an array of <code>ImageData</code> objects loaded from the specified input stream
425          *
426          * @exception IllegalArgumentException <ul>
427          *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
428          * </ul>
429          * @exception SWTException <ul>
430          *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
431          *    <li>ERROR_IO - if an input/output error occurs while reading data</li>
432          *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
433          * </ul>
434          */
435         public ImageData[] load(InputStream stream) {
436             if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
437             reset();
438             data = FileFormat.load(stream, this);
439             return data;
440         }
441
442         /**
443          * Loads an array of <code>ImageData</code> objects from the
444          * file with the specified name. Throws an error if either
445          * an error occurs while loading the images, or if the images are
446          * not of a supported type. Returns the loaded image data array.
447          *
448          * @param filename the name of the file to load the images from
449          * @return an array of <code>ImageData</code> objects loaded from the specified file
450          *
451          * @exception IllegalArgumentException <ul>
452          *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
453          * </ul>
454          * @exception SWTException <ul>
455          *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
456          *    <li>ERROR_IO - if an IO error occurs while reading data</li>
457          *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
458          * </ul>
459          */
460         public ImageData[] load(String filename) {
461             throw new Error("not implemented");
462             /*
463               if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
464               InputStream stream = null;
465               try {
466               stream = Compatibility.newFileInputStream(filename);
467               return load(stream);
468               } catch (IOException e) {
469               SWT.error(SWT.ERROR_IO, e);
470               } finally {
471               try {
472               if (stream != null) stream.close();
473               } catch (IOException e) {
474               // Ignore error
475               }
476               }
477               return null;
478             */
479         }
480
481         /**
482          * Saves the image data in this ImageLoader to the specified stream.
483          * The format parameter can have one of the following values:
484          * <dl>
485          * <dt><code>IMAGE_BMP</code></dt>
486          * <dd>Windows BMP file format, no compression</dd>
487          * <dt><code>IMAGE_BMP_RLE</code></dt>
488          * <dd>Windows BMP file format, RLE compression if appropriate</dd>
489          * <dt><code>IMAGE_GIF</code></dt>
490          * <dd>GIF file format</dd>
491          * <dt><code>IMAGE_ICO</code></dt>
492          * <dd>Windows ICO file format</dd>
493          * <dt><code>IMAGE_JPEG</code></dt>
494          * <dd>JPEG file format</dd>
495          * <dt><code>IMAGE_PNG</code></dt>
496          * <dd>PNG file format</dd>
497          * </dl>
498          *
499          * @param stream the output stream to write the images to
500          * @param format the format to write the images in
501          *
502          * @exception IllegalArgumentException <ul>
503          *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
504          * </ul>
505          * @exception SWTException <ul>
506          *    <li>ERROR_INVALID_IMAGE if the image data contains invalid data</li>
507          *    <li>ERROR_IO if an IO error occurs while writing to the stream</li>
508          * </ul>
509          */
510         public void save(OutputStream stream, int format) {
511             if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
512             FileFormat.save(stream, format, this);
513         }
514
515         /**
516          * Saves the image data in this ImageLoader to a file with the specified name.
517          * The format parameter can have one of the following values:
518          * <dl>
519          * <dt><code>IMAGE_BMP</code></dt>
520          * <dd>Windows BMP file format, no compression</dd>
521          * <dt><code>IMAGE_BMP_RLE</code></dt>
522          * <dd>Windows BMP file format, RLE compression if appropriate</dd>
523          * <dt><code>IMAGE_GIF</code></dt>
524          * <dd>GIF file format</dd>
525          * <dt><code>IMAGE_ICO</code></dt>
526          * <dd>Windows ICO file format</dd>
527          * <dt><code>IMAGE_JPEG</code></dt>
528          * <dd>JPEG file format</dd>
529          * <dt><code>IMAGE_PNG</code></dt>
530          * <dd>PNG file format</dd>
531          * </dl>
532          *
533          * @param filename the name of the file to write the images to
534          * @param format the format to write the images in
535          *
536          * @exception IllegalArgumentException <ul>
537          *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
538          * </ul>
539          * @exception SWTException <ul>
540          *    <li>ERROR_INVALID_IMAGE if the image data contains invalid data</li>
541          *    <li>ERROR_IO if an IO error occurs while writing to the file</li>
542          * </ul>
543          */
544         public void save(String filename, int format) {
545             throw new Error("not implemented");
546             /*
547               if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
548               OutputStream stream = null;
549               try {
550               stream = Compatibility.newFileOutputStream(filename);
551               } catch (IOException e) {
552               SWT.error(SWT.ERROR_IO, e);
553               }
554               save(stream, format);
555             */
556         }
557
558         /**      
559          * Adds a listener to receive image loader events.
560          * <p>
561          * An ImageLoaderListener should be added before invoking
562          * one of the receiver's load methods. The listener's 
563          * <code>imageDataLoaded</code> method is called when image
564          * data has been partially loaded, as is supported by interlaced
565          * GIF/PNG or progressive JPEG images.
566          *
567          * @param listener the ImageLoaderListener to add
568          * @exception IllegalArgumentException <ul>
569          *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
570          * </ul>
571          * 
572          * @see ImageLoaderListener
573          * @see ImageLoaderEvent
574          */
575         public void addImageLoaderListener(ImageLoaderListener listener) {
576             if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
577             if (imageLoaderListeners == null) {
578                 imageLoaderListeners = new Vector();
579             }
580             imageLoaderListeners.addElement(listener);
581         }
582
583         /**      
584          * Removes a listener that was receiving image loader events.
585          *
586          * @param listener the ImageLoaderListener to remove
587          * @exception IllegalArgumentException <ul>
588          *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
589          * </ul>
590          * 
591          * @see #addImageLoaderListener(ImageLoaderListener)
592          */
593         public void removeImageLoaderListener(ImageLoaderListener listener) {
594             if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
595             if (imageLoaderListeners == null) return;
596             imageLoaderListeners.removeElement(listener);
597         }
598
599         /**      
600          * Returns <code>true</code> if the receiver has image loader
601          * listeners, and <code>false</code> otherwise.
602          *
603          * @return <code>true</code> if there are <code>ImageLoaderListener</code>s, and <code>false</code> otherwise
604          *
605          * @see #addImageLoaderListener(ImageLoaderListener)
606          * @see #removeImageLoaderListener(ImageLoaderListener)
607          */
608         public boolean hasListeners() {
609             return imageLoaderListeners != null && imageLoaderListeners.size() > 0;
610         }
611
612         /**      
613          * Notifies all image loader listeners that an image loader event
614          * has occurred. Pass the specified event object to each listener.
615          *
616          * @param event the <code>ImageLoaderEvent</code> to send to each <code>ImageLoaderListener</code>
617          */
618         public void notifyListeners(ImageLoaderEvent event) {
619             if (!hasListeners()) return;
620             int size = imageLoaderListeners.size();
621             for (int i = 0; i < size; i++) {
622                 ImageLoaderListener listener = (ImageLoaderListener) imageLoaderListeners.elementAt(i);
623                 listener.imageDataLoaded(event);
624             }
625         }
626
627     }
628
629     /*******************************************************************************
630      * Copyright (c) 2000, 2004 IBM Corporation and others.
631      * All rights reserved. This program and the accompanying materials
632      * are made available under the terms of the Common Public License v1.0
633      * which accompanies this distribution, and is available at
634      * http://www.eclipse.org/legal/cpl-v10.html
635      * 
636      * Contributors:
637      *     IBM Corporation - initial API and implementation
638      *******************************************************************************/
639     /**
640      * Instances of this class are descriptions of colors in
641      * terms of the primary additive color model (red, green and
642      * blue). A color may be described in terms of the relative
643      * intensities of these three primary colors. The brightness
644      * of each color is specified by a value in the range 0 to 255,
645      * where 0 indicates no color (blackness) and 255 indicates
646      * maximum intensity.
647      * <p>
648      * The hashCode() method in this class uses the values of the public
649      * fields to compute the hash value. When storing instances of the
650      * class in hashed collections, do not modify these fields after the
651      * object has been inserted.  
652      * </p>
653      * <p>
654      * Application code does <em>not</em> need to explicitly release the
655      * resources managed by each instance when those instances are no longer
656      * required, and thus no <code>dispose()</code> method is provided.
657      * </p>
658      *
659      * @see Color
660      */
661
662     public static final class RGB {
663         
664         /**
665          * the red component of the RGB
666          */
667         public int red;
668         
669         /**
670          * the green component of the RGB
671          */
672         public int green;
673         
674         /**
675          * the blue component of the RGB
676          */
677         public int blue;
678         
679         /**
680          * Constructs an instance of this class with the given
681          * red, green and blue values.
682          *
683          * @param red the red component of the new instance
684          * @param green the green component of the new instance
685          * @param blue the blue component of the new instance
686          *
687          * @exception IllegalArgumentException <ul>
688          *    <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
689          * </ul>
690          */
691         public RGB(int red, int green, int blue) {
692             if ((red > 255) || (red < 0) ||
693                 (green > 255) || (green < 0) ||
694                 (blue > 255) || (blue < 0))
695                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
696             this.red = red;
697             this.green = green;
698             this.blue = blue;
699         }
700
701         /**
702          * Compares the argument to the receiver, and returns true
703          * if they represent the <em>same</em> object using a class
704          * specific comparison.
705          *
706          * @param object the object to compare with this object
707          * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
708          *
709          * @see #hashCode()
710          */
711         public boolean equals (Object object) {
712             if (object == this) return true;
713             if (!(object instanceof RGB)) return false;
714             RGB rgb = (RGB)object;
715             return (rgb.red == this.red) && (rgb.green == this.green) && (rgb.blue == this.blue);
716         }
717
718         /**
719          * Returns an integer hash code for the receiver. Any two 
720          * objects which return <code>true</code> when passed to 
721          * <code>equals</code> must return the same value for this
722          * method.
723          *
724          * @return the receiver's hash
725          *
726          * @see #equals(Object)
727          */
728         public int hashCode () {
729             return (blue << 16) | (green << 8) | red;
730         }
731
732         /**
733          * Returns a string containing a concise, human-readable
734          * description of the receiver.
735          *
736          * @return a string representation of the <code>RGB</code>
737          */
738         public String toString () {
739             return "RGB {" + red + ", " + green + ", " + blue + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
740         }
741
742     }
743
744
745     /*******************************************************************************
746      * Copyright (c) 2000, 2004 IBM Corporation and others.
747      * All rights reserved. This program and the accompanying materials
748      * are made available under the terms of the Common Public License v1.0
749      * which accompanies this distribution, and is available at
750      * http://www.eclipse.org/legal/cpl-v10.html
751      * 
752      * Contributors:
753      *     IBM Corporation - initial API and implementation
754      *******************************************************************************/
755
756     /**
757      * Instances of this class describe the color data used by an image.
758      * <p>
759      * Depending on the depth of the image, the PaletteData can take one
760      * of two forms, indicated by the isDirect field:
761      * </p>
762      * <dl>
763      * <dt>
764      * <em>isDirect is false</em>
765      * </dt>
766      * <dd>
767      * If isDirect is <code>false</code>, this palette is an indexed
768      * palette which maps pixel values to RGBs. The actual RGB values
769      * may be retrieved by using the getRGBs() method.
770      * </dd>
771      * <dt>
772      * <em>isDirect is true</em>
773      * </dt>
774      * <dd>
775      * If isDirect is <code>true</code>, this palette is a direct color
776      * palette. Instead of containing RGB values, it contains red,
777      * green and blue mask and shift information which indicates how
778      * the color components may be extracted from a given pixel.
779      * This means that the RGB value is actually encoded in the pixel value.
780      * <p>
781      * In this case, the shift data is the number of bits required to shift
782      * the RGB value to the left in order to align the high bit of the
783      * corresponding mask with the high bit of the first byte. This number
784      * may be negative, so care must be taken when shifting. For example,
785      * with a red mask of 0xFF0000, the red shift would be -16. With a red
786      * mask of 0x1F, the red shift would be 3.
787      * </p>
788      * </dd>
789      * </dl>
790      *
791      * @see Image
792      * @see RGB
793      */
794  
795     public static final class PaletteData {
796         
797         /**
798          * true if the receiver is a direct palette, 
799          * and false otherwise
800          */
801         public boolean isDirect;
802         
803         /**
804          * the RGB values for an indexed palette, where the
805          * indices of the array correspond to pixel values
806          */
807         public RGB[] colors;
808         
809         /**
810          * the red mask for a direct palette
811          */
812         public int redMask;
813         
814         /**
815          * the green mask for a direct palette
816          */
817         public int greenMask;
818         
819         /**
820          * the blue mask for a direct palette
821          */
822         public int blueMask;
823         
824         /**
825          * the red shift for a direct palette
826          */
827         public int redShift;
828         
829         /**
830          * the green shift for a direct palette
831          */
832         public int greenShift;
833         
834         /**
835          * the blue shift for a direct palette
836          */
837         public int blueShift;
838
839         /**
840          * Constructs a new indexed palette given an array of RGB values.
841          *
842          * @param colors the array of <code>RGB</code>s for the palette
843          *
844          * @exception IllegalArgumentException <ul>
845          *    <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
846          * </ul>
847          */
848         public PaletteData(RGB[] colors) {
849             if (colors == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
850             this.colors = colors;
851             this.isDirect = false;
852         }
853
854         /**
855          * Constructs a new direct palette given the red, green and blue masks.
856          *
857          * @param redMask the red mask
858          * @param greenMask the green mask
859          * @param blueMask the blue mask
860          */
861         public PaletteData(int redMask, int greenMask, int blueMask) {
862             this.redMask = redMask;
863             this.greenMask = greenMask;
864             this.blueMask = blueMask;
865             this.isDirect = true;
866             this.redShift = shiftForMask(redMask);
867             this.greenShift = shiftForMask(greenMask);
868             this.blueShift = shiftForMask(blueMask);
869         }
870
871         /**
872          * Returns the pixel value corresponding to the given <code>RBG</code>.
873          *
874          * @param rgb the RGB to get the pixel value for
875          * @return the pixel value for the given RGB
876          * 
877          * @exception IllegalArgumentException <ul>
878          *    <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
879          *    <li>ERROR_INVALID_ARGUMENT - if the RGB is not found in the palette</li>
880          * </ul>
881          */
882         public int getPixel(RGB rgb) {
883             if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
884             if (isDirect) {
885                 int pixel = 0;
886                 pixel |= (redShift < 0 ? rgb.red << -redShift : rgb.red >>> redShift) & redMask;
887                 pixel |= (greenShift < 0 ? rgb.green << -greenShift : rgb.green >>> greenShift) & greenMask;
888                 pixel |= (blueShift < 0 ? rgb.blue << -blueShift : rgb.blue >>> blueShift) & blueMask;
889                 return pixel;
890             } else {
891                 for (int i = 0; i < colors.length; i++) {
892                     if (colors[i].equals(rgb)) return i;
893                 }
894                 /* The RGB did not exist in the palette */
895                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
896                 return 0;
897             }
898         }
899
900         /**
901          * Returns an <code>RGB</code> corresponding to the given pixel value.
902          *
903          * @param pixel the pixel to get the RGB value for
904          * @return the RGB value for the given pixel
905          *
906          * @exception IllegalArgumentException <ul>
907          *    <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
908          *    <li>ERROR_INVALID_ARGUMENT - if the pixel does not exist in the palette</li>
909          * </ul>
910          */
911         public RGB getRGB(int pixel) {
912             if (isDirect) {
913                 int r = pixel & redMask;
914                 r = (redShift < 0) ? r >>> -redShift : r << redShift;
915                 int g = pixel & greenMask;
916                 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
917                 int b = pixel & blueMask;
918                 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
919                 return new RGB(r, g, b);
920             } else {
921                 if (pixel < 0 || pixel >= colors.length) {
922                     SWT.error(SWT.ERROR_INVALID_ARGUMENT);
923                 }
924                 return colors[pixel];
925             }
926         }
927
928         /**
929          * Returns all the RGB values in the receiver if it is an
930          * indexed palette, or null if it is a direct palette.
931          *
932          * @return the <code>RGB</code>s for the receiver or null
933          */
934         public RGB[] getRGBs() {
935             return colors;
936         }
937
938         /**
939          * Computes the shift value for a given mask.
940          *
941          * @param mask the mask to compute the shift for
942          * @return the shift amount
943          *
944          * @see PaletteData
945          */
946         int shiftForMask(int mask) {
947             for (int i = 31; i >= 0; i--) { 
948                 if (((mask >> i) & 0x1) != 0) return 7 - i;
949             }
950             return 32;
951         }
952
953     }
954
955
956     /*******************************************************************************
957      * Copyright (c) 2000, 2004 IBM Corporation and others.
958      * All rights reserved. This program and the accompanying materials
959      * are made available under the terms of the Common Public License v1.0
960      * which accompanies this distribution, and is available at
961      * http://www.eclipse.org/legal/cpl-v10.html
962      * 
963      * Contributors:
964      *     IBM Corporation - initial API and implementation
965      *******************************************************************************/
966
967     /**
968      * Instances of this class are device-independent descriptions
969      * of images. They are typically used as an intermediate format
970      * between loading from or writing to streams and creating an 
971      * <code>Image</code>.
972      * <p>
973      * Note that the public fields <code>x</code>, <code>y</code>, 
974      * <code>disposalMethod</code> and <code>delayTime</code> are
975      * typically only used when the image is in a set of images used
976      * for animation.
977      * </p>
978      *
979      * @see Image
980      * @see ImageLoader
981      */
982
983     public static final class ImageData {
984         
985         /**
986          * The width of the image, in pixels.
987          */
988         public int width;
989
990         /**
991          * The height of the image, in pixels.
992          */
993         public int height;
994
995         /**
996          * The color depth of the image, in bits per pixel.
997          * <p>
998          * Note that a depth of 8 or less does not necessarily
999          * mean that the image is palette indexed, or
1000          * conversely that a depth greater than 8 means that
1001          * the image is direct color.  Check the associated
1002          * PaletteData's isDirect field for such determinations.
1003          */
1004         public int depth;
1005
1006         /**
1007          * The scanline padding.
1008          * <p>
1009          * If one scanline of the image is not a multiple of
1010          * this number, it will be padded with zeros until it is.
1011          * </p>
1012          */
1013         public int scanlinePad;
1014
1015         /**
1016          * The number of bytes per scanline.
1017          * <p>
1018          * This is a multiple of the scanline padding.
1019          * </p>
1020          */
1021         public int bytesPerLine;
1022
1023         /**
1024          * The pixel data of the image.
1025          * <p>
1026          * Note that for 16 bit depth images the pixel data is stored
1027          * in least significant byte order; however, for 24bit and
1028          * 32bit depth images the pixel data is stored in most
1029          * significant byte order.
1030          * </p>
1031          */
1032         public byte[] data;
1033
1034         /**
1035          * The color table for the image.
1036          */
1037         public PaletteData palette;
1038
1039         /**
1040          * The transparent pixel.
1041          * <p>
1042          * Pixels with this value are transparent.
1043          * </p><p>
1044          * The default is -1 which means 'no transparent pixel'.
1045          * </p>
1046          */
1047         public int transparentPixel;
1048
1049         /**
1050          * An icon-specific field containing the data from the icon mask.
1051          * <p>
1052          * This is a 1 bit bitmap stored with the most significant
1053          * bit first.  The number of bytes per scanline is
1054          * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
1055          * </p><p>
1056          * The default is null which means 'no transparency mask'.
1057          * </p>
1058          */
1059         public byte[] maskData;
1060
1061         /**
1062          * An icon-specific field containing the scanline pad of the mask.
1063          * <p>
1064          * If one scanline of the transparency mask is not a
1065          * multiple of this number, it will be padded with zeros until
1066          * it is.
1067          * </p>
1068          */
1069         public int maskPad;
1070         
1071         /**
1072          * The alpha data of the image.
1073          * <p>
1074          * Every pixel can have an <em>alpha blending</em> value that
1075          * varies from 0, meaning fully transparent, to 255 meaning
1076          * fully opaque.  The number of bytes per scanline is
1077          * 'width'.
1078          * </p>
1079          */
1080         public byte[] alphaData;
1081         
1082         /**
1083          * The global alpha value to be used for every pixel.
1084          * <p>
1085          * If this value is set, the <code>alphaData</code> field
1086          * is ignored and when the image is rendered each pixel
1087          * will be blended with the background an amount
1088          * proportional to this value.
1089          * </p><p>
1090          * The default is -1 which means 'no global alpha value'
1091          * </p>
1092          */
1093         public int alpha;
1094
1095         /**
1096          * The type of file from which the image was read.
1097          * 
1098          * It is expressed as one of the following values:
1099          * <dl>
1100          * <dt><code>IMAGE_BMP</code></dt>
1101          * <dd>Windows BMP file format, no compression</dd>
1102          * <dt><code>IMAGE_BMP_RLE</code></dt>
1103          * <dd>Windows BMP file format, RLE compression if appropriate</dd>
1104          * <dt><code>IMAGE_GIF</code></dt>
1105          * <dd>GIF file format</dd>
1106          * <dt><code>IMAGE_ICO</code></dt>
1107          * <dd>Windows ICO file format</dd>
1108          * <dt><code>IMAGE_JPEG</code></dt>
1109          * <dd>JPEG file format</dd>
1110          * <dt><code>IMAGE_PNG</code></dt>
1111          * <dd>PNG file format</dd>
1112          * </dl>
1113          */
1114         public int type;
1115
1116         /**
1117          * The x coordinate of the top left corner of the image
1118          * within the logical screen (this field corresponds to
1119          * the GIF89a Image Left Position value).
1120          */
1121         public int x;
1122
1123         /**
1124          * The y coordinate of the top left corner of the image
1125          * within the logical screen (this field corresponds to
1126          * the GIF89a Image Top Position value).
1127          */
1128         public int y;
1129
1130         /**
1131          * A description of how to dispose of the current image
1132          * before displaying the next.
1133          * 
1134          * It is expressed as one of the following values:
1135          * <dl>
1136          * <dt><code>DM_UNSPECIFIED</code></dt>
1137          * <dd>disposal method not specified</dd>
1138          * <dt><code>DM_FILL_NONE</code></dt>
1139          * <dd>do nothing - leave the image in place</dd>
1140          * <dt><code>DM_FILL_BACKGROUND</code></dt>
1141          * <dd>fill with the background color</dd>
1142          * <dt><code>DM_FILL_PREVIOUS</code></dt>
1143          * <dd>restore the previous picture</dd>
1144          * </dl>
1145          * (this field corresponds to the GIF89a Disposal Method value)
1146          */
1147         public int disposalMethod;
1148
1149         /**
1150          * The time to delay before displaying the next image
1151          * in an animation (this field corresponds to the GIF89a
1152          * Delay Time value).
1153          */
1154         public int delayTime;
1155
1156         /**
1157          * Arbitrary channel width data to 8-bit conversion table.
1158          */
1159         static final byte[][] ANY_TO_EIGHT = new byte[9][];
1160         static {
1161             for (int b = 0; b < 9; ++b) {
1162                 byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
1163                 if (b == 0) continue;
1164                 int inc = 0;
1165                 for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit;
1166                 for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8);
1167             }
1168         }
1169         static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
1170
1171         /**
1172          * Scaled 8x8 Bayer dither matrix.
1173          */
1174         static final int[][] DITHER_MATRIX = {
1175             { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
1176             { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
1177             { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
1178             { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
1179             { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
1180             { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
1181             { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
1182             { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
1183         };
1184
1185         /**
1186          * Constructs a new, empty ImageData with the given width, height,
1187          * depth and palette. The data will be initialized to an (all zero)
1188          * array of the appropriate size.
1189          *
1190          * @param width the width of the image
1191          * @param height the height of the image
1192          * @param depth the depth of the image
1193          * @param palette the palette of the image (must not be null)
1194          *
1195          * @exception IllegalArgumentException <ul>
1196          *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
1197          *              one of 1, 2, 4, 8, 16, 24 or 32</li>
1198          *    <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
1199          * </ul>
1200          */
1201         public ImageData(int width, int height, int depth, PaletteData palette) {
1202             this(width, height, depth, palette,
1203                  4, null, 0, null,
1204                  null, -1, -1, SWT.IMAGE_UNDEFINED,
1205                  0, 0, 0, 0);
1206         }
1207
1208         /**
1209          * Constructs a new, empty ImageData with the given width, height,
1210          * depth, palette, scanlinePad and data.
1211          *
1212          * @param width the width of the image
1213          * @param height the height of the image
1214          * @param depth the depth of the image
1215          * @param palette the palette of the image
1216          * @param scanlinePad the padding of each line, in bytes
1217          * @param data the data of the image
1218          *
1219          * @exception IllegalArgumentException <ul>
1220          *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
1221          *              one of 1, 2, 4, 8, 16, 24 or 32</li>
1222          *    <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
1223          *    <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
1224          * </ul>
1225          */
1226         public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
1227             this(width, height, depth, palette,
1228                  scanlinePad, checkData(data), 0, null,
1229                  null, -1, -1, SWT.IMAGE_UNDEFINED,
1230                  0, 0, 0, 0);
1231         }
1232
1233         /**
1234          * Constructs an <code>ImageData</code> loaded from the specified
1235          * input stream. Throws an error if an error occurs while loading
1236          * the image, or if the image has an unsupported type.  Application
1237          * code is still responsible for closing the input stream.
1238          * <p>
1239          * This constructor is provided for convenience when loading a single
1240          * image only. If the stream contains multiple images, only the first
1241          * one will be loaded. To load multiple images, use 
1242          * <code>ImageLoader.load()</code>.
1243          * </p>
1244          *
1245          * @param stream the input stream to load the image from (must not be null)
1246          *
1247          * @exception IllegalArgumentException <ul>
1248          *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
1249          * </ul>
1250          * @exception SWTException <ul>
1251          *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
1252          *    <li>ERROR_IO - if an IO error occurs while reading data</li>
1253          * </ul>
1254          *
1255          * @see ImageLoader#load(InputStream)
1256          */
1257         public ImageData(InputStream stream) {
1258             ImageData[] data = new ImageLoader().load(stream);
1259             if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
1260             ImageData i = data[0];
1261             setAllFields(
1262                          i.width,
1263                          i.height,
1264                          i.depth,
1265                          i.scanlinePad,
1266                          i.bytesPerLine,
1267                          i.data,
1268                          i.palette,
1269                          i.transparentPixel,
1270                          i.maskData,
1271                          i.maskPad,
1272                          i.alphaData,
1273                          i.alpha,
1274                          i.type,
1275                          i.x,
1276                          i.y,
1277                          i.disposalMethod,
1278                          i.delayTime);
1279         }
1280
1281         /**
1282          * Constructs an <code>ImageData</code> loaded from a file with the
1283          * specified name. Throws an error if an error occurs loading the
1284          * image, or if the image has an unsupported type.
1285          * <p>
1286          * This constructor is provided for convenience when loading a single
1287          * image only. If the file contains multiple images, only the first
1288          * one will be loaded. To load multiple images, use 
1289          * <code>ImageLoader.load()</code>.
1290          * </p>
1291          *
1292          * @param filename the name of the file to load the image from (must not be null)
1293          *
1294          * @exception IllegalArgumentException <ul>
1295          *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
1296          * </ul>
1297          * @exception SWTException <ul>
1298          *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
1299          *    <li>ERROR_IO if an IO error occurs while reading data</li>
1300          *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
1301          * </ul>
1302          */
1303         public ImageData(String filename) {
1304             ImageData[] data = new ImageLoader().load(filename);
1305             if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
1306             ImageData i = data[0];
1307             setAllFields(
1308                          i.width,
1309                          i.height,
1310                          i.depth,
1311                          i.scanlinePad,
1312                          i.bytesPerLine,
1313                          i.data,
1314                          i.palette,
1315                          i.transparentPixel,
1316                          i.maskData,
1317                          i.maskPad,
1318                          i.alphaData,
1319                          i.alpha,
1320                          i.type,
1321                          i.x,
1322                          i.y,
1323                          i.disposalMethod,
1324                          i.delayTime);
1325         }
1326
1327         /**
1328          * Prevents uninitialized instances from being created outside the package.
1329          */
1330         ImageData() {
1331         }
1332
1333         /**
1334          * Constructs an image data by giving values for all non-computable fields.
1335          * <p>
1336          * This method is for internal use, and is not described further.
1337          * </p>
1338          */
1339         ImageData(
1340                   int width, int height, int depth, PaletteData palette,
1341                   int scanlinePad, byte[] data, int maskPad, byte[] maskData,
1342                   byte[] alphaData, int alpha, int transparentPixel, int type,
1343                   int x, int y, int disposalMethod, int delayTime)
1344         {
1345
1346             if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1347             if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8
1348                   || depth == 16 || depth == 24 || depth == 32)) {
1349                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1350             }
1351             if (width <= 0 || height <= 0) {
1352                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1353             }
1354             if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
1355
1356             int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
1357                 / scanlinePad * scanlinePad;
1358             setAllFields(
1359                          width,
1360                          height,
1361                          depth,
1362                          scanlinePad,
1363                          bytesPerLine,
1364                          data != null ? data : new byte[bytesPerLine * height],
1365                          palette,
1366                          transparentPixel,
1367                          maskData,
1368                          maskPad,
1369                          alphaData,
1370                          alpha,
1371                          type,
1372                          x,
1373                          y,
1374                          disposalMethod,
1375                          delayTime);
1376         }
1377
1378         /**
1379          * Initializes all fields in the receiver. This method must be called
1380          * by all public constructors to ensure that all fields are initialized
1381          * for a new ImageData object. If a new field is added to the class,
1382          * then it must be added to this method.
1383          * <p>
1384          * This method is for internal use, and is not described further.
1385          * </p>
1386          */
1387         void setAllFields(int width, int height, int depth, int scanlinePad,
1388                           int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
1389                           byte[] maskData, int maskPad, byte[] alphaData, int alpha,
1390                           int type, int x, int y, int disposalMethod, int delayTime) {
1391
1392             this.width = width;
1393             this.height = height;
1394             this.depth = depth;
1395             this.scanlinePad = scanlinePad;
1396             this.bytesPerLine = bytesPerLine;
1397             this.data = data;
1398             this.palette = palette;
1399             this.transparentPixel = transparentPixel;
1400             this.maskData = maskData;
1401             this.maskPad = maskPad;
1402             this.alphaData = alphaData;
1403             this.alpha = alpha;
1404             this.type = type;
1405             this.x = x;
1406             this.y = y;
1407             this.disposalMethod = disposalMethod;
1408             this.delayTime = delayTime;
1409         }
1410
1411         /**      
1412          * Invokes internal SWT functionality to create a new instance of
1413          * this class.
1414          * <p>
1415          * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
1416          * API for <code>ImageData</code>. It is marked public only so that it
1417          * can be shared within the packages provided by SWT. It is subject
1418          * to change without notice, and should never be called from
1419          * application code.
1420          * </p>
1421          * <p>
1422          * This method is for internal use, and is not described further.
1423          * </p>
1424          */
1425         public static ImageData internal_new(
1426                                              int width, int height, int depth, PaletteData palette,
1427                                              int scanlinePad, byte[] data, int maskPad, byte[] maskData,
1428                                              byte[] alphaData, int alpha, int transparentPixel, int type,
1429                                              int x, int y, int disposalMethod, int delayTime)
1430         {
1431             return new ImageData(
1432                                  width, height, depth, palette, scanlinePad, data, maskPad, maskData,
1433                                  alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
1434         }
1435
1436         ImageData colorMaskImage(int pixel) {
1437             ImageData mask = new ImageData(width, height, 1, bwPalette(),
1438                                            2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED,
1439                                            0, 0, 0, 0);
1440             int[] row = new int[width];
1441             for (int y = 0; y < height; y++) {
1442                 getPixels(0, y, width, row, 0);
1443                 for (int i = 0; i < width; i++) {
1444                     if (pixel != -1 && row[i] == pixel) {
1445                         row[i] = 0;
1446                     } else {
1447                         row[i] = 1;
1448                     }
1449                 }
1450                 mask.setPixels(0, y, width, row, 0);
1451             }
1452             return mask;
1453         }
1454
1455         static byte[] checkData(byte [] data) {
1456             if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1457             return data;
1458         }
1459
1460         /**
1461          * Returns a new instance of the same class as the receiver,
1462          * whose slots have been filled in with <em>copies</em> of
1463          * the values in the slots of the receiver. That is, the
1464          * returned object is a <em>deep copy</em> of the receiver.
1465          *
1466          * @return a copy of the receiver.
1467          */
1468         public Object clone() {
1469             byte[] cloneData = new byte[data.length];
1470             System.arraycopy(data, 0, cloneData, 0, data.length);
1471             byte[] cloneMaskData = null;
1472             if (maskData != null) {
1473                 cloneMaskData = new byte[maskData.length];
1474                 System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length);
1475             }
1476             byte[] cloneAlphaData = null;
1477             if (alphaData != null) {
1478                 cloneAlphaData = new byte[alphaData.length];
1479                 System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length);
1480             }
1481             return new ImageData(
1482                                  width,
1483                                  height,
1484                                  depth,
1485                                  palette,
1486                                  scanlinePad,
1487                                  cloneData,
1488                                  maskPad,
1489                                  cloneMaskData,
1490                                  cloneAlphaData,
1491                                  alpha,
1492                                  transparentPixel,
1493                                  type,
1494                                  x,
1495                                  y,
1496                                  disposalMethod,
1497                                  delayTime);
1498         }
1499
1500         /**
1501          * Returns the alpha value at offset <code>x</code> in
1502          * scanline <code>y</code> in the receiver's alpha data.
1503          *
1504          * @param x the x coodinate of the pixel to get the alpha value of
1505          * @param y the y coordinate of the pixel to get the alpha value of
1506          * @return the alpha value at the given coordinates
1507          *
1508          * @exception IllegalArgumentException <ul>
1509          *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li>
1510          * </ul>
1511          */
1512         public int getAlpha(int x, int y) {
1513             if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1514
1515             if (alphaData == null) return 255;
1516             return alphaData[y * width + x] & 0xFF;
1517         }
1518
1519         /**
1520          * Returns <code>getWidth</code> alpha values starting at offset
1521          * <code>x</code> in scanline <code>y</code> in the receiver's alpha
1522          * data starting at <code>startIndex</code>.
1523          *
1524          * @param x the x position of the pixel to begin getting alpha values
1525          * @param y the y position of the pixel to begin getting alpha values
1526          * @param getWidth the width of the data to get
1527          * @param alphas the buffer in which to put the alpha values
1528          * @param startIndex the offset into the image to begin getting alpha values
1529          *
1530          * @exception IndexOutOfBoundsException if getWidth is too large
1531          * @exception IllegalArgumentException <ul>
1532          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1533          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1534          *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
1535          * </ul>
1536          */
1537         public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) {
1538             if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1539             if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1540             if (getWidth == 0) return;
1541
1542             if (alphaData == null) {
1543                 int endIndex = startIndex + getWidth;
1544                 for (int i = startIndex; i < endIndex; i++) {
1545                     alphas[i] = (byte)255;
1546                 }
1547                 return;
1548             }
1549             // may throw an IndexOutOfBoundsException
1550             System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth);
1551         }
1552
1553         /**
1554          * Returns the pixel value at offset <code>x</code> in
1555          * scanline <code>y</code> in the receiver's data.
1556          *
1557          * @param x the x position of the pixel to get
1558          * @param y the y position of the pixel to get
1559          * @return the pixel at the given coordinates
1560          *
1561          * @exception IllegalArgumentException <ul>
1562          *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li>
1563          * </ul>
1564          * @exception SWTException <ul>
1565          *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1566          * </ul>
1567          */
1568         public int getPixel(int x, int y) {
1569             if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1570             int index;
1571             int theByte;
1572             int mask;
1573             if (depth == 1) {
1574                 index = (y * bytesPerLine) + (x >> 3);
1575                 theByte = data[index] & 0xFF;
1576                 mask = 1 << (7 - (x & 0x7));
1577                 if ((theByte & mask) == 0) {
1578                     return 0;
1579                 } else {
1580                     return 1;
1581                 }
1582             }
1583             if (depth == 2) {
1584                 index = (y * bytesPerLine) + (x >> 2);
1585                 theByte = data[index] & 0xFF;
1586                 int offset = 3 - (x % 4);
1587                 mask = 3 << (offset * 2);
1588                 return (theByte & mask) >> (offset * 2);
1589             }
1590             if (depth == 4) {
1591                 index = (y * bytesPerLine) + (x >> 1);
1592                 theByte = data[index] & 0xFF;
1593                 if ((x & 0x1) == 0) {
1594                     return theByte >> 4;
1595                 } else {
1596                     return theByte & 0x0F;
1597                 }
1598             }
1599             if (depth == 8) {
1600                 index = (y * bytesPerLine) + x ;
1601                 return data[index] & 0xFF;
1602             }
1603             if (depth == 16) {
1604                 index = (y * bytesPerLine) + (x * 2);
1605                 return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
1606             }
1607             if (depth == 24) {
1608                 index = (y * bytesPerLine) + (x * 3);
1609                 return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) +
1610                     (data[index+2] & 0xFF);
1611             }
1612             if (depth == 32) {
1613                 index = (y * bytesPerLine) + (x * 4);
1614                 return ((data[index] & 0xFF) << 24) + ((data[index+1] & 0xFF) << 16) +
1615                     ((data[index+2] & 0xFF) << 8) + (data[index+3] & 0xFF);
1616             }
1617             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1618             return 0;
1619         }
1620
1621         /**
1622          * Returns <code>getWidth</code> pixel values starting at offset
1623          * <code>x</code> in scanline <code>y</code> in the receiver's
1624          * data starting at <code>startIndex</code>.
1625          *
1626          * @param x the x position of the first pixel to get
1627          * @param y the y position of the first pixel to get
1628          * @param getWidth the width of the data to get
1629          * @param pixels the buffer in which to put the pixels
1630          * @param startIndex the offset into the byte array to begin storing pixels
1631          *
1632          * @exception IndexOutOfBoundsException if getWidth is too large
1633          * @exception IllegalArgumentException <ul>
1634          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1635          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1636          *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
1637          * </ul>
1638          * @exception SWTException <ul>
1639          *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8
1640          *        (For higher depths, use the int[] version of this method.)</li>
1641          * </ul>
1642          */
1643         public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) {
1644             if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1645             if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1646             if (getWidth == 0) return;
1647             int index;
1648             int theByte;
1649             int mask = 0;
1650             int n = getWidth;
1651             int i = startIndex;
1652             int srcX = x, srcY = y;
1653             if (depth == 1) {
1654                 index = (y * bytesPerLine) + (x >> 3);
1655                 theByte = data[index] & 0xFF;
1656                 while (n > 0) {
1657                     mask = 1 << (7 - (srcX & 0x7));
1658                     if ((theByte & mask) == 0) {
1659                         pixels[i] = 0;
1660                     } else {
1661                         pixels[i] = 1;
1662                     }
1663                     i++;
1664                     n--;
1665                     srcX++;
1666                     if (srcX >= width) {
1667                         srcY++;
1668                         index = srcY * bytesPerLine;
1669                         if (n > 0) theByte = data[index] & 0xFF;
1670                         srcX = 0;
1671                     } else {
1672                         if (mask == 1) {
1673                             index++;
1674                             if (n > 0) theByte = data[index] & 0xFF;
1675                         }
1676                     }
1677                 }
1678                 return;
1679             }
1680             if (depth == 2) {
1681                 index = (y * bytesPerLine) + (x >> 2);
1682                 theByte = data[index] & 0xFF;
1683                 int offset;
1684                 while (n > 0) {
1685                     offset = 3 - (srcX % 4);
1686                     mask = 3 << (offset * 2);
1687                     pixels[i] = (byte)((theByte & mask) >> (offset * 2));
1688                     i++;
1689                     n--;
1690                     srcX++;
1691                     if (srcX >= width) {
1692                         srcY++;
1693                         index = srcY * bytesPerLine;
1694                         if (n > 0) theByte = data[index] & 0xFF;
1695                         srcX = 0;
1696                     } else {
1697                         if (offset == 0) {
1698                             index++;
1699                             theByte = data[index] & 0xFF;
1700                         }
1701                     }
1702                 }
1703                 return;
1704             }
1705             if (depth == 4) {
1706                 index = (y * bytesPerLine) + (x >> 1);
1707                 if ((x & 0x1) == 1) {
1708                     theByte = data[index] & 0xFF;
1709                     pixels[i] = (byte)(theByte & 0x0F);
1710                     i++;
1711                     n--;
1712                     srcX++;
1713                     if (srcX >= width) {
1714                         srcY++;
1715                         index = srcY * bytesPerLine;
1716                         srcX = 0;
1717                     } else {
1718                         index++;
1719                     }
1720                 }
1721                 while (n > 1) {
1722                     theByte = data[index] & 0xFF;
1723                     pixels[i] = (byte)(theByte >> 4);
1724                     i++;
1725                     n--;
1726                     srcX++;
1727                     if (srcX >= width) {
1728                         srcY++;
1729                         index = srcY * bytesPerLine;
1730                         srcX = 0;
1731                     } else {
1732                         pixels[i] = (byte)(theByte & 0x0F);
1733                         i++;
1734                         n--;
1735                         srcX++;
1736                         if (srcX >= width) {
1737                             srcY++;
1738                             index = srcY * bytesPerLine;
1739                             srcX = 0;
1740                         } else {
1741                             index++;
1742                         }
1743                     }
1744                 }
1745                 if (n > 0) {
1746                     theByte = data[index] & 0xFF;
1747                     pixels[i] = (byte)(theByte >> 4);
1748                 }
1749                 return;
1750             }
1751             if (depth == 8) {
1752                 index = (y * bytesPerLine) + x;
1753                 for (int j = 0; j < getWidth; j++) {
1754                     pixels[i] = data[index];
1755                     i++;
1756                     srcX++;
1757                     if (srcX >= width) {
1758                         srcY++;
1759                         index = srcY * bytesPerLine;
1760                         srcX = 0;
1761                     } else {
1762                         index++;
1763                     }
1764                 }
1765                 return;
1766             }
1767             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1768         }
1769
1770         /**
1771          * Returns <code>getWidth</code> pixel values starting at offset
1772          * <code>x</code> in scanline <code>y</code> in the receiver's
1773          * data starting at <code>startIndex</code>.
1774          *
1775          * @param x the x position of the first pixel to get
1776          * @param y the y position of the first pixel to get
1777          * @param getWidth the width of the data to get
1778          * @param pixels the buffer in which to put the pixels
1779          * @param startIndex the offset into the buffer to begin storing pixels
1780          *
1781          * @exception IndexOutOfBoundsException if getWidth is too large
1782          * @exception IllegalArgumentException <ul>
1783          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1784          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1785          *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
1786          * </ul>
1787          * @exception SWTException <ul>
1788          *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1789          * </ul>
1790          */
1791         public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) {
1792             if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1793             if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1794             if (getWidth == 0) return;
1795             int index;
1796             int theByte;
1797             int mask;
1798             int n = getWidth;
1799             int i = startIndex;
1800             int srcX = x, srcY = y;
1801             if (depth == 1) {
1802                 index = (y * bytesPerLine) + (x >> 3);
1803                 theByte = data[index] & 0xFF;
1804                 while (n > 0) {
1805                     mask = 1 << (7 - (srcX & 0x7));
1806                     if ((theByte & mask) == 0) {
1807                         pixels[i] = 0;
1808                     } else {
1809                         pixels[i] = 1;
1810                     }
1811                     i++;
1812                     n--;
1813                     srcX++;
1814                     if (srcX >= width) {
1815                         srcY++;
1816                         index = srcY * bytesPerLine;
1817                         if (n > 0) theByte = data[index] & 0xFF;
1818                         srcX = 0;
1819                     } else {
1820                         if (mask == 1) {
1821                             index++;
1822                             if (n > 0) theByte = data[index] & 0xFF;
1823                         }
1824                     }
1825                 }
1826                 return;
1827             }           
1828             if (depth == 2) {
1829                 index = (y * bytesPerLine) + (x >> 2);
1830                 theByte = data[index] & 0xFF;
1831                 int offset;
1832                 while (n > 0) {
1833                     offset = 3 - (srcX % 4);
1834                     mask = 3 << (offset * 2);
1835                     pixels[i] = (byte)((theByte & mask) >> (offset * 2));
1836                     i++;
1837                     n--;
1838                     srcX++;
1839                     if (srcX >= width) {
1840                         srcY++;
1841                         index = srcY * bytesPerLine;
1842                         if (n > 0) theByte = data[index] & 0xFF;
1843                         srcX = 0;
1844                     } else {
1845                         if (offset == 0) {
1846                             index++;
1847                             theByte = data[index] & 0xFF;
1848                         }
1849                     }
1850                 }
1851                 return;
1852             }
1853             if (depth == 4) {
1854                 index = (y * bytesPerLine) + (x >> 1);
1855                 if ((x & 0x1) == 1) {
1856                     theByte = data[index] & 0xFF;
1857                     pixels[i] = theByte & 0x0F;
1858                     i++;
1859                     n--;
1860                     srcX++;
1861                     if (srcX >= width) {
1862                         srcY++;
1863                         index = srcY * bytesPerLine;
1864                         srcX = 0;
1865                     } else {
1866                         index++;
1867                     }
1868                 }
1869                 while (n > 1) {
1870                     theByte = data[index] & 0xFF;
1871                     pixels[i] = theByte >> 4;
1872                     i++;
1873                     n--;
1874                     srcX++;
1875                     if (srcX >= width) {
1876                         srcY++;
1877                         index = srcY * bytesPerLine;
1878                         srcX = 0;
1879                     } else {
1880                         pixels[i] = theByte & 0x0F;
1881                         i++;
1882                         n--;
1883                         srcX++;
1884                         if (srcX >= width) {
1885                             srcY++;
1886                             index = srcY * bytesPerLine;
1887                             srcX = 0;
1888                         } else {
1889                             index++;
1890                         }
1891                     }
1892                 }
1893                 if (n > 0) {
1894                     theByte = data[index] & 0xFF;
1895                     pixels[i] = theByte >> 4;
1896                 }
1897                 return;
1898             }
1899             if (depth == 8) {
1900                 index = (y * bytesPerLine) + x;
1901                 for (int j = 0; j < getWidth; j++) {
1902                     pixels[i] = data[index] & 0xFF;
1903                     i++;
1904                     srcX++;
1905                     if (srcX >= width) {
1906                         srcY++;
1907                         index = srcY * bytesPerLine;
1908                         srcX = 0;
1909                     } else {
1910                         index++;
1911                     }
1912                 }
1913                 return;
1914             }
1915             if (depth == 16) {
1916                 index = (y * bytesPerLine) + (x * 2);
1917                 for (int j = 0; j < getWidth; j++) {
1918                     pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
1919                     i++;
1920                     srcX++;
1921                     if (srcX >= width) {
1922                         srcY++;
1923                         index = srcY * bytesPerLine;
1924                         srcX = 0;
1925                     } else {
1926                         index += 2;
1927                     }
1928                 }
1929                 return;
1930             }
1931             if (depth == 24) {
1932                 index = (y * bytesPerLine) + (x * 3);
1933                 for (int j = 0; j < getWidth; j++) {
1934                     pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8)
1935                         | (data[index+2] & 0xFF);
1936                     i++;
1937                     srcX++;
1938                     if (srcX >= width) {
1939                         srcY++;
1940                         index = srcY * bytesPerLine;
1941                         srcX = 0;
1942                     } else {
1943                         index += 3;
1944                     }
1945                 }
1946                 return;
1947             }
1948             if (depth == 32) {
1949                 index = (y * bytesPerLine) + (x * 4);
1950                 i = startIndex;
1951                 for (int j = 0; j < getWidth; j++) {
1952                     pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16)
1953                         | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF);
1954                     i++;
1955                     srcX++;
1956                     if (srcX >= width) {
1957                         srcY++;
1958                         index = srcY * bytesPerLine;
1959                         srcX = 0;
1960                     } else {
1961                         index += 4;
1962                     }
1963                 }
1964                 return;
1965             }
1966             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1967         }
1968
1969         /**
1970          * Returns an array of <code>RGB</code>s which comprise the
1971          * indexed color table of the receiver, or null if the receiver
1972          * has a direct color model.
1973          *
1974          * @return the RGB values for the image or null if direct color
1975          *
1976          * @see PaletteData#getRGBs()
1977          */
1978         public RGB[] getRGBs() {
1979             return palette.getRGBs();
1980         }
1981
1982         /**
1983          * Returns an <code>ImageData</code> which specifies the
1984          * transparency mask information for the receiver, or null if the
1985          * receiver has no transparency and is not an icon.
1986          *
1987          * @return the transparency mask or null if none exists
1988          */
1989         public ImageData getTransparencyMask() {
1990             if (getTransparencyType() == SWT.TRANSPARENCY_MASK) {
1991                 return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
1992             } else {
1993                 return colorMaskImage(transparentPixel);
1994             }
1995         }
1996
1997         /**
1998          * Returns the image transparency type.
1999          *
2000          * @return the receiver's transparency type
2001          */
2002         public int getTransparencyType() {
2003             if (maskData != null) return SWT.TRANSPARENCY_MASK;
2004             if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL;
2005             if (alphaData != null) return SWT.TRANSPARENCY_ALPHA;
2006             return SWT.TRANSPARENCY_NONE;
2007         }
2008
2009         /**
2010          * Returns the byte order of the receiver.
2011          * 
2012          * @return MSB_FIRST or LSB_FIRST
2013          */
2014         int getByteOrder() {
2015             return depth != 16 ? MSB_FIRST : LSB_FIRST;
2016         }
2017
2018         /**
2019          * Returns a copy of the receiver which has been stretched or
2020          * shrunk to the specified size. If either the width or height
2021          * is negative, the resulting image will be inverted in the
2022          * associated axis.
2023          *
2024          * @param width the width of the new ImageData
2025          * @param height the height of the new ImageData
2026          * @return a scaled copy of the image
2027          */
2028         public ImageData scaledTo(int width, int height) {
2029             /* Create a destination image with no data */
2030             final boolean flipX = (width < 0);
2031             if (flipX) width = - width;
2032             final boolean flipY = (height < 0);
2033             if (flipY) height = - height;
2034
2035             ImageData dest = new ImageData(
2036                                            width, height, depth, palette,
2037                                            scanlinePad, null, 0, null,
2038                                            null, -1, transparentPixel, type,
2039                                            x, y, disposalMethod, delayTime);
2040
2041             /* Scale the image contents */
2042             if (palette.isDirect) blit(BLIT_SRC,
2043                                        this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0,
2044                                        ALPHA_OPAQUE, null, 0, 0, 0,
2045                                        dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0,
2046                                        flipX, flipY);
2047             else blit(BLIT_SRC,
2048                       this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null,
2049                       ALPHA_OPAQUE, null, 0, 0, 0,
2050                       dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null,
2051                       flipX, flipY);
2052         
2053             /* Scale the image mask or alpha */
2054             if (maskData != null) {
2055                 dest.maskPad = this.maskPad;
2056                 int destBpl = (dest.width + 7) / 8;
2057                 destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad;
2058                 dest.maskData = new byte[destBpl * dest.height];
2059                 int srcBpl = (this.width + 7) / 8;
2060                 srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad;
2061                 blit(BLIT_SRC,
2062                      this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
2063                      ALPHA_OPAQUE, null, 0, 0, 0,
2064                      dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
2065                      flipX, flipY);
2066             } else if (alpha != -1) {
2067                 dest.alpha = this.alpha;
2068             } else if (alphaData != null) {
2069                 dest.alphaData = new byte[dest.width * dest.height];
2070                 blit(BLIT_SRC,
2071                      this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
2072                      ALPHA_OPAQUE, null, 0, 0, 0,
2073                      dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
2074                      flipX, flipY);
2075             }
2076             return dest;
2077         }
2078
2079         /**
2080          * Sets the alpha value at offset <code>x</code> in
2081          * scanline <code>y</code> in the receiver's alpha data.
2082          *
2083          * @param x the x coordinate of the alpha value to set
2084          * @param y the y coordinate of the alpha value to set
2085          * @param alpha the value to set the alpha to
2086          *
2087          * @exception IllegalArgumentException <ul>
2088          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2089          *  </ul>
2090          */
2091         public void setAlpha(int x, int y, int alpha) {
2092             if (x >= width || y >= height || x < 0 || y < 0 || alpha < 0 || alpha > 255)
2093                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2094         
2095             if (alphaData == null) alphaData = new byte[width * height];
2096             alphaData[y * width + x] = (byte)alpha;     
2097         }
2098
2099         /**
2100          * Sets the alpha values starting at offset <code>x</code> in
2101          * scanline <code>y</code> in the receiver's alpha data to the
2102          * values from the array <code>alphas</code> starting at
2103          * <code>startIndex</code>.
2104          *
2105          * @param x the x coordinate of the pixel to being setting the alpha values
2106          * @param y the y coordinate of the pixel to being setting the alpha values
2107          * @param putWidth the width of the alpha values to set
2108          * @param alphas the alpha values to set
2109          * @param startIndex the index at which to begin setting
2110          *
2111          * @exception IndexOutOfBoundsException if putWidth is too large
2112          * @exception IllegalArgumentException <ul>
2113          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
2114          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2115          *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
2116          * </ul>
2117          */
2118         public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) {
2119             if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2120             if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2121             if (putWidth == 0) return;
2122         
2123             if (alphaData == null) alphaData = new byte[width * height];
2124             // may throw an IndexOutOfBoundsException
2125             System.arraycopy(alphas, startIndex, alphaData, y * width + x, putWidth);
2126         }
2127
2128         /**
2129          * Sets the pixel value at offset <code>x</code> in
2130          * scanline <code>y</code> in the receiver's data.
2131          *
2132          * @param x the x coordinate of the pixel to set
2133          * @param y the y coordinate of the pixel to set
2134          * @param pixelValue the value to set the pixel to
2135          *
2136          * @exception IllegalArgumentException <ul>
2137          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2138          * </ul>
2139          * @exception SWTException <ul>
2140          *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
2141          * </ul>
2142          */
2143         public void setPixel(int x, int y, int pixelValue) {
2144             if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2145             int index;
2146             byte theByte;
2147             int mask;
2148             if (depth == 1) {
2149                 index = (y * bytesPerLine) + (x >> 3);
2150                 theByte = data[index];
2151                 mask = 1 << (7 - (x & 0x7));
2152                 if ((pixelValue & 0x1) == 1) {
2153                     data[index] = (byte)(theByte | mask);
2154                 } else {
2155                     data[index] = (byte)(theByte & (mask ^ -1));
2156                 }
2157                 return;
2158             }
2159             if (depth == 2) {
2160                 index = (y * bytesPerLine) + (x >> 2);
2161                 theByte = data[index];
2162                 int offset = 3 - (x % 4);
2163                 mask = 0xFF ^ (3 << (offset * 2));
2164                 data[index] = (byte)((data[index] & mask) | (pixelValue << (offset * 2)));
2165                 return;
2166             }
2167             if (depth == 4) {
2168                 index = (y * bytesPerLine) + (x >> 1);
2169                 if ((x & 0x1) == 0) {
2170                     data[index] = (byte)((data[index] & 0x0F) | ((pixelValue & 0x0F) << 4));
2171                 } else {
2172                     data[index] = (byte)((data[index] & 0xF0) | (pixelValue & 0x0F));
2173                 }
2174                 return;
2175             }
2176             if (depth == 8) {
2177                 index = (y * bytesPerLine) + x ;
2178                 data[index] = (byte)(pixelValue & 0xFF);
2179                 return;
2180             }
2181             if (depth == 16) {
2182                 index = (y * bytesPerLine) + (x * 2);
2183                 data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
2184                 data[index] = (byte)(pixelValue & 0xFF);
2185                 return;
2186             }
2187             if (depth == 24) {
2188                 index = (y * bytesPerLine) + (x * 3);
2189                 data[index] = (byte)((pixelValue >> 16) & 0xFF);
2190                 data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
2191                 data[index + 2] = (byte)(pixelValue & 0xFF);
2192                 return;
2193             }
2194             if (depth == 32) {
2195                 index = (y * bytesPerLine) + (x * 4);
2196                 data[index]  = (byte)((pixelValue >> 24) & 0xFF);
2197                 data[index + 1] = (byte)((pixelValue >> 16) & 0xFF);
2198                 data[index + 2] = (byte)((pixelValue >> 8) & 0xFF);
2199                 data[index + 3] = (byte)(pixelValue & 0xFF);
2200                 return;
2201             }
2202             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
2203         }
2204
2205         /**
2206          * Sets the pixel values starting at offset <code>x</code> in
2207          * scanline <code>y</code> in the receiver's data to the
2208          * values from the array <code>pixels</code> starting at
2209          * <code>startIndex</code>.
2210          *
2211          * @param x the x position of the pixel to set
2212          * @param y the y position of the pixel to set
2213          * @param putWidth the width of the pixels to set
2214          * @param pixels the pixels to set
2215          * @param startIndex the index at which to begin setting
2216          *
2217          * @exception IndexOutOfBoundsException if putWidth is too large
2218          * @exception IllegalArgumentException <ul>
2219          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
2220          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2221          *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
2222          * </ul>
2223          * @exception SWTException <ul>
2224          *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
2225          *        (For higher depths, use the int[] version of this method.)</li>
2226          * </ul>
2227          */
2228         public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
2229             if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2230             if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2231             if (putWidth == 0) return;
2232             int index;
2233             int theByte;
2234             int mask;
2235             int n = putWidth;
2236             int i = startIndex;
2237             int srcX = x, srcY = y;
2238             if (depth == 1) {
2239                 index = (y * bytesPerLine) + (x >> 3);
2240                 while (n > 0) {
2241                     mask = 1 << (7 - (srcX & 0x7));
2242                     if ((pixels[i] & 0x1) == 1) {
2243                         data[index] = (byte)((data[index] & 0xFF) | mask);
2244                     } else {
2245                         data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
2246                     }
2247                     i++;
2248                     n--;
2249                     srcX++;
2250                     if (srcX >= width) {
2251                         srcY++;
2252                         index = srcY * bytesPerLine;
2253                         srcX = 0;
2254                     } else {
2255                         if (mask == 1) {
2256                             index++;
2257                         }
2258                     }
2259                 }
2260                 return;
2261             }
2262             if (depth == 2) {
2263                 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
2264                 index = (y * bytesPerLine) + (x >> 2);
2265                 int offset = 3 - (x % 4);
2266                 while (n > 0) {
2267                     theByte = pixels[i] & 0x3;
2268                     data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
2269                     i++;
2270                     n--;
2271                     srcX++;
2272                     if (srcX >= width) {
2273                         srcY++;
2274                         index = srcY * bytesPerLine;
2275                         offset = 0;
2276                         srcX = 0;
2277                     } else {
2278                         if (offset == 0) {
2279                             index++;
2280                             offset = 3;
2281                         } else {
2282                             offset--;
2283                         }
2284                     }
2285                 }
2286                 return;
2287             }
2288             if (depth == 4) {
2289                 index = (y * bytesPerLine) + (x >> 1);
2290                 boolean high = (x & 0x1) == 0;
2291                 while (n > 0) {
2292                     theByte = pixels[i] & 0x0F;
2293                     if (high) {
2294                         data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
2295                     } else {
2296                         data[index] = (byte)((data[index] & 0xF0) | theByte);
2297                     }
2298                     i++;
2299                     n--;
2300                     srcX++;
2301                     if (srcX >= width) {
2302                         srcY++;
2303                         index = srcY * bytesPerLine;
2304                         high = true;
2305                         srcX = 0;
2306                     } else {
2307                         if (!high) index++;
2308                         high = !high;
2309                     }
2310                 }
2311                 return;
2312             }
2313             if (depth == 8) {
2314                 index = (y * bytesPerLine) + x;
2315                 for (int j = 0; j < putWidth; j++) {
2316                     data[index] = (byte)(pixels[i] & 0xFF);
2317                     i++;
2318                     srcX++;
2319                     if (srcX >= width) {
2320                         srcY++;
2321                         index = srcY * bytesPerLine;
2322                         srcX = 0;
2323                     } else {
2324                         index++;
2325                     }
2326                 }
2327                 return;
2328             }
2329             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
2330         }
2331
2332         /**
2333          * Sets the pixel values starting at offset <code>x</code> in
2334          * scanline <code>y</code> in the receiver's data to the
2335          * values from the array <code>pixels</code> starting at
2336          * <code>startIndex</code>.
2337          *
2338          * @param x the x position of the pixel to set
2339          * @param y the y position of the pixel to set
2340          * @param putWidth the width of the pixels to set
2341          * @param pixels the pixels to set
2342          * @param startIndex the index at which to begin setting
2343          *
2344          * @exception IndexOutOfBoundsException if putWidth is too large
2345          * @exception IllegalArgumentException <ul>
2346          *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
2347          *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2348          *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
2349          * </ul>
2350          * @exception SWTException <ul>
2351          *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
2352          * </ul>
2353          */
2354         public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
2355             if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2356             if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2357             if (putWidth == 0) return;
2358             int index;
2359             int theByte;
2360             int mask;
2361             int n = putWidth;
2362             int i = startIndex;
2363             int pixel;
2364             int srcX = x, srcY = y;
2365             if (depth == 1) {
2366                 index = (y * bytesPerLine) + (x >> 3);
2367                 while (n > 0) {
2368                     mask = 1 << (7 - (srcX & 0x7));
2369                     if ((pixels[i] & 0x1) == 1) {
2370                         data[index] = (byte)((data[index] & 0xFF) | mask);
2371                     } else {
2372                         data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
2373                     }
2374                     i++;
2375                     n--;
2376                     srcX++;
2377                     if (srcX >= width) {
2378                         srcY++;
2379                         index = srcY * bytesPerLine;
2380                         srcX = 0;
2381                     } else {
2382                         if (mask == 1) {
2383                             index++;
2384                         }
2385                     }
2386                 }
2387                 return;
2388             }
2389             if (depth == 2) {
2390                 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
2391                 index = (y * bytesPerLine) + (x >> 2);
2392                 int offset = 3 - (x % 4);
2393                 while (n > 0) {
2394                     theByte = pixels[i] & 0x3;
2395                     data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
2396                     i++;
2397                     n--;
2398                     srcX++;
2399                     if (srcX >= width) {
2400                         srcY++;
2401                         index = srcY * bytesPerLine;
2402                         offset = 3;
2403                         srcX = 0;
2404                     } else {
2405                         if (offset == 0) {
2406                             index++;
2407                             offset = 3;
2408                         } else {
2409                             offset--;
2410                         }
2411                     }
2412                 }
2413                 return;
2414             }
2415             if (depth == 4) {
2416                 index = (y * bytesPerLine) + (x >> 1);
2417                 boolean high = (x & 0x1) == 0;
2418                 while (n > 0) {
2419                     theByte = pixels[i] & 0x0F;
2420                     if (high) {
2421                         data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
2422                     } else {
2423                         data[index] = (byte)((data[index] & 0xF0) | theByte);
2424                     }
2425                     i++;
2426                     n--;
2427                     srcX++;
2428                     if (srcX >= width) {
2429                         srcY++;
2430                         index = srcY * bytesPerLine;
2431                         high = true;
2432                         srcX = 0;
2433                     } else {
2434                         if (!high) index++;
2435                         high = !high;
2436                     }
2437                 }
2438                 return;
2439             }
2440             if (depth == 8) {
2441                 index = (y * bytesPerLine) + x;
2442                 for (int j = 0; j < putWidth; j++) {
2443                     data[index] = (byte)(pixels[i] & 0xFF);
2444                     i++;
2445                     srcX++;
2446                     if (srcX >= width) {
2447                         srcY++;
2448                         index = srcY * bytesPerLine;
2449                         srcX = 0;
2450                     } else {
2451                         index++;
2452                     }
2453                 }
2454                 return;
2455
2456             }
2457             if (depth == 16) {
2458                 index = (y * bytesPerLine) + (x * 2);
2459                 for (int j = 0; j < putWidth; j++) {
2460                     pixel = pixels[i];
2461                     data[index] = (byte)(pixel & 0xFF);
2462                     data[index + 1] = (byte)((pixel >> 8) & 0xFF);
2463                     i++;
2464                     srcX++;
2465                     if (srcX >= width) {
2466                         srcY++;
2467                         index = srcY * bytesPerLine;
2468                         srcX = 0;
2469                     } else {
2470                         index += 2;
2471                     }
2472                 }
2473                 return;
2474             }
2475             if (depth == 24) {
2476                 index = (y * bytesPerLine) + (x * 3);
2477                 for (int j = 0; j < putWidth; j++) {
2478                     pixel = pixels[i];
2479                     data[index] = (byte)((pixel >> 16) & 0xFF);
2480                     data[index + 1] = (byte)((pixel >> 8) & 0xFF);
2481                     data[index + 2] = (byte)(pixel & 0xFF);
2482                     i++;
2483                     srcX++;
2484                     if (srcX >= width) {
2485                         srcY++;
2486                         index = srcY * bytesPerLine;
2487                         srcX = 0;
2488                     } else {
2489                         index += 3;
2490                     }
2491                 }
2492                 return;
2493             }
2494             if (depth == 32) {
2495                 index = (y * bytesPerLine) + (x * 4);
2496                 for (int j = 0; j < putWidth; j++) {
2497                     pixel = pixels[i];
2498                     data[index] = (byte)((pixel >> 24) & 0xFF);
2499                     data[index + 1] = (byte)((pixel >> 16) & 0xFF);
2500                     data[index + 2] = (byte)((pixel >> 8) & 0xFF);
2501                     data[index + 3] = (byte)(pixel & 0xFF);
2502                     i++;
2503                     srcX++;
2504                     if (srcX >= width) {
2505                         srcY++;
2506                         index = srcY * bytesPerLine;
2507                         srcX = 0;
2508                     } else {
2509                         index += 4;
2510                     }
2511                 }
2512                 return;
2513             }
2514             SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
2515         }
2516
2517         /**
2518          * Returns a palette with 2 colors: black & white.
2519          */
2520         static PaletteData bwPalette() {
2521             return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)});
2522         }
2523
2524         /**
2525          * Gets the offset of the most significant bit for
2526          * the given mask.
2527          */
2528         static int getMSBOffset(int mask) {
2529             for (int i = 31; i >= 0; i--) {
2530                 if (((mask >> i) & 0x1) != 0) return i + 1;
2531             }
2532             return 0;
2533         }
2534
2535         /**
2536          * Finds the closest match.
2537          */
2538         static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) {
2539             if (depth > 8) {
2540                 int rshift = 32 - getMSBOffset(redMask);
2541                 int gshift = 32 - getMSBOffset(greenMask);
2542                 int bshift = 32 - getMSBOffset(blueMask);
2543                 return (((red << 24) >>> rshift) & redMask) |
2544                     (((green << 24) >>> gshift) & greenMask) |
2545                     (((blue << 24) >>> bshift) & blueMask);
2546             }
2547             int r, g, b;
2548             int minDistance = 0x7fffffff;
2549             int nearestPixel = 0;
2550             int n = reds.length;
2551             for (int j = 0; j < n; j++) {
2552                 r = (reds[j] & 0xFF) - (red & 0xFF);
2553                 g = (greens[j] & 0xFF) - (green & 0xFF);
2554                 b = (blues[j] & 0xFF) - (blue & 0xFF);
2555                 int distance = r*r + g*g + b*b;
2556                 if (distance < minDistance) {
2557                     nearestPixel = j;
2558                     if (distance == 0) break;
2559                     minDistance = distance;
2560                 }
2561             }
2562             return nearestPixel;
2563         }
2564
2565         static final ImageData convertMask(ImageData mask) {
2566             if (mask.depth == 1) return mask;
2567             PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)});
2568             ImageData newMask = new ImageData(mask.width, mask.height, 1, palette);
2569             /* Find index of black in mask palette */
2570             int blackIndex = 0;
2571             RGB[] rgbs = mask.getRGBs();
2572             if (rgbs != null) {
2573                 while (blackIndex < rgbs.length) {
2574                     if (rgbs[blackIndex].equals(palette.colors[0])) break;
2575                     blackIndex++;
2576                 }
2577             }
2578             int[] pixels = new int[mask.width];
2579             for (int y = 0; y < mask.height; y++) {
2580                 mask.getPixels(0, y, mask.width, pixels, 0);
2581                 for (int i = 0; i < pixels.length; i++) {
2582                     if (pixels[i] == blackIndex) {
2583                         pixels[i] = 0;
2584                     } else {
2585                         pixels[i] = 1;
2586                     }
2587                 }
2588                 newMask.setPixels(0, y, mask.width, pixels, 0);
2589             }
2590             return newMask;
2591         }
2592
2593         static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
2594             if (pad == newPad) return data;
2595             int stride = (width * depth + 7) / 8;
2596             int bpl = (stride + (pad - 1)) / pad * pad; 
2597             int newBpl = (stride + (newPad - 1)) / newPad * newPad;
2598             byte[] newData = new byte[height * newBpl];
2599             int srcIndex = 0, destIndex = 0;
2600             for (int y = 0; y < height; y++) {
2601                 System.arraycopy(data, srcIndex, newData, destIndex, stride);
2602                 srcIndex += bpl;
2603                 destIndex += newBpl;
2604             }
2605             return newData;
2606         }
2607
2608         /**
2609          * Blit operation bits to be OR'ed together to specify the desired operation.
2610          */
2611         static final int
2612             BLIT_SRC = 1,     // copy source directly, else applies logic operations
2613             BLIT_ALPHA = 2,   // enable alpha blending
2614             BLIT_DITHER = 4;  // enable dithering in low color modes
2615
2616         /**
2617          * Alpha mode, values 0 - 255 specify global alpha level
2618          */
2619         static final int
2620             ALPHA_OPAQUE = 255,           // Fully opaque (ignores any alpha data)
2621             ALPHA_TRANSPARENT = 0,        // Fully transparent (ignores any alpha data)
2622             ALPHA_CHANNEL_SEPARATE = -1,  // Use alpha channel from separate alphaData
2623             ALPHA_CHANNEL_SOURCE = -2,    // Use alpha channel embedded in sourceData
2624             ALPHA_MASK_UNPACKED = -3,     // Use transparency mask formed by bytes in alphaData (non-zero is opaque)
2625             ALPHA_MASK_PACKED = -4,       // Use transparency mask formed by packed bits in alphaData
2626             ALPHA_MASK_INDEX = -5,        // Consider source palette indices transparent if in alphaData array
2627             ALPHA_MASK_RGB = -6;          // Consider source RGBs transparent if in RGB888 format alphaData array
2628
2629         /**
2630          * Byte and bit order constants.
2631          */
2632         static final int LSB_FIRST = 0;
2633         static final int MSB_FIRST = 1;
2634
2635         /**
2636          * Data types (internal)
2637          */
2638         private static final int
2639             // direct / true color formats with arbitrary masks & shifts
2640             TYPE_GENERIC_8 = 0,
2641             TYPE_GENERIC_16_MSB = 1,
2642             TYPE_GENERIC_16_LSB = 2,
2643             TYPE_GENERIC_24 = 3,
2644             TYPE_GENERIC_32_MSB = 4,
2645             TYPE_GENERIC_32_LSB = 5,
2646             // palette indexed color formats
2647             TYPE_INDEX_8 = 6,
2648             TYPE_INDEX_4 = 7,
2649             TYPE_INDEX_2 = 8,
2650             TYPE_INDEX_1_MSB = 9,
2651             TYPE_INDEX_1_LSB = 10;
2652
2653         /**
2654          * Blits a direct palette image into a direct palette image.
2655          * <p>
2656          * Note: When the source and destination depth, order and masks
2657          * are pairwise equal and the blitter operation is BLIT_SRC,
2658          * the masks are ignored.  Hence when not changing the image
2659          * data format, 0 may be specified for the masks.
2660          * </p>
2661          * 
2662          * @param op the blitter operation: a combination of BLIT_xxx flags
2663          *        (see BLIT_xxx constants)
2664          * @param srcData the source byte array containing image data
2665          * @param srcDepth the source depth: one of 8, 16, 24, 32
2666          * @param srcStride the source number of bytes per line
2667          * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
2668          *        ignored if srcDepth is not 16 or 32
2669          * @param srcX the top-left x-coord of the source blit region
2670          * @param srcY the top-left y-coord of the source blit region
2671          * @param srcWidth the width of the source blit region
2672          * @param srcHeight the height of the source blit region
2673          * @param srcRedMask the source red channel mask
2674          * @param srcGreenMask the source green channel mask
2675          * @param srcBlueMask the source blue channel mask
2676          * @param alphaMode the alpha blending or mask mode, may be
2677          *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
2678          *        not specified in the blitter operations
2679          *        (see ALPHA_MODE_xxx constants)
2680          * @param alphaData the alpha blending or mask data, varies depending
2681          *        on the value of alphaMode and sometimes ignored
2682          * @param alphaStride the alpha data number of bytes per line
2683          * @param alphaX the top-left x-coord of the alpha blit region
2684          * @param alphaY the top-left y-coord of the alpha blit region
2685          * @param destData the destination byte array containing image data
2686          * @param destDepth the destination depth: one of 8, 16, 24, 32
2687          * @param destStride the destination number of bytes per line
2688          * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
2689          *        ignored if destDepth is not 16 or 32
2690          * @param destX the top-left x-coord of the destination blit region
2691          * @param destY the top-left y-coord of the destination blit region
2692          * @param destWidth the width of the destination blit region
2693          * @param destHeight the height of the destination blit region
2694          * @param destRedMask the destination red channel mask
2695          * @param destGreenMask the destination green channel mask
2696          * @param destBlueMask the destination blue channel mask
2697          * @param flipX if true the resulting image is flipped along the vertical axis
2698          * @param flipY if true the resulting image is flipped along the horizontal axis
2699          */
2700         static void blit(int op,
2701                          byte[] srcData, int srcDepth, int srcStride, int srcOrder,
2702                          int srcX, int srcY, int srcWidth, int srcHeight,
2703                          int srcRedMask, int srcGreenMask, int srcBlueMask,
2704                          int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
2705                          byte[] destData, int destDepth, int destStride, int destOrder,
2706                          int destX, int destY, int destWidth, int destHeight,
2707                          int destRedMask, int destGreenMask, int destBlueMask,
2708                          boolean flipX, boolean flipY) {
2709             if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
2710
2711             // these should be supplied as params later
2712             final int srcAlphaMask = 0, destAlphaMask = 0;
2713
2714             /*** Prepare scaling data ***/
2715             final int dwm1 = destWidth - 1;
2716             final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
2717             final int dhm1 = destHeight - 1;
2718             final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
2719
2720             /*** Prepare source-related data ***/
2721             final int sbpp, stype;
2722             switch (srcDepth) {
2723                 case 8:
2724                     sbpp = 1;
2725                     stype = TYPE_GENERIC_8;
2726                     break;
2727                 case 16:
2728                     sbpp = 2;
2729                     stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
2730                     break;
2731                 case 24:
2732                     sbpp = 3;
2733                     stype = TYPE_GENERIC_24;
2734                     break;
2735                 case 32:
2736                     sbpp = 4;
2737                     stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
2738                     break;
2739                 default:
2740                     //throw new IllegalArgumentException("Invalid source type");
2741                     return;
2742             }                   
2743             int spr = srcY * srcStride + srcX * sbpp;
2744
2745             /*** Prepare destination-related data ***/
2746             final int dbpp, dtype;
2747             switch (destDepth) {
2748                 case 8:
2749                     dbpp = 1;
2750                     dtype = TYPE_GENERIC_8;
2751                     break;
2752                 case 16:
2753                     dbpp = 2;
2754                     dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
2755                     break;
2756                 case 24:
2757                     dbpp = 3;
2758                     dtype = TYPE_GENERIC_24;
2759                     break;
2760                 case 32:
2761                     dbpp = 4;
2762                     dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
2763                     break;
2764                 default:
2765                     //throw new IllegalArgumentException("Invalid destination type");
2766                     return;
2767             }                   
2768             int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
2769             final int dprxi = (flipX) ? -dbpp : dbpp;
2770             final int dpryi = (flipY) ? -destStride : destStride;
2771
2772             /*** Prepare special processing data ***/
2773             int apr;
2774             if ((op & BLIT_ALPHA) != 0) {
2775                 switch (alphaMode) {
2776                     case ALPHA_MASK_UNPACKED:
2777                     case ALPHA_CHANNEL_SEPARATE:
2778                         if (alphaData == null) alphaMode = 0x10000;
2779                         apr = alphaY * alphaStride + alphaX;
2780                         break;
2781                     case ALPHA_MASK_PACKED:
2782                         if (alphaData == null) alphaMode = 0x10000;
2783                         alphaStride <<= 3;
2784                         apr = alphaY * alphaStride + alphaX;
2785                         break;
2786                     case ALPHA_MASK_INDEX:
2787                         //throw new IllegalArgumentException("Invalid alpha type");
2788                         return;
2789                     case ALPHA_MASK_RGB:
2790                         if (alphaData == null) alphaMode = 0x10000;
2791                         apr = 0;
2792                         break;
2793                     default:
2794                         alphaMode = (alphaMode << 16) / 255; // prescale
2795                     case ALPHA_CHANNEL_SOURCE:
2796                         apr = 0;
2797                         break;
2798                 }
2799             } else {
2800                 alphaMode = 0x10000;
2801                 apr = 0;
2802             }
2803
2804             /*** Blit ***/
2805             int dp = dpr;
2806             int sp = spr;
2807             if ((alphaMode == 0x10000) && (stype == dtype) &&
2808                 (srcRedMask == destRedMask) && (srcGreenMask == destGreenMask) &&
2809                 (srcBlueMask == destBlueMask) && (srcAlphaMask == destAlphaMask)) {
2810                 /*** Fast blit (straight copy) ***/
2811                 switch (sbpp) {
2812                     case 1:
2813                         for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2814                             for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2815                                 destData[dp] = srcData[sp];
2816                                 sp += (sfx >>> 16);
2817                             }
2818                         }
2819                         break;                                  
2820                     case 2:
2821                         for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2822                             for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2823                                 destData[dp] = srcData[sp];
2824                                 destData[dp + 1] = srcData[sp + 1];
2825                                 sp += (sfx >>> 16) * 2;
2826                             }
2827                         }
2828                         break;
2829                     case 3:
2830                         for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2831                             for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2832                                 destData[dp] = srcData[sp];
2833                                 destData[dp + 1] = srcData[sp + 1];
2834                                 destData[dp + 2] = srcData[sp + 2];
2835                                 sp += (sfx >>> 16) * 3;
2836                             }
2837                         }
2838                         break;
2839                     case 4:
2840                         for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2841                             for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2842                                 destData[dp] = srcData[sp];
2843                                 destData[dp + 1] = srcData[sp + 1];
2844                                 destData[dp + 2] = srcData[sp + 2];
2845                                 destData[dp + 3] = srcData[sp + 3];
2846                                 sp += (sfx >>> 16) * 4;
2847                             }
2848                         }
2849                         break;
2850                 }
2851                 return;
2852             }
2853             /*** Comprehensive blit (apply transformations) ***/
2854             final int srcRedShift = getChannelShift(srcRedMask);
2855             final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
2856             final int srcGreenShift = getChannelShift(srcGreenMask);
2857             final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
2858             final int srcBlueShift = getChannelShift(srcBlueMask);
2859             final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
2860             final int srcAlphaShift = getChannelShift(srcAlphaMask);
2861             final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
2862
2863             final int destRedShift = getChannelShift(destRedMask);
2864             final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
2865             final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
2866             final int destRedPreShift = 8 - destRedWidth;
2867             final int destGreenShift = getChannelShift(destGreenMask);
2868             final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
2869             final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
2870             final int destGreenPreShift = 8 - destGreenWidth;
2871             final int destBlueShift = getChannelShift(destBlueMask);
2872             final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
2873             final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
2874             final int destBluePreShift = 8 - destBlueWidth;
2875             final int destAlphaShift = getChannelShift(destAlphaMask);
2876             final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
2877             final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
2878             final int destAlphaPreShift = 8 - destAlphaWidth;
2879
2880             int ap = apr, alpha = alphaMode;
2881             int r = 0, g = 0, b = 0, a = 0;
2882             int rq = 0, gq = 0, bq = 0, aq = 0;
2883             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2884                      sp = spr += (sfy >>> 16) * srcStride,
2885                      ap = apr += (sfy >>> 16) * alphaStride,
2886                      sfy = (sfy & 0xffff) + sfyi,
2887                      dp = dpr += dpryi) {
2888                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2889                          dp += dprxi,
2890                          sfx = (sfx & 0xffff) + sfxi) {
2891                     /*** READ NEXT PIXEL ***/
2892                     switch (stype) {
2893                         case TYPE_GENERIC_8: {
2894                             final int data = srcData[sp] & 0xff;
2895                             sp += (sfx >>> 16);
2896                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2897                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2898                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2899                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2900                         } break;
2901                         case TYPE_GENERIC_16_MSB: {
2902                             final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
2903                             sp += (sfx >>> 16) * 2;
2904                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2905                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2906                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2907                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2908                         } break;
2909                         case TYPE_GENERIC_16_LSB: {
2910                             final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
2911                             sp += (sfx >>> 16) * 2;
2912                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2913                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2914                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2915                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2916                         } break;
2917                         case TYPE_GENERIC_24: {
2918                             final int data = (( ((srcData[sp] & 0xff) << 8) |
2919                                                 (srcData[sp + 1] & 0xff)) << 8) |
2920                                 (srcData[sp + 2] & 0xff);
2921                             sp += (sfx >>> 16) * 3;
2922                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2923                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2924                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2925                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2926                         } break;
2927                         case TYPE_GENERIC_32_MSB: {
2928                             final int data = (( (( ((srcData[sp] & 0xff) << 8) |
2929                                                    (srcData[sp + 1] & 0xff)) << 8) |
2930                                                 (srcData[sp + 2] & 0xff)) << 8) |
2931                                 (srcData[sp + 3] & 0xff);
2932                             sp += (sfx >>> 16) * 4;
2933                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2934                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2935                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2936                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2937                         } break;
2938                         case TYPE_GENERIC_32_LSB: {
2939                             final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
2940                                                    (srcData[sp + 2] & 0xff)) << 8) |
2941                                                 (srcData[sp + 1] & 0xff)) << 8) |
2942                                 (srcData[sp] & 0xff);
2943                             sp += (sfx >>> 16) * 4;
2944                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2945                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2946                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2947                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2948                         } break;
2949                     }
2950
2951                     /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2952                     switch (alphaMode) {
2953                         case ALPHA_CHANNEL_SEPARATE:
2954                             alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2955                             ap += (sfx >> 16);
2956                             break;
2957                         case ALPHA_CHANNEL_SOURCE:
2958                             alpha = (a << 16) / 255;
2959                             break;
2960                         case ALPHA_MASK_UNPACKED:
2961                             alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
2962                             ap += (sfx >> 16);
2963                             break;                                              
2964                         case ALPHA_MASK_PACKED:
2965                             alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2966                             ap += (sfx >> 16);
2967                             break;
2968                         case ALPHA_MASK_RGB:
2969                             alpha = 0x10000;
2970                             for (int i = 0; i < alphaData.length; i += 3) {
2971                                 if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
2972                                     alpha = 0x0000;
2973                                     break;
2974                                 }
2975                             }
2976                             break;
2977                     }
2978                     if (alpha != 0x10000) {
2979                         if (alpha == 0x0000) continue;
2980                         switch (dtype) {
2981                             case TYPE_GENERIC_8: {
2982                                 final int data = destData[dp] & 0xff;
2983                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2984                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2985                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2986                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2987                             } break;
2988                             case TYPE_GENERIC_16_MSB: {
2989                                 final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
2990                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2991                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2992                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2993                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2994                             } break;
2995                             case TYPE_GENERIC_16_LSB: {
2996                                 final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
2997                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2998                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2999                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3000                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3001                             } break;
3002                             case TYPE_GENERIC_24: {
3003                                 final int data = (( ((destData[dp] & 0xff) << 8) |
3004                                                     (destData[dp + 1] & 0xff)) << 8) |
3005                                     (destData[dp + 2] & 0xff);
3006                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3007                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3008                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3009                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3010                             } break;
3011                             case TYPE_GENERIC_32_MSB: {
3012                                 final int data = (( (( ((destData[dp] & 0xff) << 8) |
3013                                                        (destData[dp + 1] & 0xff)) << 8) |
3014                                                     (destData[dp + 2] & 0xff)) << 8) |
3015                                     (destData[dp + 3] & 0xff);
3016                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3017                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3018                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3019                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3020                             } break;
3021                             case TYPE_GENERIC_32_LSB: {
3022                                 final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
3023                                                        (destData[dp + 2] & 0xff)) << 8) |
3024                                                     (destData[dp + 1] & 0xff)) << 8) |
3025                                     (destData[dp] & 0xff);
3026                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3027                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3028                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3029                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3030                             } break;
3031                         }
3032                         // Perform alpha blending
3033                         a = aq + ((a - aq) * alpha >> 16);
3034                         r = rq + ((r - rq) * alpha >> 16);
3035                         g = gq + ((g - gq) * alpha >> 16);
3036                         b = bq + ((b - bq) * alpha >> 16);
3037                     }
3038
3039                     /*** WRITE NEXT PIXEL ***/
3040                     final int data = 
3041                         (r >>> destRedPreShift << destRedShift) |
3042                         (g >>> destGreenPreShift << destGreenShift) |
3043                         (b >>> destBluePreShift << destBlueShift) |
3044                         (a >>> destAlphaPreShift << destAlphaShift);
3045                     switch (dtype) {
3046                         case TYPE_GENERIC_8: {
3047                             destData[dp] = (byte) data;
3048                         } break;
3049                         case TYPE_GENERIC_16_MSB: {
3050                             destData[dp] = (byte) (data >>> 8);
3051                             destData[dp + 1] = (byte) (data & 0xff);
3052                         } break;
3053                         case TYPE_GENERIC_16_LSB: {
3054                             destData[dp] = (byte) (data & 0xff);
3055                             destData[dp + 1] = (byte) (data >>> 8);
3056                         } break;
3057                         case TYPE_GENERIC_24: {
3058                             destData[dp] = (byte) (data >>> 16);
3059                             destData[dp + 1] = (byte) (data >>> 8);
3060                             destData[dp + 2] = (byte) (data & 0xff);
3061                         } break;
3062                         case TYPE_GENERIC_32_MSB: {
3063                             destData[dp] = (byte) (data >>> 24);
3064                             destData[dp + 1] = (byte) (data >>> 16);
3065                             destData[dp + 2] = (byte) (data >>> 8);
3066                             destData[dp + 3] = (byte) (data & 0xff);
3067                         } break;
3068                         case TYPE_GENERIC_32_LSB: {
3069                             destData[dp] = (byte) (data & 0xff);
3070                             destData[dp + 1] = (byte) (data >>> 8);
3071                             destData[dp + 2] = (byte) (data >>> 16);
3072                             destData[dp + 3] = (byte) (data >>> 24);
3073                         } break;
3074                     }
3075                 }
3076             }                   
3077         }
3078
3079         /**
3080          * Blits an index palette image into an index palette image.
3081          * <p>
3082          * Note: The source and destination red, green, and blue
3083          * arrays may be null if no alpha blending or dither is to be
3084          * performed.
3085          * </p>
3086          * 
3087          * @param op the blitter operation: a combination of BLIT_xxx flags
3088          *        (see BLIT_xxx constants)
3089          * @param srcData the source byte array containing image data
3090          * @param srcDepth the source depth: one of 1, 2, 4, 8
3091          * @param srcStride the source number of bytes per line
3092          * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
3093          *        ignored if srcDepth is not 1
3094          * @param srcX the top-left x-coord of the source blit region
3095          * @param srcY the top-left y-coord of the source blit region
3096          * @param srcWidth the width of the source blit region
3097          * @param srcHeight the height of the source blit region
3098          * @param srcReds the source palette red component intensities
3099          * @param srcGreens the source palette green component intensities
3100          * @param srcBlues the source palette blue component intensities
3101          * @param alphaMode the alpha blending or mask mode, may be
3102          *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
3103          *        not specified in the blitter operations
3104          *        (see ALPHA_MODE_xxx constants)
3105          * @param alphaData the alpha blending or mask data, varies depending
3106          *        on the value of alphaMode and sometimes ignored
3107          * @param alphaStride the alpha data number of bytes per line
3108          * @param alphaX the top-left x-coord of the alpha blit region
3109          * @param alphaY the top-left y-coord of the alpha blit region
3110          * @param destData the destination byte array containing image data
3111          * @param destDepth the destination depth: one of 1, 2, 4, 8
3112          * @param destStride the destination number of bytes per line
3113          * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
3114          *        ignored if destDepth is not 1
3115          * @param destX the top-left x-coord of the destination blit region
3116          * @param destY the top-left y-coord of the destination blit region
3117          * @param destWidth the width of the destination blit region
3118          * @param destHeight the height of the destination blit region
3119          * @param destReds the destination palette red component intensities
3120          * @param destGreens the destination palette green component intensities
3121          * @param destBlues the destination palette blue component intensities
3122          * @param flipX if true the resulting image is flipped along the vertical axis
3123          * @param flipY if true the resulting image is flipped along the horizontal axis
3124          */
3125         static void blit(int op,
3126                          byte[] srcData, int srcDepth, int srcStride, int srcOrder,
3127                          int srcX, int srcY, int srcWidth, int srcHeight,
3128                          byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
3129                          int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
3130                          byte[] destData, int destDepth, int destStride, int destOrder,
3131                          int destX, int destY, int destWidth, int destHeight,
3132                          byte[] destReds, byte[] destGreens, byte[] destBlues,
3133                          boolean flipX, boolean flipY) {
3134             if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
3135
3136             /*** Prepare scaling data ***/
3137             final int dwm1 = destWidth - 1;
3138             final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
3139             final int dhm1 = destHeight - 1;
3140             final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
3141
3142             /*** Prepare source-related data ***/
3143             final int stype;
3144             switch (srcDepth) {
3145                 case 8:
3146                     stype = TYPE_INDEX_8;
3147                     break;
3148                 case 4:
3149                     srcStride <<= 1;
3150                     stype = TYPE_INDEX_4;
3151                     break;
3152                 case 2:
3153                     srcStride <<= 2;
3154                     stype = TYPE_INDEX_2;
3155                     break;
3156                 case 1:
3157                     srcStride <<= 3;
3158                     stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
3159                     break;
3160                 default:
3161                     //throw new IllegalArgumentException("Invalid source type");
3162                     return;             
3163             }                   
3164             int spr = srcY * srcStride + srcX;
3165
3166             /*** Prepare destination-related data ***/
3167             final int dtype;
3168             switch (destDepth) {
3169                 case 8:
3170                     dtype = TYPE_INDEX_8;
3171                     break;
3172                 case 4:
3173                     destStride <<= 1;
3174                     dtype = TYPE_INDEX_4;
3175                     break;
3176                 case 2:
3177                     destStride <<= 2;
3178                     dtype = TYPE_INDEX_2;
3179                     break;
3180                 case 1:
3181                     destStride <<= 3;
3182                     dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
3183                     break;
3184                 default:
3185                     //throw new IllegalArgumentException("Invalid source type");
3186                     return;
3187             }                   
3188             int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
3189             final int dprxi = (flipX) ? -1 : 1;
3190             final int dpryi = (flipY) ? -destStride : destStride;
3191
3192             /*** Prepare special processing data ***/
3193             int apr;
3194             if ((op & BLIT_ALPHA) != 0) {
3195                 switch (alphaMode) {
3196                     case ALPHA_MASK_UNPACKED:
3197                     case ALPHA_CHANNEL_SEPARATE:
3198                         if (alphaData == null) alphaMode = 0x10000;
3199                         apr = alphaY * alphaStride + alphaX;
3200                         break;
3201                     case ALPHA_MASK_PACKED:
3202                         if (alphaData == null) alphaMode = 0x10000;
3203                         alphaStride <<= 3;
3204                         apr = alphaY * alphaStride + alphaX;
3205                         break;
3206                     case ALPHA_MASK_INDEX:
3207                     case ALPHA_MASK_RGB:
3208                         if (alphaData == null) alphaMode = 0x10000;
3209                         apr = 0;
3210                         break;
3211                     default:
3212                         alphaMode = (alphaMode << 16) / 255; // prescale
3213                     case ALPHA_CHANNEL_SOURCE:
3214                         apr = 0;
3215                         break;
3216                 }
3217             } else {
3218                 alphaMode = 0x10000;
3219                 apr = 0;
3220             }
3221             final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
3222
3223             /*** Blit ***/
3224             int dp = dpr;
3225             int sp = spr;
3226             int ap = apr;
3227             int destPaletteSize = 1 << destDepth;
3228             if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
3229             byte[] paletteMapping = null;
3230             boolean isExactPaletteMapping = true;
3231             switch (alphaMode) {
3232                 case 0x10000:
3233                     /*** If the palettes and formats are equivalent use a one-to-one mapping ***/
3234                     if ((stype == dtype) &&
3235                         (srcReds == destReds) && (srcGreens == destGreens) && (srcBlues == destBlues)) {
3236                         paletteMapping = ONE_TO_ONE_MAPPING;
3237                         break;
3238                         /*** If palettes have not been supplied, supply a suitable mapping ***/
3239                     } else if ((srcReds == null) || (destReds == null)) {
3240                         if (srcDepth <= destDepth) {
3241                             paletteMapping = ONE_TO_ONE_MAPPING;
3242                         } else {
3243                             paletteMapping = new byte[1 << srcDepth];
3244                             int mask = (0xff << destDepth) >>> 8;
3245                             for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = (byte)(i & mask);
3246                         }
3247                         break;
3248                     }
3249                 case ALPHA_MASK_UNPACKED:
3250                 case ALPHA_MASK_PACKED:
3251                 case ALPHA_MASK_INDEX:
3252                 case ALPHA_MASK_RGB:
3253                     /*** Generate a palette mapping ***/
3254                     int srcPaletteSize = 1 << srcDepth;
3255                     paletteMapping = new byte[srcPaletteSize];
3256                     if ((srcReds != null) && (srcReds.length < srcPaletteSize)) srcPaletteSize = srcReds.length;
3257                     for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) {
3258                         r = srcReds[i] & 0xff;
3259                         g = srcGreens[i] & 0xff;
3260                         b = srcBlues[i] & 0xff;
3261                         index = 0;
3262                         int minDistance = 0x7fffffff;
3263                         for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) {
3264                             dr = (destReds[j] & 0xff) - r;
3265                             dg = (destGreens[j] & 0xff) - g;
3266                             db = (destBlues[j] & 0xff) - b;
3267                             distance = dr * dr + dg * dg + db * db;
3268                             if (distance < minDistance) {
3269                                 index = j;
3270                                 if (distance == 0) break;
3271                                 minDistance = distance;
3272                             }
3273                         }
3274                         paletteMapping[i] = (byte)index;
3275                         if (minDistance != 0) isExactPaletteMapping = false;
3276                     }
3277                     break;
3278             }
3279             if ((paletteMapping != null) && (isExactPaletteMapping || ! ditherEnabled)) {
3280                 if ((stype == dtype) && (alphaMode == 0x10000)) {
3281                     /*** Fast blit (copy w/ mapping) ***/
3282                     switch (stype) {
3283                         case TYPE_INDEX_8:
3284                             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
3285                                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
3286                                     destData[dp] = paletteMapping[srcData[sp] & 0xff];
3287                                     sp += (sfx >>> 16);
3288                                 }
3289                             }
3290                             break;                                      
3291                         case TYPE_INDEX_4:
3292                             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
3293                                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
3294                                     final int v;
3295                                     if ((sp & 1) != 0) v = paletteMapping[srcData[sp >> 1] & 0x0f];
3296                                     else v = (srcData[sp >> 1] >>> 4) & 0x0f;
3297                                     sp += (sfx >>> 16);
3298                                     if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | v);
3299                                     else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (v << 4));
3300                                 }
3301                             }
3302                             break;
3303                         case TYPE_INDEX_2:
3304                             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
3305                                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
3306                                     final int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03];
3307                                     sp += (sfx >>> 16);
3308                                     final int shift = 6 - (dp & 3) * 2;
3309                                     destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
3310                                 }
3311                             }
3312                             break;                                      
3313                         case TYPE_INDEX_1_MSB:
3314                             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
3315                                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
3316                                     final int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01];
3317                                     sp += (sfx >>> 16);
3318                                     final int shift = 7 - (dp & 7);
3319                                     destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
3320                                 }
3321                             }
3322                             break;                                      
3323                         case TYPE_INDEX_1_LSB:
3324                             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
3325                                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
3326                                     final int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01];
3327                                     sp += (sfx >>> 16);
3328                                     final int shift = dp & 7;
3329                                     destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
3330                                 }
3331                             }
3332                             break;
3333                     }
3334                 } else {
3335                     /*** Convert between indexed modes using mapping and mask ***/
3336                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
3337                              sp = spr += (sfy >>> 16) * srcStride,
3338                              sfy = (sfy & 0xffff) + sfyi,
3339                              dp = dpr += dpryi) {
3340                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
3341                                  dp += dprxi,
3342                                  sfx = (sfx & 0xffff) + sfxi) {
3343                             int index;
3344                             /*** READ NEXT PIXEL ***/
3345                             switch (stype) {
3346                                 case TYPE_INDEX_8:
3347                                     index = srcData[sp] & 0xff;
3348                                     sp += (sfx >>> 16);
3349                                     break;                                      
3350                                 case TYPE_INDEX_4:
3351                                     if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
3352                                     else index = (srcData[sp >> 1] >>> 4) & 0x0f;
3353                                     sp += (sfx >>> 16);
3354                                     break;                                      
3355                                 case TYPE_INDEX_2:
3356                                     index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
3357                                     sp += (sfx >>> 16);
3358                                     break;                                      
3359                                 case TYPE_INDEX_1_MSB:
3360                                     index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
3361                                     sp += (sfx >>> 16);
3362                                     break;                                      
3363                                 case TYPE_INDEX_1_LSB:
3364                                     index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
3365                                     sp += (sfx >>> 16);
3366                                     break;
3367                                 default:
3368                                     return;
3369                             }
3370                             /*** APPLY MASK ***/
3371                             switch (alphaMode) {
3372                                 case ALPHA_MASK_UNPACKED: {
3373                                     final byte mask = alphaData[ap];
3374                                     ap += (sfx >> 16);
3375                                     if (mask == 0) continue;
3376                                 } break;
3377                                 case ALPHA_MASK_PACKED: {
3378                                     final int mask = alphaData[ap >> 3] & (1 << (ap & 7));
3379                                     ap += (sfx >> 16);
3380                                     if (mask == 0) continue;
3381                                 } break;
3382                                 case ALPHA_MASK_INDEX: {
3383                                     int i = 0;
3384                                     while (i < alphaData.length) {
3385                                         if (index == (alphaData[i] & 0xff)) break;
3386                                     }
3387                                     if (i < alphaData.length) continue;
3388                                 } break;
3389                                 case ALPHA_MASK_RGB: {
3390                                     final byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index];
3391                                     int i = 0;
3392                                     while (i < alphaData.length) {
3393                                         if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) break;
3394                                         i += 3;
3395                                     }
3396                                     if (i < alphaData.length) continue;
3397                                 } break;
3398                             }
3399                             index = paletteMapping[index] & 0xff;
3400                         
3401                             /*** WRITE NEXT PIXEL ***/
3402                             switch (dtype) {
3403                                 case TYPE_INDEX_8:
3404                                     destData[dp] = (byte) index;
3405                                     break;
3406                                 case TYPE_INDEX_4:
3407                                     if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | index);
3408                                     else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (index << 4));
3409                                     break;                                      
3410                                 case TYPE_INDEX_2: {
3411                                     final int shift = 6 - (dp & 3) * 2;
3412                                     destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
3413                                 } break;                                        
3414                                 case TYPE_INDEX_1_MSB: {
3415                                     final int shift = 7 - (dp & 7);
3416                                     destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
3417                                 } break;
3418                                 case TYPE_INDEX_1_LSB: {
3419                                     final int shift = dp & 7;
3420                                     destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
3421                                 } break;                                        
3422                             }
3423                         }
3424                     }
3425                 }
3426                 return;
3427             }
3428                 
3429             /*** Comprehensive blit (apply transformations) ***/
3430             int alpha = alphaMode;
3431             int index = 0;
3432             int indexq = 0;
3433             int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
3434             final int[] rerr, gerr, berr;
3435             if (ditherEnabled) {
3436                 rerr = new int[destWidth + 2];
3437                 gerr = new int[destWidth + 2];
3438                 berr = new int[destWidth + 2];
3439             } else {
3440                 rerr = null; gerr = null; berr = null;
3441             }
3442             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
3443                      sp = spr += (sfy >>> 16) * srcStride,
3444                      ap = apr += (sfy >>> 16) * alphaStride,
3445                      sfy = (sfy & 0xffff) + sfyi,
3446                      dp = dpr += dpryi) {
3447                 int lrerr = 0, lgerr = 0, lberr = 0;
3448                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
3449                          dp += dprxi,
3450                          sfx = (sfx & 0xffff) + sfxi) {
3451                     /*** READ NEXT PIXEL ***/
3452                     switch (stype) {
3453                         case TYPE_INDEX_8:
3454                             index = srcData[sp] & 0xff;
3455                             sp += (sfx >>> 16);
3456                             break;
3457                         case TYPE_INDEX_4:
3458                             if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
3459                             else index = (srcData[sp >> 1] >>> 4) & 0x0f;
3460                             sp += (sfx >>> 16);
3461                             break;
3462                         case TYPE_INDEX_2:
3463                             index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
3464                             sp += (sfx >>> 16);
3465                             break;
3466                         case TYPE_INDEX_1_MSB:
3467                             index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
3468                             sp += (sfx >>> 16);
3469                             break;
3470                         case TYPE_INDEX_1_LSB:
3471                             index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
3472                             sp += (sfx >>> 16);
3473                             break;
3474                     }
3475
3476                     /*** DO SPECIAL PROCESSING IF REQUIRED ***/
3477                     int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff;
3478                     switch (alphaMode) {
3479                         case ALPHA_CHANNEL_SEPARATE:
3480                             alpha = ((alphaData[ap] & 0xff) << 16) / 255;
3481                             ap += (sfx >> 16);
3482                             break;
3483                         case ALPHA_MASK_UNPACKED:
3484                             alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
3485                             ap += (sfx >> 16);
3486                             break;                                              
3487                         case ALPHA_MASK_PACKED:
3488                             alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
3489                             ap += (sfx >> 16);
3490                             break;
3491                         case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
3492                             int i = 0;
3493                             while (i < alphaData.length) {
3494                                 if (index == (alphaData[i] & 0xff)) break;
3495                             }
3496                             if (i < alphaData.length) continue;
3497                         } break;
3498                         case ALPHA_MASK_RGB: {
3499                             int i = 0;
3500                             while (i < alphaData.length) {
3501                                 if ((r == (alphaData[i] & 0xff)) &&
3502                                     (g == (alphaData[i + 1] & 0xff)) &&
3503                                     (b == (alphaData[i + 2] & 0xff))) break;
3504                                 i += 3;
3505                             }
3506                             if (i < alphaData.length) continue;
3507                         } break;
3508                     }
3509                     if (alpha != 0x10000) {
3510                         if (alpha == 0x0000) continue;
3511                         switch (dtype) {
3512                             case TYPE_INDEX_8:
3513                                 indexq = destData[dp] & 0xff;
3514                                 break;
3515                             case TYPE_INDEX_4:
3516                                 if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
3517                                 else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
3518                                 break;
3519                             case TYPE_INDEX_2:
3520                                 indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
3521                                 break;
3522                             case TYPE_INDEX_1_MSB:
3523                                 indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
3524                                 break;
3525                             case TYPE_INDEX_1_LSB:
3526                                 indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
3527                                 break;
3528                         }
3529                         // Perform alpha blending
3530                         final int rq = destReds[indexq] & 0xff;
3531                         final int gq = destGreens[indexq] & 0xff;
3532                         final int bq = destBlues[indexq] & 0xff;
3533                         r = rq + ((r - rq) * alpha >> 16);
3534                         g = gq + ((g - gq) * alpha >> 16);
3535                         b = bq + ((b - bq) * alpha >> 16);
3536                     }
3537
3538                     /*** MAP COLOR TO THE PALETTE ***/
3539                     if (ditherEnabled) {
3540                         // Floyd-Steinberg error diffusion
3541                         r += rerr[dx] >> 4;
3542                         if (r < 0) r = 0; else if (r > 255) r = 255;
3543                         g += gerr[dx] >> 4;
3544                         if (g < 0) g = 0; else if (g > 255) g = 255;
3545                         b += berr[dx] >> 4;
3546                         if (b < 0) b = 0; else if (b > 255) b = 255;
3547                         rerr[dx] = lrerr;
3548                         gerr[dx] = lgerr;
3549                         berr[dx] = lberr;
3550                     }
3551                     if (r != lastr || g != lastg || b != lastb) {
3552                         // moving the variable declarations out seems to make the JDK JIT happier...
3553                         for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
3554                             dr = (destReds[j] & 0xff) - r;
3555                             dg = (destGreens[j] & 0xff) - g;
3556                             db = (destBlues[j] & 0xff) - b;
3557                             distance = dr * dr + dg * dg + db * db;
3558                             if (distance < minDistance) {
3559                                 lastindex = j;
3560                                 if (distance == 0) break;
3561                                 minDistance = distance;
3562                             }
3563                         }
3564                         lastr = r; lastg = g; lastb = b;
3565                     }
3566                     if (ditherEnabled) {
3567                         // Floyd-Steinberg error diffusion, cont'd...
3568                         final int dxm1 = dx - 1, dxp1 = dx + 1;
3569                         int acc;
3570                         rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
3571                         rerr[dx] += acc += lrerr + lrerr;
3572                         rerr[dxm1] += acc + lrerr + lrerr;
3573                         gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
3574                         gerr[dx] += acc += lgerr + lgerr;
3575                         gerr[dxm1] += acc + lgerr + lgerr;
3576                         berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
3577                         berr[dx] += acc += lberr + lberr;
3578                         berr[dxm1] += acc + lberr + lberr;
3579                     }
3580
3581                     /*** WRITE NEXT PIXEL ***/
3582                     switch (dtype) {
3583                         case TYPE_INDEX_8:
3584                             destData[dp] = (byte) lastindex;
3585                             break;
3586                         case TYPE_INDEX_4:
3587                             if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
3588                             else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
3589                             break;
3590                         case TYPE_INDEX_2: {
3591                             final int shift = 6 - (dp & 3) * 2;
3592                             destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
3593                         } break;                                        
3594                         case TYPE_INDEX_1_MSB: {
3595                             final int shift = 7 - (dp & 7);
3596                             destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3597                         } break;
3598                         case TYPE_INDEX_1_LSB: {
3599                             final int shift = dp & 7;
3600                             destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3601                         } break;                                        
3602                     }
3603                 }
3604             }
3605         }
3606
3607         /**
3608          * Blits an index palette image into a direct palette image.
3609          * <p>
3610          * Note: The source and destination masks and palettes must
3611          * always be fully specified.
3612          * </p>
3613          * 
3614          * @param op the blitter operation: a combination of BLIT_xxx flags
3615          *        (see BLIT_xxx constants)
3616          * @param srcData the source byte array containing image data
3617          * @param srcDepth the source depth: one of 1, 2, 4, 8
3618          * @param srcStride the source number of bytes per line
3619          * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
3620          *        ignored if srcDepth is not 1
3621          * @param srcX the top-left x-coord of the source blit region
3622          * @param srcY the top-left y-coord of the source blit region
3623          * @param srcWidth the width of the source blit region
3624          * @param srcHeight the height of the source blit region
3625          * @param srcReds the source palette red component intensities
3626          * @param srcGreens the source palette green component intensities
3627          * @param srcBlues the source palette blue component intensities
3628          * @param alphaMode the alpha blending or mask mode, may be
3629          *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
3630          *        not specified in the blitter operations
3631          *        (see ALPHA_MODE_xxx constants)
3632          * @param alphaData the alpha blending or mask data, varies depending
3633          *        on the value of alphaMode and sometimes ignored
3634          * @param alphaStride the alpha data number of bytes per line
3635          * @param alphaX the top-left x-coord of the alpha blit region
3636          * @param alphaY the top-left y-coord of the alpha blit region
3637          * @param destData the destination byte array containing image data
3638          * @param destDepth the destination depth: one of 8, 16, 24, 32
3639          * @param destStride the destination number of bytes per line
3640          * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
3641          *        ignored if destDepth is not 16 or 32
3642          * @param destX the top-left x-coord of the destination blit region
3643          * @param destY the top-left y-coord of the destination blit region
3644          * @param destWidth the width of the destination blit region
3645          * @param destHeight the height of the destination blit region
3646          * @param destRedMask the destination red channel mask
3647          * @param destGreenMask the destination green channel mask
3648          * @param destBlueMask the destination blue channel mask
3649          * @param flipX if true the resulting image is flipped along the vertical axis
3650          * @param flipY if true the resulting image is flipped along the horizontal axis
3651          */
3652         static void blit(int op,
3653                          byte[] srcData, int srcDepth, int srcStride, int srcOrder,
3654                          int srcX, int srcY, int srcWidth, int srcHeight,
3655                          byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
3656                          int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
3657                          byte[] destData, int destDepth, int destStride, int destOrder,
3658                          int destX, int destY, int destWidth, int destHeight,
3659                          int destRedMask, int destGreenMask, int destBlueMask,
3660                          boolean flipX, boolean flipY) {
3661             if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
3662
3663             // these should be supplied as params later
3664             final int destAlphaMask = 0;
3665
3666             /*** Prepare scaling data ***/
3667             final int dwm1 = destWidth - 1;
3668             final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
3669             final int dhm1 = destHeight - 1;
3670             final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
3671
3672             /*** Prepare source-related data ***/
3673             final int stype;
3674             switch (srcDepth) {
3675                 case 8:
3676                     stype = TYPE_INDEX_8;
3677                     break;
3678                 case 4:
3679                     srcStride <<= 1;
3680                     stype = TYPE_INDEX_4;
3681                     break;
3682                 case 2:
3683                     srcStride <<= 2;
3684                     stype = TYPE_INDEX_2;
3685                     break;
3686                 case 1:
3687                     srcStride <<= 3;
3688                     stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
3689                     break;
3690                 default:
3691                     //throw new IllegalArgumentException("Invalid source type");
3692                     return;
3693             }                   
3694             int spr = srcY * srcStride + srcX;
3695
3696             /*** Prepare destination-related data ***/
3697             final int dbpp, dtype;
3698             switch (destDepth) {
3699                 case 8:
3700                     dbpp = 1;
3701                     dtype = TYPE_GENERIC_8;
3702                     break;
3703                 case 16:
3704                     dbpp = 2;
3705                     dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
3706                     break;
3707                 case 24:
3708                     dbpp = 3;
3709                     dtype = TYPE_GENERIC_24;
3710                     break;
3711                 case 32:
3712                     dbpp = 4;
3713                     dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
3714                     break;
3715                 default:
3716                     //throw new IllegalArgumentException("Invalid destination type");
3717                     return;
3718             }                   
3719             int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
3720             final int dprxi = (flipX) ? -dbpp : dbpp;
3721             final int dpryi = (flipY) ? -destStride : destStride;
3722
3723             /*** Prepare special processing data ***/
3724             int apr;
3725             if ((op & BLIT_ALPHA) != 0) {
3726                 switch (alphaMode) {
3727                     case ALPHA_MASK_UNPACKED:
3728                     case ALPHA_CHANNEL_SEPARATE:
3729                         if (alphaData == null) alphaMode = 0x10000;
3730                         apr = alphaY * alphaStride + alphaX;
3731                         break;
3732                     case ALPHA_MASK_PACKED:
3733                         if (alphaData == null) alphaMode = 0x10000;
3734                         alphaStride <<= 3;
3735                         apr = alphaY * alphaStride + alphaX;
3736                         break;
3737                     case ALPHA_MASK_INDEX:
3738                     case ALPHA_MASK_RGB:
3739                         if (alphaData == null) alphaMode = 0x10000;
3740                         apr = 0;
3741                         break;
3742                     default:
3743                         alphaMode = (alphaMode << 16) / 255; // prescale
3744                     case ALPHA_CHANNEL_SOURCE:
3745                         apr = 0;
3746                         break;
3747                 }
3748             } else {
3749                 alphaMode = 0x10000;
3750                 apr = 0;
3751             }
3752
3753             /*** Comprehensive blit (apply transformations) ***/
3754             final int destRedShift = getChannelShift(destRedMask);
3755             final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
3756             final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
3757             final int destRedPreShift = 8 - destRedWidth;
3758             final int destGreenShift = getChannelShift(destGreenMask);
3759             final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
3760             final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
3761             final int destGreenPreShift = 8 - destGreenWidth;
3762             final int destBlueShift = getChannelShift(destBlueMask);
3763             final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
3764             final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
3765             final int destBluePreShift = 8 - destBlueWidth;
3766             final int destAlphaShift = getChannelShift(destAlphaMask);
3767             final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
3768             final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
3769             final int destAlphaPreShift = 8 - destAlphaWidth;
3770
3771             int dp = dpr;
3772             int sp = spr;
3773             int ap = apr, alpha = alphaMode;
3774             int r = 0, g = 0, b = 0, a = 0, index = 0;
3775             int rq = 0, gq = 0, bq = 0, aq = 0;
3776             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
3777                      sp = spr += (sfy >>> 16) * srcStride,
3778                      ap = apr += (sfy >>> 16) * alphaStride,
3779                      sfy = (sfy & 0xffff) + sfyi,
3780                      dp = dpr += dpryi) {
3781                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
3782                          dp += dprxi,
3783                          sfx = (sfx & 0xffff) + sfxi) {
3784                     /*** READ NEXT PIXEL ***/
3785                     switch (stype) {
3786                         case TYPE_INDEX_8:
3787                             index = srcData[sp] & 0xff;
3788                             sp += (sfx >>> 16);
3789                             break;
3790                         case TYPE_INDEX_4:
3791                             if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
3792                             else index = (srcData[sp >> 1] >>> 4) & 0x0f;
3793                             sp += (sfx >>> 16);
3794                             break;
3795                         case TYPE_INDEX_2:
3796                             index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
3797                             sp += (sfx >>> 16);
3798                             break;
3799                         case TYPE_INDEX_1_MSB:
3800                             index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
3801                             sp += (sfx >>> 16);
3802                             break;
3803                         case TYPE_INDEX_1_LSB:
3804                             index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
3805                             sp += (sfx >>> 16);
3806                             break;
3807                     }
3808
3809                     /*** DO SPECIAL PROCESSING IF REQUIRED ***/
3810                     r = srcReds[index] & 0xff;
3811                     g = srcGreens[index] & 0xff;
3812                     b = srcBlues[index] & 0xff;
3813                     switch (alphaMode) {
3814                         case ALPHA_CHANNEL_SEPARATE:
3815                             alpha = ((alphaData[ap] & 0xff) << 16) / 255;
3816                             ap += (sfx >> 16);
3817                             break;
3818                         case ALPHA_MASK_UNPACKED:
3819                             alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
3820                             ap += (sfx >> 16);
3821                             break;                                              
3822                         case ALPHA_MASK_PACKED:
3823                             alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
3824                             ap += (sfx >> 16);
3825                             break;
3826                         case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
3827                             int i = 0;
3828                             while (i < alphaData.length) {
3829                                 if (index == (alphaData[i] & 0xff)) break;
3830                             }
3831                             if (i < alphaData.length) continue;
3832                         } break;
3833                         case ALPHA_MASK_RGB: {
3834                             int i = 0;
3835                             while (i < alphaData.length) {
3836                                 if ((r == (alphaData[i] & 0xff)) &&
3837                                     (g == (alphaData[i + 1] & 0xff)) &&
3838                                     (b == (alphaData[i + 2] & 0xff))) break;
3839                                 i += 3;
3840                             }
3841                             if (i < alphaData.length) continue;
3842                         } break;
3843                     }
3844                     if (alpha != 0x10000) {
3845                         if (alpha == 0x0000) continue;
3846                         switch (dtype) {
3847                             case TYPE_GENERIC_8: {
3848                                 final int data = destData[dp] & 0xff;
3849                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3850                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3851                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3852                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3853                             } break;
3854                             case TYPE_GENERIC_16_MSB: {
3855                                 final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
3856                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3857                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3858                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3859                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3860                             } break;
3861                             case TYPE_GENERIC_16_LSB: {
3862                                 final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
3863                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3864                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3865                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3866                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3867                             } break;
3868                             case TYPE_GENERIC_24: {
3869                                 final int data = (( ((destData[dp] & 0xff) << 8) |
3870                                                     (destData[dp + 1] & 0xff)) << 8) |
3871                                     (destData[dp + 2] & 0xff);
3872                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3873                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3874                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3875                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3876                             } break;
3877                             case TYPE_GENERIC_32_MSB: {
3878                                 final int data = (( (( ((destData[dp] & 0xff) << 8) |
3879                                                        (destData[dp + 1] & 0xff)) << 8) |
3880                                                     (destData[dp + 2] & 0xff)) << 8) |
3881                                     (destData[dp + 3] & 0xff);
3882                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3883                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3884                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3885                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3886                             } break;
3887                             case TYPE_GENERIC_32_LSB: {
3888                                 final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
3889                                                        (destData[dp + 2] & 0xff)) << 8) |
3890                                                     (destData[dp + 1] & 0xff)) << 8) |
3891                                     (destData[dp] & 0xff);
3892                                 rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3893                                 gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3894                                 bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3895                                 aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3896                             } break;
3897                         }
3898                         // Perform alpha blending
3899                         a = aq + ((a - aq) * alpha >> 16);
3900                         r = rq + ((r - rq) * alpha >> 16);
3901                         g = gq + ((g - gq) * alpha >> 16);
3902                         b = bq + ((b - bq) * alpha >> 16);
3903                     }
3904
3905                     /*** WRITE NEXT PIXEL ***/
3906                     final int data = 
3907                         (r >>> destRedPreShift << destRedShift) |
3908                         (g >>> destGreenPreShift << destGreenShift) |
3909                         (b >>> destBluePreShift << destBlueShift) |
3910                         (a >>> destAlphaPreShift << destAlphaShift);
3911                     switch (dtype) {
3912                         case TYPE_GENERIC_8: {
3913                             destData[dp] = (byte) data;
3914                         } break;
3915                         case TYPE_GENERIC_16_MSB: {
3916                             destData[dp] = (byte) (data >>> 8);
3917                             destData[dp + 1] = (byte) (data & 0xff);
3918                         } break;
3919                         case TYPE_GENERIC_16_LSB: {
3920                             destData[dp] = (byte) (data & 0xff);
3921                             destData[dp + 1] = (byte) (data >>> 8);
3922                         } break;
3923                         case TYPE_GENERIC_24: {
3924                             destData[dp] = (byte) (data >>> 16);
3925                             destData[dp + 1] = (byte) (data >>> 8);
3926                             destData[dp + 2] = (byte) (data & 0xff);
3927                         } break;
3928                         case TYPE_GENERIC_32_MSB: {
3929                             destData[dp] = (byte) (data >>> 24);
3930                             destData[dp + 1] = (byte) (data >>> 16);
3931                             destData[dp + 2] = (byte) (data >>> 8);
3932                             destData[dp + 3] = (byte) (data & 0xff);
3933                         } break;
3934                         case TYPE_GENERIC_32_LSB: {
3935                             destData[dp] = (byte) (data & 0xff);
3936                             destData[dp + 1] = (byte) (data >>> 8);
3937                             destData[dp + 2] = (byte) (data >>> 16);
3938                             destData[dp + 3] = (byte) (data >>> 24);
3939                         } break;
3940                     }
3941                 }
3942             }                   
3943         }
3944
3945         /**
3946          * Blits a direct palette image into an index palette image.
3947          * <p>
3948          * Note: The source and destination masks and palettes must
3949          * always be fully specified.
3950          * </p>
3951          * 
3952          * @param op the blitter operation: a combination of BLIT_xxx flags
3953          *        (see BLIT_xxx constants)
3954          * @param srcData the source byte array containing image data
3955          * @param srcDepth the source depth: one of 8, 16, 24, 32
3956          * @param srcStride the source number of bytes per line
3957          * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
3958          *        ignored if srcDepth is not 16 or 32
3959          * @param srcX the top-left x-coord of the source blit region
3960          * @param srcY the top-left y-coord of the source blit region
3961          * @param srcWidth the width of the source blit region
3962          * @param srcHeight the height of the source blit region
3963          * @param srcRedMask the source red channel mask
3964          * @param srcGreenMask the source green channel mask
3965          * @param srcBlueMask the source blue channel mask
3966          * @param alphaMode the alpha blending or mask mode, may be
3967          *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
3968          *        not specified in the blitter operations
3969          *        (see ALPHA_MODE_xxx constants)
3970          * @param alphaData the alpha blending or mask data, varies depending
3971          *        on the value of alphaMode and sometimes ignored
3972          * @param alphaStride the alpha data number of bytes per line
3973          * @param alphaX the top-left x-coord of the alpha blit region
3974          * @param alphaY the top-left y-coord of the alpha blit region
3975          * @param destData the destination byte array containing image data
3976          * @param destDepth the destination depth: one of 1, 2, 4, 8
3977          * @param destStride the destination number of bytes per line
3978          * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
3979          *        ignored if destDepth is not 1
3980          * @param destX the top-left x-coord of the destination blit region
3981          * @param destY the top-left y-coord of the destination blit region
3982          * @param destWidth the width of the destination blit region
3983          * @param destHeight the height of the destination blit region
3984          * @param destReds the destination palette red component intensities
3985          * @param destGreens the destination palette green component intensities
3986          * @param destBlues the destination palette blue component intensities
3987          * @param flipX if true the resulting image is flipped along the vertical axis
3988          * @param flipY if true the resulting image is flipped along the horizontal axis
3989          */
3990         static void blit(int op,
3991                          byte[] srcData, int srcDepth, int srcStride, int srcOrder,
3992                          int srcX, int srcY, int srcWidth, int srcHeight,
3993                          int srcRedMask, int srcGreenMask, int srcBlueMask,
3994                          int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
3995                          byte[] destData, int destDepth, int destStride, int destOrder,
3996                          int destX, int destY, int destWidth, int destHeight,
3997                          byte[] destReds, byte[] destGreens, byte[] destBlues,
3998                          boolean flipX, boolean flipY) {
3999             if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
4000
4001             // these should be supplied as params later
4002             final int srcAlphaMask = 0;
4003
4004             /*** Prepare scaling data ***/
4005             final int dwm1 = destWidth - 1;
4006             final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
4007             final int dhm1 = destHeight - 1;
4008             final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
4009
4010             /*** Prepare source-related data ***/
4011             final int sbpp, stype;
4012             switch (srcDepth) {
4013                 case 8:
4014                     sbpp = 1;
4015                     stype = TYPE_GENERIC_8;
4016                     break;
4017                 case 16:
4018                     sbpp = 2;
4019                     stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
4020                     break;
4021                 case 24:
4022                     sbpp = 3;
4023                     stype = TYPE_GENERIC_24;
4024                     break;
4025                 case 32:
4026                     sbpp = 4;
4027                     stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
4028                     break;
4029                 default:
4030                     //throw new IllegalArgumentException("Invalid source type");
4031                     return;
4032             }                   
4033             int spr = srcY * srcStride + srcX * sbpp;
4034
4035             /*** Prepare destination-related data ***/
4036             final int dtype;
4037             switch (destDepth) {
4038                 case 8:
4039                     dtype = TYPE_INDEX_8;
4040                     break;
4041                 case 4:
4042                     destStride <<= 1;
4043                     dtype = TYPE_INDEX_4;
4044                     break;
4045                 case 2:
4046                     destStride <<= 2;
4047                     dtype = TYPE_INDEX_2;
4048                     break;
4049                 case 1:
4050                     destStride <<= 3;
4051                     dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
4052                     break;
4053                 default:
4054                     //throw new IllegalArgumentException("Invalid source type");
4055                     return;
4056             }                   
4057             int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
4058             final int dprxi = (flipX) ? -1 : 1;
4059             final int dpryi = (flipY) ? -destStride : destStride;
4060
4061             /*** Prepare special processing data ***/
4062             int apr;
4063             if ((op & BLIT_ALPHA) != 0) {
4064                 switch (alphaMode) {
4065                     case ALPHA_MASK_UNPACKED:
4066                     case ALPHA_CHANNEL_SEPARATE:
4067                         if (alphaData == null) alphaMode = 0x10000;
4068                         apr = alphaY * alphaStride + alphaX;
4069                         break;
4070                     case ALPHA_MASK_PACKED:
4071                         if (alphaData == null) alphaMode = 0x10000;
4072                         alphaStride <<= 3;
4073                         apr = alphaY * alphaStride + alphaX;
4074                         break;
4075                     case ALPHA_MASK_INDEX:
4076                         //throw new IllegalArgumentException("Invalid alpha type");
4077                         return;
4078                     case ALPHA_MASK_RGB:
4079                         if (alphaData == null) alphaMode = 0x10000;
4080                         apr = 0;
4081                         break;
4082                     default:
4083                         alphaMode = (alphaMode << 16) / 255; // prescale
4084                     case ALPHA_CHANNEL_SOURCE:
4085                         apr = 0;
4086                         break;
4087                 }
4088             } else {
4089                 alphaMode = 0x10000;
4090                 apr = 0;
4091             }
4092             final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
4093
4094             /*** Comprehensive blit (apply transformations) ***/
4095             final int srcRedShift = getChannelShift(srcRedMask);
4096             final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
4097             final int srcGreenShift = getChannelShift(srcGreenMask);
4098             final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
4099             final int srcBlueShift = getChannelShift(srcBlueMask);
4100             final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
4101             final int srcAlphaShift = getChannelShift(srcAlphaMask);
4102             final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
4103
4104             int dp = dpr;
4105             int sp = spr;
4106             int ap = apr, alpha = alphaMode;
4107             int r = 0, g = 0, b = 0, a = 0;
4108             int indexq = 0;
4109             int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
4110             final int[] rerr, gerr, berr;
4111             int destPaletteSize = 1 << destDepth;
4112             if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
4113             if (ditherEnabled) {
4114                 rerr = new int[destWidth + 2];
4115                 gerr = new int[destWidth + 2];
4116                 berr = new int[destWidth + 2];
4117             } else {
4118                 rerr = null; gerr = null; berr = null;
4119             }
4120             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
4121                      sp = spr += (sfy >>> 16) * srcStride,
4122                      ap = apr += (sfy >>> 16) * alphaStride,
4123                      sfy = (sfy & 0xffff) + sfyi,
4124                      dp = dpr += dpryi) {
4125                 int lrerr = 0, lgerr = 0, lberr = 0;
4126                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
4127                          dp += dprxi,
4128                          sfx = (sfx & 0xffff) + sfxi) {
4129                     /*** READ NEXT PIXEL ***/
4130                     switch (stype) {
4131                         case TYPE_GENERIC_8: {
4132                             final int data = srcData[sp] & 0xff;
4133                             sp += (sfx >>> 16);
4134                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4135                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4136                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4137                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4138                         } break;
4139                         case TYPE_GENERIC_16_MSB: {
4140                             final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
4141                             sp += (sfx >>> 16) * 2;
4142                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4143                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4144                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4145                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4146                         } break;
4147                         case TYPE_GENERIC_16_LSB: {
4148                             final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
4149                             sp += (sfx >>> 16) * 2;
4150                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4151                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4152                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4153                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4154                         } break;
4155                         case TYPE_GENERIC_24: {
4156                             final int data = (( ((srcData[sp] & 0xff) << 8) |
4157                                                 (srcData[sp + 1] & 0xff)) << 8) |
4158                                 (srcData[sp + 2] & 0xff);
4159                             sp += (sfx >>> 16) * 3;
4160                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4161                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4162                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4163                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4164                         } break;
4165                         case TYPE_GENERIC_32_MSB: {
4166                             final int data = (( (( ((srcData[sp] & 0xff) << 8) |
4167                                                    (srcData[sp + 1] & 0xff)) << 8) |
4168                                                 (srcData[sp + 2] & 0xff)) << 8) |
4169                                 (srcData[sp + 3] & 0xff);
4170                             sp += (sfx >>> 16) * 4;
4171                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4172                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4173                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4174                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4175                         } break;
4176                         case TYPE_GENERIC_32_LSB: {
4177                             final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
4178                                                    (srcData[sp + 2] & 0xff)) << 8) |
4179                                                 (srcData[sp + 1] & 0xff)) << 8) |
4180                                 (srcData[sp] & 0xff);
4181                             sp += (sfx >>> 16) * 4;
4182                             r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
4183                             g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
4184                             b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
4185                             a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
4186                         } break;
4187                     }
4188
4189                     /*** DO SPECIAL PROCESSING IF REQUIRED ***/
4190                     switch (alphaMode) {
4191                         case ALPHA_CHANNEL_SEPARATE:
4192                             alpha = ((alphaData[ap] & 0xff) << 16) / 255;
4193                             ap += (sfx >> 16);
4194                             break;
4195                         case ALPHA_CHANNEL_SOURCE:
4196                             alpha = (a << 16) / 255;
4197                             break;
4198                         case ALPHA_MASK_UNPACKED:
4199                             alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
4200                             ap += (sfx >> 16);
4201                             break;                                              
4202                         case ALPHA_MASK_PACKED:
4203                             alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
4204                             ap += (sfx >> 16);
4205                             break;
4206                         case ALPHA_MASK_RGB:
4207                             alpha = 0x10000;
4208                             for (int i = 0; i < alphaData.length; i += 3) {
4209                                 if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
4210                                     alpha = 0x0000;
4211                                     break;
4212                                 }
4213                             }
4214                             break;
4215                     }
4216                     if (alpha != 0x10000) {
4217                         if (alpha == 0x0000) continue;
4218                         switch (dtype) {
4219                             case TYPE_INDEX_8:
4220                                 indexq = destData[dp] & 0xff;
4221                                 break;
4222                             case TYPE_INDEX_4:
4223                                 if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
4224                                 else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
4225                                 break;
4226                             case TYPE_INDEX_2:
4227                                 indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
4228                                 break;
4229                             case TYPE_INDEX_1_MSB:
4230                                 indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
4231                                 break;
4232                             case TYPE_INDEX_1_LSB:
4233                                 indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
4234                                 break;
4235                         }
4236                         // Perform alpha blending
4237                         final int rq = destReds[indexq] & 0xff;
4238                         final int gq = destGreens[indexq] & 0xff;
4239                         final int bq = destBlues[indexq] & 0xff;
4240                         r = rq + ((r - rq) * alpha >> 16);
4241                         g = gq + ((g - gq) * alpha >> 16);
4242                         b = bq + ((b - bq) * alpha >> 16);
4243                     }
4244
4245                     /*** MAP COLOR TO THE PALETTE ***/
4246                     if (ditherEnabled) {
4247                         // Floyd-Steinberg error diffusion
4248                         r += rerr[dx] >> 4;
4249                         if (r < 0) r = 0; else if (r > 255) r = 255;
4250                         g += gerr[dx] >> 4;
4251                         if (g < 0) g = 0; else if (g > 255) g = 255;
4252                         b += berr[dx] >> 4;
4253                         if (b < 0) b = 0; else if (b > 255) b = 255;
4254                         rerr[dx] = lrerr;
4255                         gerr[dx] = lgerr;
4256                         berr[dx] = lberr;
4257                     }
4258                     if (r != lastr || g != lastg || b != lastb) {
4259                         // moving the variable declarations out seems to make the JDK JIT happier...
4260                         for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
4261                             dr = (destReds[j] & 0xff) - r;
4262                             dg = (destGreens[j] & 0xff) - g;
4263                             db = (destBlues[j] & 0xff) - b;
4264                             distance = dr * dr + dg * dg + db * db;
4265                             if (distance < minDistance) {
4266                                 lastindex = j;
4267                                 if (distance == 0) break;
4268                                 minDistance = distance;
4269                             }
4270                         }
4271                         lastr = r; lastg = g; lastb = b;
4272                     }
4273                     if (ditherEnabled) {
4274                         // Floyd-Steinberg error diffusion, cont'd...
4275                         final int dxm1 = dx - 1, dxp1 = dx + 1;
4276                         int acc;
4277                         rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
4278                         rerr[dx] += acc += lrerr + lrerr;
4279                         rerr[dxm1] += acc + lrerr + lrerr;
4280                         gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
4281                         gerr[dx] += acc += lgerr + lgerr;
4282                         gerr[dxm1] += acc + lgerr + lgerr;
4283                         berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
4284                         berr[dx] += acc += lberr + lberr;
4285                         berr[dxm1] += acc + lberr + lberr;
4286                     }
4287
4288                     /*** WRITE NEXT PIXEL ***/
4289                     switch (dtype) {
4290                         case TYPE_INDEX_8:
4291                             destData[dp] = (byte) lastindex;
4292                             break;
4293                         case TYPE_INDEX_4:
4294                             if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
4295                             else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
4296                             break;
4297                         case TYPE_INDEX_2: {
4298                             final int shift = 6 - (dp & 3) * 2;
4299                             destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
4300                         } break;                                        
4301                         case TYPE_INDEX_1_MSB: {
4302                             final int shift = 7 - (dp & 7);
4303                             destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
4304                         } break;
4305                         case TYPE_INDEX_1_LSB: {
4306                             final int shift = dp & 7;
4307                             destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
4308                         } break;                                        
4309                     }
4310                 }
4311             }
4312         }
4313
4314         /**
4315          * Computes the required channel shift from a mask.
4316          */
4317         static int getChannelShift(int mask) {
4318             if (mask == 0) return 0;
4319             int i;
4320             for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) {
4321                 mask >>>= 1;
4322             }
4323             return i;
4324         }
4325
4326         /**
4327          * Computes the required channel width (depth) from a mask.
4328          */
4329         static int getChannelWidth(int mask, int shift) {
4330             if (mask == 0) return 0;
4331             int i;
4332             mask >>>= shift;
4333             for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) {
4334                 mask >>>= 1;
4335             }
4336             return i - shift;
4337         }
4338
4339         /**
4340          * Extracts a field from packed RGB data given a mask for that field.
4341          */
4342         static byte getChannelField(int data, int mask) {
4343             final int shift = getChannelShift(mask);
4344             return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift];
4345         }
4346
4347         /**
4348          * Creates an ImageData containing one band's worth of a gradient filled
4349          * block.  If <code>vertical</code> is true, the band must be tiled
4350          * horizontally to fill a region, otherwise it must be tiled vertically.
4351          *
4352          * @param width the width of the region to be filled
4353          * @param height the height of the region to be filled
4354          * @param vertical if true sweeps from top to bottom, else
4355          *        sweeps from left to right
4356          * @param fromRGB the color to start with
4357          * @param toRGB the color to end with
4358          * @param redBits the number of significant red bits, 0 for palette modes
4359          * @param greenBits the number of significant green bits, 0 for palette modes
4360          * @param blueBits the number of significant blue bits, 0 for palette modes
4361          * @return the new ImageData
4362          */
4363         static ImageData createGradientBand(
4364                                             int width, int height, boolean vertical,
4365                                             RGB fromRGB, RGB toRGB,
4366                                             int redBits, int greenBits, int blueBits) {
4367             /* Gradients are drawn as tiled bands */
4368             final int bandWidth, bandHeight, bitmapDepth;
4369             final byte[] bitmapData;
4370             final PaletteData paletteData;
4371             /* Select an algorithm depending on the depth of the screen */
4372             if (redBits != 0 && greenBits != 0 && blueBits != 0) {
4373                 paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
4374                 bitmapDepth = 32;
4375                 if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
4376                     /* Precise color */
4377                     final int steps;
4378                     if (vertical) {
4379                         bandWidth = 1;
4380                         bandHeight = height;
4381                         steps = bandHeight > 1 ? bandHeight - 1 : 1;
4382                     } else {
4383                         bandWidth = width;
4384                         bandHeight = 1;
4385                         steps = bandWidth > 1 ? bandWidth - 1 : 1;
4386                     }
4387                     final int bytesPerLine = bandWidth * 4;
4388                     bitmapData = new byte[bandHeight * bytesPerLine];
4389                     buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
4390                     buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
4391                     buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
4392                 } else {
4393                     /* Dithered color */
4394                     final int steps;
4395                     if (vertical) {
4396                         bandWidth = (width < 8) ? width : 8;
4397                         bandHeight = height;
4398                         steps = bandHeight > 1 ? bandHeight - 1 : 1;
4399                     } else {
4400                         bandWidth = width;
4401                         bandHeight = (height < 8) ? height : 8;
4402                         steps = bandWidth > 1 ? bandWidth - 1 : 1;
4403                     }
4404                     final int bytesPerLine = bandWidth * 4;
4405                     bitmapData = new byte[bandHeight * bytesPerLine];
4406                     buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
4407                     buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
4408                     buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);                 
4409                 }
4410             } else {
4411                 /* Dithered two tone */
4412                 paletteData = new PaletteData(new RGB[] { fromRGB, toRGB });
4413                 bitmapDepth = 8;
4414                 final int blendi;
4415                 if (vertical) {
4416                     bandWidth = (width < 8) ? width : 8;
4417                     bandHeight = height;
4418                     blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
4419                 } else {
4420                     bandWidth = width;
4421                     bandHeight = (height < 8) ? height : 8;
4422                     blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
4423                 }
4424                 final int bytesPerLine = (bandWidth + 3) & -4;
4425                 bitmapData = new byte[bandHeight * bytesPerLine];
4426                 if (vertical) {
4427                     for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
4428                          ++dy, blend += blendi, dp += bytesPerLine) {
4429                         for (int dx = 0; dx < bandWidth; ++dx) {
4430                             bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
4431                                 0x1000000 ? (byte)0 : (byte)1;
4432                         }
4433                     }           
4434                 } else {
4435                     for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
4436                         for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
4437                             bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
4438                                 0x1000000 ? (byte)0 : (byte)1;
4439                         }
4440                     }
4441                 }
4442             }
4443             return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
4444         }
4445
4446         /* 
4447          * Fill in gradated values for a color channel
4448          */
4449         static final void buildPreciseGradientChannel(int from, int to, int steps,
4450                                                       int bandWidth, int bandHeight, boolean vertical,
4451                                                       byte[] bitmapData, int dp, int bytesPerLine) {
4452             int val = from << 16;
4453             final int inc = ((to << 16) - val) / steps + 1;
4454             if (vertical) {
4455                 for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
4456                     bitmapData[dp] = (byte)(val >>> 16);
4457                     val += inc;
4458                 }
4459             } else {
4460                 for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
4461                     bitmapData[dp] = (byte)(val >>> 16);
4462                     val += inc;
4463                 }
4464             }           
4465         }
4466
4467         /* 
4468          * Fill in dithered gradated values for a color channel
4469          */
4470         static final void buildDitheredGradientChannel(int from, int to, int steps,
4471                                                        int bandWidth, int bandHeight, boolean vertical,
4472                                                        byte[] bitmapData, int dp, int bytesPerLine, int bits) {
4473             final int mask = 0xff00 >>> bits;
4474             int val = from << 16;
4475             final int inc = ((to << 16) - val) / steps + 1;
4476             if (vertical) {
4477                 for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
4478                     for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
4479                         final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
4480                         int temp = val + thresh;
4481                         if (temp > 0xffffff) bitmapData[dptr] = -1;
4482                         else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
4483                     }
4484                     val += inc;
4485                 }
4486             } else {
4487                 for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
4488                     for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
4489                         final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
4490                         int temp = val + thresh;
4491                         if (temp > 0xffffff) bitmapData[dptr] = -1;
4492                         else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
4493                     }
4494                     val += inc;
4495                 }
4496             }
4497         }
4498
4499         /**
4500          * Renders a gradient onto a GC.
4501          * <p>
4502          * This is a GC helper.
4503          * </p>
4504          *
4505          * @param gc the GC to render the gradient onto
4506          * @param device the device the GC belongs to
4507          * @param x the top-left x coordinate of the region to be filled
4508          * @param y the top-left y coordinate of the region to be filled
4509          * @param width the width of the region to be filled
4510          * @param height the height of the region to be filled
4511          * @param vertical if true sweeps from top to bottom, else
4512          *        sweeps from left to right
4513          * @param fromRGB the color to start with
4514          * @param toRGB the color to end with
4515          * @param redBits the number of significant red bits, 0 for palette modes
4516          * @param greenBits the number of significant green bits, 0 for palette modes
4517          * @param blueBits the number of significant blue bits, 0 for palette modes
4518          */
4519         /*
4520           static void fillGradientRectangle(GC gc, Device device,
4521           int x, int y, int width, int height, boolean vertical,
4522           RGB fromRGB, RGB toRGB,
4523           int redBits, int greenBits, int blueBits) {
4524           // Create the bitmap and tile it
4525           ImageData band = createGradientBand(width, height, vertical,
4526           fromRGB, toRGB, redBits, greenBits, blueBits);
4527           Image image = new Image(device, band);
4528           if ((band.width == 1) || (band.height == 1)) {
4529           gc.drawImage(image, 0, 0, band.width, band.height, x, y, width, height);
4530           } else {
4531           if (vertical) {
4532           for (int dx = 0; dx < width; dx += band.width) {
4533           int blitWidth = width - dx;
4534           if (blitWidth > band.width) blitWidth = band.width;
4535           gc.drawImage(image, 0, 0, blitWidth, band.height, dx + x, y, blitWidth, band.height);
4536           }
4537           } else {
4538           for (int dy = 0; dy < height; dy += band.height) {
4539           int blitHeight = height - dy;
4540           if (blitHeight > band.height) blitHeight = band.height;
4541           gc.drawImage(image, 0, 0, band.width, blitHeight, x, dy + y, band.width, blitHeight);
4542           }
4543           }
4544           }
4545           image.dispose();
4546           }
4547         */
4548     }
4549
4550
4551     /*******************************************************************************
4552      * Copyright (c) 2000, 2003 IBM Corporation and others.
4553      * All rights reserved. This program and the accompanying materials 
4554      * are made available under the terms of the Common Public License v1.0
4555      * which accompanies this distribution, and is available at
4556      * http://www.eclipse.org/legal/cpl-v10.html
4557      * 
4558      * Contributors:
4559      *     IBM Corporation - initial API and implementation
4560      *******************************************************************************/
4561
4562     final static class LEDataInputStream extends InputStream {
4563         int position;
4564         InputStream in;
4565
4566         /**
4567          * The byte array containing the bytes to read.
4568          */
4569         protected byte[] buf;
4570         
4571         /**
4572          * The current position within the byte array <code>buf</code>. A value
4573          * equal to buf.length indicates no bytes available.  A value of
4574          * 0 indicates the buffer is full.
4575          */
4576         protected int pos;
4577         
4578
4579         public LEDataInputStream(InputStream input) {
4580             this(input, 512);
4581         }
4582         
4583         public LEDataInputStream(InputStream input, int bufferSize) {
4584             this.in = input;
4585             if (bufferSize > 0) {
4586                 buf = new byte[bufferSize];
4587                 pos = bufferSize;
4588             } 
4589             else throw new IllegalArgumentException();
4590         }
4591         
4592         public void close() throws IOException {
4593             buf = null;
4594             if (in != null) {
4595                 in.close();
4596                 in = null;
4597             }
4598         }
4599         
4600         /**
4601          * Answer how many bytes were read.
4602          */
4603         public int getPosition() {
4604             return position;
4605         }
4606         
4607         /**
4608          * Answers how many bytes are available for reading without blocking
4609          */
4610         public int available() throws IOException {
4611             if (buf == null) throw new IOException();
4612             return (buf.length - pos) + in.available();
4613         }
4614         
4615         /**
4616          * Answer the next byte of the input stream.
4617          */
4618         public int read() throws IOException {
4619             if (buf == null) throw new IOException();
4620             position++;
4621             if (pos < buf.length) return (buf[pos++] & 0xFF);
4622             return in.read();
4623         }
4624         
4625         /**
4626          * Don't imitate the JDK behaviour of reading a random number
4627          * of bytes when you can actually read them all.
4628          */
4629         public int read(byte b[], int off, int len) throws IOException {
4630             int result;
4631             int left = len;
4632             result = readData(b, off, len);
4633             while (true) {
4634                 if (result == -1) return -1;
4635                 position += result;
4636                 if (result == left) return len;
4637                 left -= result;
4638                 off += result;
4639                 result = readData(b, off, left);
4640             }
4641         }
4642         
4643         /**
4644          * Reads at most <code>length</code> bytes from this LEDataInputStream and 
4645          * stores them in byte array <code>buffer</code> starting at <code>offset</code>.
4646          * <p>
4647          * Answer the number of bytes actually read or -1 if no bytes were read and 
4648          * end of stream was encountered.  This implementation reads bytes from 
4649          * the pushback buffer first, then the target stream if more bytes are required
4650          * to satisfy <code>count</code>.
4651          * </p>
4652          * @param buffer the byte array in which to store the read bytes.
4653          * @param offset the offset in <code>buffer</code> to store the read bytes.
4654          * @param length the maximum number of bytes to store in <code>buffer</code>.
4655          *
4656          * @return int the number of bytes actually read or -1 if end of stream.
4657          *
4658          * @exception java.io.IOException if an IOException occurs.
4659          */
4660         private int readData(byte[] buffer, int offset, int length) throws IOException {
4661             if (buf == null) throw new IOException();
4662             if (offset < 0 || offset > buffer.length ||
4663                 length < 0 || (length > buffer.length - offset)) {
4664                 throw new ArrayIndexOutOfBoundsException();
4665             }
4666                                 
4667             int cacheCopied = 0;
4668             int newOffset = offset;
4669         
4670             // Are there pushback bytes available?
4671             int available = buf.length - pos;
4672             if (available > 0) {
4673                 cacheCopied = (available >= length) ? length : available;
4674                 System.arraycopy(buf, pos, buffer, newOffset, cacheCopied);
4675                 newOffset += cacheCopied;
4676                 pos += cacheCopied;
4677             }
4678         
4679             // Have we copied enough?
4680             if (cacheCopied == length) return length;
4681
4682             int inCopied = in.read(buffer, newOffset, length - cacheCopied);
4683
4684             if (inCopied > 0) return inCopied + cacheCopied;
4685             if (cacheCopied == 0) return inCopied;
4686             return cacheCopied;
4687         }
4688         
4689         /**
4690          * Answer an integer comprised of the next
4691          * four bytes of the input stream.
4692          */
4693         public int readInt() throws IOException {
4694             byte[] buf = new byte[4];
4695             read(buf);
4696             return ((((((buf[3] & 0xFF) << 8) | 
4697                        (buf[2] & 0xFF)) << 8) | 
4698                      (buf[1] & 0xFF)) << 8) | 
4699                 (buf[0] & 0xFF);
4700         }
4701         
4702         /**
4703          * Answer a short comprised of the next
4704          * two bytes of the input stream.
4705          */
4706         public short readShort() throws IOException {
4707             byte[] buf = new byte[2];
4708             read(buf);
4709             return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF));
4710         }
4711         
4712         /**
4713          * Push back the entire content of the given buffer <code>b</code>.
4714          * <p>
4715          * The bytes are pushed so that they would be read back b[0], b[1], etc. 
4716          * If the push back buffer cannot handle the bytes copied from <code>b</code>, 
4717          * an IOException will be thrown and no byte will be pushed back.
4718          * </p>
4719          * 
4720          * @param b the byte array containing bytes to push back into the stream
4721          *
4722          * @exception   java.io.IOException if the pushback buffer is too small
4723          */
4724         public void unread(byte[] b) throws IOException {
4725             int length = b.length;
4726             if (length > pos) throw new IOException();
4727             position -= length;
4728             pos -= length;
4729             System.arraycopy(b, 0, buf, pos, length);
4730         }
4731     }
4732
4733
4734     /*******************************************************************************
4735      * Copyright (c) 2000, 2003 IBM Corporation and others.
4736      * All rights reserved. This program and the accompanying materials 
4737      * are made available under the terms of the Common Public License v1.0
4738      * which accompanies this distribution, and is available at
4739      * http://www.eclipse.org/legal/cpl-v10.html
4740      * 
4741      * Contributors:
4742      *     IBM Corporation - initial API and implementation
4743      *******************************************************************************/
4744
4745
4746     final static class JPEGAppn extends JPEGVariableSizeSegment {
4747
4748         public JPEGAppn(byte[] reference) {
4749             super(reference);
4750         }
4751         
4752         public JPEGAppn(LEDataInputStream byteStream) {
4753             super(byteStream);
4754         }
4755         
4756         public boolean verify() {
4757             int marker = getSegmentMarker();
4758             return marker >= JPEGFileFormat.APP0 && marker <= JPEGFileFormat.APP15;
4759         }
4760     }
4761     /*******************************************************************************
4762      * Copyright (c) 2000, 2003 IBM Corporation and others.
4763      * All rights reserved. This program and the accompanying materials 
4764      * are made available under the terms of the Common Public License v1.0
4765      * which accompanies this distribution, and is available at
4766      * http://www.eclipse.org/legal/cpl-v10.html
4767      * 
4768      * Contributors:
4769      *     IBM Corporation - initial API and implementation
4770      *******************************************************************************/
4771
4772
4773     final static class JPEGArithmeticConditioningTable extends JPEGVariableSizeSegment {
4774
4775         public JPEGArithmeticConditioningTable(LEDataInputStream byteStream) {
4776             super(byteStream);
4777         }
4778         
4779         public int signature() {
4780             return JPEGFileFormat.DAC;
4781         }
4782     }
4783     /*******************************************************************************
4784      * Copyright (c) 2000, 2003 IBM Corporation and others.
4785      * All rights reserved. This program and the accompanying materials 
4786      * are made available under the terms of the Common Public License v1.0
4787      * which accompanies this distribution, and is available at
4788      * http://www.eclipse.org/legal/cpl-v10.html
4789      * 
4790      * Contributors:
4791      *     IBM Corporation - initial API and implementation
4792      *******************************************************************************/
4793
4794
4795     final static class JPEGComment extends JPEGVariableSizeSegment {
4796
4797         public JPEGComment(byte[] reference) {
4798             super(reference);
4799         }
4800         
4801         public JPEGComment(LEDataInputStream byteStream) {
4802             super(byteStream);
4803         }
4804         
4805         public int signature() {
4806             return JPEGFileFormat.COM;
4807         }
4808     }
4809     /*******************************************************************************
4810      * Copyright (c) 2000, 2003 IBM Corporation and others.
4811      * All rights reserved. This program and the accompanying materials 
4812      * are made available under the terms of the Common Public License v1.0
4813      * which accompanies this distribution, and is available at
4814      * http://www.eclipse.org/legal/cpl-v10.html
4815      * 
4816      * Contributors:
4817      *     IBM Corporation - initial API and implementation
4818      *******************************************************************************/
4819
4820
4821     final static class JPEGEndOfImage extends JPEGFixedSizeSegment {
4822
4823         public JPEGEndOfImage() {
4824             super();
4825         }
4826         
4827         public JPEGEndOfImage(byte[] reference) {
4828             super(reference);
4829         }
4830         
4831         public int signature() {
4832             return JPEGFileFormat.EOI;
4833         }
4834         
4835         public int fixedSize() {
4836             return 2;
4837         }
4838     }
4839     /*******************************************************************************
4840      * Copyright (c) 2000, 2004 IBM Corporation and others.
4841      * All rights reserved. This program and the accompanying materials
4842      * are made available under the terms of the Common Public License v1.0
4843      * which accompanies this distribution, and is available at
4844      * http://www.eclipse.org/legal/cpl-v10.html
4845      * 
4846      * Contributors:
4847      *     IBM Corporation - initial API and implementation
4848      *******************************************************************************/
4849
4850
4851
4852     final static class JPEGFileFormat extends FileFormat {
4853         int restartInterval;
4854         JPEGFrameHeader frameHeader;
4855         int imageWidth, imageHeight;
4856         int interleavedMcuCols, interleavedMcuRows;
4857         int maxV, maxH;
4858         boolean progressive;
4859         int samplePrecision;
4860         int nComponents;
4861         int[][] frameComponents;
4862         int[] componentIds;
4863         byte[][] imageComponents;
4864         int[] dataUnit;
4865         int[][][] dataUnits;
4866         int[] precedingDCs;
4867         JPEGScanHeader scanHeader;
4868         byte[] dataBuffer;
4869         int currentBitCount;
4870         int bufferCurrentPosition;
4871         int restartsToGo;
4872         int nextRestartNumber;
4873         JPEGArithmeticConditioningTable arithmeticTables;
4874         JPEGHuffmanTable[] acHuffmanTables;
4875         JPEGHuffmanTable[] dcHuffmanTables;
4876         int[][] quantizationTables;
4877         int currentByte;
4878         int decoderQFactor;
4879         int encoderQFactor = 75;
4880         int eobrun = 0;
4881         /* JPEGConstants */
4882         public static final int DCTSIZE = 8;
4883         public static final int DCTSIZESQR = 64;
4884         /* JPEGFixedPointConstants */
4885         public static final int FIX_0_899976223 = 7373;
4886         public static final int FIX_1_961570560 = 16069;
4887         public static final int FIX_2_053119869 = 16819;
4888         public static final int FIX_0_298631336 = 2446;
4889         public static final int FIX_1_847759065 = 15137;
4890         public static final int FIX_1_175875602 = 9633;
4891         public static final int FIX_3_072711026 = 25172;
4892         public static final int FIX_0_765366865 = 6270;
4893         public static final int FIX_2_562915447 = 20995;
4894         public static final int FIX_0_541196100 = 4433;
4895         public static final int FIX_0_390180644 = 3196;
4896         public static final int FIX_1_501321110 = 12299;
4897         /* JPEGMarkerCodes */
4898         public static final int APP0  = 0xFFE0;
4899         public static final int APP15 = 0xFFEF;
4900         public static final int COM   = 0xFFFE;
4901         public static final int DAC   = 0xFFCC;
4902         public static final int DHP   = 0xFFDE;
4903         public static final int DHT   = 0xFFC4;
4904         public static final int DNL   = 0xFFDC;
4905         public static final int DRI   = 0xFFDD;
4906         public static final int DQT   = 0xFFDB;
4907         public static final int EOI   = 0xFFD9;
4908         public static final int EXP   = 0xFFDF;
4909         public static final int JPG   = 0xFFC8;
4910         public static final int JPG0  = 0xFFF0;
4911         public static final int JPG13 = 0xFFFD;
4912         public static final int RST0  = 0xFFD0;
4913         public static final int RST1  = 0xFFD1;
4914         public static final int RST2  = 0xFFD2;
4915         public static final int RST3  = 0xFFD3;
4916         public static final int RST4  = 0xFFD4;
4917         public static final int RST5  = 0xFFD5;
4918         public static final int RST6  = 0xFFD6;
4919         public static final int RST7  = 0xFFD7;
4920         public static final int SOF0  = 0xFFC0;
4921         public static final int SOF1  = 0xFFC1;
4922         public static final int SOF2  = 0xFFC2;
4923         public static final int SOF3  = 0xFFC3;
4924         public static final int SOF5  = 0xFFC5;
4925         public static final int SOF6  = 0xFFC6;
4926         public static final int SOF7  = 0xFFC7;
4927         public static final int SOF9  = 0xFFC9;
4928         public static final int SOF10 = 0xFFCA;
4929         public static final int SOF11 = 0xFFCB;
4930         public static final int SOF13 = 0xFFCD;
4931         public static final int SOF14 = 0xFFCE;
4932         public static final int SOF15 = 0xFFCF;
4933         public static final int SOI   = 0xFFD8;
4934         public static final int SOS   = 0xFFDA;
4935         public static final int TEM   = 0xFF01;
4936         /* JPEGFrameComponentParameterConstants */
4937         public static final int TQI     = 0;
4938         public static final int HI      = 1;
4939         public static final int VI      = 2;
4940         public static final int CW      = 3;
4941         public static final int CH      = 4;
4942         /* JPEGScanComponentParameterConstants */
4943         public static final int DC      = 0;
4944         public static final int AC      = 1;
4945         /* JFIF Component Constants */
4946         public static final int ID_Y            = 1 - 1;
4947         public static final int ID_CB   = 2 - 1;
4948         public static final int ID_CR   = 3 - 1;
4949
4950         public static final int[] ExtendTest = {
4951             0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 
4952             4096, 8192, 16384, 32768, 65536, 131072, 262144
4953         };
4954         public static final int[] ExtendOffset = new int[] {
4955             0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, 
4956             -4095, -8191, -16383, -32767, -65535, -131071, -262143
4957         };
4958         public static final int[] ZigZag8x8 = {
4959             0, 1, 8, 16, 9, 2, 3, 10,
4960             17, 24, 32, 25, 18, 11, 4, 5,
4961             12, 19, 26, 33, 40, 48, 41, 34,
4962             27, 20, 13, 6, 7, 14, 21, 28,
4963             35, 42, 49, 56, 57, 50, 43, 36,
4964             29, 22, 15, 23, 30, 37, 44, 51,
4965             58, 59, 52, 45, 38, 31, 39, 46,
4966             53, 60, 61, 54, 47, 55, 62, 63
4967         };
4968         public static int[] CrRTable, CbBTable, CrGTable, CbGTable;
4969         public static int[] RYTable, GYTable, BYTable,
4970             RCbTable, GCbTable, BCbTable, RCrTable, GCrTable, BCrTable, NBitsTable;
4971         static {
4972             initialize();
4973         }
4974         void compress(ImageData image, byte[] dataYComp, byte[] dataCbComp, byte[] dataCrComp) {
4975             int srcWidth = image.width;
4976             int srcHeight = image.height;
4977             int vhFactor = maxV * maxH;
4978             int[] frameComponent;
4979             imageComponents = new byte[nComponents][];
4980             for (int i = 0; i < nComponents; i++) {
4981                 frameComponent = frameComponents[componentIds[i]];
4982                 imageComponents[i] = new byte[frameComponent[CW] * frameComponent[CH]];
4983             }
4984             frameComponent = frameComponents[componentIds[ID_Y]];
4985             for (int yPos = 0; yPos < srcHeight; yPos++) {
4986                 int srcOfs = yPos * srcWidth;
4987                 int dstOfs = yPos * frameComponent[CW];
4988                 System.arraycopy(dataYComp, srcOfs, imageComponents[ID_Y], dstOfs, srcWidth);
4989             }
4990             frameComponent = frameComponents[componentIds[ID_CB]];
4991             for (int yPos = 0; yPos < srcHeight / maxV; yPos++) {
4992                 int destRowIndex = yPos * frameComponent[CW];
4993                 for (int xPos = 0; xPos < srcWidth / maxH; xPos++) {
4994                     int sum = 0;
4995                     for (int iv = 0; iv < maxV; iv++) {
4996                         int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH);
4997                         for (int ih = 0; ih < maxH; ih++) {
4998                             sum += dataCbComp[srcIndex + ih] & 0xFF;
4999                         }
5000                     }
5001                     imageComponents[ID_CB][destRowIndex + xPos] = (byte)(sum / vhFactor);
5002                 }
5003             }
5004             frameComponent = frameComponents[componentIds[ID_CR]];
5005             for (int yPos = 0; yPos < srcHeight / maxV; yPos++) {
5006                 int destRowIndex = yPos * frameComponent[CW];
5007                 for (int xPos = 0; xPos < srcWidth / maxH; xPos++) {
5008                     int sum = 0;
5009                     for (int iv = 0; iv < maxV; iv++) {
5010                         int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH);
5011                         for (int ih = 0; ih < maxH; ih++) {
5012                             sum += dataCrComp[srcIndex + ih] & 0xFF;
5013                         }
5014                     }
5015                     imageComponents[ID_CR][destRowIndex + xPos] = (byte)(sum / vhFactor);
5016                 }
5017             }
5018             for (int iComp = 0; iComp < nComponents; iComp++) {
5019                 byte[] imageComponent = imageComponents[iComp];
5020                 frameComponent = frameComponents[componentIds[iComp]];
5021                 int hFactor = frameComponent[HI];
5022                 int vFactor = frameComponent[VI];
5023                 int componentWidth = frameComponent[CW];
5024                 int componentHeight = frameComponent[CH];
5025                 int compressedWidth = srcWidth / (maxH / hFactor);
5026                 int compressedHeight = srcHeight / (maxV / vFactor);
5027                 if (compressedWidth < componentWidth) {
5028                     int delta = componentWidth - compressedWidth;
5029                     for (int yPos = 0; yPos < compressedHeight; yPos++) {
5030                         int dstOfs = ((yPos + 1) * componentWidth - delta);
5031                         int dataValue = imageComponent[dstOfs - 1] & 0xFF;
5032                         for (int i = 0; i < delta; i++) {
5033                             imageComponent[dstOfs + i] = (byte)dataValue;
5034                         }
5035                     }
5036                 }
5037                 if (compressedHeight < componentHeight) {
5038                     int srcOfs = (compressedHeight - 1) * componentWidth;
5039                     for (int yPos = compressedHeight; yPos <= componentHeight; yPos++) {
5040                         int dstOfs = (yPos - 1) * componentWidth;
5041                         System.arraycopy(imageComponent, srcOfs, imageComponent, dstOfs, componentWidth);
5042                     }
5043                 }
5044             }
5045         }
5046         void convert4BitRGBToYCbCr(ImageData image) {
5047             RGB[] rgbs = image.getRGBs();
5048             int paletteSize = rgbs.length;
5049             byte[] yComp = new byte[paletteSize];
5050             byte[] cbComp = new byte[paletteSize];
5051             byte[] crComp = new byte[paletteSize];
5052             int srcWidth = image.width;
5053             int srcHeight = image.height;
5054             for (int i = 0; i < paletteSize; i++) {
5055                 RGB color = rgbs[i];
5056                 int r = color.red;
5057                 int g = color.green;
5058                 int b = color.blue;
5059                 int n = RYTable[r] + GYTable[g] + BYTable[b];
5060                 yComp[i] = (byte)(n / 65536);
5061                 if ((n < 0) && (n % 65536 != 0)) yComp[i]--;
5062                 n = RCbTable[r] + GCbTable[g] + BCbTable[b];
5063                 cbComp[i] = (byte)(n / 65536);
5064                 if ((n < 0) && (n % 65536 != 0)) cbComp[i]--;
5065                 n = RCrTable[r] + GCrTable[g] + BCrTable[b];
5066                 crComp[i] = (byte)(n / 65536);
5067                 if ((n < 0) && (n % 65536 != 0)) crComp[i]--;
5068             }
5069             int bSize = srcWidth * srcHeight;
5070             byte[] dataYComp = new byte[bSize];
5071             byte[] dataCbComp = new byte[bSize];
5072             byte[] dataCrComp = new byte[bSize];
5073             byte[] origData = image.data;
5074             for (int yPos = 0; yPos < srcHeight; yPos++) {
5075                 for (int xPos = 0; xPos < srcWidth / 2; xPos++) {
5076                     int srcIndex = yPos * (srcWidth / 2) + xPos;
5077                     int dstIndex = yPos * srcWidth + (xPos * 2);
5078                     int value2 = origData[srcIndex] & 0xFF;
5079                     int value1 = value2 / 16;
5080                     value2 = value2 % 16;
5081                     dataYComp[dstIndex] = yComp[value1];
5082                     dataCbComp[dstIndex] = cbComp[value1];
5083                     dataCrComp[dstIndex] = crComp[value1];
5084                     dataYComp[dstIndex + 1] = yComp[value2];
5085                     dataCbComp[dstIndex + 1] = cbComp[value2];
5086                     dataCrComp[dstIndex + 1] = crComp[value2];
5087                 }
5088             }
5089             compress(image, dataYComp, dataCbComp, dataCrComp);
5090         }
5091         void convert8BitRGBToYCbCr(ImageData image) {
5092             RGB[] rgbs = image.getRGBs();
5093             int paletteSize = rgbs.length;
5094             byte[] yComp = new byte[paletteSize];
5095             byte[] cbComp = new byte[paletteSize];
5096             byte[] crComp = new byte[paletteSize];
5097             int srcWidth = image.width;
5098             int srcHeight = image.height;
5099             for (int i = 0; i < paletteSize; i++) {
5100                 RGB color = rgbs[i];
5101                 int r = color.red;
5102                 int g = color.green;
5103                 int b = color.blue;
5104                 int n = RYTable[r] + GYTable[g] + BYTable[b];
5105                 yComp[i] = (byte)(n / 65536);
5106                 if ((n < 0) && (n % 65536 != 0)) yComp[i]--;
5107                 n = RCbTable[r] + GCbTable[g] + BCbTable[b];
5108                 cbComp[i] = (byte)(n / 65536);
5109                 if ((n < 0) && (n % 65536 != 0)) cbComp[i]--;
5110                 n = RCrTable[r] + GCrTable[g] + BCrTable[b];
5111                 crComp[i] = (byte)(n / 65536);
5112                 if ((n < 0) && (n % 65536 != 0)) crComp[i]--;
5113             }
5114             int dstWidth = image.width;
5115             int dstHeight = srcHeight;
5116             int stride = (srcWidth + 3) / 4 * 4;
5117             int bSize = dstWidth * dstHeight;
5118             byte[] dataYComp = new byte[bSize];
5119             byte[] dataCbComp = new byte[bSize];
5120             byte[] dataCrComp = new byte[bSize];
5121             byte[] origData = image.data;
5122             for (int yPos = 0; yPos < srcHeight; yPos++) {
5123                 int srcRowIndex = yPos * stride;
5124                 int dstRowIndex = yPos * dstWidth;
5125                 for (int xPos = 0; xPos < srcWidth; xPos++) {
5126                     int value = origData[srcRowIndex + xPos] & 0xFF;
5127                     int dstIndex = dstRowIndex + xPos;
5128                     dataYComp[dstIndex] = yComp[value];
5129                     dataCbComp[dstIndex] = cbComp[value];
5130                     dataCrComp[dstIndex] = crComp[value];
5131                 }
5132             }
5133             compress(image, dataYComp, dataCbComp, dataCrComp);
5134         }
5135         byte[] convertCMYKToRGB() {
5136             /* Unsupported CMYK format. Answer an empty byte array. */
5137             return new byte[0];
5138         }
5139         void convertImageToYCbCr(ImageData image) {
5140             switch (image.depth) {
5141                 case 4:
5142                     convert4BitRGBToYCbCr(image);
5143                     return;
5144                 case 8:
5145                     convert8BitRGBToYCbCr(image);
5146                     return;
5147                 case 16:
5148                 case 24:
5149                 case 32:
5150                     convertMultiRGBToYCbCr(image);
5151                     return;
5152                 default:
5153                     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
5154             }
5155             return;
5156         }
5157         void convertMultiRGBToYCbCr(ImageData image) {
5158             int srcWidth = image.width;
5159             int srcHeight = image.height;
5160             int bSize = srcWidth * srcHeight;
5161             byte[] dataYComp = new byte[bSize];
5162             byte[] dataCbComp = new byte[bSize];
5163             byte[] dataCrComp = new byte[bSize];
5164             PaletteData palette = image.palette;
5165             int[] buffer = new int[srcWidth];
5166             if (palette.isDirect) {
5167                 int redMask = palette.redMask;
5168                 int greenMask = palette.greenMask;
5169                 int blueMask = palette.blueMask;
5170                 int redShift = palette.redShift;
5171                 int greenShift = palette.greenShift;
5172                 int blueShift = palette.blueShift;
5173                 for (int yPos = 0; yPos < srcHeight; yPos++) {
5174                     image.getPixels(0, yPos, srcWidth, buffer, 0);
5175                     int dstRowIndex = yPos * srcWidth;
5176                     for (int xPos = 0; xPos < srcWidth; xPos++) {
5177                         int pixel = buffer[xPos];
5178                         int dstDataIndex = dstRowIndex + xPos;
5179                         int r = pixel & redMask;
5180                         r = (redShift < 0) ? r >>> -redShift : r << redShift;
5181                         int g = pixel & greenMask;
5182                         g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
5183                         int b = pixel & blueMask;
5184                         b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;                                
5185                         dataYComp[dstDataIndex] = (byte)((RYTable[r] + GYTable[g] + BYTable[b]) / 65536);
5186                         dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) / 65536);
5187                         dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) / 65536);
5188                     }
5189                 }
5190             } else {
5191                 for (int yPos = 0; yPos < srcHeight; yPos++) {
5192                     image.getPixels(0, yPos, srcWidth, buffer, 0);
5193                     int dstRowIndex = yPos * srcWidth;
5194                     for (int xPos = 0; xPos < srcWidth; xPos++) {
5195                         int pixel = buffer[xPos];
5196                         int dstDataIndex = dstRowIndex + xPos;
5197                         RGB rgb = palette.getRGB(pixel);
5198                         int r = rgb.red;
5199                         int g = rgb.green;
5200                         int b = rgb.blue;
5201                         dataYComp[dstDataIndex] = (byte)((RYTable[r] + GYTable[g] + BYTable[b]) / 65536);
5202                         dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) / 65536);
5203                         dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) / 65536);
5204                     }
5205                 }
5206             }
5207             compress(image, dataYComp, dataCbComp, dataCrComp);
5208         }
5209         byte[] convertYToRGB() {
5210             int compWidth = frameComponents[componentIds[ID_Y]][CW];
5211             int bytesPerLine = (((imageWidth * 8 + 7) / 8) + 3) / 4 * 4;
5212             byte[] data = new byte[bytesPerLine * imageHeight];
5213             byte[] yComp = imageComponents[ID_Y];
5214             int destIndex = 0;
5215             for (int i = 0; i < imageHeight; i++) {
5216                 int srcIndex = i * compWidth;
5217                 for (int j = 0; j < bytesPerLine; j++) {
5218                     int y = yComp[srcIndex] & 0xFF;
5219                     if (y < 0) {
5220                         y = 0;
5221                     } else {
5222                         if (y > 255) y = 255;
5223                     }
5224                     if (j >= imageWidth) {
5225                         y = 0;
5226                     }
5227                     data[destIndex] = (byte)y;
5228                     srcIndex++;
5229                     destIndex++;
5230                 }
5231             }
5232             return data;
5233         }
5234         byte[] convertYCbCrToRGB() {
5235             /**
5236              * Convert existing image components into an RGB format.
5237              * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
5238              * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
5239              * The conversion equations to be implemented are therefore
5240              *  R = Y                + 1.40200 * Cr
5241              *  G = Y - 0.34414 * Cb - 0.71414 * Cr
5242              *  B = Y + 1.77200 * Cb
5243              * where Cb and Cr represent the incoming values less MAXJSAMPLE/2.
5244              * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
5245              * 
5246              * To avoid floating-point arithmetic, we represent the fractional constants
5247              * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
5248              * the products by 2^16, with appropriate rounding, to get the correct answer.
5249              * Notice that Y, being an integral input, does not contribute any fraction
5250              * so it need not participate in the rounding.
5251              * 
5252              * For even more speed, we avoid doing any multiplications in the inner loop
5253              * by precalculating the constants times Cb and Cr for all possible values.
5254              * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
5255              * for 12-bit samples it is still acceptable.  It's not very reasonable for
5256              * 16-bit samples, but if you want lossless storage you shouldn't be changing
5257              * colorspace anyway.
5258              * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
5259              * values for the G calculation are left scaled up, since we must add them
5260              * together before rounding.
5261              */
5262             int bSize = imageWidth * imageHeight * nComponents;
5263             byte[] rgbData = new byte[bSize];
5264             int destIndex = 0;
5265             expandImageComponents();
5266             byte[] yComp = imageComponents[ID_Y];
5267             byte[] cbComp = imageComponents[ID_CB];
5268             byte[] crComp = imageComponents[ID_CR];
5269             int compWidth = frameComponents[componentIds[ID_Y]][CW];
5270             for (int v = 0; v < imageHeight; v++) {
5271                 int srcIndex = v * compWidth;
5272                 for (int i = 0; i < imageWidth; i++) {
5273                     int y = yComp[srcIndex] & 0xFF;
5274                     int cb = cbComp[srcIndex] & 0xFF;
5275                     int cr = crComp[srcIndex] & 0xFF;
5276                     int r = y + CrRTable[cr];
5277                     int g = y + ((CbGTable[cb] + CrGTable[cr]) / 65536);
5278                     int b = y + CbBTable[cb];
5279                     if (r < 0) {
5280                         r = 0;
5281                     } else {
5282                         if (r > 255) r = 255;
5283                     }
5284                     if (g < 0) {
5285                         g = 0;
5286                     } else {
5287                         if (g > 255) g = 255;
5288                     }
5289                     if (b < 0) {
5290                         b = 0;
5291                     } else {
5292                         if (b > 255) b = 255;
5293                     }
5294                     rgbData[destIndex] = (byte)b;
5295                     rgbData[destIndex + 1] = (byte)g;
5296                     rgbData[destIndex + 2] = (byte)r;
5297                     destIndex += 3;
5298                     srcIndex++;
5299                 }
5300             }
5301             return rgbData;
5302         }
5303         byte[] convertYIQToRGB() {
5304             /* Unsupported CMYK format. Answer an empty byte array. */
5305             return new byte[0];
5306         }
5307         void decodeACCoefficients(int[] dataUnit, int iComp) {
5308             int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
5309             JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
5310             int k = 1;
5311             while (k < 64) {
5312                 int rs = decodeUsingTable(acTable);
5313                 int r = rs >> 4;
5314                 int s = rs & 0xF;
5315                 if (s == 0) {
5316                     if (r == 15) {
5317                         k += 16;
5318                     } else {
5319                         break;
5320                     }
5321                 } else {
5322                     k += r;
5323                     int bits = receive(s);
5324                     dataUnit[ZigZag8x8[k]] = extendBy(bits, s);
5325                     k++;
5326                 }
5327             }
5328         }
5329         void decodeACFirstCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) {
5330             if (eobrun > 0) {
5331                 eobrun--;
5332                 return;
5333             }
5334             int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
5335             JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
5336             int k = start;
5337             while (k <= end) {
5338                 int rs = decodeUsingTable(acTable);
5339                 int r = rs >> 4;
5340                 int s = rs & 0xF;
5341                 if (s == 0) {
5342                     if (r == 15) {
5343                         k += 16;
5344                     } else {
5345                         eobrun = (1 << r) + receive(r) - 1;
5346                         break;
5347                     }
5348                 } else {
5349                     k += r;
5350                     int bits = receive(s);
5351                     dataUnit[ZigZag8x8[k]] = extendBy(bits, s) << approxBit;
5352                     k++;
5353                 }
5354             }
5355         }
5356         void decodeACRefineCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) {
5357             int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
5358             JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
5359             int k = start;
5360             while (k <= end) {
5361                 if (eobrun > 0) {
5362                     while (k <= end) {
5363                         int zzIndex = ZigZag8x8[k];
5364                         if (dataUnit[zzIndex] != 0) {
5365                             dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
5366                         }
5367                         k++;
5368                     }
5369                     eobrun--;
5370                 } else {
5371                     int rs = decodeUsingTable(acTable);
5372                     int r = rs >> 4;
5373                     int s = rs & 0xF;
5374                     if (s == 0) {
5375                         if (r == 15) {
5376                             int zeros = 0;
5377                             while (zeros < 16 && k <= end) {
5378                                 int zzIndex = ZigZag8x8[k];
5379                                 if (dataUnit[zzIndex] != 0) {
5380                                     dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
5381                                 } else {
5382                                     zeros++;
5383                                 }
5384                                 k++;
5385                             }
5386                         } else {
5387                             eobrun = (1 << r) + receive(r);
5388                         }
5389                     } else {
5390                         int bit = receive(s);
5391                         int zeros = 0;
5392                         int zzIndex = ZigZag8x8[k];
5393                         while ((zeros < r || dataUnit[zzIndex] != 0) && k <= end) {
5394                             if (dataUnit[zzIndex] != 0) {
5395                                 dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
5396                             } else {
5397                                 zeros++;
5398                             }
5399                             k++;
5400                             zzIndex = ZigZag8x8[k];
5401                         }
5402                         if (bit != 0) {
5403                             dataUnit[zzIndex] = 1 << approxBit;
5404                         } else {
5405                             dataUnit[zzIndex] = -1 << approxBit;
5406                         }
5407                         k++;
5408                     }
5409                 }
5410             }
5411         }
5412         int refineAC(int ac, int approxBit) {
5413             if (ac > 0) {
5414                 int bit = nextBit();
5415                 if (bit != 0) {
5416                     ac = ac + (1 << approxBit);
5417                 }
5418             } else if (ac < 0) {
5419                 int bit = nextBit();
5420                 if (bit != 0) {
5421                     ac = ac + (-1 << approxBit);
5422                 }
5423             }
5424             return ac;
5425         }
5426         void decodeDCCoefficient(int[] dataUnit, int iComp, boolean first, int approxBit) {
5427             int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
5428             JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]];
5429             int lastDC = 0;
5430             if (progressive && !first) {
5431                 int bit = nextBit();
5432                 lastDC = dataUnit[0] + (bit << approxBit);
5433             } else {
5434                 lastDC = precedingDCs[iComp];
5435                 int nBits = decodeUsingTable(dcTable);
5436                 if (nBits != 0) {
5437                     int bits = receive(nBits);
5438                     int diff = extendBy(bits, nBits);
5439                     lastDC = lastDC + diff;
5440                     precedingDCs[iComp] = lastDC;
5441                 }
5442                 if (progressive) {
5443                     lastDC = lastDC << approxBit;
5444                 }
5445             }
5446             dataUnit[0] = lastDC;
5447         }
5448         void dequantize(int[] dataUnit, int iComp) {
5449             int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]];
5450             for (int i = 0; i < dataUnit.length; i++) {
5451                 int zzIndex = ZigZag8x8[i];
5452                 dataUnit[zzIndex] = dataUnit[zzIndex] * qTable[i];
5453             }
5454         }
5455         byte[] decodeImageComponents() {
5456             int[] compIds = new int[nComponents];
5457             int compIdsIndex = 0;
5458             for (int i = 0; i < nComponents; i++) {
5459                 compIds[compIdsIndex] = i + 1;
5460                 compIdsIndex++;
5461             }
5462             if ((compIds.length == 3) &&
5463                 (compIds[0] == 1) &&
5464                 (compIds[1] == 2) &&
5465                 (compIds[2] == 3)) {
5466                 return convertYCbCrToRGB();
5467             }
5468             if ((compIds.length == 3) &&
5469                 (compIds[0] == 1) &&
5470                 (compIds[1] == 4) &&
5471                 (compIds[2] == 5)) {
5472                 return convertYIQToRGB();
5473             }
5474             if (compIds.length == 4) {
5475                 return convertCMYKToRGB();
5476             }
5477             return convertYToRGB();
5478         }
5479         void decodeMCUAtXAndY(int xmcu, int ymcu, int nComponentsInScan, boolean first, int start, int end, int approxBit) {
5480             for (int iComp = 0; iComp < nComponentsInScan; iComp++) {
5481                 int scanComponent = iComp;
5482                 while (scanHeader.componentParameters[componentIds[scanComponent]] == null) {
5483                     scanComponent++;
5484                 }
5485                 int[] frameComponent = frameComponents[componentIds[scanComponent]];
5486                 int hi = frameComponent[HI];
5487                 int vi = frameComponent[VI];
5488                 if (nComponentsInScan == 1) {
5489                     hi = 1;
5490                     vi = 1;
5491                 }
5492                 int compWidth = frameComponent[CW];
5493                 for (int ivi = 0; ivi < vi; ivi++) {
5494                     for (int ihi = 0; ihi < hi; ihi++) {
5495                         if (progressive) {
5496                             // Progressive: First scan - create a new data unit.
5497                             // Subsequent scans - refine the existing data unit.
5498                             int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi;
5499                             dataUnit = dataUnits[scanComponent][index];
5500                             if (dataUnit == null) {
5501                                 dataUnit = new int[64];
5502                                 dataUnits[scanComponent][index] = dataUnit;
5503                             }
5504                         } else {
5505                             // Sequential: Clear and reuse the data unit buffer.
5506                             for (int i = 0; i < dataUnit.length; i++) {
5507                                 dataUnit[i] = 0;
5508                             }
5509                         }
5510                         if (!progressive || scanHeader.isDCProgressiveScan()) {
5511                             decodeDCCoefficient(dataUnit, scanComponent, first, approxBit);
5512                         }
5513                         if (!progressive) {
5514                             decodeACCoefficients(dataUnit, scanComponent);
5515                         } else {
5516                             if (scanHeader.isACProgressiveScan()) {
5517                                 if (first) {
5518                                     decodeACFirstCoefficients(dataUnit, scanComponent, start, end, approxBit);
5519                                 } else {
5520                                     decodeACRefineCoefficients(dataUnit, scanComponent, start, end, approxBit);
5521                                 }
5522                             }
5523                             if (loader.hasListeners()) {
5524                                 // Dequantization, IDCT, up-sampling and color conversion
5525                                 // are done on a copy of the coefficient data in order to
5526                                 // display the image incrementally.
5527                                 int[] temp = dataUnit;
5528                                 dataUnit = new int[64];
5529                                 System.arraycopy(temp, 0, dataUnit, 0, 64);
5530                             }
5531                         }
5532                         if (!progressive || (progressive && loader.hasListeners())) {
5533                             dequantize(dataUnit, scanComponent);
5534                             inverseDCT(dataUnit);
5535                             storeData(dataUnit, scanComponent, xmcu, ymcu, hi, ihi, vi, ivi);
5536                         }
5537                     }
5538                 }
5539             }
5540         }
5541         void decodeScan() {
5542             if (progressive && !scanHeader.verifyProgressiveScan()) {
5543                 SWT.error(SWT.ERROR_INVALID_IMAGE);
5544             }
5545             int nComponentsInScan = scanHeader.getNumberOfImageComponents();
5546             int mcuRowsInScan = interleavedMcuRows;
5547             int mcusPerRow = interleavedMcuCols;
5548             if (nComponentsInScan == 1) {
5549                 // Non-interleaved.
5550                 int scanComponent = 0;
5551                 while (scanHeader.componentParameters[componentIds[scanComponent]] == null) {
5552                     scanComponent++;
5553                 }
5554                 int[] frameComponent = frameComponents[componentIds[scanComponent]];
5555                 int hi = frameComponent[HI];
5556                 int vi = frameComponent[VI];
5557                 int mcuWidth = DCTSIZE * maxH / hi;
5558                 int mcuHeight = DCTSIZE * maxV / vi;
5559                 mcusPerRow = (imageWidth + mcuWidth - 1) / mcuWidth;
5560                 mcuRowsInScan = (imageHeight + mcuHeight - 1) / mcuHeight;
5561             }
5562             boolean first = scanHeader.isFirstScan();
5563             int start = scanHeader.getStartOfSpectralSelection();
5564             int end = scanHeader.getEndOfSpectralSelection();
5565             int approxBit = scanHeader.getApproxBitPositionLow();
5566             restartsToGo = restartInterval;
5567             nextRestartNumber = 0;
5568             for (int ymcu = 0; ymcu < mcuRowsInScan; ymcu++) {
5569                 for (int xmcu = 0; xmcu < mcusPerRow; xmcu++) {
5570                     if (restartInterval != 0) {
5571                         if (restartsToGo == 0) processRestartInterval();
5572                         restartsToGo--;
5573                     }
5574                     decodeMCUAtXAndY(xmcu, ymcu, nComponentsInScan, first, start, end, approxBit);
5575                 }
5576             }
5577         }
5578         int decodeUsingTable(JPEGHuffmanTable huffmanTable) {
5579             int i = 0;
5580             int[] maxCodes = huffmanTable.getDhMaxCodes();
5581             int[] minCodes = huffmanTable.getDhMinCodes();
5582             int[] valPtrs = huffmanTable.getDhValPtrs();
5583             int[] huffVals = huffmanTable.getDhValues();
5584             int code = nextBit();
5585             while (code > maxCodes[i]) {
5586                 code = code * 2 + nextBit();
5587                 i++;
5588             }
5589             int j = valPtrs[i];
5590             j = j + code - minCodes[i];
5591             return huffVals[j];
5592         }
5593         void emit(int huffCode, int nBits) {
5594             if (nBits == 0) {
5595                 SWT.error(SWT.ERROR_INVALID_IMAGE);
5596             }
5597             int[] power2m1 = new int[] {
5598                 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 
5599                 16383, 32767, 65535, 131125
5600             };
5601             int code = (huffCode & power2m1[nBits - 1]) << (24 - nBits - currentBitCount);
5602             byte[] codeBuffer = new byte[4];
5603             codeBuffer[0] = (byte)(code % 256);
5604             codeBuffer[1] = (byte)((code / 256) % 256);
5605             codeBuffer[2] = (byte)((code / 65536) % 256);
5606             codeBuffer[3] = (byte)((code / 16777216) % 256);
5607             int abs = nBits - (8 - currentBitCount);
5608             if (abs < 0) abs = -abs;
5609             if ((abs / 8) > 0) {
5610                 currentByte += codeBuffer[2];
5611                 emitByte((byte)currentByte);
5612                 emitByte((byte)codeBuffer[1]);
5613                 currentByte = codeBuffer[0];
5614                 currentBitCount += nBits - 16;
5615             } else {
5616                 currentBitCount += nBits;
5617                 if (currentBitCount >= 8) {
5618                     currentByte += codeBuffer[2];
5619                     emitByte((byte)currentByte);
5620                     currentByte = codeBuffer[1];
5621                     currentBitCount -= 8;
5622                 } else {
5623                     currentByte += codeBuffer[2];
5624                 }
5625             }
5626         }
5627         void emitByte(byte byteValue) {
5628             if (bufferCurrentPosition >= 512) {
5629                 resetOutputBuffer();
5630             }
5631             dataBuffer[bufferCurrentPosition] = byteValue;
5632             bufferCurrentPosition++;
5633             if (byteValue == -1) {
5634                 emitByte((byte)0);
5635             }
5636         }
5637         void encodeACCoefficients(int[] dataUnit, int iComp) {
5638             int[] sParams = scanHeader.componentParameters[iComp];
5639             JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
5640             int[] ehCodes = acTable.ehCodes;
5641             byte[] ehSizes = acTable.ehCodeLengths;
5642             int r = 0;
5643             int k = 1;
5644             while (k < 64) {
5645                 k++;
5646                 int acValue = dataUnit[ZigZag8x8[k - 1]];
5647                 if (acValue == 0) {
5648                     if (k == 64) {
5649                         emit(ehCodes[0], ehSizes[0] & 0xFF);
5650                     } else {
5651                         r++;
5652                     }
5653                 } else {
5654                     while (r > 15) {
5655                         emit(ehCodes[0xF0], ehSizes[0xF0] & 0xFF);
5656                         r -= 16;
5657                     }
5658                     if (acValue < 0) {
5659                         int absACValue = acValue;
5660                         if (absACValue < 0) absACValue = -absACValue;
5661                         int nBits = NBitsTable[absACValue];
5662                         int rs = r * 16 + nBits;
5663                         emit(ehCodes[rs], ehSizes[rs] & 0xFF);
5664                         emit(0xFFFFFF - absACValue, nBits);
5665                     } else {
5666                         int nBits = NBitsTable[acValue];
5667                         int rs = r * 16 + nBits;
5668                         emit(ehCodes[rs], ehSizes[rs] & 0xFF);
5669                         emit(acValue, nBits);
5670                     }
5671                     r = 0;
5672                 }
5673             }
5674         }
5675         void encodeDCCoefficients(int[] dataUnit, int iComp) {
5676             int[] sParams = scanHeader.componentParameters[iComp];
5677             JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]];
5678             int lastDC = precedingDCs[iComp];
5679             int dcValue = dataUnit[0];
5680             int diff = dcValue - lastDC;
5681             precedingDCs[iComp] = dcValue;
5682             if (diff < 0) {
5683                 int absDiff = 0 - diff;
5684                 int nBits = NBitsTable[absDiff];
5685                 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]);
5686                 emit(0xFFFFFF - absDiff, nBits);
5687             } else {
5688                 int nBits = NBitsTable[diff];
5689                 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]);
5690                 if (nBits != 0) {
5691                     emit(diff, nBits);
5692                 }
5693             }
5694         }
5695         void encodeMCUAtXAndY(int xmcu, int ymcu) {
5696             int nComponentsInScan = scanHeader.getNumberOfImageComponents();
5697             dataUnit = new int[64];
5698             for (int iComp = 0; iComp < nComponentsInScan; iComp++) {
5699                 int[] frameComponent = frameComponents[componentIds[iComp]];
5700                 int hi = frameComponent[HI];
5701                 int vi = frameComponent[VI];
5702                 for (int ivi = 0; ivi < vi; ivi++) {
5703                     for (int ihi = 0; ihi < hi; ihi++) {
5704                         extractData(dataUnit, iComp, xmcu, ymcu, ihi, ivi);
5705                         forwardDCT(dataUnit);
5706                         quantizeData(dataUnit, iComp);
5707                         encodeDCCoefficients(dataUnit, iComp);
5708                         encodeACCoefficients(dataUnit, iComp);
5709                     }
5710                 }
5711             }
5712         }
5713         void encodeScan() {
5714             for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) {
5715                 for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) {
5716                     encodeMCUAtXAndY(xmcu, ymcu);
5717                 }
5718             }
5719             if (currentBitCount != 0) {
5720                 emitByte((byte)currentByte);
5721             }
5722             resetOutputBuffer();
5723         }
5724         void expandImageComponents() {
5725             for (int iComp = 0; iComp < nComponents; iComp++) {
5726                 int[] frameComponent = frameComponents[componentIds[iComp]];
5727                 int hi = frameComponent[HI];
5728                 int vi = frameComponent[VI];
5729                 int upH = maxH / hi;
5730                 int upV = maxV / vi;
5731                 if ((upH * upV) > 1) {
5732                     byte[] component = imageComponents[iComp];
5733                     int compWidth = frameComponent[CW];
5734                     int compHeight = frameComponent[CH];
5735                     int upCompWidth = compWidth * upH;
5736                     int upCompHeight = compHeight * upV;
5737                     RGB[] rgbs = new RGB[] {
5738                         new RGB(0,0,0),
5739                         new RGB(0x80,0,0),
5740                         new RGB(0,0x80,0),
5741                         new RGB(0x80,0x80,0),
5742                         new RGB(0,0,0x80),
5743                         new RGB(0x80,0,0x80),
5744                         new RGB(0,0x80,0x80),
5745                         new RGB(0xC0,0xC0,0xC0),
5746                         new RGB(0x80,0x80,0x80),
5747                         new RGB(0xFF,0,0),
5748                         new RGB(0,0xFF,0),
5749                         new RGB(0xFF,0xFF,0),
5750                         new RGB(0,0,0xFF),
5751                         new RGB(0xFF,0,0xFF),
5752                         new RGB(0,0xFF,0xFF),
5753                         new RGB(0xFF,0xFF,0xFF),
5754                     };
5755                     ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(rgbs), 4, component);
5756                     ImageData dest = src.scaledTo(upCompWidth, upCompHeight);
5757                     imageComponents[iComp] = dest.data;
5758                 }
5759             }
5760         }
5761         int extendBy(int diff, int t) {
5762             if (diff < ExtendTest[t]) {
5763                 return diff + ExtendOffset[t];
5764             } else {
5765                 return diff;
5766             }
5767         }
5768         void extractData(int[] dataUnit, int iComp, int xmcu, int ymcu, int ihi, int ivi) {
5769             byte[] compImage = imageComponents[iComp];
5770             int[] frameComponent = frameComponents[componentIds[iComp]];
5771             int hi = frameComponent[HI];
5772             int vi = frameComponent[VI];
5773             int compWidth = frameComponent[CW];
5774             int srcIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE);
5775             int destIndex = 0;
5776             for (int i = 0; i < DCTSIZE; i++) {
5777                 for (int col = 0; col < DCTSIZE; col++) {
5778                     dataUnit[destIndex] = (compImage[srcIndex + col] & 0xFF) - 128;
5779                     destIndex++;
5780                 }
5781                 srcIndex += compWidth;
5782             }
5783         }
5784         void forwardDCT(int[] dataUnit) {
5785             for (int row = 0; row < 8; row++) {
5786                 int rIndex = row * DCTSIZE;
5787                 int tmp0 = dataUnit[rIndex] + dataUnit[rIndex + 7];
5788                 int tmp7 = dataUnit[rIndex] - dataUnit[rIndex + 7];
5789                 int tmp1 = dataUnit[rIndex + 1] + dataUnit[rIndex + 6];
5790                 int tmp6 = dataUnit[rIndex + 1] - dataUnit[rIndex + 6];
5791                 int tmp2 = dataUnit[rIndex + 2] + dataUnit[rIndex + 5];
5792                 int tmp5 = dataUnit[rIndex + 2] - dataUnit[rIndex + 5];
5793                 int tmp3 = dataUnit[rIndex + 3] + dataUnit[rIndex + 4];
5794                 int tmp4 = dataUnit[rIndex + 3] - dataUnit[rIndex + 4];
5795
5796                 /**
5797                  * Even part per LL&M figure 1 --- note that published figure 
5798                  * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'.
5799                  */
5800                 int tmp10 = tmp0 + tmp3;
5801                 int tmp13 = tmp0 - tmp3;
5802                 int tmp11 = tmp1 + tmp2;
5803                 int tmp12 = tmp1 - tmp2;
5804
5805                 dataUnit[rIndex] = (tmp10 + tmp11) * 4;
5806                 dataUnit[rIndex + 4]  = (tmp10 - tmp11) * 4;
5807
5808                 int z1 = (tmp12 + tmp13) * FIX_0_541196100;
5809                 int scaleFactor1 = ExtendTest[11];
5810                 int scaleFactor2 = ExtendTest[12];
5811                 int n = z1 + (tmp13 * FIX_0_765366865) + scaleFactor1;
5812                 dataUnit[rIndex + 2] = n / scaleFactor2;
5813                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 2]--;
5814                 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + scaleFactor1;
5815                 dataUnit[rIndex + 6] = n / scaleFactor2;
5816                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 6]--;
5817
5818                 /**
5819                  * Odd part per figure 8 --- note paper omits factor of sqrt(2).
5820                  * cK represents cos(K*pi/16).
5821                  * i0..i3 in the paper are tmp4..tmp7 here.
5822                  */
5823                 z1 = tmp4 + tmp7;
5824                 int z2 = tmp5 + tmp6;
5825                 int z3 = tmp4 + tmp6;
5826                 int z4 = tmp5 + tmp7;
5827                 int z5 = (z3 + z4) * FIX_1_175875602;   // sqrt(2) * c3
5828
5829                 tmp4 = tmp4 * FIX_0_298631336;  // sqrt(2) * (-c1+c3+c5-c7)
5830                 tmp5 = tmp5 * FIX_2_053119869;  // sqrt(2) * ( c1+c3-c5+c7)
5831                 tmp6 = tmp6 * FIX_3_072711026;  // sqrt(2) * ( c1+c3+c5-c7)
5832                 tmp7 = tmp7 * FIX_1_501321110;  // sqrt(2) * ( c1+c3-c5-c7)
5833                 z1 = z1 * (0 - FIX_0_899976223);        // sqrt(2) * (c7-c3)
5834                 z2 = z2 * (0 - FIX_2_562915447);        // sqrt(2) * (-c1-c3)
5835                 z3 = z3 * (0 - FIX_1_961570560);        // sqrt(2) * (-c3-c5)
5836                 z4 = z4 * (0 - FIX_0_390180644);        // sqrt(2) * (c5-c3)
5837
5838                 z3 = z3 + z5;
5839                 z4 = z4 + z5;
5840
5841                 n = tmp4 + z1 + z3 + scaleFactor1;
5842                 dataUnit[rIndex + 7] = n / scaleFactor2;
5843                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 7]--;
5844                 n = tmp5 + z2 + z4 + scaleFactor1;
5845                 dataUnit[rIndex + 5] = n / scaleFactor2;
5846                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 5]--;
5847                 n = tmp6 + z2 + z3 + scaleFactor1;
5848                 dataUnit[rIndex + 3] = n / scaleFactor2;
5849                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 3]--;
5850                 n = tmp7 + z1 + z4 + scaleFactor1;
5851                 dataUnit[rIndex + 1] = n / scaleFactor2;
5852                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 1]--;
5853             }
5854
5855             /**
5856              * Pass 2: process columns.
5857              * Note that we must descale the results by a factor of 8 == 2**3,
5858              * and also undo the PASS1_BITS scaling.
5859              */
5860             for (int col = 0; col < 8; col++) {
5861                 int c0 = col;
5862                 int c1 = col + 8;
5863                 int c2 = col + 16;
5864                 int c3 = col + 24;
5865                 int c4 = col + 32;
5866                 int c5 = col + 40;
5867                 int c6 = col + 48;
5868                 int c7 = col + 56;
5869                 int tmp0 = dataUnit[c0] + dataUnit[c7];
5870                 int tmp7 = dataUnit[c0] - dataUnit[c7];
5871                 int tmp1 = dataUnit[c1] + dataUnit[c6];
5872                 int tmp6 = dataUnit[c1] - dataUnit[c6];
5873                 int tmp2 = dataUnit[c2] + dataUnit[c5];
5874                 int tmp5 = dataUnit[c2] - dataUnit[c5];
5875                 int tmp3 = dataUnit[c3] + dataUnit[c4];
5876                 int tmp4 = dataUnit[c3] - dataUnit[c4];
5877
5878                 /**
5879                  * Even part per LL&M figure 1 --- note that published figure 
5880                  * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'.
5881                  */
5882                 int tmp10 = tmp0 + tmp3;
5883                 int tmp13 = tmp0 - tmp3;
5884                 int tmp11 = tmp1 + tmp2;
5885                 int tmp12 = tmp1 - tmp2;
5886
5887                 int scaleFactor1 = ExtendTest[5];
5888                 int scaleFactor2 = ExtendTest[6];
5889                 int n = tmp10 + tmp11 + scaleFactor1;
5890                 dataUnit[c0] = n / scaleFactor2;
5891                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c0]--;
5892                 n = tmp10 - tmp11 + scaleFactor1;
5893                 dataUnit[c4] = n / scaleFactor2;
5894                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c4]--;
5895
5896                 int z1 = (tmp12 + tmp13) * FIX_0_541196100;
5897                 scaleFactor1 = ExtendTest[18];
5898                 scaleFactor2 = ExtendTest[19];
5899                 n = z1 + (tmp13 * FIX_0_765366865) + scaleFactor1;
5900                 dataUnit[c2] = n / scaleFactor2;
5901                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c2]--;
5902                 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + scaleFactor1;
5903                 dataUnit[c6] = n / scaleFactor2;
5904                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c6]--;
5905
5906                 /**
5907                  * Odd part per figure 8 --- note paper omits factor of sqrt(2).
5908                  * cK represents cos(K*pi/16).
5909                  * i0..i3 in the paper are tmp4..tmp7 here.
5910                  */
5911                 z1 = tmp4 + tmp7;
5912                 int z2 = tmp5 + tmp6;
5913                 int z3 = tmp4 + tmp6;
5914                 int z4 = tmp5 + tmp7;
5915                 int z5 = (z3 + z4) * FIX_1_175875602;   // sqrt(2) * c3
5916
5917                 tmp4 = tmp4 * FIX_0_298631336;  // sqrt(2) * (-c1+c3+c5-c7)
5918                 tmp5 = tmp5 * FIX_2_053119869;  // sqrt(2) * ( c1+c3-c5+c7)
5919                 tmp6 = tmp6 * FIX_3_072711026;  // sqrt(2) * ( c1+c3+c5-c7)
5920                 tmp7 = tmp7 * FIX_1_501321110;  // sqrt(2) * ( c1+c3-c5-c7)
5921                 z1 = z1 * (0 - FIX_0_899976223);        // sqrt(2) * (c7-c3)
5922                 z2 = z2 * (0 - FIX_2_562915447);        // sqrt(2) * (-c1-c3)
5923                 z3 = z3 * (0 - FIX_1_961570560);        // sqrt(2) * (-c3-c5)
5924                 z4 = z4 * (0 - FIX_0_390180644);        // sqrt(2) * (c5-c3)
5925
5926                 z3 = z3 + z5;
5927                 z4 = z4 + z5;
5928
5929                 n = tmp4 + z1 + z3 + scaleFactor1;
5930                 dataUnit[c7] = n / scaleFactor2;
5931                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c7]--;
5932                 n = tmp5 + z2 + z4 + scaleFactor1;
5933                 dataUnit[c5] = n / scaleFactor2;
5934                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c5]--;
5935                 n = tmp6 + z2 + z3 + scaleFactor1;
5936                 dataUnit[c3] = n / scaleFactor2;
5937                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c3]--;
5938                 n = tmp7 + z1 + z4 + scaleFactor1;
5939                 dataUnit[c1] = n / scaleFactor2;
5940                 if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c1]--;
5941             }
5942         }
5943         void getAPP0() {
5944             JPEGAppn appn = new JPEGAppn(inputStream);
5945             if (!appn.verify()) {
5946                 SWT.error(SWT.ERROR_INVALID_IMAGE);
5947             }
5948         }
5949         void getCOM() {
5950             new JPEGComment(inputStream);
5951         }
5952         void getDAC() {
5953             JPEGArithmeticConditioningTable dac = new JPEGArithmeticConditioningTable(inputStream);
5954             arithmeticTables = dac;
5955         }
5956         void getDHT() {
5957             JPEGHuffmanTable dht = new JPEGHuffmanTable(inputStream);
5958             if (!dht.verify()) {
5959                 SWT.error(SWT.ERROR_INVALID_IMAGE);
5960             }
5961             if (acHuffmanTables == null) {
5962                 acHuffmanTables = new JPEGHuffmanTable[4];
5963             }
5964             if (dcHuffmanTables == null) {
5965                 dcHuffmanTables = new JPEGHuffmanTable[4];
5966             }
5967             JPEGHuffmanTable[] dhtTables = dht.getAllTables();
5968             for (int i = 0; i < dhtTables.length; i++) {
5969                 JPEGHuffmanTable dhtTable = dhtTables[i];
5970                 if (dhtTable.getTableClass() == 0) {
5971                     dcHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable;
5972                 } else {
5973                     acHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable;
5974                 }
5975             }
5976         }
5977         void getDNL() {
5978             new JPEGRestartInterval(inputStream);
5979         }
5980         void getDQT() {
5981             JPEGQuantizationTable dqt = new JPEGQuantizationTable(inputStream);
5982             int[][] currentTables = quantizationTables;
5983             if (currentTables == null) {
5984                 currentTables = new int[4][];
5985             }
5986             int[] dqtTablesKeys = dqt.getQuantizationTablesKeys();
5987             int[][] dqtTablesValues = dqt.getQuantizationTablesValues();
5988             for (int i = 0; i < dqtTablesKeys.length; i++) {
5989                 int index = dqtTablesKeys[i];
5990                 currentTables[index] = dqtTablesValues[i];
5991             }
5992             quantizationTables = currentTables;
5993         }
5994         void getDRI() {
5995             JPEGRestartInterval dri = new JPEGRestartInterval(inputStream);
5996             if (!dri.verify()) {
5997                 SWT.error(SWT.ERROR_INVALID_IMAGE);
5998             }
5999             restartInterval = dri.getRestartInterval();
6000         }
6001         static void initialize() {
6002             initializeRGBYCbCrTables();
6003             initializeYCbCrRGBTables();
6004             initializeBitCountTable();
6005         }
6006         static void initializeBitCountTable() {
6007             int nBits = 1;
6008             int power2 = 2;
6009             NBitsTable = new int[2048];
6010             NBitsTable[0] = 0;
6011             for (int i = 1; i < NBitsTable.length; i++) {
6012                 if (!(i < power2)) {
6013                     nBits++;
6014                     power2 *= 2;
6015                 }
6016                 NBitsTable[i] = nBits;
6017             }
6018         }
6019         static void initializeRGBYCbCrTables() {
6020             RYTable = new int[256];
6021             GYTable = new int[256];
6022             BYTable = new int[256];
6023             RCbTable = new int[256];
6024             GCbTable = new int[256];
6025             BCbTable = new int[256];
6026             RCrTable = BCbTable;
6027             GCrTable = new int[256];
6028             BCrTable = new int[256];
6029             for (int i = 0; i < 256; i++) {
6030                 RYTable[i] = i * 19595;
6031                 GYTable[i] = i * 38470;
6032                 BYTable[i] = i * 7471 + 32768;
6033                 RCbTable[i] = i * -11059;
6034                 GCbTable[i] = i * -21709;
6035                 BCbTable[i] = i * 32768 + 8388608;
6036                 GCrTable[i] = i * -27439;
6037                 BCrTable[i] = i * -5329;
6038             }
6039         }
6040         static void initializeYCbCrRGBTables() {
6041             CrRTable = new int[256];
6042             CbBTable = new int[256];
6043             CrGTable = new int[256];
6044             CbGTable = new int[256];
6045             for (int i = 0; i < 256; i++) {
6046                 int x2 = 2 * i - 255;
6047                 CrRTable[i] = (45941 * x2 + 32768) / 65536;
6048                 CbBTable[i] = (58065 * x2 + 32768) / 65536;
6049                 CrGTable[i] = -23401 * x2;
6050                 CbGTable[i] = -11277 * x2 + 32768;
6051             }
6052         }
6053         void inverseDCT(int[] dataUnit) {
6054             for (int row = 0; row < 8; row++) {
6055                 int rIndex = row * DCTSIZE;
6056                 /**
6057                  * Due to quantization, we will usually find that many of the input
6058                  * coefficients are zero, especially the AC terms.  We can exploit this
6059                  * by short-circuiting the IDCT calculation for any row in which all
6060                  * the AC terms are zero.  In that case each output is equal to the
6061                  * DC coefficient (with scale factor as needed).
6062                  * With typical images and quantization tables, half or more of the
6063                  * row DCT calculations can be simplified this way.
6064                  */
6065                 if (isZeroInRow(dataUnit, rIndex)) {
6066                     int dcVal = dataUnit[rIndex] * 4;
6067                     for (int i = rIndex; i < rIndex + 8; i++) {
6068                         dataUnit[i] = dcVal;
6069                     }
6070                 } else {
6071                     /**
6072                      * Even part: reverse the even part of the forward DCT.
6073                      * The rotator is sqrt(2)*c(-6).
6074                      */
6075                     int z2 = dataUnit[rIndex + 2];
6076                     int z3 = dataUnit[rIndex + 6];
6077                     int z1 = (z2 + z3) * FIX_0_541196100;
6078                     int tmp2 = z1 + (z3 * (0 - FIX_1_847759065));
6079                     int tmp3 = z1 + (z2 * FIX_0_765366865);
6080                     int tmp0 = (dataUnit[rIndex] + dataUnit[rIndex + 4]) * 8192;
6081                     int tmp1 = (dataUnit[rIndex] - dataUnit[rIndex + 4]) * 8192;
6082                     int tmp10 = tmp0 + tmp3;
6083                     int tmp13 = tmp0 - tmp3;
6084                     int tmp11 = tmp1 + tmp2;
6085                     int tmp12 = tmp1 - tmp2;
6086                     /**
6087                      * Odd part per figure 8; the matrix is unitary and hence its
6088                      * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
6089                      */
6090                     tmp0 = dataUnit[rIndex + 7];
6091                     tmp1 = dataUnit[rIndex + 5];
6092                     tmp2 = dataUnit[rIndex + 3];
6093                     tmp3 = dataUnit[rIndex + 1];
6094                     z1 = tmp0 + tmp3;
6095                     z2 = tmp1 + tmp2;
6096                     z3 = tmp0 + tmp2;
6097                     int z4 = tmp1 + tmp3;
6098                     int z5 = (z3 + z4)* FIX_1_175875602; /* sqrt(2) * c3 */
6099                           
6100                     tmp0 = tmp0 * FIX_0_298631336;              /* sqrt(2) * (-c1+c3+c5-c7) */
6101                     tmp1 = tmp1 * FIX_2_053119869;              /* sqrt(2) * ( c1+c3-c5+c7) */
6102                     tmp2 = tmp2 * FIX_3_072711026;              /* sqrt(2) * ( c1+c3+c5-c7) */
6103                     tmp3 = tmp3 * FIX_1_501321110;              /* sqrt(2) * ( c1+c3-c5-c7) */
6104                     z1 = z1 * (0 - FIX_0_899976223);    /* sqrt(2) * (c7-c3) */
6105                     z2 = z2 * (0 - FIX_2_562915447);    /* sqrt(2) * (-c1-c3) */
6106                     z3 = z3 * (0 - FIX_1_961570560);    /* sqrt(2) * (-c3-c5) */
6107                     z4 = z4 * (0 - FIX_0_390180644);    /* sqrt(2) * (c5-c3) */
6108
6109                     z3 = z3 + z5;
6110                     z4 = z4 + z5;
6111                     tmp0 = tmp0 + z1 + z3;
6112                     tmp1 = tmp1 + z2 + z4;
6113                     tmp2 = tmp2 + z2 + z3;
6114                     tmp3 = tmp3 + z1 + z4;
6115
6116                     int descaleFactor1 = ExtendTest[11];
6117                     int descaleFactor2 = ExtendTest[12];
6118                     dataUnit[rIndex] = (tmp10 + tmp3 + descaleFactor1) / descaleFactor2;
6119                     dataUnit[rIndex + 7] = (tmp10 - tmp3 + descaleFactor1) / descaleFactor2;
6120                     dataUnit[rIndex + 1] = (tmp11 + tmp2 + descaleFactor1) / descaleFactor2;
6121                     dataUnit[rIndex + 6] = (tmp11 - tmp2 + descaleFactor1) / descaleFactor2;
6122                     dataUnit[rIndex + 2] = (tmp12 + tmp1 + descaleFactor1) / descaleFactor2;
6123                     dataUnit[rIndex + 5] = (tmp12 - tmp1 + descaleFactor1) / descaleFactor2;
6124                     dataUnit[rIndex + 3] = (tmp13 + tmp0 + descaleFactor1) / descaleFactor2;
6125                     dataUnit[rIndex + 4] = (tmp13 - tmp0 + descaleFactor1) / descaleFactor2;
6126                 }
6127             }
6128             /**
6129              * Pass 2: process columns.
6130              * Note that we must descale the results by a factor of 8 == 2**3,
6131              * and also undo the PASS1_BITS scaling.
6132              */
6133             for (int col = 0; col < 8; col++) {
6134                 int c0 = col;
6135                 int c1 = col + 8;
6136                 int c2 = col + 16;
6137                 int c3 = col + 24;
6138                 int c4 = col + 32;
6139                 int c5 = col + 40;
6140                 int c6 = col + 48;
6141                 int c7 = col + 56;
6142                 if (isZeroInColumn(dataUnit, col)) {
6143                     int dcVal = (dataUnit[c0] + 16) / 32;
6144                     dataUnit[c0] = dcVal;
6145                     dataUnit[c1] = dcVal;
6146                     dataUnit[c2] = dcVal;
6147                     dataUnit[c3] = dcVal;
6148                     dataUnit[c4] = dcVal;
6149                     dataUnit[c5] = dcVal;
6150                     dataUnit[c6] = dcVal;
6151                     dataUnit[c7] = dcVal;
6152                 } else {
6153                     /**
6154                      * Even part: reverse the even part of the forward DCT.
6155                      * The rotator is sqrt(2)*c(-6).
6156                      */
6157                     int z2 = dataUnit[c2];
6158                     int z3 = dataUnit[c6];
6159                     int z1 = (z2 + z3) * FIX_0_541196100;
6160                     int tmp2 = z1 + (z3 * (0 - FIX_1_847759065));
6161                     int tmp3 = z1 + (z2 * FIX_0_765366865);
6162                     int tmp0 = (dataUnit[c0] + dataUnit[c4]) * 8192;
6163                     int tmp1 = (dataUnit[c0] - dataUnit[c4]) * 8192;
6164                     int tmp10 = tmp0 + tmp3;
6165                     int tmp13 = tmp0 - tmp3;
6166                     int tmp11 = tmp1 + tmp2;
6167                     int tmp12 = tmp1 - tmp2;
6168                     /**
6169                      * Odd part per figure 8; the matrix is unitary and hence its
6170                      * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
6171                      */
6172                     tmp0 = dataUnit[c7];
6173                     tmp1 = dataUnit[c5];
6174                     tmp2 = dataUnit[c3];
6175                     tmp3 = dataUnit[c1];
6176                     z1 = tmp0 + tmp3;
6177                     z2 = tmp1 + tmp2;
6178                     z3 = tmp0 + tmp2;
6179                     int z4 = tmp1 + tmp3;
6180                     int z5 = (z3 + z4) * FIX_1_175875602;       /* sqrt(2) * c3 */
6181                         
6182                     tmp0 = tmp0 * FIX_0_298631336;              /* sqrt(2) * (-c1+c3+c5-c7) */
6183                     tmp1 = tmp1 * FIX_2_053119869;              /* sqrt(2) * ( c1+c3-c5+c7) */
6184                     tmp2 = tmp2 * FIX_3_072711026;              /* sqrt(2) * ( c1+c3+c5-c7) */
6185                     tmp3 = tmp3 * FIX_1_501321110;              /* sqrt(2) * ( c1+c3-c5-c7) */
6186                     z1 = z1 * (0 - FIX_0_899976223);    /* sqrt(2) * (c7-c3) */
6187                     z2 = z2 * (0 - FIX_2_562915447);    /* sqrt(2) * (-c1-c3) */
6188                     z3 = z3 * (0 - FIX_1_961570560);    /* sqrt(2) * (-c3-c5) */
6189                     z4 = z4 * (0 - FIX_0_390180644);    /* sqrt(2) * (c5-c3) */
6190                         
6191                     z3 = z3 + z5;
6192                     z4 = z4 + z5;
6193                         
6194                     tmp0 = tmp0 + z1 + z3;
6195                     tmp1 = tmp1 + z2 + z4;
6196                     tmp2 = tmp2 + z2 + z3;
6197                     tmp3 = tmp3 + z1 + z4;
6198
6199                     /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
6200                     int descaleFactor1 = ExtendTest[18];
6201                     int descaleFactor2 = ExtendTest[19];
6202                     dataUnit[c0] = (tmp10 + tmp3 + descaleFactor1) / descaleFactor2;
6203                     dataUnit[c7] = (tmp10 - tmp3 + descaleFactor1) / descaleFactor2;
6204                     dataUnit[c1] = (tmp11 + tmp2 + descaleFactor1) / descaleFactor2;
6205                     dataUnit[c6] = (tmp11 - tmp2 + descaleFactor1) / descaleFactor2;
6206                     dataUnit[c2] = (tmp12 + tmp1 + descaleFactor1) / descaleFactor2;
6207                     dataUnit[c5] = (tmp12 - tmp1 + descaleFactor1) / descaleFactor2;
6208                     dataUnit[c3] = (tmp13 + tmp0 + descaleFactor1) / descaleFactor2;
6209                     dataUnit[c4] = (tmp13 - tmp0 + descaleFactor1) / descaleFactor2;
6210                 }
6211             }
6212         }
6213         boolean isFileFormat(LEDataInputStream stream) {
6214             try {
6215                 JPEGStartOfImage soi = new JPEGStartOfImage(stream);
6216                 stream.unread(soi.reference);
6217                 return soi.verify();  // we no longer check for appN
6218             } catch (Exception e) {
6219                 return false;
6220             }
6221         }
6222         boolean isZeroInColumn(int[] dataUnit, int col) {
6223             return (dataUnit[col + 8] + dataUnit[col + 16] +
6224                     dataUnit[col + 24] + dataUnit[col + 32] +
6225                     dataUnit[col + 40] + dataUnit[col + 48] +
6226                     dataUnit[col + 56]) == 0;
6227         }
6228         boolean isZeroInRow(int[] dataUnit, int rIndex) {
6229             return (dataUnit[rIndex + 1] + dataUnit[rIndex + 2] +
6230                     dataUnit[rIndex + 3] + dataUnit[rIndex + 4] +
6231                     dataUnit[rIndex + 5] + dataUnit[rIndex + 6] +
6232                     dataUnit[rIndex + 7]) == 0;
6233         }
6234         ImageData[] loadFromByteStream() {
6235             JPEGStartOfImage soi = new JPEGStartOfImage(inputStream);
6236             if (!soi.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
6237             restartInterval = 0;
6238
6239             /* Process the tables preceding the frame header. */
6240             processTables();
6241         
6242             /* Start of Frame. */
6243             frameHeader = new JPEGFrameHeader(inputStream);
6244             if (!frameHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
6245             imageWidth = frameHeader.getSamplesPerLine();
6246             imageHeight = frameHeader.getNumberOfLines();
6247             maxH = frameHeader.getMaxHFactor();
6248             maxV = frameHeader.getMaxVFactor();
6249             int mcuWidth = maxH * DCTSIZE;
6250             int mcuHeight = maxV * DCTSIZE;
6251             interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth;
6252             interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight;
6253             progressive = frameHeader.isProgressive();
6254             samplePrecision = frameHeader.getSamplePrecision();
6255             nComponents = frameHeader.getNumberOfImageComponents();
6256             frameComponents = frameHeader.componentParameters;
6257             componentIds = frameHeader.componentIdentifiers;
6258             imageComponents = new byte[nComponents][];
6259             if (progressive) {
6260                 // Progressive jpeg: need to keep all of the data units.
6261                 dataUnits = new int[nComponents][][];
6262             } else {
6263                 // Sequential jpeg: only need one data unit.
6264                 dataUnit = new int[8 * 8];
6265             }
6266             for (int i = 0; i < nComponents; i++) {
6267                 int[] frameComponent = frameComponents[componentIds[i]];
6268                 int bufferSize = frameComponent[CW] * frameComponent[CH];
6269                 imageComponents[i] = new byte[bufferSize];
6270                 if (progressive) {
6271                     dataUnits[i] = new int[bufferSize][];
6272                 }
6273             }
6274
6275             /* Process the tables preceding the scan header. */
6276             processTables();
6277         
6278             /* Start of Scan. */
6279             scanHeader = new JPEGScanHeader(inputStream);
6280             if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
6281         
6282             /* Process scan(s) and further tables until EOI. */
6283             int progressiveScanCount = 0;
6284             boolean done = false;
6285             while(!done) {
6286                 resetInputBuffer();
6287                 precedingDCs = new int[4];
6288                 decodeScan();
6289                 if (progressive && loader.hasListeners()) {
6290                     ImageData imageData = createImageData();
6291                     loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, false));
6292                     progressiveScanCount++;
6293                 }
6294
6295                 /* Unread any buffered data before looking for tables again. */
6296                 int delta = 512 - bufferCurrentPosition - 1;
6297                 if (delta > 0) {
6298                     byte[] unreadBuffer = new byte[delta];
6299                     System.arraycopy(dataBuffer, bufferCurrentPosition + 1, unreadBuffer, 0, delta);
6300                     try {
6301                         inputStream.unread(unreadBuffer);
6302                     } catch (IOException e) {
6303                         SWT.error(SWT.ERROR_IO, e);
6304                     }
6305                 }
6306                 
6307                 /* Process the tables preceding the next scan header. */
6308                 JPEGSegment jpegSegment = processTables();
6309                 if (jpegSegment == null || jpegSegment.getSegmentMarker() == EOI) {
6310                     done = true;
6311                 } else {
6312                     scanHeader = new JPEGScanHeader(inputStream);
6313                     if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
6314                 }
6315             }
6316         
6317             if (progressive) {
6318                 for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) {
6319                     for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) {
6320                         for (int iComp = 0; iComp < nComponents; iComp++) {
6321                             int[] frameComponent = frameComponents[componentIds[iComp]];
6322                             int hi = frameComponent[HI];
6323                             int vi = frameComponent[VI];
6324                             int compWidth = frameComponent[CW];
6325                             for (int ivi = 0; ivi < vi; ivi++) {
6326                                 for (int ihi = 0; ihi < hi; ihi++) {
6327                                     int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi;
6328                                     dataUnit = dataUnits[iComp][index];
6329                                     dequantize(dataUnit, iComp);
6330                                     inverseDCT(dataUnit);
6331                                     storeData(dataUnit, iComp, xmcu, ymcu, hi, ihi, vi, ivi);
6332                                 }
6333                             }
6334                         }
6335                     }
6336                 }
6337             }
6338             ImageData imageData = createImageData();
6339             if (progressive && loader.hasListeners()) {
6340                 loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, true));
6341             }
6342             return new ImageData[] {imageData};
6343         }
6344         ImageData createImageData() {
6345             return ImageData.internal_new(
6346                                           imageWidth,
6347                                           imageHeight, 
6348                                           nComponents * samplePrecision,
6349                                           setUpPalette(),
6350                                           nComponents == 1 ? 4 : 1,
6351                                           decodeImageComponents(),
6352                                           0,
6353                                           null,
6354                                           null,
6355                                           -1,
6356                                           -1,
6357                                           SWT.IMAGE_JPEG,
6358                                           0,
6359                                           0,
6360                                           0,
6361                                           0);
6362         }
6363         int nextBit() {
6364             if (currentBitCount != 0) {
6365                 currentBitCount--;
6366                 currentByte *= 2;
6367                 if (currentByte > 255) {
6368                     currentByte -= 256;
6369                     return 1;
6370                 } else {
6371                     return 0;
6372                 }
6373             }
6374             bufferCurrentPosition++;
6375             if (bufferCurrentPosition >= 512) {
6376                 resetInputBuffer();
6377                 bufferCurrentPosition = 0;
6378             }
6379             currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
6380             currentBitCount = 8;
6381             byte nextByte;
6382             if (bufferCurrentPosition == 511) {
6383                 resetInputBuffer();
6384                 currentBitCount = 8;
6385                 nextByte = dataBuffer[0];
6386             } else {
6387                 nextByte = dataBuffer[bufferCurrentPosition + 1];
6388             }
6389             if (currentByte == 0xFF) {
6390                 if (nextByte == 0) {
6391                     bufferCurrentPosition ++;
6392                     currentBitCount--;
6393                     currentByte *= 2;
6394                     if (currentByte > 255) {
6395                         currentByte -= 256;
6396                         return 1;
6397                     } else {
6398                         return 0;
6399                     }
6400                 } else {
6401                     if ((nextByte & 0xFF) + 0xFF00 == DNL) {
6402                         getDNL();
6403                         return 0;
6404                     } else {
6405                         SWT.error(SWT.ERROR_INVALID_IMAGE);
6406                         return 0;
6407                     }
6408                 }
6409             } else {
6410                 currentBitCount--;
6411                 currentByte *= 2;
6412                 if (currentByte > 255) {
6413                     currentByte -= 256;
6414                     return 1;
6415                 } else {
6416                     return 0;
6417                 }
6418             }
6419         }
6420         void processRestartInterval() {
6421             do {
6422                 bufferCurrentPosition++;
6423                 if (bufferCurrentPosition > 511) {
6424                     resetInputBuffer();
6425                     bufferCurrentPosition = 0;
6426                 }
6427                 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
6428             } while (currentByte != 0xFF);
6429             while (currentByte == 0xFF) {
6430                 bufferCurrentPosition++;
6431                 if (bufferCurrentPosition > 511) {
6432                     resetInputBuffer();
6433                     bufferCurrentPosition = 0;
6434                 }
6435                 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
6436             }
6437             if (currentByte != ((RST0 + nextRestartNumber) % 256)) {
6438                 SWT.error(SWT.ERROR_INVALID_IMAGE);
6439             }
6440             bufferCurrentPosition++;
6441             if (bufferCurrentPosition > 511) {
6442                 resetInputBuffer();
6443                 bufferCurrentPosition = 0;
6444             }
6445             currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
6446             currentBitCount = 8;
6447             restartsToGo = restartInterval;
6448             nextRestartNumber = (nextRestartNumber + 1) % 8;
6449             precedingDCs = new int[4];
6450             eobrun = 0;
6451         }
6452         /* Process all markers until a frame header, scan header, or EOI is found. */
6453         JPEGSegment processTables() {
6454             while (true) {
6455                 JPEGSegment jpegSegment = seekUnspecifiedMarker(inputStream);
6456                 if (jpegSegment == null) return null;
6457                 JPEGFrameHeader sof = new JPEGFrameHeader(jpegSegment.reference);
6458                 if (sof.verify()) {
6459                     return jpegSegment;
6460                 }
6461                 int marker = jpegSegment.getSegmentMarker();
6462                 switch (marker) {
6463                     case SOI: // there should only be one SOI per file
6464                         SWT.error(SWT.ERROR_INVALID_IMAGE);
6465                     case EOI:
6466                     case SOS:
6467                         return jpegSegment;
6468                     case DQT:
6469                         getDQT();
6470                         break;
6471                     case DHT:
6472                         getDHT();
6473                         break;
6474                     case DAC:
6475                         getDAC();
6476                         break;
6477                     case DRI:
6478                         getDRI();
6479                         break;
6480                     case APP0:
6481                         getAPP0();
6482                         break;
6483                     case COM:
6484                         getCOM();
6485                         break;
6486                     default:
6487                         skipSegmentFrom(inputStream);
6488                         
6489                 }
6490             }
6491         }
6492         void quantizeData(int[] dataUnit, int iComp) {
6493             int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]];
6494             for (int i = 0; i < dataUnit.length; i++) {
6495                 int zzIndex = ZigZag8x8[i];
6496                 int data = dataUnit[zzIndex];
6497                 int absData = data < 0 ? 0 - data : data;
6498                 int qValue = qTable[i];
6499                 int q2 = qValue / 2;
6500                 absData += q2;
6501                 if (absData < qValue) {
6502                     dataUnit[zzIndex] = 0;
6503                 } else {
6504                     absData /= qValue;
6505                     if (data >= 0) {
6506                         dataUnit[zzIndex] = absData;
6507                     } else {
6508                         dataUnit[zzIndex] = 0 - absData;
6509                     }
6510                 }
6511             }
6512         }
6513         int receive(int nBits) {
6514             int v = 0;
6515             for (int i = 0; i < nBits; i++) {
6516                 v = v * 2 + nextBit();
6517             }
6518             return v;
6519         }
6520         void resetInputBuffer() {
6521             if (dataBuffer == null) {
6522                 dataBuffer = new byte[512];
6523             }
6524             try {
6525                 inputStream.read(dataBuffer);
6526             } catch (IOException e) {
6527                 SWT.error(SWT.ERROR_IO, e);
6528             }
6529             currentBitCount = 0;
6530             bufferCurrentPosition = -1;
6531         }
6532         void resetOutputBuffer() {
6533             if (dataBuffer == null) {
6534                 dataBuffer = new byte[512];
6535             } else {
6536                 try {
6537                     outputStream.write(dataBuffer, 0, bufferCurrentPosition);
6538                 } catch (IOException e) {
6539                     SWT.error(SWT.ERROR_IO, e);
6540                 }
6541             }
6542             bufferCurrentPosition = 0;
6543         }
6544         static JPEGSegment seekUnspecifiedMarker(LEDataInputStream byteStream) {
6545             byte[] byteArray = new byte[2];
6546             try {
6547                 while (true) {
6548                     if (byteStream.read(byteArray, 0, 1) != 1) return null;
6549                     if (byteArray[0] == (byte) 0xFF) {
6550                         if (byteStream.read(byteArray, 1, 1) != 1) return null;
6551                         if (byteArray[1] != (byte) 0xFF && byteArray[1] != 0) {
6552                             byteStream.unread(byteArray);
6553                             return new JPEGSegment(byteArray);
6554                         }
6555                     }
6556                 }
6557             } catch (IOException e) {
6558                 SWT.error(SWT.ERROR_IO, e);
6559             }
6560             return null;
6561         }
6562         PaletteData setUpPalette() {
6563             if (nComponents == 1) {
6564                 RGB[] entries = new RGB[256];
6565                 for (int i = 0; i < 256; i++) {
6566                     entries[i] = new RGB(i, i, i);
6567                 }
6568                 return new PaletteData(entries);
6569             }
6570             return new PaletteData(0xFF, 0xFF00, 0xFF0000);
6571         }
6572         static void skipSegmentFrom(LEDataInputStream byteStream) {
6573             try {
6574                 byte[] byteArray = new byte[4];
6575                 JPEGSegment jpegSegment = new JPEGSegment(byteArray);
6576         
6577                 if (byteStream.read(byteArray) != byteArray.length) {
6578                     SWT.error(SWT.ERROR_INVALID_IMAGE);
6579                 }
6580                 if (!(byteArray[0] == -1 && byteArray[1] != 0 && byteArray[1] != -1)) {
6581                     SWT.error(SWT.ERROR_INVALID_IMAGE);
6582                 }
6583                 int delta = jpegSegment.getSegmentLength() - 2;
6584                 byteStream.skip(delta);
6585             } catch (Exception e) {
6586                 SWT.error(SWT.ERROR_IO, e);
6587             }
6588         }
6589         void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, int vi, int ivi) {
6590             byte[] compImage = imageComponents[iComp];
6591             int[] frameComponent = frameComponents[componentIds[iComp]];
6592             int compWidth = frameComponent[CW];
6593             int destIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE);
6594             int srcIndex = 0;
6595             for (int i = 0; i < DCTSIZE; i++) {
6596                 for (int col = 0; col < DCTSIZE; col++) {
6597                     int x = dataUnit[srcIndex] + 128;
6598                     if (x < 0) {
6599                         x = 0;
6600                     } else {
6601                         if (x > 255) x = 255;
6602                     }
6603                     compImage[destIndex + col] = (byte)x;
6604                     srcIndex++;
6605                 }
6606                 destIndex += compWidth;
6607             }
6608         }
6609         void unloadIntoByteStream(ImageData image) {
6610             if (!new JPEGStartOfImage().writeToStream(outputStream)) {
6611                 SWT.error(SWT.ERROR_IO);
6612             }
6613             JPEGAppn appn = new JPEGAppn(new byte[] {(byte)0xFF, (byte)0xE0, 0, 0x10, 0x4A, 0x46, 0x49, 0x46, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0});
6614             if (!appn.writeToStream(outputStream)) {
6615                 SWT.error(SWT.ERROR_IO);
6616             }
6617             quantizationTables = new int[4][];
6618             JPEGQuantizationTable chromDQT = JPEGQuantizationTable.defaultChrominanceTable();
6619             chromDQT.scaleBy(encoderQFactor);
6620             int[] jpegDQTKeys = chromDQT.getQuantizationTablesKeys();
6621             int[][] jpegDQTValues = chromDQT.getQuantizationTablesValues();
6622             for (int i = 0; i < jpegDQTKeys.length; i++) {
6623                 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i];
6624             }
6625             JPEGQuantizationTable lumDQT = JPEGQuantizationTable.defaultLuminanceTable();
6626             lumDQT.scaleBy(encoderQFactor);
6627             jpegDQTKeys = lumDQT.getQuantizationTablesKeys();
6628             jpegDQTValues = lumDQT.getQuantizationTablesValues();
6629             for (int i = 0; i < jpegDQTKeys.length; i++) {
6630                 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i];
6631             }
6632             if (!lumDQT.writeToStream(outputStream)) {
6633                 SWT.error(SWT.ERROR_IO);
6634             }
6635             if (!chromDQT.writeToStream(outputStream)) {
6636                 SWT.error(SWT.ERROR_IO);
6637             }
6638             int frameLength, scanLength, precision;
6639             int[][] frameParams, scanParams;
6640             if (image.depth == 1) {
6641                 frameLength = 11;
6642                 frameParams = new int[1][];
6643                 frameParams[0] = new int[] {1, 1, 1, 0, 0};
6644                 scanParams = new int[1][];
6645                 scanParams[0] = new int[] {0, 0};
6646                 scanLength = 8;
6647                 nComponents = 1;
6648                 precision = 1;
6649             } else {
6650                 frameLength = 17;
6651                 frameParams = new int[3][];
6652                 frameParams[0] = new int[] {0, 2, 2, 0, 0};
6653                 frameParams[1] = new int[] {1, 1, 1, 0, 0};
6654                 frameParams[2] = new int[] {1, 1, 1, 0, 0};
6655                 scanParams = new int[3][];
6656                 scanParams[0] = new int[] {0, 0};
6657                 scanParams[1] = new int[] {1, 1};
6658                 scanParams[2] = new int[] {1, 1};
6659                 scanLength = 12;
6660                 nComponents = 3;
6661                 precision = 8;
6662             }
6663             imageWidth = image.width;
6664             imageHeight = image.height;
6665             frameHeader = new JPEGFrameHeader(new byte[19]);
6666             frameHeader.setSegmentMarker(SOF0);
6667             frameHeader.setSegmentLength(frameLength);
6668             frameHeader.setSamplePrecision(precision);
6669             frameHeader.setSamplesPerLine(imageWidth);
6670             frameHeader.setNumberOfLines(imageHeight);
6671             frameHeader.setNumberOfImageComponents(nComponents);
6672             frameHeader.componentParameters = frameParams;
6673             frameHeader.componentIdentifiers = new int[] {0, 1, 2};
6674             frameHeader.initializeContents();
6675             if (!frameHeader.writeToStream(outputStream)) {
6676                 SWT.error(SWT.ERROR_IO);
6677             }
6678             frameComponents = frameParams;
6679             componentIds = frameHeader.componentIdentifiers;
6680             maxH = frameHeader.getMaxHFactor();
6681             maxV = frameHeader.getMaxVFactor();
6682             int mcuWidth = maxH * DCTSIZE;
6683             int mcuHeight = maxV * DCTSIZE;
6684             interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth;
6685             interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight;
6686             acHuffmanTables = new JPEGHuffmanTable[4];
6687             dcHuffmanTables = new JPEGHuffmanTable[4];
6688             JPEGHuffmanTable[] dhtTables = new JPEGHuffmanTable[] {
6689                 JPEGHuffmanTable.getDefaultDCLuminanceTable(),
6690                 JPEGHuffmanTable.getDefaultDCChrominanceTable(),
6691                 JPEGHuffmanTable.getDefaultACLuminanceTable(),
6692                 JPEGHuffmanTable.getDefaultACChrominanceTable()
6693             };
6694             for (int i = 0; i < dhtTables.length; i++) {
6695                 JPEGHuffmanTable dhtTable = dhtTables[i];
6696                 if (!dhtTable.writeToStream(outputStream)) {
6697                     SWT.error(SWT.ERROR_IO);
6698                 }
6699                 JPEGHuffmanTable[] allTables = dhtTable.getAllTables();
6700                 for (int j = 0; j < allTables.length; j++) {
6701                     JPEGHuffmanTable huffmanTable = allTables[j];
6702                     if (huffmanTable.getTableClass() == 0) {
6703                         dcHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable;
6704                     } else {
6705                         acHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable;
6706                     }
6707                 }
6708             }
6709             precedingDCs = new int[4];
6710             scanHeader = new JPEGScanHeader(new byte[14]);
6711             scanHeader.setSegmentMarker(SOS);
6712             scanHeader.setSegmentLength(scanLength);
6713             scanHeader.setNumberOfImageComponents(nComponents);
6714             scanHeader.setStartOfSpectralSelection(0);
6715             scanHeader.setEndOfSpectralSelection(63);
6716             scanHeader.componentParameters = scanParams;
6717             scanHeader.initializeContents();
6718             if (!scanHeader.writeToStream(outputStream)) {
6719                 SWT.error(SWT.ERROR_IO);
6720             }
6721             convertImageToYCbCr(image);
6722             resetOutputBuffer();
6723             currentByte = 0;
6724             currentBitCount = 0;
6725             encodeScan();
6726             if (!new JPEGEndOfImage().writeToStream(outputStream)) {
6727                 SWT.error(SWT.ERROR_IO);
6728             }
6729         }
6730     }
6731     /*******************************************************************************
6732      * Copyright (c) 2000, 2003 IBM Corporation and others.
6733      * All rights reserved. This program and the accompanying materials 
6734      * are made available under the terms of the Common Public License v1.0
6735      * which accompanies this distribution, and is available at
6736      * http://www.eclipse.org/legal/cpl-v10.html
6737      * 
6738      * Contributors:
6739      *     IBM Corporation - initial API and implementation
6740      *******************************************************************************/
6741
6742  
6743
6744     abstract static class JPEGFixedSizeSegment extends JPEGSegment {
6745
6746         public JPEGFixedSizeSegment() {
6747             reference = new byte[fixedSize()];
6748             setSegmentMarker(signature());
6749         }
6750         
6751         public JPEGFixedSizeSegment(byte[] reference) {
6752             super(reference);
6753         }
6754         
6755         public JPEGFixedSizeSegment(LEDataInputStream byteStream) {
6756             reference = new byte[fixedSize()];
6757             try {
6758                 byteStream.read(reference);
6759             } catch (Exception e) { 
6760                 SWT.error(SWT.ERROR_IO, e);
6761             }
6762         }
6763         
6764         abstract public int fixedSize();
6765
6766         public int getSegmentLength() {
6767             return fixedSize() - 2;
6768         }
6769         
6770         public void setSegmentLength(int length) {
6771         }
6772     }
6773     /*******************************************************************************
6774      * Copyright (c) 2000, 2004 IBM Corporation and others.
6775      * All rights reserved. This program and the accompanying materials
6776      * are made available under the terms of the Common Public License v1.0
6777      * which accompanies this distribution, and is available at
6778      * http://www.eclipse.org/legal/cpl-v10.html
6779      * 
6780      * Contributors:
6781      *     IBM Corporation - initial API and implementation
6782      *******************************************************************************/
6783
6784
6785
6786     final static class JPEGFrameHeader extends JPEGVariableSizeSegment {
6787         int maxVFactor;
6788         int maxHFactor;
6789         public int[] componentIdentifiers;
6790         public int[][] componentParameters;
6791
6792         public JPEGFrameHeader(byte[] reference) {
6793             super(reference);
6794         }
6795         
6796         public JPEGFrameHeader(LEDataInputStream byteStream) {
6797             super(byteStream);
6798             initializeComponentParameters();
6799         }
6800         
6801         public int getSamplePrecision() {
6802             return reference[4] & 0xFF;
6803         }
6804         
6805         public int getNumberOfLines() {
6806             return (reference[5] & 0xFF) << 8 | (reference[6] & 0xFF);
6807         }
6808         
6809         public int getSamplesPerLine() {
6810             return (reference[7] & 0xFF) << 8 | (reference[8] & 0xFF);
6811         }
6812         
6813         public int getNumberOfImageComponents() {
6814             return reference[9] & 0xFF;
6815         }
6816         
6817         public void setSamplePrecision(int precision) {
6818             reference[4] = (byte)(precision & 0xFF);
6819         }
6820         
6821         public void setNumberOfLines(int anInteger) {
6822             reference[5] = (byte)((anInteger & 0xFF00) >> 8);
6823             reference[6] = (byte)(anInteger & 0xFF);
6824         }
6825         
6826         public void setSamplesPerLine(int samples) {
6827             reference[7] = (byte)((samples & 0xFF00) >> 8);
6828             reference[8] = (byte)(samples & 0xFF);
6829         }
6830         
6831         public void setNumberOfImageComponents(int anInteger) {
6832             reference[9] = (byte)(anInteger & 0xFF);
6833         }
6834         
6835         public int getMaxHFactor() {
6836             return maxHFactor;
6837         }
6838         
6839         public int getMaxVFactor() {
6840             return maxVFactor;
6841         }
6842         
6843         public void setMaxHFactor(int anInteger) {
6844             maxHFactor = anInteger;
6845         }
6846         
6847         public void setMaxVFactor(int anInteger) {
6848             maxVFactor = anInteger;
6849         }
6850         
6851         /* Used when decoding. */
6852         void initializeComponentParameters() {
6853             int nf = getNumberOfImageComponents();
6854             componentIdentifiers = new int[nf];
6855             int[][] compSpecParams = new int[0][];
6856             int hmax = 1;
6857             int vmax = 1;
6858             for (int i = 0; i < nf; i++) {
6859                 int ofs = i * 3 + 10;
6860                 int ci = reference[ofs] & 0xFF;
6861                 componentIdentifiers[i] = ci;
6862                 int hi = (reference[ofs + 1] & 0xFF) / 16;
6863                 int vi = (reference[ofs + 1] & 0xFF) % 16;
6864                 int tqi = reference[ofs + 2] & 0xFF;
6865                 if (hi > hmax) {
6866                     hmax = hi;
6867                 }
6868                 if (vi > vmax) {
6869                     vmax = vi;
6870                 }
6871                 int[] compParam = new int[5];
6872                 compParam[0] = tqi;
6873                 compParam[1] = hi;
6874                 compParam[2] = vi;
6875                 if (compSpecParams.length <= ci) {
6876                     int[][] newParams = new int[ci + 1][];
6877                     System.arraycopy(compSpecParams, 0, newParams, 0, compSpecParams.length);
6878                     compSpecParams = newParams;
6879                 }
6880                 compSpecParams[ci] = compParam;
6881             }
6882             int x = getSamplesPerLine();
6883             int y = getNumberOfLines();
6884             int[] multiples = new int[] { 8, 16, 24, 32 };
6885             for (int i = 0; i < nf; i++) {
6886                 int[] compParam = compSpecParams[componentIdentifiers[i]];
6887                 int hi = compParam[1];
6888                 int vi = compParam[2];
6889                 int compWidth = (x * hi + hmax - 1) / hmax;
6890                 int compHeight = (y * vi + vmax - 1) / vmax;
6891                 int dsWidth = roundUpToMultiple(compWidth, multiples[hi - 1]);
6892                 int dsHeight = roundUpToMultiple(compHeight, multiples[vi - 1]);
6893                 compParam[3] = dsWidth;
6894                 compParam[4] = dsHeight;
6895             }
6896             setMaxHFactor(hmax);
6897             setMaxVFactor(vmax);
6898             componentParameters = compSpecParams;
6899         }
6900         
6901         /* Used when encoding. */
6902         public void initializeContents() {
6903             int nf = getNumberOfImageComponents();
6904             if (nf == 0 || nf != componentParameters.length) {
6905                 SWT.error(SWT.ERROR_INVALID_IMAGE);
6906             }
6907             int hmax = 0;
6908             int vmax = 0;
6909             int[][] compSpecParams = componentParameters;
6910             for (int i = 0; i < nf; i++) {
6911                 int ofs = i * 3 + 10;
6912                 int[] compParam = compSpecParams[componentIdentifiers[i]];
6913                 int hi = compParam[1];
6914                 int vi = compParam[2];
6915                 if (hi * vi > 4) {
6916                     SWT.error(SWT.ERROR_INVALID_IMAGE);
6917                 }
6918                 reference[ofs] = (byte)(i + 1);
6919                 reference[ofs + 1] = (byte)(hi * 16 + vi);
6920                 reference[ofs + 2] = (byte)(compParam[0]);
6921                 if (hi > hmax) hmax = hi;
6922                 if (vi > vmax) vmax = vi;
6923             }
6924             int x = getSamplesPerLine();
6925             int y = getNumberOfLines();
6926             int[] multiples = new int[] {8, 16, 24, 32};
6927             for (int i = 0; i < nf; i++) {
6928                 int[] compParam = compSpecParams[componentIdentifiers[i]];
6929                 int hi = compParam[1];
6930                 int vi = compParam[2];
6931                 int compWidth = (x * hi + hmax - 1) / hmax;
6932                 int compHeight = (y * vi + vmax - 1) / vmax;
6933                 int dsWidth = roundUpToMultiple(compWidth, multiples[hi - 1]);
6934                 int dsHeight = roundUpToMultiple(compHeight, multiples[vi - 1]);
6935                 compParam[3] = dsWidth;
6936                 compParam[4] = dsHeight;
6937             }
6938             setMaxHFactor(hmax);
6939             setMaxVFactor(vmax);
6940         }
6941         
6942         int roundUpToMultiple(int anInteger, int mInteger) {
6943             int a = anInteger + mInteger - 1;
6944             return a - (a % mInteger);
6945         }
6946         
6947         /*
6948          * Verify the information contained in the receiver is correct.
6949          * Answer true if the header contains a valid marker. Otherwise,
6950          * answer false. Valid Start Of Frame markers are:
6951          *      SOF_0  - Baseline DCT, Huffman coding
6952          *      SOF_1  - Extended sequential DCT, Huffman coding
6953          *      SOF_2  - Progressive DCT, Huffman coding
6954          *      SOF_3  - Lossless (sequential), Huffman coding
6955          *      SOF_5  - Differential sequential, Huffman coding
6956          *      SOF_6  - Differential progressive, Huffman coding
6957          *      SOF_7  - Differential lossless, Huffman coding
6958          *      SOF_9  - Extended sequential DCT, arithmetic coding
6959          *      SOF_10 - Progressive DCT, arithmetic coding
6960          *      SOF_11 - Lossless (sequential), arithmetic coding
6961          *      SOF_13 - Differential sequential, arithmetic coding
6962          *      SOF_14 - Differential progressive, arithmetic coding
6963          *      SOF_15 - Differential lossless, arithmetic coding
6964          */
6965         public boolean verify() {
6966             int marker = getSegmentMarker();
6967             return (marker >= JPEGFileFormat.SOF0 && marker <= JPEGFileFormat.SOF3) ||
6968                 (marker >= JPEGFileFormat.SOF5 && marker <= JPEGFileFormat.SOF7) ||
6969                 (marker >= JPEGFileFormat.SOF9 && marker <= JPEGFileFormat.SOF11) ||
6970                 (marker >= JPEGFileFormat.SOF13 && marker <= JPEGFileFormat.SOF15);
6971         }
6972
6973         public boolean isProgressive() {
6974             int marker = getSegmentMarker();
6975             return marker == JPEGFileFormat.SOF2
6976                 || marker == JPEGFileFormat.SOF6
6977                 || marker == JPEGFileFormat.SOF10
6978                 || marker == JPEGFileFormat.SOF14;
6979         }
6980         
6981         public boolean isArithmeticCoding() {
6982             return getSegmentMarker() >= JPEGFileFormat.SOF9;
6983         }
6984     }
6985     /*******************************************************************************
6986      * Copyright (c) 2000, 2003 IBM Corporation and others.
6987      * All rights reserved. This program and the accompanying materials 
6988      * are made available under the terms of the Common Public License v1.0
6989      * which accompanies this distribution, and is available at
6990      * http://www.eclipse.org/legal/cpl-v10.html
6991      * 
6992      * Contributors:
6993      *     IBM Corporation - initial API and implementation
6994      *******************************************************************************/
6995
6996
6997     /**
6998      * JPEGHuffmanTable static class actually represents two types of object:
6999      * 1) A DHT (Define Huffman Tables) segment, which may represent
7000      *  as many as 4 Huffman tables. In this case, the tables are
7001      *  stored in the allTables array.
7002      * 2) A single Huffman table. In this case, the allTables array
7003      *  will be null.
7004      * The 'reference' field is stored in both types of object, but
7005      * 'initialize' is only called if the object represents a DHT.
7006      */
7007     final static class JPEGHuffmanTable extends JPEGVariableSizeSegment {
7008         JPEGHuffmanTable[] allTables;
7009         int tableClass;
7010         int tableIdentifier;
7011         int[] dhCodes;
7012         int[] dhCodeLengths;
7013         int[] dhMaxCodes;
7014         int[] dhMinCodes;
7015         int[] dhValPtrs;
7016         int[] dhValues;
7017         int[] ehCodes;
7018         byte[] ehCodeLengths;
7019         static byte[] DCLuminanceTable = {
7020             (byte)255, (byte)196, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
7021             0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
7022         };
7023         static byte[] DCChrominanceTable = {
7024             (byte)255, (byte)196, 0, 31, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
7025             0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
7026         };
7027         static byte[] ACLuminanceTable = {
7028             (byte)255, (byte)196, 0, (byte)181, 16, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, 
7029             1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 
7030             50, (byte)129, (byte)145, (byte)161, 8, 35, 66, (byte)177, (byte)193, 21, 82, (byte)209, (byte)240, 36, 51, 98, 
7031             114, (byte)130, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 
7032             54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 
7033             88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 
7034             119, 120, 121, 122, (byte)131, (byte)132, (byte)133, (byte)134, (byte)135, (byte)136, (byte)137, (byte)138, (byte)146, (byte)147, (byte)148, 
7035             (byte)149, (byte)150, (byte)151, (byte)152, (byte)153, (byte)154, (byte)162, (byte)163, (byte)164, (byte)165, (byte)166, (byte)167, (byte)168, (byte)169, (byte)170, 
7036             (byte)178, (byte)179, (byte)180, (byte)181, (byte)182, (byte)183, (byte)184, (byte)185, (byte)186, (byte)194, (byte)195, (byte)196, (byte)197, (byte)198, (byte)199, 
7037             (byte)200, (byte)201, (byte)202, (byte)210, (byte)211, (byte)212, (byte)213, (byte)214, (byte)215, (byte)216, (byte)217, (byte)218, (byte)225, (byte)226, (byte)227, 
7038             (byte)228, (byte)229, (byte)230, (byte)231, (byte)232, (byte)233, (byte)234, (byte)241, (byte)242, (byte)243, (byte)244, (byte)245, (byte)246, (byte)247, (byte)248, 
7039             (byte)249, (byte)250
7040         };
7041         static byte[] ACChrominanceTable = {
7042             (byte)255, (byte)196, 0, (byte)181, 17, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 
7043             1, 2, 119, 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 97, 113, 19, 34, 
7044             50, (byte)129, 8, 20, 66, (byte)145, (byte)161, (byte)177, (byte)193, 9, 35, 
7045             51, 82, (byte)240, 21, 98, 114, (byte)209, 10, 22, 36, 52, (byte)225, 37, 
7046             (byte)241, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 57, 58, 67, 
7047             68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 
7048             103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, (byte)130, 
7049             (byte)131, (byte)132, (byte)133, (byte)134, (byte)135, (byte)136, (byte)137, 
7050             (byte)138, (byte)146, (byte)147, (byte)148, (byte)149, (byte)150, (byte)151, 
7051             (byte)152, (byte)153, (byte)154, (byte)162, (byte)163, (byte)164, (byte)165, 
7052             (byte)166, (byte)167, (byte)168, (byte)169, (byte)170, (byte)178, (byte)179, 
7053             (byte)180, (byte)181, (byte)182, (byte)183, (byte)184, (byte)185, (byte)186, 
7054             (byte)194, (byte)195, (byte)196, (byte)197, (byte)198, (byte)199, (byte)200, 
7055             (byte)201, (byte)202, (byte)210, (byte)211, (byte)212, (byte)213, (byte)214, 
7056             (byte)215, (byte)216, (byte)217, (byte)218, (byte)226, (byte)227, (byte)228, 
7057             (byte)229, (byte)230, (byte)231, (byte)232, (byte)233, (byte)234, (byte)242, 
7058             (byte)243, (byte)244, (byte)245, (byte)246, (byte)247, (byte)248, (byte)249, 
7059             (byte)250
7060         };
7061         
7062         public JPEGHuffmanTable(byte[] reference) {
7063             super(reference);
7064         }
7065
7066         public JPEGHuffmanTable(LEDataInputStream byteStream) {
7067             super(byteStream);
7068             initialize();
7069         }
7070
7071         public JPEGHuffmanTable[] getAllTables() {
7072             return allTables;
7073         }
7074
7075         public static JPEGHuffmanTable getDefaultACChrominanceTable() {
7076             JPEGHuffmanTable result = new JPEGHuffmanTable(ACChrominanceTable);
7077             result.initialize();
7078             return result;
7079         }
7080
7081         public static JPEGHuffmanTable getDefaultACLuminanceTable() {
7082             JPEGHuffmanTable result = new JPEGHuffmanTable(ACLuminanceTable);
7083             result.initialize();
7084             return result;
7085         }
7086
7087         public static JPEGHuffmanTable getDefaultDCChrominanceTable() {
7088             JPEGHuffmanTable result = new JPEGHuffmanTable(DCChrominanceTable);
7089             result.initialize();
7090             return result;
7091         }
7092
7093         public static JPEGHuffmanTable getDefaultDCLuminanceTable() {
7094             JPEGHuffmanTable result = new JPEGHuffmanTable(DCLuminanceTable);
7095             result.initialize();
7096             return result;
7097         }
7098
7099         public int[] getDhMaxCodes() {
7100             return dhMaxCodes;
7101         }
7102
7103         public int[] getDhMinCodes() {
7104             return dhMinCodes;
7105         }
7106
7107         public int[] getDhValPtrs() {
7108             return dhValPtrs;
7109         }
7110
7111         public int[] getDhValues() {
7112             return dhValues;
7113         }
7114
7115         public int getTableClass() {
7116             return tableClass;
7117         }
7118
7119         public int getTableIdentifier() {
7120             return tableIdentifier;
7121         }
7122
7123         void initialize() {
7124             int totalLength = getSegmentLength() - 2;
7125             int ofs = 4;
7126             int[] bits = new int[16];
7127             JPEGHuffmanTable[] huffTables = new JPEGHuffmanTable[8]; // maximum is 4 AC + 4 DC
7128             int huffTableCount = 0;
7129             while (totalLength > 0) {
7130                 int tc = (reference[ofs] & 0xFF) / 16; // table class: AC (1) or DC (0)
7131                 int tid = (reference[ofs] & 0xFF) % 16; // table id: 0-1 baseline, 0-3 prog/ext
7132                 ofs++;
7133                 
7134                 /* Read the 16 count bytes and add them together to get the table size. */
7135                 int count = 0;
7136                 for (int i = 0; i < bits.length; i++) {
7137                     int bCount = reference[ofs + i] & 0xFF;
7138                     bits[i] = bCount;
7139                     count += bCount;
7140                 }
7141                 ofs += 16;
7142                 totalLength -= 17;
7143                 
7144                 /* Read the table. */
7145                 int[] huffVals = new int[count];
7146                 for (int i = 0; i < count; i++) {
7147                     huffVals[i] = reference[ofs + i] & 0xFF;
7148                 }
7149                 ofs += count;
7150                 totalLength -= count;
7151                 
7152                 /* Calculate the lengths. */
7153                 int[] huffCodeLengths = new int[50]; // start with 50 and increment as needed
7154                 int huffCodeLengthsIndex = 0;
7155                 for (int i = 0; i < 16; i++) {
7156                     for (int j = 0; j < bits[i]; j++) {
7157                         if (huffCodeLengthsIndex >= huffCodeLengths.length) {
7158                             int[] newHuffCodeLengths = new int[huffCodeLengths.length + 50];
7159                             System.arraycopy(huffCodeLengths, 0, newHuffCodeLengths, 0, huffCodeLengths.length);
7160                             huffCodeLengths = newHuffCodeLengths;
7161                         }
7162                         huffCodeLengths[huffCodeLengthsIndex] = i + 1;
7163                         huffCodeLengthsIndex++;
7164                     }
7165                 }
7166                 
7167                 /* Truncate huffCodeLengths to the correct size. */
7168                 if (huffCodeLengthsIndex < huffCodeLengths.length) {
7169                     int[] newHuffCodeLengths = new int[huffCodeLengthsIndex];
7170                     System.arraycopy(huffCodeLengths, 0, newHuffCodeLengths, 0, huffCodeLengthsIndex);
7171                     huffCodeLengths = newHuffCodeLengths;
7172                 }
7173                 
7174                 /* Calculate the Huffman codes. */
7175                 int[] huffCodes = new int[50]; // start with 50 and increment as needed
7176                 int huffCodesIndex = 0;
7177                 int k = 1;
7178                 int code = 0;
7179                 int si = huffCodeLengths[0];
7180                 int p = 0;
7181                 while (p < huffCodeLengthsIndex) {
7182                     while ((p < huffCodeLengthsIndex) && (huffCodeLengths[p] == si)) {
7183                         if (huffCodesIndex >= huffCodes.length) {
7184                             int[] newHuffCodes = new int[huffCodes.length + 50];
7185                             System.arraycopy(huffCodes, 0, newHuffCodes, 0, huffCodes.length);
7186                             huffCodes = newHuffCodes;
7187                         }
7188                         huffCodes[huffCodesIndex] = code;
7189                         huffCodesIndex++;
7190                         code++;
7191                         p++;
7192                     }
7193                     code *= 2;
7194                     si++;
7195                 }
7196                 
7197                 /* Truncate huffCodes to the correct size. */
7198                 if (huffCodesIndex < huffCodes.length) {
7199                     int[] newHuffCodes = new int[huffCodesIndex];
7200                     System.arraycopy(huffCodes, 0, newHuffCodes, 0, huffCodesIndex);
7201                     huffCodes = newHuffCodes;
7202                 }
7203                 
7204                 /* Calculate the maximum and minimum codes */
7205                 k = 0;
7206                 int[] maxCodes = new int[16];
7207                 int[] minCodes = new int[16];
7208                 int[] valPtrs = new int[16];
7209                 for (int i = 0; i < 16; i++) {
7210                     int bSize = bits[i];
7211                     if (bSize == 0) {
7212                         maxCodes[i] = -1;
7213                     } else {
7214                         valPtrs[i] = k;
7215                         minCodes[i] = huffCodes[k];
7216                         k += bSize;
7217                         maxCodes[i] = huffCodes[k - 1];
7218                     }
7219                 }
7220                 
7221                 /* Calculate the eHuffman codes and lengths. */
7222                 int[] eHuffCodes = new int[256];
7223                 byte[] eHuffSize = new byte[256];
7224                 for (int i = 0; i < huffCodesIndex; i++) {
7225                     eHuffCodes[huffVals[i]] = huffCodes[i];
7226                     eHuffSize[huffVals[i]] = (byte)huffCodeLengths[i];
7227                 }
7228                 
7229                 /* Create the new JPEGHuffmanTable and add it to the allTables array. */
7230                 JPEGHuffmanTable dhtTable = new JPEGHuffmanTable(reference);
7231                 dhtTable.tableClass = tc;
7232                 dhtTable.tableIdentifier = tid;
7233                 dhtTable.dhValues = huffVals;
7234                 dhtTable.dhCodes = huffCodes;
7235                 dhtTable.dhCodeLengths = huffCodeLengths;
7236                 dhtTable.dhMinCodes = minCodes;
7237                 dhtTable.dhMaxCodes = maxCodes;
7238                 dhtTable.dhValPtrs = valPtrs;
7239                 dhtTable.ehCodes = eHuffCodes;
7240                 dhtTable.ehCodeLengths = eHuffSize;
7241                 huffTables[huffTableCount] = dhtTable;
7242                 huffTableCount++;
7243             }
7244             allTables = new JPEGHuffmanTable[huffTableCount];
7245             System.arraycopy(huffTables, 0, allTables, 0, huffTableCount);
7246         }
7247
7248         public int signature() {
7249             return JPEGFileFormat.DHT;
7250         }
7251     }
7252     /*******************************************************************************
7253      * Copyright (c) 2000, 2003 IBM Corporation and others.
7254      * All rights reserved. This program and the accompanying materials 
7255      * are made available under the terms of the Common Public License v1.0
7256      * which accompanies this distribution, and is available at
7257      * http://www.eclipse.org/legal/cpl-v10.html
7258      * 
7259      * Contributors:
7260      *     IBM Corporation - initial API and implementation
7261      *******************************************************************************/
7262
7263
7264     final static class JPEGQuantizationTable extends JPEGVariableSizeSegment {
7265         public static byte[] DefaultLuminanceQTable = {
7266             (byte)255, (byte)219, 0, 67, 0,
7267             16, 11, 10, 16, 24, 40, 51, 61,
7268             12, 12, 14, 19, 26, 58, 60, 55,
7269             14, 13, 16, 24, 40, 57, 69, 56,
7270             14, 17, 22, 29, 51, 87, 80, 62,
7271             18, 22, 37, 56, 68, 109, 103, 77,
7272             24, 35, 55, 64, 81, 104, 113, 92,
7273             49, 64, 78, 87, 103, 121, 120, 101,
7274             72, 92, 95, 98, 112, 100, 103, 99
7275         };
7276         public static byte[] DefaultChrominanceQTable = {
7277             (byte)255, (byte)219, 0, 67, 1,
7278             17, 18, 24, 47, 99, 99, 99, 99,
7279             18, 21, 26, 66, 99, 99, 99, 99,
7280             24, 26, 56, 99, 99, 99, 99, 99,
7281             47, 66, 99, 99, 99, 99, 99, 99,
7282             99, 99, 99, 99, 99, 99, 99, 99,
7283             99, 99, 99, 99, 99, 99, 99, 99,
7284             99, 99, 99, 99, 99, 99, 99, 99,
7285             99, 99, 99, 99, 99, 99, 99, 99
7286         };
7287         
7288         public JPEGQuantizationTable(byte[] reference) {
7289             super(reference);
7290         }
7291
7292         public JPEGQuantizationTable(LEDataInputStream byteStream) {
7293             super(byteStream);
7294         }
7295
7296         public static JPEGQuantizationTable defaultChrominanceTable() {
7297             byte[] data = new byte[DefaultChrominanceQTable.length];
7298             System.arraycopy(DefaultChrominanceQTable, 0, data, 0, data.length);
7299             return new JPEGQuantizationTable(data);
7300         }
7301
7302         public static JPEGQuantizationTable defaultLuminanceTable() {
7303             byte[] data = new byte[DefaultLuminanceQTable.length];
7304             System.arraycopy(DefaultLuminanceQTable, 0, data, 0, data.length);
7305             return new JPEGQuantizationTable(data);
7306         }
7307
7308         public int[] getQuantizationTablesKeys() {
7309             int[] keys = new int[4];
7310             int keysIndex = 0;
7311             int totalLength = getSegmentLength() - 2;
7312             int ofs = 4;
7313             while (totalLength > 64) {
7314                 int tq = (reference[ofs] & 0xFF) % 16;
7315                 int pq = (reference[ofs] & 0xFF) / 16;
7316                 if (pq == 0) {
7317                     ofs += 65;
7318                     totalLength -= 65;
7319                 } else {
7320                     ofs += 129;
7321                     totalLength -= 129;
7322                 }
7323                 if (keysIndex >= keys.length) {
7324                     int[] newKeys = new int[keys.length + 4];
7325                     System.arraycopy(keys, 0, newKeys, 0, keys.length);
7326                     keys = newKeys;
7327                 }
7328                 keys[keysIndex] = tq;
7329                 keysIndex++;
7330             }
7331             int[] newKeys = new int[keysIndex];
7332             System.arraycopy(keys, 0, newKeys, 0, keysIndex);
7333             return newKeys;
7334         }
7335
7336         public int[][] getQuantizationTablesValues() {
7337             int[][] values = new int[4][];
7338             int valuesIndex = 0;
7339             int totalLength = getSegmentLength() - 2;
7340             int ofs = 4;
7341             while (totalLength > 64) {
7342                 int[] qk = new int[64];
7343                 int pq = (reference[ofs] & 0xFF) / 16;
7344                 if (pq == 0) {
7345                     for (int i = 0; i < qk.length; i++) {
7346                         qk[i] = reference[ofs + i + 1];
7347                     }
7348                     ofs += 65;
7349                     totalLength -= 65;
7350                 } else {
7351                     for (int i = 0; i < qk.length; i++) {
7352                         int idx = (i - 1) * 2 ;
7353                         qk[i] = (reference[ofs + idx + 1] & 0xFF) * 256 + (reference[ofs + idx + 2] & 0xFF);
7354                     }
7355                     ofs += 129;
7356                     totalLength -= 129;
7357                 }
7358                 if (valuesIndex >= values.length) {
7359                     int[][] newValues = new int[values.length + 4][];
7360                     System.arraycopy(values, 0, newValues, 0, values.length);
7361                     values = newValues;
7362                 }
7363                 values[valuesIndex] = qk;
7364                 valuesIndex++;
7365             }
7366             int[][] newValues = new int[valuesIndex][];
7367             System.arraycopy(values, 0, newValues, 0, valuesIndex);
7368             return newValues;
7369         }
7370
7371         public void scaleBy(int qualityFactor) {
7372             int qFactor = qualityFactor;
7373             if (qFactor <= 0) {
7374                 qFactor = 1;
7375             }
7376             if (qFactor > 100) {
7377                 qFactor = 100;
7378             }
7379             if (qFactor < 50) {
7380                 qFactor = 5000 / qFactor;
7381             } else {
7382                 qFactor = 200 - (qFactor * 2);
7383             }
7384             int totalLength = getSegmentLength() - 2;
7385             int ofs = 4;
7386             while (totalLength > 64) {
7387                 //              int tq = (reference[ofs] & 0xFF) % 16;
7388                 int pq = (reference[ofs] & 0xFF) / 16;
7389                 if (pq == 0) {
7390                     for (int i = ofs + 1; i <= ofs + 64; i++) {
7391                         int temp = ((reference[i] & 0xFF) * qFactor + 50) / 100;
7392                         if (temp <= 0) temp = 1;
7393                         if (temp > 255) temp = 255;
7394                         reference[i] = (byte)temp;
7395                     }
7396                     ofs += 65;
7397                     totalLength -= 65;
7398                 } else {
7399                     for (int i = ofs + 1; i <= ofs + 128; i += 2) {
7400                         int temp = (((reference[i] & 0xFF) * 256 + (reference[i + 1] & 0xFF)) * qFactor + 50) / 100;
7401                         if (temp <= 0) temp = 1;
7402                         if (temp > 32767) temp = 32767;
7403                         reference[i] = (byte)(temp / 256);
7404                         reference[i + 1] = (byte)(temp % 256);
7405                     }
7406                     ofs += 129;
7407                     totalLength -= 129;
7408                 }
7409             }
7410         }
7411
7412         public int signature() {
7413             return JPEGFileFormat.DQT;
7414         }
7415     }
7416     /*******************************************************************************
7417      * Copyright (c) 2000, 2003 IBM Corporation and others.
7418      * All rights reserved. This program and the accompanying materials 
7419      * are made available under the terms of the Common Public License v1.0
7420      * which accompanies this distribution, and is available at
7421      * http://www.eclipse.org/legal/cpl-v10.html
7422      * 
7423      * Contributors:
7424      *     IBM Corporation - initial API and implementation
7425      *******************************************************************************/
7426
7427
7428     final static class JPEGRestartInterval extends JPEGFixedSizeSegment {
7429
7430         public JPEGRestartInterval(LEDataInputStream byteStream) {
7431             super(byteStream);
7432         }
7433         
7434         public int signature() {
7435             return JPEGFileFormat.DRI;
7436         }
7437         
7438         public int getRestartInterval() {
7439             return ((reference[4] & 0xFF) << 8 | (reference[5] & 0xFF));
7440         }
7441
7442         public int fixedSize() {
7443             return 6;
7444         }
7445     }
7446     /*******************************************************************************
7447      * Copyright (c) 2000, 2004 IBM Corporation and others.
7448      * All rights reserved. This program and the accompanying materials
7449      * are made available under the terms of the Common Public License v1.0
7450      * which accompanies this distribution, and is available at
7451      * http://www.eclipse.org/legal/cpl-v10.html
7452      * 
7453      * Contributors:
7454      *     IBM Corporation - initial API and implementation
7455      *******************************************************************************/
7456
7457
7458
7459     final static class JPEGScanHeader extends JPEGVariableSizeSegment {
7460         public int[][] componentParameters;
7461
7462         public JPEGScanHeader(byte[] reference) {
7463             super(reference);
7464         }
7465
7466         public JPEGScanHeader(LEDataInputStream byteStream) {
7467             super(byteStream);
7468             initializeComponentParameters();
7469         }
7470
7471         public int getApproxBitPositionHigh() {
7472             return (reference[(2 * getNumberOfImageComponents()) + 7] & 0xFF) / 16;
7473         }
7474
7475         public int getApproxBitPositionLow() {
7476             return (reference[(2 * getNumberOfImageComponents()) + 7] & 0xFF) % 16;
7477         }
7478
7479         public int getEndOfSpectralSelection() {
7480             return (reference[(2 * getNumberOfImageComponents()) + 6] & 0xFF);
7481         }
7482
7483         public int getNumberOfImageComponents() {
7484             return (reference[4] & 0xFF);
7485         }
7486
7487         public int getStartOfSpectralSelection() {
7488             return (reference[(2 * getNumberOfImageComponents()) + 5] & 0xFF);
7489         }
7490
7491         /* Used when decoding. */
7492         void initializeComponentParameters() {
7493             int compCount = getNumberOfImageComponents();
7494             componentParameters = new int[0][];
7495             for (int i = 0; i < compCount; i++) {
7496                 int ofs = 5 + i * 2;
7497                 int cid = reference[ofs] & 0xFF;
7498                 int dc = (reference[ofs + 1] & 0xFF) / 16;
7499                 int ac = (reference[ofs + 1] & 0xFF) % 16;
7500                 if (componentParameters.length <= cid) {
7501                     int[][] newParams = new int[cid + 1][];
7502                     System.arraycopy(componentParameters, 0, newParams, 0, componentParameters.length);
7503                     componentParameters = newParams;
7504                 }
7505                 componentParameters[cid] = new int[] { dc, ac };
7506             }
7507         }
7508
7509         /* Used when encoding. */
7510         public void initializeContents() {
7511             int compCount = getNumberOfImageComponents();
7512             int[][] compSpecParams = componentParameters;
7513             if (compCount == 0 || compCount != compSpecParams.length) {
7514                 SWT.error(SWT.ERROR_INVALID_IMAGE);
7515             }
7516             for (int i = 0; i < compCount; i++) {
7517                 int ofs = i * 2 + 5;
7518                 int[] compParams = compSpecParams[i];
7519                 reference[ofs] = (byte)(i + 1);
7520                 reference[ofs + 1] = (byte)(compParams[0] * 16 + compParams[1]);
7521             }
7522         }
7523
7524         public void setEndOfSpectralSelection(int anInteger) {
7525             reference[(2 * getNumberOfImageComponents()) + 6] = (byte)anInteger;
7526         }
7527
7528         public void setNumberOfImageComponents(int anInteger) {
7529             reference[4] = (byte)(anInteger & 0xFF);
7530         }
7531
7532         public void setStartOfSpectralSelection(int anInteger) {
7533             reference[(2 * getNumberOfImageComponents()) + 5] = (byte)anInteger;
7534         }
7535
7536         public int signature() {
7537             return JPEGFileFormat.SOS;
7538         }
7539
7540         public boolean verifyProgressiveScan() {
7541             int start = getStartOfSpectralSelection();
7542             int end = getEndOfSpectralSelection();
7543             int low = getApproxBitPositionLow();
7544             int high = getApproxBitPositionHigh();
7545             int count = getNumberOfImageComponents();
7546             if ((start == 0 && end == 00) || (start <= end && end <= 63)) {
7547                 if (low <= 13 && high <= 13 && (high == 0 || high == low + 1)) {
7548                     return start == 0 || (start > 0 && count == 1);
7549                 }
7550             }
7551             return false;
7552         }
7553
7554         public boolean isACProgressiveScan() {
7555             return getStartOfSpectralSelection() != 0 && getEndOfSpectralSelection() != 0;
7556         }
7557
7558         public boolean isDCProgressiveScan() {
7559             return getStartOfSpectralSelection() == 0 && getEndOfSpectralSelection() == 0;
7560         }
7561
7562         public boolean isFirstScan() {
7563             return getApproxBitPositionHigh() == 0;
7564         }
7565
7566     }
7567     /*******************************************************************************
7568      * Copyright (c) 2000, 2003 IBM Corporation and others.
7569      * All rights reserved. This program and the accompanying materials 
7570      * are made available under the terms of the Common Public License v1.0
7571      * which accompanies this distribution, and is available at
7572      * http://www.eclipse.org/legal/cpl-v10.html
7573      * 
7574      * Contributors:
7575      *     IBM Corporation - initial API and implementation
7576      *******************************************************************************/
7577
7578
7579     static class JPEGSegment {
7580         public byte[] reference;
7581
7582         JPEGSegment() {
7583         }
7584         
7585         public JPEGSegment(byte[] reference) {
7586             this.reference = reference;
7587         }
7588         
7589         public int signature() {
7590             return 0;
7591         }
7592         
7593         public boolean verify() {
7594             return getSegmentMarker() == signature();
7595         }
7596         
7597         public int getSegmentMarker() {
7598             return ((reference[0] & 0xFF) << 8 | (reference[1] & 0xFF));
7599         }
7600         
7601         public void setSegmentMarker(int marker) {
7602             reference[0] = (byte)((marker & 0xFF00) >> 8);
7603             reference[1] = (byte)(marker & 0xFF);
7604         }
7605         
7606         public int getSegmentLength() {
7607             return ((reference[2] & 0xFF) << 8 | (reference[3] & 0xFF));
7608         }
7609         
7610         public void setSegmentLength(int length) {
7611             reference[2] = (byte)((length & 0xFF00) >> 8);
7612             reference[3] = (byte)(length & 0xFF);
7613         }
7614         
7615         public boolean writeToStream(LEDataOutputStream byteStream) {
7616             try {
7617                 byteStream.write(reference);
7618                 return true;
7619             } catch (Exception e) {
7620                 return false;
7621             }
7622         }
7623     }
7624     /*******************************************************************************
7625      * Copyright (c) 2000, 2003 IBM Corporation and others.
7626      * All rights reserved. This program and the accompanying materials 
7627      * are made available under the terms of the Common Public License v1.0
7628      * which accompanies this distribution, and is available at
7629      * http://www.eclipse.org/legal/cpl-v10.html
7630      * 
7631      * Contributors:
7632      *     IBM Corporation - initial API and implementation
7633      *******************************************************************************/
7634
7635
7636     final static class JPEGStartOfImage extends JPEGFixedSizeSegment {
7637
7638         public JPEGStartOfImage() {
7639             super();
7640         }
7641         
7642         public JPEGStartOfImage(byte[] reference) {
7643             super(reference);
7644         }
7645         
7646         public JPEGStartOfImage(LEDataInputStream byteStream) {
7647             super(byteStream);
7648         }
7649         
7650         public int signature() {
7651             return JPEGFileFormat.SOI;
7652         }
7653         
7654         public int fixedSize() {
7655             return 2;
7656         }
7657     }
7658     /*******************************************************************************
7659      * Copyright (c) 2000, 2003 IBM Corporation and others.
7660      * All rights reserved. This program and the accompanying materials 
7661      * are made available under the terms of the Common Public License v1.0
7662      * which accompanies this distribution, and is available at
7663      * http://www.eclipse.org/legal/cpl-v10.html
7664      * 
7665      * Contributors:
7666      *     IBM Corporation - initial API and implementation
7667      *******************************************************************************/
7668
7669
7670
7671     abstract static class JPEGVariableSizeSegment extends JPEGSegment {
7672
7673         public JPEGVariableSizeSegment(byte[] reference) {
7674             super(reference);
7675         }
7676         
7677         public JPEGVariableSizeSegment(LEDataInputStream byteStream) {
7678             try {
7679                 byte[] header = new byte[4];
7680                 byteStream.read(header);
7681                 reference = header; // to use getSegmentLength()
7682                 byte[] contents = new byte[getSegmentLength() + 2];
7683                 contents[0] = header[0];
7684                 contents[1] = header[1];
7685                 contents[2] = header[2];
7686                 contents[3] = header[3];
7687                 byteStream.read(contents, 4, contents.length - 4);
7688                 reference = contents;
7689             } catch (Exception e) {
7690                 SWT.error(SWT.ERROR_IO, e);
7691             }
7692         }
7693     }
7694 }