1 /* -*- mode: C; mode: fold; -*- */
2 /*
3 Copyright (C) 2005-2017,2018 John E. Davis
4 
5 This file is part of the S-Lang Library.
6 
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11 
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <slang.h>
29 
30 #include <png.h>
31 
32 SLANG_MODULE(png);
33 
34 static SLFUTURE_CONST char *Module_Version_String = "0.2.0";
35 #define MODULE_VERSION_NUMBER  (0*10000 + 2*100 + 0)
36 
37 /*{{{ Byte-swapping routines */
38 
39 static int Is_Little_Endian;
40 
byte_swap32(unsigned char * p,unsigned char * t,SLuindex_Type n)41 static void byte_swap32 (unsigned char *p, unsigned char *t, SLuindex_Type n)
42 {
43    unsigned char *pmax;
44 
45    /* t and p could point to the same buffer */
46    pmax = p + 4 * n;
47    while (p < pmax)
48      {
49 	unsigned char ch = *p;
50 	*t = *(p + 3);
51 	*(t + 3) = ch;
52 
53 	ch = *(p + 1);
54 	*(t + 1) = *(p + 2);
55 	*(t + 2) = ch;
56 	p += 4;
57 	t += 4;
58      }
59 }
60 
byte_swap16(unsigned char * p,unsigned char * t,SLuindex_Type n)61 static void byte_swap16 (unsigned char *p, unsigned char *t, SLuindex_Type n)
62 {
63    unsigned char *pmax;
64 
65    pmax = p + 2 * n;
66    while (p < pmax)
67      {
68 	unsigned char ch = *p;
69 	*t = *(p + 1);
70 	*(t + 1) = ch;
71 	p += 2;
72 	t += 2;
73      }
74 }
75 
76 /*}}}*/
77 
78 /*{{{ Png_Type */
79 
80 typedef struct
81 {
82    FILE *fp;
83    int mode;			       /* 'r' or 'w' */
84    png_struct *png;
85    png_info *info;
86 }
87 Png_Type;
88 
free_png_type(Png_Type * p)89 static void free_png_type (Png_Type *p)
90 {
91    if (p == NULL)
92      return;
93    if (p->png != NULL)
94      {
95 	if (p->mode == 'r')
96 	  {
97 	     if (p->info != NULL)
98 	       png_destroy_read_struct (&p->png, &p->info, NULL);
99 	     else
100 	       png_destroy_read_struct (&p->png, NULL, NULL);
101 	  }
102 	else
103 	  {
104 	     if (p->info != NULL)
105 	       png_destroy_write_struct (&p->png, &p->info);
106 	     else
107 	       png_destroy_write_struct (&p->png, NULL);
108 	  }
109      }
110 
111    if (p->fp != NULL)
112      fclose (p->fp);
113 
114    SLfree ((char *) p);
115 }
116 
alloc_png_type(int mode)117 static Png_Type *alloc_png_type (int mode)
118 {
119    Png_Type *p;
120 
121    if (NULL != (p = (Png_Type *)SLmalloc (sizeof (Png_Type))))
122      {
123 	memset ((char *) p, 0, sizeof (Png_Type));
124 	p->mode = mode;
125      }
126    return p;
127 }
128 
129 /*}}}*/
130 
allocate_image_pointers(png_uint_32 height,png_byte * data,png_uint_32 rowbytes,int flip)131 static png_byte **allocate_image_pointers (png_uint_32 height, png_byte *data, png_uint_32 rowbytes, int flip)
132 {
133    png_byte **image_pointers;
134    png_uint_32 i;
135 
136    if (NULL == (image_pointers = (png_byte **) SLmalloc (height * sizeof (png_byte *))))
137      return NULL;
138 
139    if (flip)
140      {
141 	i = height;
142 	while (i != 0)
143 	  {
144 	     i--;
145 	     image_pointers[i] = data;
146 	     data += rowbytes;
147 	  }
148 	return image_pointers;
149      }
150    for (i = 0; i < height; i++)
151      {
152 	image_pointers[i] = data;
153 	data += rowbytes;
154      }
155    return image_pointers;
156 }
157 
free_image_pointers(png_byte ** image_pointers)158 static void free_image_pointers (png_byte **image_pointers)
159 {
160    if (image_pointers == NULL)
161      return;
162 
163    SLfree ((char *) image_pointers);
164 }
165 
166 /*{{{ png read functions */
167 
open_png_file(char * file)168 static Png_Type *open_png_file (char *file)
169 {
170    png_byte header[8];
171    Png_Type *p;
172 
173    if (NULL == (p = alloc_png_type ('r')))
174      return NULL;
175 
176    if ((NULL == (p->fp = fopen (file, "rb")))
177        || (8 != fread (header, 1, 8, p->fp))
178        || (0 != png_sig_cmp(header, 0, 8)))
179      {
180 	SLang_verror (SL_Open_Error, "Unable to open %s as a png file", file);
181 	free_png_type (p);
182 	return NULL;
183      }
184 
185    if (NULL == (p->png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
186      {
187 	SLang_verror (SL_Open_Error, "Unable to read png structure from %s", file);
188 	free_png_type (p);
189 	return NULL;
190      }
191 
192    if (NULL == (p->info = png_create_info_struct (p->png)))
193      {
194 	SLang_verror (SL_Read_Error, "Unable to create info struct for %s", file);
195 	free_png_type (p);
196 	return NULL;
197      }
198 
199    return p;
200 }
201 
fixup_array_rgb(SLang_Array_Type * at)202 static void fixup_array_rgb (SLang_Array_Type *at)
203 {
204    SLindex_Type num_rows, num_cols, row;
205    unsigned char *data;
206 
207    num_rows = at->dims[0];
208    num_cols = at->dims[1];
209    data = (unsigned char *) at->data;
210 
211    /* Convert RGBRGBRGB....  to 0RGB0RGB0RGB ... */
212    for (row = 0; row < num_rows; row++)
213      {
214 	unsigned char *p = data + 3*num_cols;
215 	unsigned char *q = p + num_cols;
216 	while (p != data)
217 	  {
218 	     *(--q) = *(--p);
219 	     *(--q) = *(--p);
220 	     *(--q) = *(--p);
221 	     *(--q) = 0;	       /* or 0xFF */
222 	  }
223 	data += 4*num_cols;
224      }
225 
226    if (Is_Little_Endian)
227      byte_swap32 ((unsigned char *)at->data, (unsigned char *)at->data, at->num_elements);
228 }
229 
fixup_array_rgba(SLang_Array_Type * at)230 static void fixup_array_rgba (SLang_Array_Type *at)
231 {
232    unsigned char *data, *data_max;
233 
234    data = (unsigned char *) at->data;
235    data_max = data + 4*at->num_elements;
236 
237    /* RGBARGBA -> ARGBARGB */
238    while (data < data_max)
239      {
240 	unsigned char a = data[3];
241 	data[3] = data[2];
242 	data[2] = data[1];
243 	data[1] = data[0];
244 	data[0] = a;
245 	data += 4;
246      }
247    if (Is_Little_Endian)
248      byte_swap32 ((unsigned char *)at->data, (unsigned char *)at->data, at->num_elements);
249 }
250 
fixup_array_ga(SLang_Array_Type * at)251 static void fixup_array_ga (SLang_Array_Type *at)
252 {
253    if (Is_Little_Endian)
254      byte_swap16 ((unsigned char *)at->data, (unsigned char *) at->data, at->num_elements);
255 }
256 
257 /* For little endian systems, ARGB is equivalent to the int32 BGRA.
258  * So, to read the image as RGB
259  */
read_image_internal(char * file,int flip,int * color_typep)260 static SLang_Array_Type *read_image_internal (char *file, int flip, int *color_typep)
261 {
262    Png_Type *p;
263    png_uint_32 width, height, rowbytes;
264    png_struct *png;
265    png_info *info;
266    int bit_depth;
267    /* int interlace_type; */
268    int color_type;
269    unsigned int sizeof_type;
270    SLindex_Type dims[2];
271    SLtype data_type;
272    png_byte **image_pointers = NULL;
273    png_byte *data = NULL;
274    SLang_Array_Type *at;
275    void (*fixup_array_fun) (SLang_Array_Type *);
276 
277    if (NULL == (p = open_png_file (file)))
278      return NULL;
279 
280    png = p->png;
281    if (setjmp (png_jmpbuf (png)))
282      {
283 	free_png_type (p);
284 	if (data != NULL) SLfree ((char *) data);
285 	free_image_pointers (image_pointers);
286 	SLang_verror (SL_Read_Error, "Error encountered during I/O to %s", file);
287 	return NULL;
288      }
289 
290    png_init_io (png, p->fp);
291    png_set_sig_bytes (png, 8);
292    info = p->info;
293    png_read_info(png, info);
294 
295    width = png_get_image_width (png, info);
296    height = png_get_image_height (png, info);
297    /* interlace_type = png_get_interlace_type (png, info); */
298    bit_depth = png_get_bit_depth (png, info);
299 
300    if (bit_depth == 16)
301      png_set_strip_16 (png);
302 
303    switch (png_get_color_type (png, info))
304      {
305       case PNG_COLOR_TYPE_GRAY:
306 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10209)
307 	if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8 (png);
308 #else				       /* deprecated */
309 	if (bit_depth < 8) png_set_gray_1_2_4_to_8 (png);
310 #endif
311 	break;
312       case PNG_COLOR_TYPE_GRAY_ALPHA:
313 	/* png_set_gray_to_rgb (png); */
314 	break;
315 
316       case PNG_COLOR_TYPE_PALETTE:
317 	png_set_palette_to_rgb (png);
318 	break;
319      }
320 
321    if (png_get_valid(png, info, PNG_INFO_tRNS))
322      png_set_tRNS_to_alpha(png);
323 
324    png_read_update_info (png, info);
325 
326    color_type = png_get_color_type (png, info);
327    switch (color_type)
328      {
329       case PNG_COLOR_TYPE_RGBA:
330 	sizeof_type = 4;
331 	fixup_array_fun = fixup_array_rgba;
332 	data_type = SLang_get_int_type (32);
333 	break;
334 
335       case PNG_COLOR_TYPE_RGB:
336 	sizeof_type = 4;
337 	fixup_array_fun = fixup_array_rgb;
338 	data_type = SLang_get_int_type (32);
339 	break;
340 
341       case PNG_COLOR_TYPE_GRAY_ALPHA:
342 	sizeof_type = 2;
343 	fixup_array_fun = fixup_array_ga;
344 	data_type = SLang_get_int_type (16);
345 	break;
346 
347       case PNG_COLOR_TYPE_GRAY:
348 	sizeof_type = 1;
349 	fixup_array_fun = NULL;
350 	data_type = SLANG_UCHAR_TYPE;
351 	break;
352 
353       default:
354 	SLang_verror (SL_Read_Error, "Unsupported PNG color-type");
355 	free_png_type (p);
356 	return NULL;
357      }
358    *color_typep = color_type;
359 
360    /* Use the high-level interface */
361    rowbytes = png_get_rowbytes (png, info);
362    if (rowbytes > width * sizeof_type)
363      {
364 	SLang_verror (SL_INTERNAL_ERROR, "Unexpected value returned from png_get_rowbytes");
365 	free_png_type (p);
366 	return NULL;
367      }
368 
369    if (NULL == (data = (png_byte *) SLmalloc (height * width * sizeof_type)))
370      {
371 	free_png_type (p);
372 	return NULL;
373      }
374 
375    if (NULL == (image_pointers = allocate_image_pointers (height, data, width * sizeof_type, flip)))
376      {
377 	SLfree ((char *) data);
378 	free_png_type (p);
379 	return NULL;
380      }
381    png_read_image(png, image_pointers);
382 
383    dims[0] = height;
384    dims[1] = width;
385 
386    if (NULL == (at = SLang_create_array (data_type, 0, (VOID_STAR) data, dims, 2)))
387      {
388 	SLfree ((char *) data);
389 	free_image_pointers (image_pointers);
390 	free_png_type (p);
391 	return NULL;
392      }
393    free_png_type (p);
394    free_image_pointers (image_pointers);
395    if (fixup_array_fun != NULL)
396      (*fixup_array_fun) (at);
397    return at;
398 }
399 
read_image(int flipped)400 static void read_image (int flipped)
401 {
402    int color_type;
403    char *file;
404    SLang_Ref_Type *ref = NULL;
405    SLang_Array_Type *at;
406 
407    if ((SLang_Num_Function_Args == 2)
408        && (-1 == SLang_pop_ref (&ref)))
409      return;
410 
411    if (-1 == SLang_pop_slstring (&file))
412      {
413 	file = NULL;
414 	goto free_return;
415      }
416 
417    if (NULL == (at = read_image_internal (file, flipped, &color_type)))
418      goto free_return;
419 
420    if ((ref != NULL)
421        && (-1 == SLang_assign_to_ref (ref, SLANG_INT_TYPE, &color_type)))
422      {
423 	SLang_free_array (at);
424 	goto free_return;
425      }
426 
427    (void) SLang_push_array (at, 1);
428 
429    free_return:
430    SLang_free_slstring (file);
431    if (ref != NULL)
432      SLang_free_ref (ref);
433 }
434 
435 /*}}}*/
436 
write_gray_to_gray(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)437 static void write_gray_to_gray (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
438 {
439    (void) num_cols;
440    (void) tmpbuf;
441    png_write_row (png, data);
442 }
443 
write_gray_to_gray_alpha(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)444 static void write_gray_to_gray_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
445 {
446    SLindex_Type i, j;
447 
448    j = 0;
449    for (i = 0; i < num_cols; i++)
450      {
451 	tmpbuf[j] = data[i];
452 	tmpbuf[j+1] = 0xFF;
453 	j += 2;
454      }
455    png_write_row (png, tmpbuf);
456 }
457 
write_gray_alpha_to_gray(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)458 static void write_gray_alpha_to_gray (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
459 {
460    SLindex_Type i;
461 
462    if (Is_Little_Endian == 0)
463      data++; /* AGAGAG... -> GAGAGA... */
464 
465    for (i = 0; i < num_cols; i++)
466      {
467 	tmpbuf[i] = *data;
468 	data += 2;
469      }
470    png_write_row (png, tmpbuf);
471 }
472 
write_gray_alpha_to_gray_alpha(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)473 static void write_gray_alpha_to_gray_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
474 {
475    if (Is_Little_Endian == 0)
476      {
477 	png_write_row (png, data);
478 	return;
479      }
480 
481    byte_swap16 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
482    png_write_row (png, tmpbuf);
483 }
484 
write_rgb_alpha_to_rgb_alpha(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)485 static void write_rgb_alpha_to_rgb_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
486 {
487    unsigned char *data_max;
488    unsigned char *p;
489 
490    if (Is_Little_Endian)
491      {
492 	byte_swap32 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
493 	data = tmpbuf;
494      }
495    data_max = data + 4 * num_cols;
496    p = tmpbuf;
497    /* Change ARGBARGB... to RGBARGBA... */
498    while (data < data_max)
499      {
500 	unsigned char a = data[0];
501 	p[0] = data[1];
502 	p[1] = data[2];
503 	p[2] = data[3];
504 	p[3] = a;
505 	data += 4;
506 	p += 4;
507      }
508    png_write_row (png, tmpbuf);
509 }
510 
write_rgb_to_rgb(png_struct * png,png_byte * data,SLindex_Type num_cols,png_byte * tmpbuf)511 static void write_rgb_to_rgb (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
512 {
513    SLindex_Type i;
514    png_byte *p, *q;
515 
516    if (Is_Little_Endian)
517      {
518 	byte_swap32 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
519 	p = tmpbuf;
520      }
521    else p = data;
522 
523    /* ARGBARGB... -> RGBRGBRGB */
524    q = tmpbuf;
525    for (i = 0; i < num_cols; i++)
526      {
527 	p++;
528 	*q++ = *p++;
529 	*q++ = *p++;
530 	*q++ = *p++;
531      }
532    png_write_row (png, tmpbuf);
533 }
534 
write_array(png_struct * png,png_byte ** image_pointers,SLindex_Type num_rows,SLindex_Type num_cols,void (* write_row_func)(png_struct *,png_byte *,SLindex_Type,png_byte *),png_byte * tmpbuf)535 static int write_array (png_struct *png, png_byte **image_pointers, SLindex_Type num_rows, SLindex_Type num_cols,
536 			void (*write_row_func) (png_struct *, png_byte *, SLindex_Type, png_byte *),
537 			png_byte *tmpbuf)
538 {
539    int num_pass;
540    SLindex_Type i;
541 
542    num_pass = png_set_interlace_handling(png);
543    while (num_pass > 0)
544      {
545 	num_pass--;
546 	for (i = 0; i < num_rows; i++)
547 	  (*write_row_func) (png, image_pointers[i], num_cols, tmpbuf);
548      }
549    return 0;
550 }
551 
write_image_internal(char * file,SLang_Array_Type * at,int color_type,void (* write_fun)(png_struct *,png_byte * p,SLindex_Type,png_byte *),int flip,int compress_level)552 static int write_image_internal (char *file, SLang_Array_Type *at,
553 				 int color_type,
554 				 void (*write_fun)(png_struct *, png_byte *p, SLindex_Type, png_byte *),
555 				 int flip, int compress_level)
556 {
557    FILE *fp;
558    Png_Type *p = NULL;
559    png_struct *png;
560    png_info *info;
561    SLindex_Type width, height;
562    png_byte **image_pointers;
563    int bit_depth;
564    int status = -1;
565    png_byte *tmpbuf;
566 
567    bit_depth = 8;
568 
569    height = at->dims[0];
570    width = at->dims[1];
571 
572    if (NULL == (image_pointers = allocate_image_pointers (height, (png_byte *)at->data, width * at->sizeof_type, flip)))
573      return -1;
574 
575    if (NULL == (tmpbuf = (png_byte *)SLmalloc (4*width)))
576      {
577 	free_image_pointers (image_pointers);
578 	return -1;
579      }
580 
581    if (NULL == (fp = fopen (file, "wb")))
582      {
583 	(void)SLerrno_set_errno (errno);
584 	SLang_verror (SL_Open_Error, "Unable to open %s", file);
585 	goto return_error;
586      }
587 
588    if (NULL == (p = alloc_png_type ('w')))
589      goto return_error;
590 
591    p->fp = fp;
592 
593    if (NULL == (p->png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
594      {
595 	SLang_verror (SL_Open_Error, "png_create_write_struct failed");
596 	goto return_error;
597      }
598    png = p->png;
599    if (NULL == (p->info = png_create_info_struct (png)))
600      {
601 	SLang_verror (SL_Open_Error, "png_create_info_struct failed");
602 	goto return_error;
603      }
604    info = p->info;
605    if (setjmp(png_jmpbuf(png)))
606      {
607 	SLang_verror (SL_Write_Error, "PNG I/O error");
608 	goto return_error;
609      }
610    png_init_io(png, fp);
611 
612    if ((compress_level >= 0) && (compress_level <= 9))
613      png_set_compression_level (png, compress_level);
614 
615    png_set_IHDR (png, info, width, height,
616 		 bit_depth, color_type, PNG_INTERLACE_NONE,
617 		 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
618    png_write_info(png, info);
619 
620    if (-1 == write_array (png, image_pointers, height, width, write_fun, tmpbuf))
621      goto return_error;
622 
623    png_write_end(png, NULL);
624    if (EOF == fclose (p->fp))
625      {
626 	SLang_verror (SL_Write_Error, "Error closing %s", file);
627 	SLerrno_set_errno (errno);
628      }
629    else status = 0;
630 
631    p->fp = NULL;
632    /* drop */
633    return_error:
634    if (tmpbuf != NULL)
635      SLfree ((char *) tmpbuf);
636    free_image_pointers (image_pointers);
637    if (p != NULL)
638      free_png_type (p);
639 
640    return status;
641 }
642 
write_image(int flip)643 static void write_image (int flip)
644 {
645    char *file;
646    SLang_Array_Type *at;
647    int with_alpha = 0;
648    int has_with_alpha = 0;
649    int compress_level;
650    int color_type;
651    void (*write_fun) (png_struct *, png_byte *, SLindex_Type, png_byte *);
652 
653    if (SLang_Num_Function_Args == 3)
654      {
655 	if (-1 == SLang_pop_int (&with_alpha))
656 	  return;
657 	has_with_alpha = 1;
658      }
659 
660    if (-1 == SLang_get_int_qualifier ("compress", &compress_level, -1))
661      return;
662 
663    if (-1 == SLang_pop_array (&at, 0))
664      return;
665 
666    if (at->num_dims != 2)
667      {
668 	SLang_verror (SL_InvalidParm_Error, "Expecting a 2-d array");
669 	SLang_free_array (at);
670 	return;
671      }
672 
673    switch (SLang_get_int_size (at->data_type))
674      {
675       case -8:
676       case 8:
677 	if (with_alpha)
678 	  {
679 	     write_fun = write_gray_to_gray_alpha;
680 	     color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
681 	  }
682 	else
683 	  {
684 	     write_fun = write_gray_to_gray;
685 	     color_type = PNG_COLOR_TYPE_GRAY;
686 	  }
687 	break;
688       case -16:
689       case 16:
690 	if (has_with_alpha && (with_alpha == 0))
691 	  {
692 	     write_fun = write_gray_alpha_to_gray;
693 	     color_type = PNG_COLOR_TYPE_GRAY;
694 	  }
695 	else
696 	  {
697 	     write_fun = write_gray_alpha_to_gray_alpha;
698 	     color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
699 	  }
700 	break;
701       case -32:
702       case 32:
703 	if (with_alpha)
704 	  {
705 	     write_fun = write_rgb_alpha_to_rgb_alpha;
706 	     color_type = PNG_COLOR_TYPE_RGBA;
707 	  }
708 	else
709 	  {
710 	     write_fun = write_rgb_to_rgb;
711 	     color_type = PNG_COLOR_TYPE_RGB;
712 	  }
713 	break;
714       default:
715 	SLang_verror (SL_InvalidParm_Error, "Expecting an 8, 16, or 32 bit integer array");
716 	SLang_free_array (at);
717 	return;
718      }
719 
720    if (-1 == SLang_pop_slstring (&file))
721      {
722 	SLang_free_array (at);
723 	return;
724      }
725    (void) write_image_internal (file, at, color_type, write_fun, flip, compress_level);
726    SLang_free_slstring (file);
727    SLang_free_array (at);
728 }
729 
read_intrin(void)730 static void read_intrin (void)
731 {
732    read_image (0);
733 }
read_flipped_intrin(void)734 static void read_flipped_intrin (void)
735 {
736    read_image (1);
737 }
738 
write_intrin(void)739 static void write_intrin (void)
740 {
741    write_image (0);
742 }
write_flipped_intrin(void)743 static void write_flipped_intrin (void)
744 {
745    write_image (1);
746 }
747 
748 static SLang_Intrin_Fun_Type Module_Intrinsics [] =
749 {
750    MAKE_INTRINSIC_0("png_read", read_intrin, SLANG_VOID_TYPE),
751    MAKE_INTRINSIC_0("png_read_flipped", read_flipped_intrin, SLANG_VOID_TYPE),
752    MAKE_INTRINSIC_0("png_write", write_intrin, SLANG_VOID_TYPE),
753    MAKE_INTRINSIC_0("png_write_flipped", write_flipped_intrin, SLANG_VOID_TYPE),
754    SLANG_END_INTRIN_FUN_TABLE
755 };
756 
757 static SLang_Intrin_Var_Type Module_Variables [] =
758 {
759    MAKE_VARIABLE("_png_module_version_string", &Module_Version_String, SLANG_STRING_TYPE, 1),
760    SLANG_END_INTRIN_VAR_TABLE
761 };
762 
763 static SLang_IConstant_Type Module_IConstants [] =
764 {
765    MAKE_ICONSTANT("PNG_COLOR_TYPE_GRAY", PNG_COLOR_TYPE_GRAY),
766    MAKE_ICONSTANT("PNG_COLOR_TYPE_GRAY_ALPHA", PNG_COLOR_TYPE_GRAY_ALPHA),
767    MAKE_ICONSTANT("PNG_COLOR_TYPE_RGB", PNG_COLOR_TYPE_RGB),
768    MAKE_ICONSTANT("PNG_COLOR_TYPE_RGBA", PNG_COLOR_TYPE_RGBA),
769 
770    MAKE_ICONSTANT("_png_module_version", MODULE_VERSION_NUMBER),
771    SLANG_END_ICONST_TABLE
772 };
773 
init_png_module_ns(char * ns_name)774 int init_png_module_ns (char *ns_name)
775 {
776    unsigned short x;
777 
778    SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
779    if (ns == NULL)
780      return -1;
781 
782    x = 0xFF;
783    Is_Little_Endian = (*(unsigned char *)&x == 0xFF);
784 
785    if (
786        (-1 == SLns_add_intrin_var_table (ns, Module_Variables, NULL))
787        || (-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
788        || (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL))
789        )
790      return -1;
791 
792    return 0;
793 }
794 
795 /* This function is optional */
deinit_png_module(void)796 void deinit_png_module (void)
797 {
798 }
799