Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / Image / source / IoImage.c
blobc6fc13841e8eef5a659324a2330dc73a68309a70
1 /*#io
2 Image ioDoc(
3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
5 docCategory("Graphics")
6 docDescription("The Image object can read and draw images and provide the image data as a buffer. Example use;
7 <pre>
8 image = Image clone open(\"curly.png\")
9 image draw
10 image scaleTo(image width / 2, image height / 2)
11 image save(\"curly.tiff\")
12 </pre>
13 When loading an attempt will be made to convert the image into whichever of the following formats it is closest to: L8, LA8, RGB8, RGBA8.
14 <p>
15 Currently supported formats include PNG(which supports alpha), JPG and TIFF. ")
18 #include "IoImage.h"
19 #include "List.h"
20 #include "IoState.h"
21 #include "IoNumber.h"
22 #include "IoSeq.h"
23 #include "Image.h"
25 #define DATA(self) ((IoImageData *)IoObject_dataPointer(self))
27 IoTag *IoImage_newTag(void *state)
29 IoTag *tag = IoTag_newWithName_("Image");
30 IoTag_state_(tag, state);
31 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoImage_rawClone);
32 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoImage_free);
33 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoImage_mark);
34 return tag;
37 IoImage *IoImage_proto(void *state)
39 IoObject *self = IoObject_new(state);
40 IoObject_tag_(self, IoImage_newTag(state));
42 IoObject_setDataPointer_(self, calloc(1, sizeof(IoImageData)));
44 DATA(self)->buffer = IoSeq_newWithCString_(IOSTATE, "");
45 DATA(self)->image = Image_new();
46 Image_setExternalUArray_(DATA(self)->image, IoSeq_rawUArray(DATA(self)->buffer));
48 IoState_registerProtoWithFunc_(state, self, IoImage_proto);
51 IoMethodTable methodTable[] = {
52 {"setDataWidthHeightComponentCount", IoImage_setDataWidthHeightComponentCount},
53 {"setPath", IoImage_setPath},
54 {"open", IoImage_open},
55 {"save", IoImage_save},
57 {"width", IoImage_width},
58 {"height", IoImage_height},
60 {"data", IoImage_data},
61 {"componentCount", IoImage_componentCount},
62 {"isL8", IoImage_isL8},
63 {"isLA8", IoImage_isLA8},
64 {"isRGB8", IoImage_isRGB8},
65 {"isRGBA8", IoImage_isRGBA8},
66 {"error", IoImage_error},
67 {"resizedTo", IoImage_resizedTo},
68 {"crop", IoImage_crop},
70 // extras
72 {"setEncodingQuality", IoImage_setEncodingQuality},
73 {"encodingQuality", IoImage_encodingQuality},
75 {"setDecodingWidthHint", IoImage_setDecodingWidthHint},
76 {"decodingWidthHint", IoImage_decodingWidthHint},
78 {"setDecodingHeightHint", IoImage_setDecodingHeightHint},
79 {"decodingHeightHint", IoImage_decodingHeightHint},
80 {NULL, NULL},
82 IoObject_addMethodTable_(self, methodTable);
84 return self;
87 IoImage *IoImage_rawClone(IoImage *proto)
89 IoObject *self = IoObject_rawClonePrimitive(proto);
90 IoObject_setDataPointer_(self, cpalloc(IoObject_dataPointer(proto), sizeof(IoImageData)));
91 DATA(self)->buffer = IOCLONE(DATA(proto)->buffer);
92 DATA(self)->image = Image_copyWithUArray_(DATA(proto)->image, IoSeq_rawUArray(DATA(self)->buffer));
93 return self;
96 IoImage *IoImage_new(void *state)
98 IoObject *proto = IoState_protoWithInitFunction_(state, IoImage_proto);
99 return IOCLONE(proto);
102 /* ----------------------------------------------------------- */
104 void IoImage_free(IoImage *self)
106 Image_free(DATA(self)->image);
107 free(IoObject_dataPointer(self));
110 void IoImage_mark(IoImage *self)
112 IoObject_shouldMark(DATA(self)->buffer);
115 Image *IoImage_image(IoImage *self)
117 return DATA(self)->image;
120 Image *IoImage_rawImage(IoImage *self)
122 return DATA(self)->image;
125 /* ----------------------------------------------------------- */
127 IoObject *IoImage_path(IoImage *self, IoObject *locals, IoMessage *m)
129 /*#io
130 docSlot("path",
131 "Returns the image path. ")
134 return IOSYMBOL(Image_path(DATA(self)->image));
137 IoObject *IoImage_setPath(IoImage *self, IoObject *locals, IoMessage *m)
139 /*#io
140 docSlot("setPath(aString)",
141 "Sets the image path. Returns self. ")
144 IoSymbol *s = IoMessage_locals_symbolArgAt_(m, locals, 0);
145 Image_path_(DATA(self)->image, CSTRING(s));
146 return self;
149 void IoImage_checkError(IoImage *self, IoObject *locals, IoMessage *m)
151 const char *e = Image_error(DATA(self)->image);
153 if (e != NULL)
155 IoState_error_(IOSTATE, m, "Image %s on %s", e, Image_path(DATA(self)->image));
160 IoObject *IoImage_setDataWidthHeightComponentCount(IoImage *self, IoObject *locals, IoMessage *m)
162 /*#io
163 docSlot("setDataWidthHeightComponentCount(aSequence, width, height, componentCount)",
164 "Sets the image data and it's parameters. Returns self.")
167 IoSeq *data = IoMessage_locals_seqArgAt_(m, locals, 0);
168 int w = IoMessage_locals_intArgAt_(m, locals, 1);
169 int h = IoMessage_locals_intArgAt_(m, locals, 2);
170 int c = IoMessage_locals_intArgAt_(m, locals, 3);
172 Image_setData_width_height_componentCount_(DATA(self)->image, IoSeq_rawUArray(data), w, h, c);
174 return self;
177 IoObject *IoImage_open(IoImage *self, IoObject *locals, IoMessage *m)
179 /*#io
180 docSlot("open(optionalPathString)",
181 "Sets the path to optionalPathString if provided and opens the image file. Returns self on success, Nil on failure. ")
184 /*printf("opening Image %p %s\n", self, Image_path(DATA(self)->image));*/
186 if (IoMessage_argCount(m) > 0)
188 IoSymbol *path = IoMessage_locals_symbolArgAt_(m, locals, 0);
189 Image_path_(DATA(self)->image, CSTRING(path));
192 Image_load(DATA(self)->image);
193 IoImage_checkError(self, locals, m);
194 return self;
197 IoObject *IoImage_save(IoImage *self, IoObject *locals, IoMessage *m)
199 /*#io
200 docSlot("save(optionalPathString)",
201 "Sets the path to optionalPathString if provided and saves the image in the format specified by the path extension. Returns self on success, Nil on failure. ")
204 if (IoMessage_argCount(m) > 0)
206 IoSymbol *path = IoMessage_locals_symbolArgAt_(m, locals, 0);
207 Image_path_(DATA(self)->image, CSTRING(path));
210 Image_save(DATA(self)->image);
211 IoImage_checkError(self, locals, m);
212 return self;
215 IoObject *IoImage_width(IoImage *self, IoObject *locals, IoMessage *m)
217 /*#io
218 docSlot("width", "Returns the image width. ")
221 return IONUMBER(Image_width(DATA(self)->image));
224 IoObject *IoImage_height(IoImage *self, IoObject *locals, IoMessage *m)
226 /*#io
227 docSlot("height", "Returns the image hieght. ")
230 return IONUMBER(Image_height(DATA(self)->image));
233 IoObject *IoImage_data(IoImage *self, IoObject *locals, IoMessage *m)
235 /*#io
236 docSlot("data",
237 "Returns a Buffer primitive containing the image data(loading it first if needed). Manipulating this data will effect what is drawn when the receiver's draw method is called. ")
240 return DATA(self)->buffer;
243 IoObject *IoImage_componentCount(IoImage *self, IoObject *locals, IoMessage *m)
245 return IONUMBER(Image_componentCount(DATA(self)->image));
248 IoObject *IoImage_error(IoImage *self, IoObject *locals, IoMessage *m)
250 /*#io
251 docSlot("error",
252 "Returns a String containing the current error or Nil if there is no error. ")
255 char *s = (char *)Image_error(DATA(self)->image);
257 if ((!s) || (!strlen(s)))
259 return IONIL(self);
262 return IOSYMBOL(s);
265 IoObject *IoImage_isRGB8(IoImage *self, IoObject *locals, IoMessage *m)
267 /*#io
268 docSlot("isRGB8",
269 "Returns true if the receiver is in RGB8 format, false otherwise.")
272 return IOBOOL(self, Image_componentCount(DATA(self)->image) == 3);
275 IoObject *IoImage_isRGBA8(IoImage *self, IoObject *locals, IoMessage *m)
277 /*#io
278 docSlot("isRGBA8",
279 "Returns true if the receiver is in RGBA8 format, false otherwise.")
282 return IOBOOL(self, Image_componentCount(DATA(self)->image) == 4);
285 IoObject *IoImage_isL8(IoImage *self, IoObject *locals, IoMessage *m)
287 /*#io
288 docSlot("isL8",
289 "Returns true if the receiver is in L8 (8bit Luminance) format, false otherwise.")
292 return IOBOOL(self, Image_componentCount(DATA(self)->image) == 1);
295 IoObject *IoImage_isLA8(IoImage *self, IoObject *locals, IoMessage *m)
297 /*#io
298 docSlot("isLA8",
299 "Returns true if the receiver is in LA8 (8bit Luminance-Alpha) format, false otherwise.")
302 return IOBOOL(self, Image_componentCount(DATA(self)->image) == 2);
305 IoObject *IoImage_crop(IoImage *self, IoObject *locals, IoMessage *m)
307 /*#io
308 docSlot("crop(x, y, width, height)",
309 "Crops the image to the specified values. Returns self.")
312 int cx = IoMessage_locals_intArgAt_(m, locals, 0);
313 int cy = IoMessage_locals_intArgAt_(m, locals, 1);
314 int width = IoMessage_locals_intArgAt_(m, locals, 2);
315 int height = IoMessage_locals_intArgAt_(m, locals, 3);
317 Image_crop(DATA(self)->image, cx, cy, width, height);
318 IoImage_checkError(self, locals, m);
319 return self;
322 IoObject *IoImage_resizedTo(IoImage *self, IoObject *locals, IoMessage *m)
324 int w = IoMessage_locals_intArgAt_(m, locals, 0);
325 int h = IoMessage_locals_intArgAt_(m, locals, 1);
327 IoImage *outImage = IoImage_new(IOSTATE);
328 Image_resizeTo(DATA(self)->image, w, h, DATA(outImage)->image);
329 IoImage_checkError(self, locals, m);
330 return outImage;
334 /* --- extras -------------------------------------------------------- */
336 IoObject *IoImage_setEncodingQuality(IoImage *self, IoObject *locals, IoMessage *m)
338 /*#io
339 docSlot("setEncodingQuality(aNumber)",
340 "Sets the image encoding quality (range is 0.0 - 1.0, 1.0 with being the highest).")
343 Image_encodingQuality_(DATA(self)->image, IoMessage_locals_doubleArgAt_(m, locals, 0));
344 return self;
347 IoObject *IoImage_encodingQuality(IoImage *self, IoObject *locals, IoMessage *m)
349 /*#io
350 docSlot("encodingQuality",
351 "Returns the encodingQuality setting.")
354 return IONUMBER(Image_encodingQuality(DATA(self)->image));
357 IoObject *IoImage_setDecodingWidthHint(IoImage *self, IoObject *locals, IoMessage *m)
361 Image_decodingWidthHint_(DATA(self)->image, IoMessage_locals_intArgAt_(m, locals, 0));
362 return self;
365 IoObject *IoImage_decodingWidthHint(IoImage *self, IoObject *locals, IoMessage *m)
368 return IONUMBER(Image_decodingWidthHint(DATA(self)->image));
371 IoObject *IoImage_setDecodingHeightHint(IoImage *self, IoObject *locals, IoMessage *m)
374 Image_decodingHeightHint_(DATA(self)->image, IoMessage_locals_intArgAt_(m, locals, 0));
375 return self;
378 IoObject *IoImage_decodingHeightHint(IoImage *self, IoObject *locals, IoMessage *m)
381 return IONUMBER(Image_decodingHeightHint(DATA(self)->image));