Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / Image / source / Image.c
blob1b03753164718096c7e0ea7380617dfea6c5794c
1 /*
2 docCopyright("Steve Dekorte", 2002)
3 docLicense("BSD revised")
4 */
5 #include "Image.h"
6 #include <stdio.h>
7 #include <stdlib.h>
9 #ifndef _WIN32
10 #include <unistd.h>
11 #endif
13 #include <string.h>
14 #include <ctype.h>
15 #include <math.h>
17 #include "PNGImage.h"
18 #include "JPGImage.h"
19 #include "TIFFImage.h"
22 #include <stdarg.h>
23 typedef void (*TIFFErrorHandler)(const char* module, const char* fmt, va_list ap);
24 TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler handler);
27 Image *Image_new(void)
29 Image *self = (Image *)calloc(1, sizeof(Image));
30 Image_path_(self, "");
31 Image_fileType_(self, "");
32 self->byteArray = UArray_new();
33 self->ownsUArray = 1;
34 self->componentCount = 4;
35 self->encodingQuality = 1.0;
36 return self;
39 Image *Image_newWithPath_(char *path)
41 Image *self = Image_new();
42 Image_path_(self, path);
43 Image_load(self);
44 return self;
47 Image *Image_copyWithUArray_(Image *self, UArray *ba)
49 Image *image = Image_new();
51 Image_setExternalUArray_(image, ba);
52 Image_path_(image, self->path);
53 Image_error_(image, self->error);
55 image->width = self->width;
56 image->height = self->height;
57 image->componentCount = self->componentCount;
59 image->encodingQuality = self->encodingQuality;
60 image->decodingWidthHint = self->decodingWidthHint;
61 image->decodingHeightHint = self->decodingHeightHint;
63 return image;
66 void Image_free(Image *self)
68 if (self->ownsUArray)
70 UArray_free(self->byteArray);
73 if (self->error)
75 free(self->error);
78 free(self->fileType);
79 free(self->path);
81 free(self);
84 UArray *Image_byteArray(Image *self)
86 return self->byteArray;
89 void Image_copyUArray_(Image *self, UArray *ba) /* private */
91 UArray_copy_(self->byteArray, ba);
94 void Image_setExternalUArray_(Image *self, UArray *ba)
96 if (self->ownsUArray) UArray_free(self->byteArray);
97 self->byteArray = ba;
98 self->ownsUArray = 0;
101 void Image_getFileType(Image *self) /* private */
103 char *ext = strrchr(self->path, '.');
104 char *e;
105 if (!ext) { Image_fileType_(self, ""); return; }
107 ext++;
108 Image_fileType_(self, ext);
109 e = self->fileType;
111 while (*e) { *e = tolower(*e); e++; }
112 if (strcmp(self->fileType, "jpeg")==0) Image_fileType_(self, "jpg");
115 void Image_path_(Image *self, const char *path)
117 self->path = strcpy((char *)realloc(self->path, strlen(path)+1), path);
118 Image_getFileType(self);
121 char *Image_path(Image *self)
123 return self->path;
126 void Image_fileType_(Image *self, const char *fileType)
128 self->fileType = strcpy((char *)realloc(self->fileType, strlen(fileType)+1), fileType);
131 char *Image_fileType(Image *self) { return self->fileType; }
133 void Image_error_(Image *self, const char *error)
135 if (error && strlen(error))
137 /*printf("Image_error_(%s)\n", error);*/
138 self->error = strcpy((char *)realloc(self->error, strlen(error)+1), error);
140 else
142 if (self->error) free(self->error);
143 self->error = NULL;
147 char *Image_error(Image *self) { return self->error; }
150 void Image_setData_width_height_componentCount_(Image *self, UArray *ba, int width, int height, int componentCount)
152 int size = width * height * componentCount;
154 if (size != UArray_size(ba))
156 printf("Image_setData_width_height_componentCount_() error - %i x %i x %i = %i, but buffer is %i\n",
157 width, height, componentCount, size, (int)UArray_size(ba));
158 return;
161 Image_copyUArray_(self, ba);
162 self->width = width;
163 self->height = height;
164 self->componentCount = componentCount;
167 void Image_load(Image *self)
169 if (strcmp(self->fileType, "png")==0)
171 PNGImage *image = PNGImage_new();
172 PNGImage_setExternalUArray_(image, self->byteArray);
173 PNGImage_path_(image, self->path);
174 PNGImage_load(image);
175 Image_error_(self, PNGImage_error(image));
176 self->width = PNGImage_width(image);
177 self->height = PNGImage_height(image);
178 self->componentCount = PNGImage_components(image);
179 PNGImage_free(image);
181 else if (strcmp(self->fileType, "jpg")==0)
183 JPGImage *image = JPGImage_new();
184 JPGImage_setExternalUArray_(image, self->byteArray);
185 JPGImage_path_(image, self->path);
186 JPGImage_decodingWidthHint_(image, self->decodingWidthHint);
187 JPGImage_decodingHeightHint_(image, self->decodingHeightHint);
188 JPGImage_load(image);
189 Image_error_(self, JPGImage_error(image));
190 self->width = JPGImage_width(image);
191 self->height = JPGImage_height(image);
192 self->componentCount = JPGImage_components(image);
193 JPGImage_free(image);
195 else if (strcmp(self->fileType, "tif")==0 || strcmp(self->fileType, "tiff")==0)
197 TIFFImage *image = TIFFImage_new();
198 TIFFImage_setExternalUArray_(image, self->byteArray);
199 TIFFImage_path_(image, self->path);
200 TIFFImage_load(image);
201 Image_error_(self, TIFFImage_error(image));
202 self->width = TIFFImage_width(image);
203 self->height = TIFFImage_height(image);
204 self->componentCount = TIFFImage_components(image);
205 TIFFImage_free(image);
207 else
209 Image_error_(self, "unknown file type");
212 if (UArray_size(self->byteArray) == 0)
214 Image_error_(self, "error reading file");
218 void Image_save(Image *self)
220 //Image_flipY(self);
222 if (strcmp(self->fileType, "png")==0)
224 PNGImage *image = PNGImage_new();
225 PNGImage_setExternalUArray_(image, self->byteArray);
226 PNGImage_path_(image, self->path);
227 PNGImage_width_(image, self->width);
228 PNGImage_height_(image, self->height);
229 PNGImage_components_(image, Image_componentCount(self));
230 PNGImage_save(image);
231 Image_error_(self, PNGImage_error(image));
232 PNGImage_free(image);
234 else if (strcmp(self->fileType, "jpg")==0)
236 JPGImage *image = JPGImage_new();
237 JPGImage_setExternalUArray_(image, self->byteArray);
238 JPGImage_path_(image, self->path);
239 JPGImage_quality_(image, self->encodingQuality);
240 JPGImage_width_(image, self->width);
241 JPGImage_height_(image, self->height);
242 /* TODO - convert image to RGB first */
243 if (Image_componentCount(self) != 3)
245 Image_error_(self, "can only save RGB images to JPEG");
246 return;
248 JPGImage_components_(image, Image_componentCount(self));
249 JPGImage_save(image);
250 Image_error_(self, JPGImage_error(image));
251 JPGImage_free(image);
253 else if (strcmp(self->fileType, "tiff")==0 || strcmp(self->fileType, "tif")==0)
255 TIFFImage *image = TIFFImage_new();
256 TIFFImage_setExternalUArray_(image, self->byteArray);
257 TIFFImage_path_(image, self->path);
258 TIFFImage_width_(image, self->width);
259 TIFFImage_height_(image, self->height);
260 TIFFImage_components_(image, Image_componentCount(self));
261 TIFFImage_save(image);
262 Image_error_(self, TIFFImage_error(image));
263 TIFFImage_free(image);
265 else
267 Image_error_(self, "unknown file type");
270 //Image_flipY(self);
273 int Image_width(Image *self)
275 return self->width;
278 int Image_height(Image *self)
280 return self->height;
283 int Image_componentCount(Image *self)
285 return self->componentCount;
288 int Image_sizeInBytes(Image *self)
290 return self->height * self->width * self->componentCount;
293 uint8_t *Image_data(Image *self)
295 return (uint8_t *)UArray_bytes(self->byteArray);
298 void Image_data_length_(Image *self, unsigned char *data, size_t length)
300 UArray_setData_type_size_copy_(self->byteArray, data, CTYPE_uint8_t, length, 1);
304 void Image_flipY(Image *self)
306 int y;
307 int w = self->width;
308 int h = self->height;
309 int componentCount = self->componentCount;
310 uint8_t *bytes = UArray_mutableBytes(self->byteArray);
311 int bytesPerLine = componentCount * w;
312 unsigned char *buf = malloc(bytesPerLine);
314 for (y = 0; y < self->height/2; y ++)
316 uint8_t *a = bytes + componentCount * (y * w);
317 uint8_t *b = bytes + componentCount * ((h-1-y) * w);
319 memcpy(buf, a, bytesPerLine);
320 memcpy(a, b, bytesPerLine);
321 memcpy(b, buf, bytesPerLine);
326 void Image_resizeTo(Image *self, int w, int h, Image *outImage)
328 int componentCount = self->componentCount;
330 int inStride = self->width * componentCount;
331 uint8_t *inPtr = Image_data(self);
333 int outStride = w * componentCount;
334 UArray *outUArray = UArray_new();
335 UArray_setSize_(outUArray, h * outStride);
336 uint8_t *outPtr = (uint8_t *)UArray_bytes(outUArray);
338 int y;
339 for (y=0; y < self->height; y++, inPtr += inStride, outPtr += outStride)
340 memcpy(outPtr, inPtr, inStride);
342 Image_setData_width_height_componentCount_(outImage, outUArray, w, h, componentCount);
345 inline unsigned char *Image_pixelAt(Image *self, int x, int y)
347 int bps = 8;
348 int spp = Image_componentCount(self);
349 int w = self->width;
350 int h = self->height;
351 uint8_t *p = (uint8_t *)UArray_bytes(self->byteArray);
353 if (x < 0) { x = 0; } else if (x > w - 1) { x = w - 1; }
354 if (y < 0) { y = 0; } else if (y > h - 1) { y = h - 1; }
355 return p + (((x + (y * w)) * (spp * bps)) / 8);
358 void Image_crop(Image *self, int cx, int cy, int w, int h)
360 int pixelSize = Image_componentCount(self);
361 int x, y;
363 if (cx > self->width) { Image_error_(self, "crop x > width"); return; }
364 if (cy > self->height) { Image_error_(self, "crop y > height"); return; }
365 if (cx+w > self->width) { w = self->width - cx; }
366 if (cy+h > self->height) { h = self->height - cy; }
368 for (x = 0; x < w; x ++)
370 for (y = 0; y < h; y ++)
372 unsigned char *ip = Image_pixelAt(self, cx+x, cy+y);
373 unsigned char *op = Image_pixelAt(self, x, y);
374 memcpy(op, ip, pixelSize);
377 UArray_setSize_(self->byteArray, w*h*pixelSize);
378 self->width = w;
379 self->height = h;
383 /* --- extras --------------------------------------------------------- */
385 void Image_encodingQuality_(Image *self, float q)
387 self->encodingQuality = q;
390 float Image_encodingQuality(Image *self)
392 return self->encodingQuality;
395 void Image_decodingWidthHint_(Image *self, int v)
397 self->decodingWidthHint = v;
400 int Image_decodingWidthHint(Image *self)
402 return self->decodingWidthHint;
405 void Image_decodingHeightHint_(Image *self, int v)
407 self->decodingHeightHint = v;
410 int Image_decodingHeightHint(Image *self)
412 return self->decodingHeightHint;