1
2 /**
3 * IMAGE OPCODES
4 *
5 * imageOpcodes.c
6 *
7 * Copyright (c) 2007 by Cesare Marilungo. All rights reserved.
8 *
9 * L I C E N S E
10 *
11 * This software is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this software; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * C S O U N D M A N P A G E
26 *
27 * imageload - opens an image (in PNG format)
28 * imagesave - saves an image (in PNG format)
29 * imagecreate - create an empty image
30 * imagesize - gets the size of an image
31 * imagegetpixel - gets the rgb values of a pixel
32 * imagesetpixel - sets the rgb values of a pixel
33 * imagefree - free memory from a previously loaded or created image.
34 *
35 * SYNTAX
36 *
37 * iImageNumber imageload sFilename
38 *
39 * imageSave iImageNumber, sFilename
40 *
41 * iImageNumber imagecreate iWidth, iHeight
42 *
43 * iWidth, iHeight imagesize iImageNumber
44 *
45 * kred, kgreen, kblue imagegetpixel iImageNumber, kX, kY
46 * ared, agreen, ablue imagegetpixel iImageNumber, aX, aY
47 *
48 * imagesetpixel iImageNumber, kX, kY, kred, kgreen, kblue
49 * imagesetpixel iImageNumber, aX, aY, ared, agreen, ablue
50 *
51 * imageFree iImageNumber
52 *
53 */
54
55 #define USE_LIBPNG
56
57 #ifdef USE_LIBPNG
58 #include <png.h>
59 #else
60 #include <Imlib.h>
61 #include <X11/Xlib.h>
62 #endif
63
64 /* #include <SDL/SDL.h> */
65 /* #include <SDL/SDL_image.h> */
66
67 #include "csdl.h"
68 #include "imageOpcodes.h"
69
70 /*
71 __doOpenImage and __doSaveImage are the only two functions that deal
72 with the actual image loading saving library.
73
74 imageData stores the image content as an array of RGB bytes for each
75 row (l->r t->b) so a pixel value in imageData is located at: (w*y+x)*3.
76 */
77
78 /* #undef CS_KSMPS */
79 /* #define CS_KSMPS (csound->GetKsmps(csound)) */
80
__doOpenImage(char * filename,CSOUND * csound)81 static Image * __doOpenImage(char * filename, CSOUND *csound)
82 {
83 #ifdef USE_LIBPNG
84 #define HS (8)
85 FILE *fp;
86 void *fd;
87 unsigned char header[HS];
88 png_structp png_ptr;
89 png_infop info_ptr;
90 /* png_infop end_ptr; */
91 int32_t is_png;
92 png_uint_32 width, height, rowbytes;
93 int32_t bit_depth;
94 int32_t color_type;
95 unsigned char *image_data;
96 png_bytepp row_pointers;
97 uint32_t i;
98
99 Image *img;
100
101 fd = csound->FileOpen2(csound, &fp, CSFILE_STD, filename, "rb",
102 "SFDIR;SSDIR", CSFTYPE_IMAGE_PNG, 0);
103 if (UNLIKELY(fd == NULL)) {
104 csound->InitError(csound,
105 Str("imageload: cannot open image %s.\n"), filename);
106 return NULL;
107 }
108
109 if (UNLIKELY(HS!=fread(header, 1, HS, fp)))
110 csound->InitError(csound,
111 Str("imageload: file %s is not in PNG format.\n"),
112 filename);
113 is_png = !png_sig_cmp(header, 0, HS);
114
115 if (UNLIKELY(!is_png)) {
116 csound->InitError(csound,
117 Str("imageload: file %s is not in PNG format.\n"),
118 filename);
119 csound->FileClose(csound, fd);
120 return NULL;
121 }
122
123 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
124 if (UNLIKELY(!png_ptr)) {
125 csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
126 csound->FileClose(csound, fd);
127 return NULL;
128 }
129 info_ptr = png_create_info_struct(png_ptr);
130 if (UNLIKELY(!info_ptr)) {
131 png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
132 csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
133 csound->FileClose(csound, fd);
134 return NULL;
135 }
136
137 /* end_ptr = png_create_info_struct(png_ptr); */
138 /* if (UNLIKELY(!end_ptr)) { */
139 /* png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); */
140 /* csound->InitError(csound, "%s", Str("imageload: out of memory.\n")); */
141 /* csound->FileClose(csound, fd); */
142 /* return NULL; */
143 /* } */
144
145 png_init_io(png_ptr, fp);
146 png_set_sig_bytes(png_ptr, HS);
147
148 png_read_info(png_ptr, info_ptr);
149 {
150
151 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
152 &color_type, NULL, NULL, NULL);
153 }
154 if (color_type & PNG_COLOR_MASK_ALPHA)
155 png_set_strip_alpha(png_ptr);
156 if (bit_depth == 16)
157 png_set_strip_16(png_ptr);
158 if (bit_depth < 8)
159 png_set_packing(png_ptr);
160 if (color_type == PNG_COLOR_TYPE_GRAY ||
161 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
162 png_set_gray_to_rgb(png_ptr);
163 if (color_type == PNG_COLOR_TYPE_PALETTE)
164 png_set_palette_to_rgb(png_ptr);
165
166 png_read_update_info(png_ptr, info_ptr);
167 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
168
169 if (UNLIKELY((image_data =
170 (unsigned char *)csound->Malloc(csound,rowbytes*height))==NULL)) {
171 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
172 csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
173 return NULL;
174 }
175
176 row_pointers = (png_bytepp) csound->Malloc(csound, height*sizeof(png_bytep));
177 if (UNLIKELY(row_pointers == NULL)) {
178 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
179 csound->Free(csound,image_data);
180 image_data = NULL;
181 csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
182 return NULL;
183 }
184
185 for (i = 0; i < height; i++)
186 row_pointers[i] = image_data + i*rowbytes;
187
188 png_read_image(png_ptr, row_pointers);
189 csound->Free(csound,row_pointers);
190 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
191 csound->FileClose(csound, fd);
192
193 img = csound->Malloc(csound, sizeof(Image));
194 if (UNLIKELY(!img)) {
195 csound->Free(csound,image_data);
196 csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
197 return NULL;
198 }
199
200 img->w = width;
201 img->h = height;
202 img->imageData = image_data;
203
204 return img;
205
206 #else
207
208 Display *disp;
209 ImlibData *id;
210 ImlibImage *im;
211 Image *img;
212 size_t datasize;
213
214 disp=XOpenDisplay(NULL);
215 id=Imlib_init(disp);
216 im=Imlib_load_image(id, filename);
217
218 img = csound->Malloc(csound, sizeof(Image));
219 img->w = im->rgb_width;
220 img->h = im->rgb_height;
221 datasize = img->w*img->h*3 * sizeof(unsigned char);
222 img->imageData = csound->Malloc(csound, datasize);
223 memcpy(img->imageData, im->rgb_data, datasize);
224
225 return img;
226 #endif
227
228 /* SDL */
229 /* Image *img;
230 size_t datasize;
231 SDL_Surface *srfc;
232 int32_t x,y;
233 int32_t bpp;
234 int32_t indcount = 0;
235 Uint32 *pixel;
236 Uint8 r, g, b;
237
238 srfc = IMG_Load(filename);
239 if (srfc) {
240 SDL_LockSurface(srfc);
241 img = csound->Malloc(csound, sizeof(Image));
242 img->w = srfc->w;
243 img->h = srfc->h;
244 bpp = srfc->format->BitsPerPixel;
245
246 datasize = img->w*img->h*3 * sizeof(unsigned char);
247 img->imageData = csound->Malloc(csound, datasize);
248
249 for(y = 0; y < img->h; y++) {
250 for(x = 0; x < img->w; x++) {
251 if (bpp<=8) //need to test on other platforms
252 pixel = srfc->pixels + y * srfc->pitch + x * bpp;
253 else
254 pixel = srfc->pixels + y * srfc->pitch + x * bpp / 8;
255 SDL_GetRGB(*pixel,srfc->format, &r, &g, &b);
256 img->imageData[indcount]= r;
257 img->imageData[indcount+1]= g;
258 img->imageData[indcount+2]= b;
259 indcount += 3;
260 }
261 }
262 SDL_UnlockSurface(srfc);
263 SDL_FreeSurface ( srfc );
264 return img;
265 }
266
267 return NULL;
268 */
269
270 }
271
272
__doSaveImage(Image * image,char * filename,CSOUND * csound)273 static int32_t __doSaveImage(Image *image, char *filename, CSOUND *csound)
274 {
275 #ifdef USE_LIBPNG
276
277 png_structp png_ptr;
278 png_infop info_ptr;
279 png_bytepp row_pointers;
280 uint32_t rowbytes;
281 int32_t i;
282
283 FILE *fp;
284 void *fd;
285
286 fd = csound->FileOpen2(csound, &fp, CSFILE_STD, filename, "wb",
287 "", CSFTYPE_IMAGE_PNG, 0);
288 if (UNLIKELY(fd == NULL)) {
289 return
290 csound->InitError(csound,
291 Str("imageload: cannot open image %s for writing.\n"),
292 filename);
293 }
294
295 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
296
297 if (UNLIKELY(!png_ptr)){
298 csound->FileClose(csound, fd);
299 return csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
300 }
301
302 info_ptr = png_create_info_struct(png_ptr);
303 if (UNLIKELY(!info_ptr)) {
304 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
305 csound->FileClose(csound, fd);
306 return csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
307 }
308
309 png_init_io(png_ptr, fp);
310 png_set_IHDR(png_ptr, info_ptr, image->w, image->h,
311 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
312 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
313
314 png_write_info(png_ptr, info_ptr);
315
316 row_pointers = (png_bytepp)csound->Malloc(csound, image->h*sizeof(png_bytep));
317 if (UNLIKELY(row_pointers == NULL)) {
318 png_destroy_write_struct(&png_ptr, &info_ptr);
319 return csound->InitError(csound, "%s", Str("imageload: out of memory.\n"));
320 }
321
322 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
323
324 for (i = 0; i < image->h; i++)
325 row_pointers[i] = image->imageData + i*rowbytes;
326
327 png_write_image(png_ptr, row_pointers);
328 png_write_end(png_ptr, info_ptr);
329
330 csound->Free(csound,row_pointers);
331 png_destroy_write_struct(&png_ptr, &info_ptr);
332 csound->FileClose(csound, fd);
333
334 return OK;
335 #else
336 Display *disp;
337 ImlibData *id;
338 ImlibImage *im;
339
340 disp=XOpenDisplay(NULL);
341 id=Imlib_init(disp);
342
343 im = Imlib_create_image_from_data(id, image->imageData,
344 NULL, image->w, image->h);
345 Imlib_save_image(id, im, filename, NULL);
346 Imlib_kill_image(id, im);
347
348 return OK;
349 #endif
350 }
351
352
createImage(CSOUND * csound,int32_t w,int32_t h)353 static Image * createImage(CSOUND *csound, int32_t w, int32_t h)
354 {
355 Image *img;
356 size_t datasize;
357
358 img = csound->Malloc(csound, sizeof(Image));
359 img->w = w;
360 img->h = h;
361
362 datasize = img->w*img->h*3 * sizeof(unsigned char);
363 img->imageData = csound->Malloc(csound, datasize);
364
365 return img;
366 }
367
368
getImages(CSOUND * csound)369 static Images * getImages(CSOUND *csound)
370 {
371 Images *pimages;
372 pimages = (Images*)csound->QueryGlobalVariable(csound,
373 "imageOpcodes.images");
374 if (pimages==NULL) { /* first call */
375 csound->CreateGlobalVariable(csound, "imageOpcodes.images",
376 sizeof(Images));
377 pimages = (Images*)csound->QueryGlobalVariable(csound,
378 "imageOpcodes.images");
379 pimages->images = (Image **) NULL;
380 pimages->cnt = (size_t) 0;
381 }
382 return pimages;
383 }
384
imagecreate(CSOUND * csound,IMGCREATE * p)385 static int32_t imagecreate (CSOUND *csound, IMGCREATE * p)
386 {
387 Images *pimages;
388 Image *img;
389
390 pimages = getImages(csound);
391
392 pimages->cnt++;
393 pimages->images =
394 (Image **) csound->ReAlloc(csound, pimages->images,
395 sizeof(Image *) * pimages->cnt);
396
397 img = createImage(csound, *p->kw, *p->kh);
398
399 if (UNLIKELY(img==NULL)) {
400 return csound->InitError(csound, "%s", Str("Cannot allocate memory.\n"));
401 }
402 else {
403 pimages->images[pimages->cnt-1] = img;
404 *(p->kn) = (MYFLT) pimages->cnt;
405 return OK;
406 }
407 }
408
imageload(CSOUND * csound,IMGLOAD * p)409 static int32_t imageload (CSOUND *csound, IMGLOAD * p)
410 {
411 char filename[256];
412 Images *pimages;
413 Image *img;
414
415 pimages = getImages(csound);
416
417 pimages->cnt++;
418 pimages->images =
419 (Image **) csound->ReAlloc(csound, pimages->images,
420 sizeof(Image *) * pimages->cnt);
421
422 strncpy(filename, (char*) (p->ifilnam->data), 255); filename[255]='\0';
423
424 img = __doOpenImage(filename, csound);
425
426 if (LIKELY(img)) {
427 pimages->images[pimages->cnt-1] = img;
428 *(p->kn) = (MYFLT) pimages->cnt;
429 return OK;
430 }
431 else {
432 return csound->InitError(csound,
433 Str("imageload: cannot open image %s.\n"),
434 filename);
435 }
436 }
437
438
imagesize(CSOUND * csound,IMGSIZE * p)439 static int32_t imagesize (CSOUND *csound, IMGSIZE * p)
440 {
441 Images *pimages;
442 Image *img;
443
444 pimages = (Images *) csound->QueryGlobalVariable(csound,
445 "imageOpcodes.images");
446 img = pimages->images[(int32_t)(*p->kn)-1];
447
448 *(p->kw) = (MYFLT) img->w;
449 *(p->kh) = (MYFLT) img->h;
450 return OK;
451 }
452
453
imagegetpixel(CSOUND * csound,IMGGETPIXEL * p)454 static int32_t imagegetpixel (CSOUND *csound, IMGGETPIXEL * p)
455 {
456 Images *pimages;
457 Image *img;
458 int32_t w, h, x, y;
459
460 pimages = (Images *) csound->QueryGlobalVariable(csound,
461 "imageOpcodes.images");
462 img = pimages->images[(int32_t)(*p->kn)-1];
463
464 w = img->w;
465 h = img->h;
466
467 x = *p->kx*w;
468 y = *p->ky*h;
469
470 if (x >= 0 && x < w && y >= 0 && y < h ) {
471 int32_t pixel = (w*y+x)*3;
472 *p->kr = img->imageData[pixel]/FL(255.0);
473 *p->kg = img->imageData[pixel+1]/FL(255.0);
474 *p->kb = img->imageData[pixel+2]/FL(255.0);
475 }
476 else {
477 *p->kr = FL(0.0);
478 *p->kg = FL(0.0);
479 *p->kb = FL(0.0);
480 }
481
482 return OK;
483 }
484
imagegetpixel_a(CSOUND * csound,IMGGETPIXEL * p)485 static int32_t imagegetpixel_a (CSOUND *csound, IMGGETPIXEL * p)
486 {
487 Images *pimages;
488 Image *img;
489
490 MYFLT *r = p->kr;
491 MYFLT *g = p->kg;
492 MYFLT *b = p->kb;
493
494 MYFLT *tx = p->kx;
495 MYFLT *ty = p->ky;
496
497 uint32_t offset = p->h.insdshead->ksmps_offset;
498 uint32_t early = p->h.insdshead->ksmps_no_end;
499 uint32_t i, nsmps = CS_KSMPS;
500 int32_t w, h, x, y, pixel;
501
502 pimages = (Images *) csound->QueryGlobalVariable(csound,
503 "imageOpcodes.images");
504 img = pimages->images[(int32_t)(*p->kn)-1];
505 w = img->w;
506 h = img->h;
507
508
509 if (UNLIKELY(offset)) {
510 memset(r, '\0', offset*sizeof(MYFLT));
511 memset(g, '\0', offset*sizeof(MYFLT));
512 memset(b, '\0', offset*sizeof(MYFLT));
513 }
514 if (UNLIKELY(early)) {
515 nsmps -= early;
516 memset(&r[nsmps], '\0', early*sizeof(MYFLT));
517 memset(&g[nsmps], '\0', early*sizeof(MYFLT));
518 memset(&b[nsmps], '\0', early*sizeof(MYFLT));
519 }
520 for (i = 0; i < nsmps; i++) {
521
522 x = tx[i]*w;
523 y = ty[i]*h;
524
525 if ( x >= 0 && x < w && y >= 0 && y < h ) {
526 pixel = (w*y+x)*3;
527 r[i] = img->imageData[pixel]/FL(255.0);
528 g[i] = img->imageData[pixel+1]/FL(255.0);
529 b[i] = img->imageData[pixel+2]/FL(255.0);
530 }
531 else {
532 r[i] = FL(0.0);
533 g[i] = FL(0.0);
534 b[i] = FL(0.0);
535 }
536 }
537
538 return OK;
539 }
540
imagesetpixel_a(CSOUND * csound,IMGSETPIXEL * p)541 static int32_t imagesetpixel_a (CSOUND *csound, IMGSETPIXEL * p)
542 {
543 Images *pimages;
544 Image *img;
545
546 MYFLT *r = p->kr;
547 MYFLT *g = p->kg;
548 MYFLT *b = p->kb;
549
550 MYFLT *tx = p->kx;
551 MYFLT *ty = p->ky;
552
553 uint32_t offset = p->h.insdshead->ksmps_offset;
554 uint32_t early = p->h.insdshead->ksmps_no_end;
555 uint32_t i, nsmps = CS_KSMPS;
556 int32_t h,w,x, y, pixel;
557
558 pimages = (Images *) csound->QueryGlobalVariable(csound,
559 "imageOpcodes.images");
560 img = pimages->images[(int32_t)(*p->kn)-1];
561
562 w = img->w;
563 h = img->h;
564
565 if (UNLIKELY(early)) nsmps -= early;
566 for (i = offset; i < nsmps; i++) {
567
568 x = tx[i]*w;
569 y = ty[i]*h;
570
571 if (x >= 0 && x < w && y >= 0 && y < h ) {
572 pixel = (w*y+x)*3;
573 img->imageData[pixel] = (unsigned char)(r[i]*255) % 256;
574 img->imageData[pixel+1] = (unsigned char)(g[i]*255) % 256;
575 img->imageData[pixel+2] = (unsigned char)(b[i]*255) % 256;
576 }
577
578 }
579
580 return OK;
581 }
582
imagesetpixel(CSOUND * csound,IMGSETPIXEL * p)583 static int32_t imagesetpixel (CSOUND *csound, IMGSETPIXEL * p)
584 {
585 Images *pimages;
586 Image *img;
587 int32_t w, h, x, y, pixel;
588
589 pimages = (Images *) csound->QueryGlobalVariable(csound,
590 "imageOpcodes.images");
591 img = pimages->images[(int32_t)(*p->kn)-1];
592
593 w = img->w;
594 h = img->h;
595
596 x = *p->kx*w;
597 y = *p->ky*h;
598
599 if (x >= 0 && x < w && y >= 0 && y < h ) {
600 pixel = (w*y+x)*3;
601 img->imageData[pixel] = (unsigned char)((*p->kr)*255) % 256;
602 img->imageData[pixel+1] = (unsigned char)((*p->kg)*255) % 256;
603 img->imageData[pixel+2] = (unsigned char)((*p->kb)*255) % 256;
604 }
605 return OK;
606 }
607
imagesave(CSOUND * csound,IMGSAVE * p)608 static int32_t imagesave (CSOUND *csound, IMGSAVE * p)
609 {
610 Images *pimages;
611 Image *img;
612 char filename[256];
613
614 strncpy(filename, (char*) (p->ifilnam->data), 254); filename[255]='\0';
615
616 pimages = (Images *) csound->QueryGlobalVariable(csound,
617 "imageOpcodes.images");
618 img = pimages->images[(int32_t)(*p->kn)-1];
619
620 return __doSaveImage(img, filename, csound);
621 }
622
imagefree(CSOUND * csound,IMGSAVE * p)623 static int32_t imagefree (CSOUND *csound, IMGSAVE * p)
624 {
625 Images *pimages;
626 Image *img;
627
628 pimages = (Images *) csound->QueryGlobalVariable(csound,
629 "imageOpcodes.images");
630 img = pimages->images[(int32_t
631 )(*p->kn)-1];
632 csound->Free(csound,img->imageData);
633 csound->Free(csound,img);
634
635 return OK;
636 }
637
638 #define S(x) sizeof(x)
639
640 static OENTRY image_localops[] = {
641 { "imageload", S(IMGLOAD), 0, 1, "i", "S", (SUBR)imageload, NULL, NULL },
642 { "imagecreate",S(IMGCREATE),0, 1, "i", "ii", (SUBR)imagecreate, NULL, NULL },
643 { "imagesize", S(IMGSIZE), 0, 1, "ii", "i", (SUBR)imagesize, NULL, NULL },
644 { "imagegetpixel", S(IMGGETPIXEL), 0, 3, "kkk", "ixx",
645 (SUBR)imagegetpixel, (SUBR)imagegetpixel, },
646 { "imagegetpixel", S(IMGGETPIXEL), 0, 3, "aaa", "ixx",
647 (SUBR)imagegetpixel, (SUBR)imagegetpixel_a },
648 { "imagesetpixel", S(IMGSETPIXEL), 0, 3, "", "ikkkkk",
649 (SUBR)imagesetpixel, (SUBR)imagesetpixel, (SUBR)imagesetpixel_a },
650 { "imagesetpixel", S(IMGSETPIXEL), 0, 3, "", "iaaaaa",
651 (SUBR)imagesetpixel, (SUBR)imagesetpixel_a },
652 { "imagesave", S(IMGSAVE), 0, 1, "", "iS", (SUBR)imagesave, NULL, NULL },
653 { "imagefree", S(IMGFREE), 0, 1, "", "i", (SUBR)imagefree, NULL, NULL },
654 };
655
656
657 LINKAGE_BUILTIN(image_localops)
658