1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.graphics.Image;
14 
15 import org.eclipse.swt.internal.Converter;
16 import org.eclipse.swt.internal.cairo.Cairo : Cairo;
17 import org.eclipse.swt.internal.gtk.OS;
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.SWTException;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.Device;
22 import org.eclipse.swt.graphics.Drawable;
23 import org.eclipse.swt.graphics.GC;
24 import org.eclipse.swt.graphics.GCData;
25 import org.eclipse.swt.graphics.ImageData;
26 import org.eclipse.swt.graphics.PaletteData;
27 import org.eclipse.swt.graphics.RGB;
28 import org.eclipse.swt.graphics.Rectangle;
29 import org.eclipse.swt.graphics.Resource;
30 
31 import java.io.InputStream;
32 import java.lang.all;
33 
34 version(Tango){
35 import tango.stdc..string;
36 } else { // Phobos
37 }
38 
39 /**
40  * Instances of this class are graphics which have been prepared
41  * for display on a specific device. That is, they are ready
42  * to paint using methods such as <code>GC.drawImage()</code>
43  * and display on widgets with, for example, <code>Button.setImage()</code>.
44  * <p>
45  * If loaded from a file format that supports it, an
46  * <code>Image</code> may have transparency, meaning that certain
47  * pixels are specified as being transparent when drawn. Examples
48  * of file formats that support transparency are GIF and PNG.
49  * </p><p>
50  * There are two primary ways to use <code>Images</code>.
51  * The first is to load a graphic file from disk and create an
52  * <code>Image</code> from it. This is done using an <code>Image</code>
53  * constructor, for example:
54  * <pre>
55  *    Image i = new Image(device, "C:\\graphic.bmp");
56  * </pre>
57  * A graphic file may contain a color table specifying which
58  * colors the image was intended to possess. In the above example,
59  * these colors will be mapped to the closest available color in
60  * SWT. It is possible to get more control over the mapping of
61  * colors as the image is being created, using code of the form:
62  * <pre>
63  *    ImageData data = new ImageData("C:\\graphic.bmp");
64  *    RGB[] rgbs = data.getRGBs();
65  *    // At this point, rgbs contains specifications of all
66  *    // the colors contained within this image. You may
67  *    // allocate as many of these colors as you wish by
68  *    // using the Color constructor Color(RGB), then
69  *    // create the image:
70  *    Image i = new Image(device, data);
71  * </pre>
72  * <p>
73  * Applications which require even greater control over the image
74  * loading process should use the support provided in class
75  * <code>ImageLoader</code>.
76  * </p><p>
77  * Application code must explicitly invoke the <code>Image.dispose()</code>
78  * method to release the operating system resources managed by each instance
79  * when those instances are no longer required.
80  * </p>
81  *
82  * @see Color
83  * @see ImageData
84  * @see ImageLoader
85  * @see <a href="http://www.eclipse.org/swt/snippets/#image">Image snippets</a>
86  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, ImageAnalyzer</a>
87  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
88  */
89 public final class Image : Resource, Drawable {
90     alias Resource.init_ init_;
91     /**
92      * specifies whether the receiver is a bitmap or an icon
93      * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
94      * <p>
95      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
96      * public API. It is marked public only so that it can be shared
97      * within the packages provided by SWT. It is not available on all
98      * platforms and should never be accessed from application code.
99      * </p>
100      */
101     public int type;
102 
103     /**
104      * The handle to the OS pixmap resource.
105      * (Warning: This field is platform dependent)
106      * <p>
107      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
108      * public API. It is marked public only so that it can be shared
109      * within the packages provided by SWT. It is not available on all
110      * platforms and should never be accessed from application code.
111      * </p>
112      */
113     public GdkDrawable* pixmap;
114 
115     /**
116      * The handle to the OS mask resource.
117      * (Warning: This field is platform dependent)
118      * <p>
119      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
120      * public API. It is marked public only so that it can be shared
121      * within the packages provided by SWT. It is not available on all
122      * platforms and should never be accessed from application code.
123      * </p>
124      */
125     public GdkDrawable* mask;
126 
127     org.eclipse.swt.internal.gtk.OS.cairo_surface_t* surface;
128     org.eclipse.swt.internal.gtk.OS.cairo_surface_t* surfaceData;
129 
130     /**
131      * specifies the transparent pixel
132      */
133     int transparentPixel = -1;
134 
135     /**
136      * The GC the image is currently selected in.
137      */
138     GC memGC;
139 
140     /**
141      * The alpha data of the image.
142      */
143     byte[] alphaData;
144 
145     /**
146      * The global alpha value to be used for every pixel.
147      */
148     int alpha = -1;
149 
150     /**
151      * The width of the image.
152      */
153     int width = -1;
154 
155     /**
156      * The height of the image.
157      */
158     int height = -1;
159 
160     /**
161      * Specifies the default scanline padding.
162      */
163     static const int DEFAULT_SCANLINE_PAD = 4;
164 
165 this(Device device) {
166     super(device);
167 }
168 
169 /**
170  * Constructs an empty instance of this class with the
171  * specified width and height. The result may be drawn upon
172  * by creating a GC and using any of its drawing operations,
173  * as shown in the following example:
174  * <pre>
175  *    Image i = new Image(device, width, height);
176  *    GC gc = new GC(i);
177  *    gc.drawRectangle(0, 0, 50, 50);
178  *    gc.dispose();
179  * </pre>
180  * <p>
181  * Note: Some platforms may have a limitation on the size
182  * of image that can be created (size depends on width, height,
183  * and depth). For example, Windows 95, 98, and ME do not allow
184  * images larger than 16M.
185  * </p>
186  *
187  * @param device the device on which to create the image
188  * @param width the width of the new image
189  * @param height the height of the new image
190  *
191  * @exception IllegalArgumentException <ul>
192  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
193  *    <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
194  * </ul>
195  * @exception SWTError <ul>
196  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
197  * </ul>
198  */
199 public this(Device device, int width, int height) {
200     super(device);
201     init_(width, height);
202     init_();
203 }
204 
205 /**
206  * Constructs a new instance of this class based on the
207  * provided image, with an appearance that varies depending
208  * on the value of the flag. The possible flag values are:
209  * <dl>
210  * <dt><b>{@link SWT#IMAGE_COPY}</b></dt>
211  * <dd>the result is an identical copy of srcImage</dd>
212  * <dt><b>{@link SWT#IMAGE_DISABLE}</b></dt>
213  * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
214  * <dt><b>{@link SWT#IMAGE_GRAY}</b></dt>
215  * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
216  * </dl>
217  *
218  * @param device the device on which to create the image
219  * @param srcImage the image to use as the source
220  * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
221  *
222  * @exception IllegalArgumentException <ul>
223  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
224  *    <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
225  *    <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li>
226  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
227  * </ul>
228  * @exception SWTException <ul>
229  *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
230  *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
231  * </ul>
232  * @exception SWTError <ul>
233  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
234  * </ul>
235  */
236 public this(Device device, Image srcImage, int flag) {
237     super(device);
238     if (srcImage is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
239     if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
240     switch (flag) {
241         case SWT.IMAGE_COPY:
242         case SWT.IMAGE_DISABLE:
243         case SWT.IMAGE_GRAY:
244             break;
245         default:
246             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
247     }
248     device = this.device;
249     this.type = srcImage.type;
250 
251     /* Get source image size */
252     int w, h;
253     OS.gdk_drawable_get_size(srcImage.pixmap, &w, &h);
254     int width = w;
255     int height = h;
256 
257     /* Copy the mask */
258     if ((srcImage.type is SWT.ICON && srcImage.mask !is null ) || srcImage.transparentPixel !is -1) {
259         /* Generate the mask if necessary. */
260         if (srcImage.transparentPixel !is -1) srcImage.createMask();
261         //PORTING_FIXME cast
262         GdkDrawable* mask = cast(GdkDrawable*) OS.gdk_pixmap_new( null, width, height, 1);
263         if (mask is null ) SWT.error(SWT.ERROR_NO_HANDLES);
264         auto gdkGC = OS.gdk_gc_new(mask);
265         if (gdkGC is null) SWT.error(SWT.ERROR_NO_HANDLES);
266         OS.gdk_draw_drawable(mask, gdkGC, srcImage.mask, 0, 0, 0, 0, width, height);
267         OS.g_object_unref(gdkGC);
268         this.mask = mask;
269         /* Destroy the image mask if the there is a GC created on the image */
270         if (srcImage.transparentPixel !is -1 && srcImage.memGC !is null) srcImage.destroyMask();
271     }
272 
273     /* Copy transparent pixel and alpha data */
274     if (flag !is SWT.IMAGE_DISABLE) transparentPixel = srcImage.transparentPixel;
275     alpha = srcImage.alpha;
276     if (srcImage.alphaData !is null) {
277         alphaData = new byte[srcImage.alphaData.length];
278         System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length);
279     }
280     createAlphaMask(width, height);
281 
282     /* Create the new pixmap */
283     auto pixmap = cast(GdkDrawable*) OS.gdk_pixmap_new (cast(GdkDrawable*)OS.GDK_ROOT_PARENT(), width, height, -1);
284     if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
285     auto gdkGC = OS.gdk_gc_new(pixmap);
286     if (gdkGC is null) SWT.error(SWT.ERROR_NO_HANDLES);
287     this.pixmap = pixmap;
288 
289     if (flag is SWT.IMAGE_COPY) {
290         OS.gdk_draw_drawable(pixmap, gdkGC, srcImage.pixmap, 0, 0, 0, 0, width, height);
291         OS.g_object_unref(gdkGC);
292     } else {
293 
294         /* Retrieve the source pixmap data */
295         auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
296         if (pixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
297         auto colormap = OS.gdk_colormap_get_system();
298         OS.gdk_pixbuf_get_from_drawable(pixbuf, srcImage.pixmap, colormap, 0, 0, 0, 0, width, height);
299         int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
300         auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
301 
302         /* Apply transformation */
303         switch (flag) {
304             case SWT.IMAGE_DISABLE: {
305                 Color zeroColor = device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
306                 RGB zeroRGB = zeroColor.getRGB();
307                 byte zeroRed = cast(byte)zeroRGB.red;
308                 byte zeroGreen = cast(byte)zeroRGB.green;
309                 byte zeroBlue = cast(byte)zeroRGB.blue;
310                 Color oneColor = device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
311                 RGB oneRGB = oneColor.getRGB();
312                 byte oneRed = cast(byte)oneRGB.red;
313                 byte oneGreen = cast(byte)oneRGB.green;
314                 byte oneBlue = cast(byte)oneRGB.blue;
315                 byte[] line = new byte[stride];
316                 for (int y=0; y<height; y++) {
317                     OS.memmove(line.ptr, pixels + (y * stride), stride);
318                     for (int x=0; x<width; x++) {
319                         int offset = x*3;
320                         int red = line[offset] & 0xFF;
321                         int green = line[offset+1] & 0xFF;
322                         int blue = line[offset+2] & 0xFF;
323                         int intensity = red * red + green * green + blue * blue;
324                         if (intensity < 98304) {
325                             line[offset] = zeroRed;
326                             line[offset+1] = zeroGreen;
327                             line[offset+2] = zeroBlue;
328                         } else {
329                             line[offset] = oneRed;
330                             line[offset+1] = oneGreen;
331                             line[offset+2] = oneBlue;
332                         }
333                     }
334                     OS.memmove(pixels + (y * stride), line.ptr, stride);
335                 }
336                 break;
337             }
338             case SWT.IMAGE_GRAY: {
339                 byte[] line = new byte[stride];
340                 for (int y=0; y<height; y++) {
341                 OS.memmove(line.ptr, pixels + (y * stride), stride);
342                     for (int x=0; x<width; x++) {
343                         int offset = x*3;
344                         int red = line[offset] & 0xFF;
345                         int green = line[offset+1] & 0xFF;
346                         int blue = line[offset+2] & 0xFF;
347                         byte intensity = cast(byte)((red+red+green+green+green+green+green+blue) >> 3);
348                         line[offset] = line[offset+1] = line[offset+2] = intensity;
349                     }
350                     OS.memmove(pixels + (y * stride), line.ptr, stride);
351                 }
352                 break;
353             }
354         default:
355         }
356 
357         /* Copy data back to destination pixmap */
358         OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
359 
360         /* Free resources */
361         OS.g_object_unref(pixbuf);
362         OS.g_object_unref(gdkGC);
363     }
364     init_();
365 }
366 
367 /**
368  * Constructs an empty instance of this class with the
369  * width and height of the specified rectangle. The result
370  * may be drawn upon by creating a GC and using any of its
371  * drawing operations, as shown in the following example:
372  * <pre>
373  *    Image i = new Image(device, boundsRectangle);
374  *    GC gc = new GC(i);
375  *    gc.drawRectangle(0, 0, 50, 50);
376  *    gc.dispose();
377  * </pre>
378  * <p>
379  * Note: Some platforms may have a limitation on the size
380  * of image that can be created (size depends on width, height,
381  * and depth). For example, Windows 95, 98, and ME do not allow
382  * images larger than 16M.
383  * </p>
384  *
385  * @param device the device on which to create the image
386  * @param bounds a rectangle specifying the image's width and height (must not be null)
387  *
388  * @exception IllegalArgumentException <ul>
389  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
390  *    <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
391  *    <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
392  * </ul>
393  * @exception SWTError <ul>
394  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
395  * </ul>
396  */
397 public this(Device device, Rectangle bounds) {
398     super(device);
399     if (bounds is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
400     init_(bounds.width, bounds.height);
401     init_();
402 }
403 
404 /**
405  * Constructs an instance of this class from the given
406  * <code>ImageData</code>.
407  *
408  * @param device the device on which to create the image
409  * @param data the image data to create the image from (must not be null)
410  *
411  * @exception IllegalArgumentException <ul>
412  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
413  *    <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
414  * </ul>
415  * @exception SWTException <ul>
416  *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
417  * </ul>
418  * @exception SWTError <ul>
419  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
420  * </ul>
421  */
422 public this(Device device, ImageData data) {
423     super(device);
424     init_(data);
425     init_();
426 }
427 
428 /**
429  * Constructs an instance of this class, whose type is
430  * <code>SWT.ICON</code>, from the two given <code>ImageData</code>
431  * objects. The two images must be the same size. Pixel transparency
432  * in either image will be ignored.
433  * <p>
434  * The mask image should contain white wherever the icon is to be visible,
435  * and black wherever the icon is to be transparent. In addition,
436  * the source image should contain black wherever the icon is to be
437  * transparent.
438  * </p>
439  *
440  * @param device the device on which to create the icon
441  * @param source the color data for the icon
442  * @param mask the mask data for the icon
443  *
444  * @exception IllegalArgumentException <ul>
445  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
446  *    <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li>
447  *    <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li>
448  * </ul>
449  * @exception SWTError <ul>
450  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
451  * </ul>
452  */
453 public this(Device device, ImageData source, ImageData mask) {
454     super(device);
455     if (source is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
456     if (mask is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
457     if (source.width !is mask.width || source.height !is mask.height) {
458         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
459     }
460     mask = ImageData.convertMask (mask);
461     ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data);
462     image.maskPad = mask.scanlinePad;
463     image.maskData = mask.data;
464     init_(image);
465     init_();
466 }
467 
468 /**
469  * Constructs an instance of this class by loading its representation
470  * from the specified input stream. Throws an error if an error
471  * occurs while loading the image, or if the result is an image
472  * of an unsupported type.  Application code is still responsible
473  * for closing the input stream.
474  * <p>
475  * This constructor is provided for convenience when loading a single
476  * image only. If the stream contains multiple images, only the first
477  * one will be loaded. To load multiple images, use
478  * <code>ImageLoader.load()</code>.
479  * </p><p>
480  * This constructor may be used to load a resource as follows:
481  * </p>
482  * <pre>
483  *     static Image loadImage (Display display, Class clazz, String string) {
484  *          InputStream stream = clazz.getResourceAsStream (string);
485  *          if (stream is null) return null;
486  *          Image image = null;
487  *          try {
488  *               image = new Image (display, stream);
489  *          } catch (SWTException ex) {
490  *          } finally {
491  *               try {
492  *                    stream.close ();
493  *               } catch (IOException ex) {}
494  *          }
495  *          return image;
496  *     }
497  * </pre>
498  *
499  * @param device the device on which to create the image
500  * @param stream the input stream to load the image from
501  *
502  * @exception IllegalArgumentException <ul>
503  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
504  *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
505  * </ul>
506  * @exception SWTException <ul>
507  *    <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
508  *    <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
509  *    <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
510  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
511  * </ul>
512  * @exception SWTError <ul>
513  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
514  * </ul>
515  */
516 public this(Device device, InputStream stream) {
517     super(device);
518     init_(new ImageData(stream));
519     init_();
520 }
521 
522 /**
523  * Constructs an instance of this class by loading its representation
524  * from the file with the specified name. Throws an error if an error
525  * occurs while loading the image, or if the result is an image
526  * of an unsupported type.
527  * <p>
528  * This constructor is provided for convenience when loading
529  * a single image only. If the specified file contains
530  * multiple images, only the first one will be used.
531  *
532  * @param device the device on which to create the image
533  * @param filename the name of the file to load the image from
534  *
535  * @exception IllegalArgumentException <ul>
536  *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
537  *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
538  * </ul>
539  * @exception SWTException <ul>
540  *    <li>ERROR_IO - if an IO error occurs while reading from the file</li>
541  *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
542  *    <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
543  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
544  * </ul>
545  * @exception SWTError <ul>
546  *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
547  * </ul>
548  */
549 public this(Device device, String filename) {
550     super(device);
551     if (filename is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
552     try {
553         auto length = filename.length;
554         auto pixbuf = OS.gdk_pixbuf_new_from_file(toStringz(filename), null);
555         if (pixbuf !is null) {
556             bool hasAlpha = cast(bool)OS.gdk_pixbuf_get_has_alpha(pixbuf);
557             if (hasAlpha) {
558                 /*
559                 * Bug in GTK. Depending on the image (seems to affect images that have
560                 * some degree of transparency all over the image), gdk_pixbuff_render_pixmap_and_mask()
561                 * will return a corrupt pixmap. To avoid this, read in and store the alpha channel data
562                 * for the image and then set it to 0xFF to prevent any possible corruption from
563                 * gdk_pixbuff_render_pixmap_and_mask().
564                 */
565                 int width = OS.gdk_pixbuf_get_width(pixbuf);
566                 int height = OS.gdk_pixbuf_get_height(pixbuf);
567                 int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
568                 auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
569                 byte[] line = new byte[stride];
570                 alphaData = new byte[width * height];
571                 for (int y = 0; y < height; y++) {
572                     OS.memmove(line.ptr, pixels + (y * stride), stride);
573                     for (int x = 0; x < width; x++) {
574                         alphaData[y*width+x] = line[x*4 + 3];
575                         line[x*4 + 3] = cast(byte) 0xFF;
576                     }
577                     OS.memmove(pixels + (y * stride), line.ptr, stride);
578                 }
579                 createAlphaMask(width, height);
580             }
581             GdkPixmap* pixmap_return;
582             OS.gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap_return, null, 0);
583             this.type = SWT.BITMAP;
584             this.pixmap = cast(GdkDrawable*)pixmap_return;
585             if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
586             OS.g_object_unref (pixbuf);
587             return;
588         }
589     } catch (SWTException e) {}
590     init_(new ImageData(filename));
591     init_();
592 }
593 
594 void createAlphaMask (int width, int height) {
595     if (device.useXRender && (alpha !is -1 || alphaData !is null)) {
596         mask = cast(GdkDrawable*)OS.gdk_pixmap_new(null, alpha !is -1 ? 1 : width, alpha !is -1 ? 1 : height, 8);
597         if (mask is null) SWT.error(SWT.ERROR_NO_HANDLES);
598         auto gc = OS.gdk_gc_new(mask);
599         if (alpha !is -1) {
600             GdkColor* color = new GdkColor();
601             color.pixel = (alpha & 0xFF) << 8 | (alpha & 0xFF);
602             OS.gdk_gc_set_foreground(gc, color);
603             OS.gdk_draw_rectangle(mask, gc, 1, 0, 0, 1, 1);
604         } else {
605             GdkImage* imagePtr = OS.gdk_drawable_get_image(mask, 0, 0, width, height);
606             if (imagePtr is null) SWT.error(SWT.ERROR_NO_HANDLES);
607             GdkImage* gdkImage = new GdkImage();
608             *gdkImage = *imagePtr;
609             if (gdkImage.bpl is width) {
610                 OS.memmove(gdkImage.mem, alphaData.ptr,
611                            alphaData.length);
612             } else {
613                 byte[] line = new byte[gdkImage.bpl];
614                 for (int y = 0; y < height; y++) {
615                     System.arraycopy(alphaData, width * y, line, 0, width);
616                     OS.memmove(gdkImage.mem + (gdkImage.bpl * y), line.ptr, gdkImage.bpl);
617                 }
618             }
619             OS.gdk_draw_image(mask, gc, imagePtr, 0, 0, 0, 0, width, height);
620             OS.g_object_unref(imagePtr);
621         }
622         OS.g_object_unref(gc);
623     }
624 }
625 
626 /**
627  * Create the receiver's mask if necessary.
628  */
629 void createMask() {
630     if (mask !is null ) return;
631     mask = createMask(getImageData(), false);
632     if (mask is null ) SWT.error(SWT.ERROR_NO_HANDLES);
633 }
634 
635 GdkDrawable* createMask(ImageData image, bool copy) {
636     ImageData mask = image.getTransparencyMask();
637     byte[] data = mask.data;
638     byte[] maskData = copy ? new byte[data.length] : data;
639     for (int i = 0; i < maskData.length; i++) {
640         byte s = data[i];
641         maskData[i] = cast(byte)(((s & 0x80) >> 7) | ((s & 0x40) >> 5) |
642             ((s & 0x20) >> 3) | ((s & 0x10) >> 1) | ((s & 0x08) << 1) |
643             ((s & 0x04) << 3) | ((s & 0x02) << 5) | ((s & 0x01) << 7));
644     }
645     maskData = ImageData.convertPad(maskData, mask.width, mask.height, mask.depth, mask.scanlinePad, 1);
646     return cast(GdkDrawable*)OS.gdk_bitmap_create_from_data(null, cast(char*)maskData.ptr, mask.width, mask.height);
647 }
648 
649 void createSurface() {
650     if (surface !is null ) return;
651     /* Generate the mask if necessary. */
652     if (transparentPixel !is -1) createMask();
653     int w, h;
654     OS.gdk_drawable_get_size(pixmap, &w, &h);
655     int width = w, height = h;
656     if (mask !is null || alpha !is -1 || alphaData !is null) {
657         auto pixbuf = OS.gdk_pixbuf_new( OS.GDK_COLORSPACE_RGB, true, 8, width, height);
658         if (pixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
659         auto colormap = OS.gdk_colormap_get_system();
660         OS.gdk_pixbuf_get_from_drawable(pixbuf, pixmap, colormap, 0, 0, 0, 0, width, height);
661         int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
662         auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
663         byte[] line = new byte[stride];
664         if (mask !is null && OS.gdk_drawable_get_depth(mask) is 1) {
665             auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
666             if (maskPixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
667             OS.gdk_pixbuf_get_from_drawable(maskPixbuf, mask, null, 0, 0, 0, 0, width, height);
668             int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
669             auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
670             byte[] maskLine = new byte[maskStride];
671             auto offset = pixels, maskOffset = maskPixels;
672             for (int y=0; y<height; y++) {
673                 OS.memmove(line.ptr, offset, stride);
674                 OS.memmove(maskLine.ptr, maskOffset, maskStride);
675                 for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
676                     if (maskLine[x * 3] is 0) {
677                         line[offset1 + 0] = line[offset1 + 1] = line[offset1 + 2] = line[offset1 + 3] = 0;
678                     }
679                     byte temp = line[offset1];
680                     line[offset1] = line[offset1 + 2];
681                     line[offset1 + 2] = temp;
682                 }
683                 OS.memmove(offset, line.ptr, stride);
684                 offset += stride;
685                 maskOffset += maskStride;
686             }
687             OS.g_object_unref(maskPixbuf);
688         } else if (alpha !is -1) {
689             auto offset = pixels;
690             for (int y=0; y<height; y++) {
691                 OS.memmove(line.ptr, offset, stride);
692                 for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
693                     line[offset1+3] = cast(byte)alpha;
694                     /* pre-multiplied alpha */
695                     int r = ((line[offset1 + 0] & 0xFF) * alpha) + 128;
696                     r = (r + (r >> 8)) >> 8;
697                     int g = ((line[offset1 + 1] & 0xFF) * alpha) + 128;
698                     g = (g + (g >> 8)) >> 8;
699                     int b = ((line[offset1 + 2] & 0xFF) * alpha) + 128;
700                     b = (b + (b >> 8)) >> 8;
701                     line[offset1 + 0] = cast(byte)b;
702                     line[offset1 + 1] = cast(byte)g;
703                     line[offset1 + 2] = cast(byte)r;
704                 }
705                 OS.memmove(offset, line.ptr, stride);
706                 offset += stride;
707             }
708         } else if (alphaData !is null) {
709             auto offset = pixels;
710             for (int y = 0; y < h; y++) {
711                 OS.memmove (line.ptr, offset, stride);
712                 for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
713                     int alpha = alphaData [y*w+x] & 0xFF;
714                     line[offset1+3] = cast(byte)alpha;
715                     /* pre-multiplied alpha */
716                     int r = ((line[offset1 + 0] & 0xFF) * alpha) + 128;
717                     r = (r + (r >> 8)) >> 8;
718                     int g = ((line[offset1 + 1] & 0xFF) * alpha) + 128;
719                     g = (g + (g >> 8)) >> 8;
720                     int b = ((line[offset1 + 2] & 0xFF) * alpha) + 128;
721                     b = (b + (b >> 8)) >> 8;
722                     line[offset1 + 0] = cast(byte)b;
723                     line[offset1 + 1] = cast(byte)g;
724                     line[offset1 + 2] = cast(byte)r;
725                 }
726                 OS.memmove (offset, line.ptr, stride);
727                 offset += stride;
728             }
729         } else {
730             auto offset = pixels;
731             for (int y = 0; y < h; y++) {
732                 OS.memmove (line.ptr, offset, stride);
733                 for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
734                     line[offset1+3] = cast(byte)0xFF;
735                     byte temp = line[offset1];
736                     line[offset1] = line[offset1 + 2];
737                     line[offset1 + 2] = temp;
738                 }
739                 OS.memmove (offset, line.ptr, stride);
740                 offset += stride;
741             }
742         }
743         surfaceData = cast(org.eclipse.swt.internal.gtk.OS.cairo_surface_t*) OS.g_malloc(stride * height);
744         OS.memmove(surfaceData, pixels, stride * height);
745         surface = Cairo.cairo_image_surface_create_for_data(cast(char*)surfaceData, Cairo.CAIRO_FORMAT_ARGB32, width, height, stride);
746         OS.g_object_unref(pixbuf);
747     } else {
748         auto xDisplay = OS.GDK_DISPLAY();
749         auto xDrawable = OS.GDK_PIXMAP_XID(pixmap);
750         auto xVisual = OS.gdk_x11_visual_get_xvisual(OS.gdk_visual_get_system());
751         // PORTING_FIXME  cast and types not good
752         surface = Cairo.cairo_xlib_surface_create(cast(void*)xDisplay, xDrawable, xVisual, width, height);
753     }
754     /* Destroy the image mask if the there is a GC created on the image */
755     if (transparentPixel !is -1 && memGC !is null) destroyMask();
756 }
757 
758 /**
759  * Destroy the receiver's mask if it exists.
760  */
761 void destroyMask() {
762     if (mask is null) return;
763     OS.g_object_unref(mask);
764     mask = null;
765 }
766 
767 override
768 void destroy() {
769     if (memGC !is null) memGC.dispose();
770     if (pixmap !is null) OS.g_object_unref(pixmap);
771     if (mask !is null) OS.g_object_unref(mask);
772     if (surface !is null) Cairo.cairo_surface_destroy(surface);
773     if (surfaceData !is null) OS.g_free(surfaceData);
774     surfaceData = null;
775     surface = null;
776     pixmap = null;
777     mask = null;
778     memGC = null;
779 }
780 
781 /**
782  * Compares the argument to the receiver, and returns true
783  * if they represent the <em>same</em> object using a class
784  * specific comparison.
785  *
786  * @param object the object to compare with this object
787  * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
788  *
789  * @see #hashCode
790  */
791 public override equals_t opEquals (Object object) {
792     if (object is this) return true;
793     if ( auto image = cast(Image)object ){
794         return device is image.device && pixmap is image.pixmap;
795     }
796     return false;
797 }
798 
799 /**
800  * Returns the color to which to map the transparent pixel, or null if
801  * the receiver has no transparent pixel.
802  * <p>
803  * There are certain uses of Images that do not support transparency
804  * (for example, setting an image into a button or label). In these cases,
805  * it may be desired to simulate transparency by using the background
806  * color of the widget to paint the transparent pixels of the image.
807  * Use this method to check which color will be used in these cases
808  * in place of transparency. This value may be set with setBackground().
809  * <p>
810  *
811  * @return the background color of the image, or null if there is no transparency in the image
812  *
813  * @exception SWTException <ul>
814  *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
815  * </ul>
816  */
817 public Color getBackground() {
818     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
819     if (transparentPixel is -1) return null;
820     //NOT DONE
821     return null;
822 }
823 
824 /**
825  * Returns the bounds of the receiver. The rectangle will always
826  * have x and y values of 0, and the width and height of the
827  * image.
828  *
829  * @return a rectangle specifying the image's bounds
830  *
831  * @exception SWTException <ul>
832  *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
833  *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
834  * </ul>
835  */
836 public Rectangle getBounds() {
837     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
838     if (width !is -1 && height !is -1) {
839         return new Rectangle(0, 0, width, height);
840     }
841     int w, h;
842     OS.gdk_drawable_get_size(pixmap, &w, &h);
843     return new Rectangle(0, 0, width = w, height = h);
844 }
845 
846 /**
847  * Returns an <code>ImageData</code> based on the receiver
848  * Modifications made to this <code>ImageData</code> will not
849  * affect the Image.
850  *
851  * @return an <code>ImageData</code> containing the image's data and attributes
852  *
853  * @exception SWTException <ul>
854  *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
855  *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
856  * </ul>
857  *
858  * @see ImageData
859  */
860 public ImageData getImageData() {
861     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
862 
863     int w, h;
864     OS.gdk_drawable_get_size(pixmap, &w, &h);
865     int width = w, height = h;
866     auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
867     if (pixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
868     auto colormap = OS.gdk_colormap_get_system();
869     OS.gdk_pixbuf_get_from_drawable(pixbuf, pixmap, colormap, 0, 0, 0, 0, width, height);
870     int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
871     auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
872     byte[] srcData = new byte[stride * height];
873     OS.memmove(srcData.ptr, pixels, srcData.length);
874     OS.g_object_unref(pixbuf);
875 
876     PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
877     ImageData data = new ImageData(width, height, 24, palette);
878     data.data = srcData;
879     data.bytesPerLine = stride;
880 
881     if (transparentPixel is -1 && type is SWT.ICON && mask !is null) {
882         /* Get the icon mask data */
883         auto gdkImagePtr = OS.gdk_drawable_get_image(mask, 0, 0, width, height);
884         if (gdkImagePtr is null) SWT.error(SWT.ERROR_NO_HANDLES);
885         GdkImage* gdkImage = new GdkImage();
886         OS.memmove(gdkImage, gdkImagePtr, GdkImage.sizeof );
887         byte[] maskData = new byte[gdkImage.bpl * gdkImage.height];
888         OS.memmove(maskData.ptr, gdkImage.mem, maskData.length);
889         OS.g_object_unref(gdkImagePtr);
890         int maskPad;
891         for (maskPad = 1; maskPad < 128; maskPad++) {
892             int bpl = ((((width + 7) / 8) + (maskPad - 1)) / maskPad * maskPad);
893             if (gdkImage.bpl is bpl) break;
894         }
895         /* Make mask scanline pad equals to 2 */
896         data.maskPad = 2;
897         maskData = ImageData.convertPad(maskData, width, height, 1, maskPad, data.maskPad);
898         /* Bit swap the mask data if necessary */
899         if (gdkImage.byte_order is OS.GDK_LSB_FIRST) {
900             for (int i = 0; i < maskData.length; i++) {
901                 byte b = maskData[i];
902                 maskData[i] = cast(byte)(((b & 0x01) << 7) | ((b & 0x02) << 5) |
903                     ((b & 0x04) << 3) | ((b & 0x08) << 1) | ((b & 0x10) >> 1) |
904                     ((b & 0x20) >> 3) | ((b & 0x40) >> 5) | ((b & 0x80) >> 7));
905             }
906         }
907         data.maskData = maskData;
908     }
909     data.transparentPixel = transparentPixel;
910     data.alpha = alpha;
911     if (alpha is -1 && alphaData !is null) {
912         data.alphaData = new byte[alphaData.length];
913         System.arraycopy(alphaData, 0, data.alphaData, 0, alphaData.length);
914     }
915     return data;
916 }
917 
918 /**
919  * Invokes platform specific functionality to allocate a new image.
920  * <p>
921  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
922  * API for <code>Image</code>. It is marked public only so that it
923  * can be shared within the packages provided by SWT. It is not
924  * available on all platforms, and should never be called from
925  * application code.
926  * </p>
927  *
928  * @param device the device on which to allocate the color
929  * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>)
930  * @param pixmap the OS handle for the image
931  * @param mask the OS handle for the image mask
932  *
933  * @private
934  */
935 public static Image gtk_new(Device device, int type, GdkDrawable* pixmap, GdkDrawable* mask) {
936     Image image = new Image(device);
937     image.type = type;
938     image.pixmap = cast(GdkDrawable*)pixmap;
939     image.mask = cast(GdkDrawable*)mask;
940     return image;
941 }
942 
943 /**
944  * Returns an integer hash code for the receiver. Any two
945  * objects that return <code>true</code> when passed to
946  * <code>equals</code> must return the same value for this
947  * method.
948  *
949  * @return the receiver's hash
950  *
951  * @see #equals
952  */
953 public override hash_t toHash () {
954     return cast(hash_t)pixmap;
955 }
956 
957 void init_(int width, int height) {
958     if (width <= 0 || height <= 0) {
959         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
960     }
961     this.type = SWT.BITMAP;
962 
963     /* Create the pixmap */
964     this.pixmap = cast(GdkDrawable*) OS.gdk_pixmap_new(cast(GdkDrawable*)OS.GDK_ROOT_PARENT(), width, height, -1);
965     if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
966     /* Fill the bitmap with white */
967     GdkColor* white = new GdkColor();
968     white.red = 0xFFFF;
969     white.green = 0xFFFF;
970     white.blue = 0xFFFF;
971     auto colormap = OS.gdk_colormap_get_system();
972     OS.gdk_colormap_alloc_color(colormap, white, true, true);
973     auto gdkGC = OS.gdk_gc_new(pixmap);
974     OS.gdk_gc_set_foreground(gdkGC, white);
975     OS.gdk_draw_rectangle(pixmap, gdkGC, 1, 0, 0, width, height);
976     OS.g_object_unref(gdkGC);
977     OS.gdk_colormap_free_colors(colormap, white, 1);
978 }
979 
980 void init_(ImageData image) {
981     if (image is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
982     int width = image.width;
983     int height = image.height;
984     PaletteData palette = image.palette;
985     if (!(((image.depth is 1 || image.depth is 2 || image.depth is 4 || image.depth is 8) && !palette.isDirect) ||
986         ((image.depth is 8) || (image.depth is 16 || image.depth is 24 || image.depth is 32) && palette.isDirect)))
987             SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
988     auto pixbuf = OS.gdk_pixbuf_new( OS.GDK_COLORSPACE_RGB, false, 8, width, height);
989     if (pixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
990     int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
991     auto data = OS.gdk_pixbuf_get_pixels(pixbuf);
992     byte[] buffer = image.data;
993     if (!palette.isDirect || image.depth !is 24 || stride !is image.bytesPerLine || palette.redMask !is 0xFF0000 || palette.greenMask !is 0xFF00 || palette.blueMask !is 0xFF) {
994         buffer = new byte[stride * height];
995         if (palette.isDirect) {
996             ImageData.blit(ImageData.BLIT_SRC,
997                 image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
998                 ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
999                 buffer, 24, stride, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
1000                 false, false);
1001         } else {
1002             RGB[] rgbs = palette.getRGBs();
1003             auto length = rgbs.length;
1004             byte[] srcReds = new byte[length];
1005             byte[] srcGreens = new byte[length];
1006             byte[] srcBlues = new byte[length];
1007             for (ptrdiff_t i = 0; i < rgbs.length; i++) {
1008                 RGB rgb = rgbs[i];
1009                 if (rgb is null) continue;
1010                 srcReds[i] = cast(byte)rgb.red;
1011                 srcGreens[i] = cast(byte)rgb.green;
1012                 srcBlues[i] = cast(byte)rgb.blue;
1013             }
1014             ImageData.blit(ImageData.BLIT_SRC,
1015                 image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
1016                 ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
1017                 buffer, 24, stride, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
1018                 false, false);
1019         }
1020     }
1021     OS.memmove(data, buffer.ptr, stride * height);
1022     auto pixmap = cast(GdkDrawable*) OS.gdk_pixmap_new (cast(GdkDrawable*) OS.GDK_ROOT_PARENT(), width, height, -1);
1023     if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
1024     auto gdkGC = OS.gdk_gc_new(pixmap);
1025     if (gdkGC is null) SWT.error(SWT.ERROR_NO_HANDLES);
1026     OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
1027     OS.g_object_unref(gdkGC);
1028     OS.g_object_unref(pixbuf);
1029 
1030     bool isIcon = image.getTransparencyType() is SWT.TRANSPARENCY_MASK;
1031     if (isIcon || image.transparentPixel !is -1) {
1032         if (image.transparentPixel !is -1) {
1033             RGB rgb = null;
1034             if (palette.isDirect) {
1035                 rgb = palette.getRGB(image.transparentPixel);
1036             } else {
1037                 if (image.transparentPixel < palette.colors.length) {
1038                     rgb = palette.getRGB(image.transparentPixel);
1039                 }
1040             }
1041             if (rgb !is null) {
1042                 transparentPixel = rgb.red << 16 | rgb.green << 8 | rgb.blue;
1043             }
1044         }
1045         auto mask = createMask(image, isIcon);
1046         if (mask is null) SWT.error(SWT.ERROR_NO_HANDLES);
1047         this.mask = mask;
1048         if (isIcon) {
1049             this.type = SWT.ICON;
1050         } else {
1051             this.type = SWT.BITMAP;
1052         }
1053     } else {
1054         this.type = SWT.BITMAP;
1055         this.mask = null;
1056         this.alpha = image.alpha;
1057         if (image.alpha is -1 && image.alphaData !is null) {
1058             this.alphaData = new byte[image.alphaData.length];
1059             System.arraycopy(image.alphaData, 0, this.alphaData, 0, alphaData.length);
1060         }
1061         createAlphaMask(width, height);
1062     }
1063     this.pixmap = pixmap;
1064 }
1065 
1066 /**
1067  * Invokes platform specific functionality to allocate a new GC handle.
1068  * <p>
1069  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
1070  * API for <code>Image</code>. It is marked public only so that it
1071  * can be shared within the packages provided by SWT. It is not
1072  * available on all platforms, and should never be called from
1073  * application code.
1074  * </p>
1075  *
1076  * @param data the platform specific GC data
1077  * @return the platform specific GC handle
1078  */
1079 public GdkGC* internal_new_GC (GCData data) {
1080     if (pixmap is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1081     if (type !is SWT.BITMAP || memGC !is null) {
1082         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1083     }
1084     auto gdkGC = OS.gdk_gc_new(pixmap);
1085     if (data !is null) {
1086         int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
1087         if ((data.style & mask) is 0) {
1088             data.style |= SWT.LEFT_TO_RIGHT;
1089         } else {
1090             if ((data.style & SWT.RIGHT_TO_LEFT) !is 0) {
1091                 data.style |= SWT.MIRRORED;
1092             }
1093         }
1094         data.device = device;
1095         data.drawable = pixmap;
1096         data.background = device.COLOR_WHITE.handle;
1097         data.foreground = device.COLOR_BLACK.handle;
1098         data.font = device.systemFont;
1099         data.image = this;
1100     }
1101     return gdkGC;
1102 }
1103 
1104 /**
1105  * Invokes platform specific functionality to dispose a GC handle.
1106  * <p>
1107  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
1108  * API for <code>Image</code>. It is marked public only so that it
1109  * can be shared within the packages provided by SWT. It is not
1110  * available on all platforms, and should never be called from
1111  * application code.
1112  * </p>
1113  *
1114  * @param hDC the platform specific GC handle
1115  * @param data the platform specific GC data
1116  */
1117 public void internal_dispose_GC ( GdkGC* gdkGC, GCData data) {
1118     OS.g_object_unref(gdkGC);
1119 }
1120 
1121 /**
1122  * Returns <code>true</code> if the image has been disposed,
1123  * and <code>false</code> otherwise.
1124  * <p>
1125  * This method gets the dispose state for the image.
1126  * When an image has been disposed, it is an error to
1127  * invoke any other method using the image.
1128  *
1129  * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
1130  */
1131 public override bool isDisposed() {
1132     return pixmap is null;
1133 }
1134 
1135 /**
1136  * Sets the color to which to map the transparent pixel.
1137  * <p>
1138  * There are certain uses of <code>Images</code> that do not support
1139  * transparency (for example, setting an image into a button or label).
1140  * In these cases, it may be desired to simulate transparency by using
1141  * the background color of the widget to paint the transparent pixels
1142  * of the image. This method specifies the color that will be used in
1143  * these cases. For example:
1144  * <pre>
1145  *    Button b = new Button();
1146  *    image.setBackground(b.getBackground());
1147  *    b.setImage(image);
1148  * </pre>
1149  * </p><p>
1150  * The image may be modified by this operation (in effect, the
1151  * transparent regions may be filled with the supplied color).  Hence
1152  * this operation is not reversible and it is not legal to call
1153  * this function twice or with a null argument.
1154  * </p><p>
1155  * This method has no effect if the receiver does not have a transparent
1156  * pixel value.
1157  * </p>
1158  *
1159  * @param color the color to use when a transparent pixel is specified
1160  *
1161  * @exception IllegalArgumentException <ul>
1162  *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
1163  *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
1164  * </ul>
1165  * @exception SWTException <ul>
1166  *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1167  * </ul>
1168  */
1169 public void setBackground(Color color) {
1170     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1171     if (color is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1172     if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1173     if (transparentPixel is -1) return;
1174     //NOT DONE
1175 }
1176 
1177 /**
1178  * Returns a string containing a concise, human-readable
1179  * description of the receiver.
1180     import tango.core.Exception;
1181  *
1182  * @return a string representation of the receiver
1183  */
1184 public override String toString () {
1185     if (isDisposed()) return "Image {*DISPOSED*}";
1186     return Format( "Image {{{}}", pixmap);
1187 }
1188 
1189 }
1190