1 /** \file
2  * \brief Image Manipulation
3  *
4  * See Copyright Notice in im_lib.h
5  */
6 module im.im_image;
7 
8 version(IM) :
9 
10 import core.stdc.config : c_long;
11 import im.im : imFile, IM_RGB;
12 
13 //version(DigitalMars) version(Windows) { pragma(lib, "im.lib"); } // required anyway
14 
15 @nogc nothrow :
16 extern(C) {
17 
18 /** \defgroup imgclass imImage 
19  *
20  * \par
21  *  Base definitions and functions for image representation. \n
22  * Only the image processing operations depends on these definitions, 
23  * Image Storage and Image Capture are completely independent.
24  * \par
25  * You can also initialize a structure with your own memory buffer, see \ref imImageInit.
26  * To release the structure without releasing the buffer, 
27  * set "data[0]" to NULL before calling imImageDestroy.
28  * \par
29  * See \ref im_image.h
30  * \ingroup imagerep */
31 
32 
33 
34 /** \brief Image Representation Structure
35  *
36  * \par
37  * An image representation than supports all the color spaces, 
38  * but planes are always unpacked and the orientation is always bottom up.
39  * \ingroup imgclass */
40 struct _imImage // typedef struct _imImage  imImage;
41 {
42   /* main parameters */
43   int width;          /**< Number of columns. image:Width() -> width: number [in Lua 5]. */
44   int height;         /**< Number of lines. image:Height() -> height: number [in Lua 5]. */
45   int color_space;    /**< Color space descriptor. See also \ref imColorSpace. image:ColorSpace() -> color_space: number [in Lua 5]. */
46   int data_type;      /**< Data type descriptor. See also \ref imDataType. image:DataType() -> data_type: number [in Lua 5]. */
47   int has_alpha;      /**< Indicates that there is an extra channel with alpha. image:HasAlpha() -> has_alpha: boolean [in Lua 5]. \n
48                            It will not affect the secondary parameters, i.e. the number of planes will be in fact depth+1. \n
49                            It is always 0 unless imImageAddAlpha is called. Alpha is automatically added in image loading functions. */
50 
51   /* secondary parameters */
52   int depth;          /**< Number of planes                      (ColorSpaceDepth)   image:Depth() -> depth: number [in Lua 5].       */
53   int line_size;      /**< Number of bytes per line in one plane (width * DataTypeSize)    */
54   int plane_size;     /**< Number of bytes per plane.            (line_size * height)      */
55   int size;           /**< Number of bytes occupied by the image (plane_size * depth)      */
56   int count;          /**< Number of pixels per plane            (width * height)          */
57 
58   /* image data */
59   void** data;        /**< Image data organized as a 2D matrix with several planes.   \n
60                            But plane 0 is also a pointer to the full data.            \n
61                            The remaining planes are: "data[i] = data[0] + i*plane_size". \n
62                            In Lua, data indexing is possible using: "image[plane][line][column]". \n
63                            Also in Lua, is possible to set all pixels using a table calling "image:SetPixels(table)"
64                            and get all pixels using "table = image:GetPixels()" (Since 3.9). */
65 
66   /* image attributes */
67   c_long *palette;      /**< Color palette. image:GetPalette() -> palette: imPalette [in Lua 5]. \n
68                            Used only when depth=1. Otherwise is NULL. */
69   int palette_count;  /**< The palette is always 256 colors allocated, but can have less colors used. */
70 
71   void* attrib_table; /**< in fact is an imAttribTable, but we hide this here */
72 }
73 alias imImage = _imImage;
74 
75 /** Creates a new image.
76  * See also \ref imDataType and \ref imColorSpace. Image data is cleared as \ref imImageClear. \n
77  * In Lua the IM image metatable name is "imImage".
78  * When converted to a string will return "imImage(%p) [width=%d,height=%d,color_space=%s,data_type=%s,depth=%d]" where %p is replaced by the userdata address,
79  * and other values are replaced by the respective attributes.
80  * If the image is already destroyed by im.ImageDestroy, then it will return also the suffix "-destroyed".
81  *
82  * \verbatim im.ImageCreate(width: number, height: number, color_space: number, data_type: number) -> image: imImage [in Lua 5] \endverbatim
83  * \ingroup imgclass */
84 imImage* imImageCreate(int width, int height, int color_space, int data_type);
85 
86 /** Initializes the image structure but does not allocates image data.
87  * See also \ref imDataType and \ref imColorSpace. 
88  * The only addtional flag thar color_mode can has here is IM_ALPHA.
89  * To release the image structure without releasing the buffer, 
90  * set "data[0]" to NULL before calling imImageDestroy.
91  * \ingroup imgclass */
92 imImage* imImageInit(int width, int height, int color_mode, int data_type, void* data_buffer, c_long* palette, int palette_count);
93 
94 /** Creates a new image based on an existing one. \n
95  * If the addicional parameters are -1, the given image parameters are used. \n
96  * The image atributes always are copied. HasAlpha is copied.
97  * See also \ref imDataType and \ref imColorSpace.
98  *
99  * \verbatim im.ImageCreateBased(image: imImage, [width: number], [height: number], [color_space: number], [data_type: number]) -> image: imImage [in Lua 5] \endverbatim
100  * The addicional parameters in Lua can be nil, 
101  * and they can also be functions with the based image as a parameter to return the respective value.
102  * \ingroup imgclass */
103 imImage* imImageCreateBased(const(imImage)* image, int width, int height, int color_space, int data_type);
104 
105 /** Destroys the image and frees the memory used.
106  * image data is destroyed only if its data[0] is not NULL. \n
107  * In Lua if this function is not called, the image is destroyed by the garbage collector.
108  *
109  * \verbatim im.ImageDestroy(image: imImage) [in Lua 5] \endverbatim
110  * \verbatim image:Destroy() [in Lua 5] \endverbatim
111  * \ingroup imgclass */
112 void imImageDestroy(imImage* image);
113 
114 /** Adds an alpha channel plane and sets its value to 0 (transparent).
115  *
116  * \verbatim image:AddAlpha() [in Lua 5] \endverbatim
117  * \ingroup imgclass */
118 void imImageAddAlpha(imImage* image);
119 
120 /** Sets the alpha channel plane to a constant.
121  *
122  * \verbatim image:SetAlpha(alpha: number) [in Lua 5] \endverbatim
123  * \ingroup imgclass */
124 void imImageSetAlpha(imImage* image, float alpha);
125 
126 /** Removes the alpha channel plane if any.
127  *
128  * \verbatim image:RemoveAlpha() [in Lua 5] \endverbatim
129  * \ingroup imgclass */
130 void imImageRemoveAlpha(imImage* image);
131 
132 /** Changes the buffer size. Reallocate internal buffers if the new size is larger than the original.
133  *
134  * \verbatim image:Reshape(width: number, height: number) [in Lua 5] \endverbatim
135  * \ingroup imgclass */
136 void imImageReshape(imImage* image, int width, int height);
137 
138 /** Copy image data and attributes from one image to another. \n
139  * Images must have the same size and type.
140  *
141  * \verbatim image:Copy(dst_image: imImage) [in Lua 5] \endverbatim
142  * \ingroup imgclass */
143 void imImageCopy(const(imImage)* src_image, imImage* dst_image);
144 
145 /** Copy image data only fom one image to another. \n
146  * Images must have the same size and type.
147  *
148  * \verbatim image:CopyData(dst_image: imImage) [in Lua 5] \endverbatim
149  * \ingroup imgclass */
150 void imImageCopyData(const(imImage)* src_image, imImage* dst_image);
151 
152 /** Copies the image attributes from src to dst.
153  * Includes the pallete if defined in both images.
154  *
155  * \verbatim image:CopyAttributes(dst_image: imImage) [in Lua 5] \endverbatim
156  * \ingroup imgclass */
157 void imImageCopyAttributes(const(imImage)* src_image, imImage* dst_image);
158 
159 /** Merges the image attributes from src to dst. \n
160  * Attributes that exist in dst are not replaced. 
161  * Doens NOT include the pallete.
162  *
163  * \verbatim image:MergeAttributes(dst_image: imImage) [in Lua 5] \endverbatim
164  * \ingroup imgclass */
165 void imImageMergeAttributes(const(imImage)* src_image, imImage* dst_image);
166 
167 /** Copy one image plane fom one image to another. \n
168  * Images must have the same size and type.
169  *
170  * \verbatim image:CopyPlane(src_plane: number, dst_image: imImage, dst_plane: number) [in Lua 5] \endverbatim
171  * \ingroup imgclass */
172 void imImageCopyPlane(const(imImage)* src_image, int src_plane, imImage* dst_image, int dst_plane);
173 
174 /** Creates a copy of the image.
175  *
176  * \verbatim image:Duplicate() -> new_image: imImage [in Lua 5] \endverbatim
177  * \ingroup imgclass */
178 imImage* imImageDuplicate(const(imImage)* image);
179 
180 /** Creates a clone of the image. i.e. same attributes but ignore contents.
181  *
182  * \verbatim image:Clone() -> new_image: imImage [in Lua 5] \endverbatim
183  * \ingroup imgclass */
184 imImage* imImageClone(const(imImage)* image);
185 
186 /** Changes an extended attribute. \n
187  * The data will be internally duplicated. \n
188  * If data is NULL and count==0 the attribute is removed. \n
189  * If count is -1 and data_type is IM_BYTE then data is zero terminated.
190  * See also \ref imDataType.
191  *
192  * \verbatim image:SetAttribute(attrib: string, data_type: number, data: table of numbers or string) [in Lua 5] \endverbatim
193  * If data_type is IM_BYTE, a string can be used as data.
194  * \ingroup imgclass */
195 void imImageSetAttribute(const(imImage)* image, const(char)* attrib, int data_type, int count, const(void)* data);
196 
197 /** Changes an extended attribute as an integer.
198 *
199 * \verbatim image:SetAttribInteger(attrib: string, data_type: number, value: number) [in Lua 5] \endverbatim
200 * \ingroup imgclass */
201 void imImageSetAttribInteger(const(imImage)* image, const(char)* attrib, int data_type, int value);
202 
203 /** Changes an extended attribute as a real.
204 *
205 * \verbatim image:SetAttribReal(attrib: string, data_type: number, value: number) [in Lua 5] \endverbatim
206 * \ingroup imgclass */
207 void imImageSetAttribReal(const(imImage)* image, const(char)* attrib, int data_type, double value);
208 
209 /** Changes an extended attribute as a string.
210 *
211 * \verbatim image:SetAttribString(attrib: string, value: string) [in Lua 5] \endverbatim
212 * \ingroup imgclass */
213 void imImageSetAttribString(const(imImage)* image, const(char)* attrib, const(char)* value);
214 
215 /** Returns an extended attribute. \n
216  * Returns NULL if not found.
217  * See also \ref imDataType.
218  *
219  * \verbatim image:GetAttribute(attrib: string, [as_string: boolean]) -> data: table of numbers or string, data_type: number [in Lua 5] \endverbatim
220  * If data_type is IM_BYTE, as_string can be used to return a string instead of a table.
221  * \ingroup imgclass */
222 const(void)* imImageGetAttribute(const(imImage)* image, const(char)* attrib, int* data_type, int* count);
223 
224 /** Returns an extended attribute as an integer.
225 *
226 * \verbatim image:GetAttribInteger(attrib: string, [index: number]) -> value: number [in Lua 5] \endverbatim
227 * \ingroup imgclass */
228 int imImageGetAttribInteger(const(imImage)* image, const(char)* attrib, int index);
229 
230 /** Returns an extended attribute as a real.
231 *
232 * \verbatim image:GetAttribReal(attrib: string, [index: number]) -> value: number [in Lua 5] \endverbatim
233 * \ingroup imgclass */
234 double imImageGetAttribReal(const(imImage)* image, const(char)* attrib, int index);
235 
236 /** Returns an extended attribute as a string.
237 *
238 * \verbatim image:GetAttribString(attrib: string) -> value: string [in Lua 5] \endverbatim
239 * \ingroup imgclass */
240 const(char)* imImageGetAttribString(const(imImage)* image, const(char)* attrib);
241 
242 /** Returns a list of the attribute names. \n
243  * "attrib" must contain room enough for "attrib_count" names. Use "attrib=NULL" to return only the count.
244  *
245  * \verbatim image:GetAttributeList() -> data: table of strings [in Lua 5] \endverbatim
246  * \ingroup imgclass */
247 void imImageGetAttributeList(const(imImage)* image, char** attrib, int* attrib_count);
248 
249 /** Sets all image data to zero. But if color space is YCBCR, LAB or LUV, and data type is BYTE or USHORT, then
250  * data is initialized with 128 or 32768 accordingly. Alpha is initialized as transparent (0).
251  *
252  * \verbatim image:Clear() [in Lua 5] \endverbatim
253  * \ingroup imgclass */
254 void imImageClear(imImage* image);
255 
256 /** Indicates that the image can be viewed in common graphic devices.     
257  * Data type must be IM_BYTE. Color mode can be IM_RGB, IM_MAP, IM_GRAY or IM_BINARY.
258  *
259  * \verbatim image:IsBitmap() -> is_bitmap: boolean [in Lua 5] \endverbatim
260  * \ingroup imgclass */
261 int imImageIsBitmap(const(imImage)* image);
262 
263 /** Changes the image palette.
264  * This will destroy the existing palette and replace it with the given palette pointer.
265  * Only the pointer is stored, so the palette should be a new palette and it can not be a static array.
266  *
267  * \verbatim image:SetPalette(palette: imPalette) [in Lua 5] \endverbatim
268  * \ingroup imgclass */
269 void imImageSetPalette(imImage* image, c_long* palette, int palette_count);
270 
271 /** Returns 1 if the images match width and height. Returns 0 otherwise.
272  *
273  * \verbatim image:MatchSize(image2: imImage) -> match: boolean [in Lua 5] \endverbatim
274  * \ingroup imgclass */
275 int imImageMatchSize(const(imImage)* image1, const(imImage)* image2);
276 
277 /** Returns 1 if the images match color mode and data type. Returns 0 otherwise.
278  *
279  * \verbatim image:MatchColor(image2: imImage) -> match: boolean [in Lua 5] \endverbatim
280  * \ingroup imgclass */
281 int imImageMatchColor(const(imImage)* image1, const(imImage)* image2);
282 
283 /** Returns 1 if the images match width, height and data type. Returns 0 otherwise.
284  *
285  * \verbatim image:MatchDataType(image2: imImage) -> match: boolean [in Lua 5] \endverbatim
286  * \ingroup imgclass */
287 int imImageMatchDataType(const(imImage)* image1, const(imImage)* image2);
288 
289 /** Returns 1 if the images match width, height and color space. Returns 0 otherwise.
290  *
291  * \verbatim image:MatchColorSpace(image2: imImage) -> match: boolean [in Lua 5] \endverbatim
292  * \ingroup imgclass */
293 int imImageMatchColorSpace(const(imImage)* image1, const(imImage)* image2);
294 
295 /** Returns 1 if the images match in width, height, data type and color space. Returns 0 otherwise.
296  *
297  * \verbatim image:Match(image2: imImage) -> match: boolean [in Lua 5] \endverbatim
298  * \ingroup imgclass */
299 int imImageMatch(const(imImage)* image1, const(imImage)* image2);
300 
301 /** Changes the image color space to map
302  * by just changing color_space. \n
303  * Image must be BINARY or GRAY/BYTE.
304  *
305  * \verbatim image:SetMap() [in Lua 5] \endverbatim
306  * \ingroup imgclass */
307 void imImageSetMap(imImage* image);
308 
309 /** Changes the image color space to binary 
310  * by just changing color_space and the palette.
311  * Image must be MAP or GRAY/BYTE.
312  *
313  * \verbatim image:SetBinary() [in Lua 5] \endverbatim
314  * \ingroup imgclass */
315 void imImageSetBinary(imImage* image);
316 
317 /** Changes the image color space to gray
318  * by just changing color_space and the palette.
319  * Image must be BINARY or MAP. Palette is changed only if image was BINARY.
320  *
321  * \verbatim image:SetGray() [in Lua 5] \endverbatim
322  * \ingroup imgclass */
323 void imImageSetGray(imImage* image);
324 
325 /** Changes a gray BYTE data (0,255) into a binary data (0,1), done in-place. 
326  * Color space is not changed. Data type must be IM_BYTE.
327  *
328  * \verbatim image:MakeBinary() [in Lua 5] \endverbatim
329  * \ingroup imgclass */
330 void imImageMakeBinary(imImage* image);
331 
332 /** Changes a binary data (0,1) into a gray BYTE data (0,255), done in-place. 
333  * Color space is not changed. Data type must be IM_BYTE.
334  *
335  * \verbatim image:MakeGray() [in Lua 5] \endverbatim
336  * \ingroup imgclass */
337 void imImageMakeGray(imImage* image);
338 
339 
340 
341 /** \defgroup imgfile imImage Storage
342  *
343  * \par
344  *  Functions to simplify the process of reading and writting imImage structures. 
345  *  Will also load and save the alpha planes when possible.
346  * \par
347  * See \ref im_image.h
348  * \ingroup file */
349 
350 
351 /** Loads an image from an already open file. Returns NULL if failed. \n
352  * This will call \ref imFileReadImageInfo and \ref imFileReadImageData. \n
353  * index specifies the image number between 0 and image_count-1. \n
354  * The returned image will be of the same color_space and data_type of the image in the file. \n
355  * Attributes from the file will be stored at the image.
356  * See also \ref imErrorCodes.
357  *
358  * \verbatim ifile:LoadImage([index: number]) -> image: imImage, error: number [in Lua 5] \endverbatim
359  * Default index is 0.
360  * \ingroup imgfile */
361 imImage* imFileLoadImage(imFile* ifile, int index, int* error);
362 
363 /** Loads an image from an already open file. Returns NULL if failed. \n
364  * This function assumes that the image in the file has the same parameters as the given image. \n
365  * This will call \ref imFileReadImageInfo and \ref imFileReadImageData. \n
366  * index specifies the image number between 0 and image_count-1. \n
367  * The returned image will be of the same color_space and data_type of the image in the file. \n
368  * Attributes from the file will be stored at the image.
369  * See also \ref imErrorCodes.
370  *
371  * \verbatim ifile:LoadImageFrame(index: number, image: imImage) -> error: number [in Lua 5] \endverbatim
372  * Default index is 0.
373  * \ingroup imgfile */
374 void imFileLoadImageFrame(imFile* ifile, int index, imImage* image, int* error);
375 
376 /** Loads an image from an already open file, but forces the image to be a bitmap.\n
377  * The returned imagem will be always a Bitmap image, with color_space RGB, MAP, GRAY or BINARY, and data_type IM_BYTE. \n
378  * index specifies the image number between 0 and image_count-1. \n
379  * Returns NULL if failed.
380  * Attributes from the file will be stored at the image.
381  * See also \ref imErrorCodes.
382  *
383  * \verbatim ifile:LoadBitmap([index: number]) -> image: imImage, error: number [in Lua 5] \endverbatim
384  * Default index is 0.
385  * \ingroup imgfile */
386 imImage* imFileLoadBitmap(imFile* ifile, int index, int* error);
387 
388 /** Loads an image region from an already open file. Returns NULL if failed. \n
389  * This will call \ref imFileReadImageInfo and \ref imFileReadImageData. \n
390  * index specifies the image number between 0 and image_count-1. \n
391  * The returned image will be of the same color_space and data_type of the image in the file, 
392  * or will be a Bitmap image. \n
393  * Attributes from the file will be stored at the image.
394  * See also \ref imErrorCodes. \n
395  * For now, it works only for the ECW file format.
396  *
397  * \verbatim ifile:LoadRegion(index, bitmap, xmin, xmax, ymin, ymax, width, height: number) -> image: imImage, error: number [in Lua 5] \endverbatim
398  * Default index is 0.
399  * \ingroup imgfile */
400 imImage* imFileLoadImageRegion(imFile* ifile, int index, int bitmap, int* error, 
401                                int xmin, int xmax, int ymin, int ymax, int width, int height);
402 
403 /** Loads an image from an already open file, but forces the image to be a bitmap.\n
404  * This function assumes that the image in the file has the same parameters as the given image. \n
405  * The imagem must be a Bitmap image, with color_space RGB, MAP, GRAY or BINARY, and data_type IM_BYTE. \n
406  * index specifies the image number between 0 and image_count-1. \n
407  * Returns NULL if failed.
408  * Attributes from the file will be stored at the image.
409  * See also \ref imErrorCodes.
410  *
411  * \verbatim ifile:LoadBitmapFrame(index: number, image: imImage) -> error: number [in Lua 5] \endverbatim
412  * Default index is 0.
413  * \ingroup imgfile */
414 void imFileLoadBitmapFrame(imFile* ifile, int index, imImage* image, int* error);
415 
416 /** Saves the image to an already open file. \n
417  * This will call \ref imFileWriteImageInfo and \ref imFileWriteImageData. \n
418  * Attributes from the image will be stored at the file.
419  * Returns error code.
420  *
421  * \verbatim ifile:SaveImage(image: imImage) -> error: number [in Lua 5] \endverbatim
422  * \ingroup imgfile */
423 int imFileSaveImage(imFile* ifile, const(imImage)* image);
424 
425 /** Loads an image from file. Open, loads and closes the file. \n
426  * index specifies the image number between 0 and image_count-1. \n
427  * Returns NULL if failed.
428  * Attributes from the file will be stored at the image.
429  * See also \ref imErrorCodes.
430  *
431  * \verbatim im.FileImageLoad(file_name: string, [index: number]) -> image: imImage, error: number [in Lua 5] \endverbatim
432  * Default index is 0.
433  * \ingroup imgfile */
434 imImage* imFileImageLoad(const(char)* file_name, int index, int* error);
435 
436 /** Loads an image from file, but forces the image to be a bitmap. Open, loads and closes the file. \n
437  * index specifies the image number between 0 and image_count-1. \n
438  * Returns NULL if failed.
439  * Attributes from the file will be stored at the image.
440  * See also \ref imErrorCodes.
441  *
442  * \verbatim im.FileImageLoadBitmap(file_name: string, [index: number]) -> image: imImage, error: number [in Lua 5] \endverbatim
443  * Default index is 0.
444  * \ingroup imgfile */
445 imImage* imFileImageLoadBitmap(const(char)* file_name, int index, int* error);
446 
447 /** Loads an image region from file. Open, loads and closes the file. \n
448  * index specifies the image number between 0 and image_count-1. \n
449  * Returns NULL if failed.
450  * Attributes from the file will be stored at the image.
451  * See also \ref imErrorCodes. \n
452  * For now, it works only for the ECW file format.
453  *
454  * \verbatim im.FileImageLoadRegion(file_name: string, index, bitmap, xmin, xmax, ymin, ymax, width, height: number, ) -> image: imImage, error: number [in Lua 5] \endverbatim
455  * Default index is 0.
456  * \ingroup imgfile */
457 imImage* imFileImageLoadRegion(const(char)* file_name, int index, int bitmap, int* error, 
458                                int xmin, int xmax, int ymin, int ymax, int width, int height);
459 
460 /** Saves the image to file. Open, saves and closes the file. \n
461  * Returns error code. \n
462  * Attributes from the image will be stored at the file.
463  *
464  * \verbatim im.FileImageSave(file_name: string, format: string, image: imImage) -> error: number [in Lua 5] \endverbatim
465  * \verbatim image:Save(file_name: string, format: string) -> error: number [in Lua 5] \endverbatim
466  * \ingroup imgfile */
467 int imFileImageSave(const(char)* file_name, const(char)* format, const(imImage)* image);
468 
469 } // extern(C)
470 
471 version(CD) {
472   import cd.cd : cdCanvas, cdCanvasPutImageRectRGB, cdCanvasPutImageRectRGBA, cdCanvasPutImageRectMap;
473 
474   /** Utility macro to draw the image in a CD library canvas.
475    * Works only for data_type IM_BYTE, and color spaces: IM_RGB, IM_MAP, IMGRAY and IM_BINARY.
476    * \ingroup imgclass */ // C origin was a #define : doesn't need to have C-linkage
477   void imcdCanvasPutImage(cdCanvas* _canvas, imImage* _image, int _x, int _y, int _w, int _h, int _xmin, int _xmax, int _ymin, int _ymax)
478   {
479     if (_image.color_space == IM_RGB)
480     {
481       if (_image.has_alpha)
482         cdCanvasPutImageRectRGBA(_canvas, _image.width, _image.height,
483                           cast(ubyte*)_image.data[0],
484                           cast(ubyte*)_image.data[1],
485                           cast(ubyte*)_image.data[2],
486                           cast(ubyte*)_image.data[3],
487                           _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);
488       else
489         cdCanvasPutImageRectRGB(_canvas, _image.width, _image.height,
490                           cast(ubyte*)_image.data[0],
491                           cast(ubyte*)_image.data[1],
492                           cast(ubyte*)_image.data[2],
493                           _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);
494     }
495     else
496       cdCanvasPutImageRectMap(_canvas, _image.width, _image.height,
497                         cast(ubyte*)_image.data[0], _image.palette,
498                         _x, _y, _w, _h, _xmin, _xmax, _ymin, _ymax);
499   }
500 
501 } // version(CD)