799 строки
18 KiB
C
799 строки
18 KiB
C
/* -*- mode: C; mode: fold; -*- */
|
|
/*
|
|
Copyright (C) 2005-2017,2018 John E. Davis
|
|
|
|
This file is part of the S-Lang Library.
|
|
|
|
The S-Lang Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The S-Lang Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <slang.h>
|
|
|
|
#include <png.h>
|
|
|
|
SLANG_MODULE(png);
|
|
|
|
static SLFUTURE_CONST char *Module_Version_String = "0.2.0";
|
|
#define MODULE_VERSION_NUMBER (0*10000 + 2*100 + 0)
|
|
|
|
/*{{{ Byte-swapping routines */
|
|
|
|
static int Is_Little_Endian;
|
|
|
|
static void byte_swap32 (unsigned char *p, unsigned char *t, SLuindex_Type n)
|
|
{
|
|
unsigned char *pmax;
|
|
|
|
/* t and p could point to the same buffer */
|
|
pmax = p + 4 * n;
|
|
while (p < pmax)
|
|
{
|
|
unsigned char ch = *p;
|
|
*t = *(p + 3);
|
|
*(t + 3) = ch;
|
|
|
|
ch = *(p + 1);
|
|
*(t + 1) = *(p + 2);
|
|
*(t + 2) = ch;
|
|
p += 4;
|
|
t += 4;
|
|
}
|
|
}
|
|
|
|
static void byte_swap16 (unsigned char *p, unsigned char *t, SLuindex_Type n)
|
|
{
|
|
unsigned char *pmax;
|
|
|
|
pmax = p + 2 * n;
|
|
while (p < pmax)
|
|
{
|
|
unsigned char ch = *p;
|
|
*t = *(p + 1);
|
|
*(t + 1) = ch;
|
|
p += 2;
|
|
t += 2;
|
|
}
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/*{{{ Png_Type */
|
|
|
|
typedef struct
|
|
{
|
|
FILE *fp;
|
|
int mode; /* 'r' or 'w' */
|
|
png_struct *png;
|
|
png_info *info;
|
|
}
|
|
Png_Type;
|
|
|
|
static void free_png_type (Png_Type *p)
|
|
{
|
|
if (p == NULL)
|
|
return;
|
|
if (p->png != NULL)
|
|
{
|
|
if (p->mode == 'r')
|
|
{
|
|
if (p->info != NULL)
|
|
png_destroy_read_struct (&p->png, &p->info, NULL);
|
|
else
|
|
png_destroy_read_struct (&p->png, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (p->info != NULL)
|
|
png_destroy_write_struct (&p->png, &p->info);
|
|
else
|
|
png_destroy_write_struct (&p->png, NULL);
|
|
}
|
|
}
|
|
|
|
if (p->fp != NULL)
|
|
fclose (p->fp);
|
|
|
|
SLfree ((char *) p);
|
|
}
|
|
|
|
static Png_Type *alloc_png_type (int mode)
|
|
{
|
|
Png_Type *p;
|
|
|
|
if (NULL != (p = (Png_Type *)SLmalloc (sizeof (Png_Type))))
|
|
{
|
|
memset ((char *) p, 0, sizeof (Png_Type));
|
|
p->mode = mode;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
static png_byte **allocate_image_pointers (png_uint_32 height, png_byte *data, png_uint_32 rowbytes, int flip)
|
|
{
|
|
png_byte **image_pointers;
|
|
png_uint_32 i;
|
|
|
|
if (NULL == (image_pointers = (png_byte **) SLmalloc (height * sizeof (png_byte *))))
|
|
return NULL;
|
|
|
|
if (flip)
|
|
{
|
|
i = height;
|
|
while (i != 0)
|
|
{
|
|
i--;
|
|
image_pointers[i] = data;
|
|
data += rowbytes;
|
|
}
|
|
return image_pointers;
|
|
}
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
image_pointers[i] = data;
|
|
data += rowbytes;
|
|
}
|
|
return image_pointers;
|
|
}
|
|
|
|
static void free_image_pointers (png_byte **image_pointers)
|
|
{
|
|
if (image_pointers == NULL)
|
|
return;
|
|
|
|
SLfree ((char *) image_pointers);
|
|
}
|
|
|
|
/*{{{ png read functions */
|
|
|
|
static Png_Type *open_png_file (char *file)
|
|
{
|
|
png_byte header[8];
|
|
Png_Type *p;
|
|
|
|
if (NULL == (p = alloc_png_type ('r')))
|
|
return NULL;
|
|
|
|
if ((NULL == (p->fp = fopen (file, "rb")))
|
|
|| (8 != fread (header, 1, 8, p->fp))
|
|
|| (0 != png_sig_cmp(header, 0, 8)))
|
|
{
|
|
SLang_verror (SL_Open_Error, "Unable to open %s as a png file", file);
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == (p->png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
|
|
{
|
|
SLang_verror (SL_Open_Error, "Unable to read png structure from %s", file);
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == (p->info = png_create_info_struct (p->png)))
|
|
{
|
|
SLang_verror (SL_Read_Error, "Unable to create info struct for %s", file);
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
static void fixup_array_rgb (SLang_Array_Type *at)
|
|
{
|
|
SLindex_Type num_rows, num_cols, row;
|
|
unsigned char *data;
|
|
|
|
num_rows = at->dims[0];
|
|
num_cols = at->dims[1];
|
|
data = (unsigned char *) at->data;
|
|
|
|
/* Convert RGBRGBRGB.... to 0RGB0RGB0RGB ... */
|
|
for (row = 0; row < num_rows; row++)
|
|
{
|
|
unsigned char *p = data + 3*num_cols;
|
|
unsigned char *q = p + num_cols;
|
|
while (p != data)
|
|
{
|
|
*(--q) = *(--p);
|
|
*(--q) = *(--p);
|
|
*(--q) = *(--p);
|
|
*(--q) = 0; /* or 0xFF */
|
|
}
|
|
data += 4*num_cols;
|
|
}
|
|
|
|
if (Is_Little_Endian)
|
|
byte_swap32 ((unsigned char *)at->data, (unsigned char *)at->data, at->num_elements);
|
|
}
|
|
|
|
static void fixup_array_rgba (SLang_Array_Type *at)
|
|
{
|
|
unsigned char *data, *data_max;
|
|
|
|
data = (unsigned char *) at->data;
|
|
data_max = data + 4*at->num_elements;
|
|
|
|
/* RGBARGBA -> ARGBARGB */
|
|
while (data < data_max)
|
|
{
|
|
unsigned char a = data[3];
|
|
data[3] = data[2];
|
|
data[2] = data[1];
|
|
data[1] = data[0];
|
|
data[0] = a;
|
|
data += 4;
|
|
}
|
|
if (Is_Little_Endian)
|
|
byte_swap32 ((unsigned char *)at->data, (unsigned char *)at->data, at->num_elements);
|
|
}
|
|
|
|
static void fixup_array_ga (SLang_Array_Type *at)
|
|
{
|
|
if (Is_Little_Endian)
|
|
byte_swap16 ((unsigned char *)at->data, (unsigned char *) at->data, at->num_elements);
|
|
}
|
|
|
|
/* For little endian systems, ARGB is equivalent to the int32 BGRA.
|
|
* So, to read the image as RGB
|
|
*/
|
|
static SLang_Array_Type *read_image_internal (char *file, int flip, int *color_typep)
|
|
{
|
|
Png_Type *p;
|
|
png_uint_32 width, height, rowbytes;
|
|
png_struct *png;
|
|
png_info *info;
|
|
int bit_depth;
|
|
/* int interlace_type; */
|
|
int color_type;
|
|
unsigned int sizeof_type;
|
|
SLindex_Type dims[2];
|
|
SLtype data_type;
|
|
png_byte **image_pointers = NULL;
|
|
png_byte *data = NULL;
|
|
SLang_Array_Type *at;
|
|
void (*fixup_array_fun) (SLang_Array_Type *);
|
|
|
|
if (NULL == (p = open_png_file (file)))
|
|
return NULL;
|
|
|
|
png = p->png;
|
|
if (setjmp (png_jmpbuf (png)))
|
|
{
|
|
free_png_type (p);
|
|
if (data != NULL) SLfree ((char *) data);
|
|
free_image_pointers (image_pointers);
|
|
SLang_verror (SL_Read_Error, "Error encountered during I/O to %s", file);
|
|
return NULL;
|
|
}
|
|
|
|
png_init_io (png, p->fp);
|
|
png_set_sig_bytes (png, 8);
|
|
info = p->info;
|
|
png_read_info(png, info);
|
|
|
|
width = png_get_image_width (png, info);
|
|
height = png_get_image_height (png, info);
|
|
/* interlace_type = png_get_interlace_type (png, info); */
|
|
bit_depth = png_get_bit_depth (png, info);
|
|
|
|
if (bit_depth == 16)
|
|
png_set_strip_16 (png);
|
|
|
|
switch (png_get_color_type (png, info))
|
|
{
|
|
case PNG_COLOR_TYPE_GRAY:
|
|
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10209)
|
|
if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8 (png);
|
|
#else /* deprecated */
|
|
if (bit_depth < 8) png_set_gray_1_2_4_to_8 (png);
|
|
#endif
|
|
break;
|
|
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
/* png_set_gray_to_rgb (png); */
|
|
break;
|
|
|
|
case PNG_COLOR_TYPE_PALETTE:
|
|
png_set_palette_to_rgb (png);
|
|
break;
|
|
}
|
|
|
|
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
|
png_set_tRNS_to_alpha(png);
|
|
|
|
png_read_update_info (png, info);
|
|
|
|
color_type = png_get_color_type (png, info);
|
|
switch (color_type)
|
|
{
|
|
case PNG_COLOR_TYPE_RGBA:
|
|
sizeof_type = 4;
|
|
fixup_array_fun = fixup_array_rgba;
|
|
data_type = SLang_get_int_type (32);
|
|
break;
|
|
|
|
case PNG_COLOR_TYPE_RGB:
|
|
sizeof_type = 4;
|
|
fixup_array_fun = fixup_array_rgb;
|
|
data_type = SLang_get_int_type (32);
|
|
break;
|
|
|
|
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
sizeof_type = 2;
|
|
fixup_array_fun = fixup_array_ga;
|
|
data_type = SLang_get_int_type (16);
|
|
break;
|
|
|
|
case PNG_COLOR_TYPE_GRAY:
|
|
sizeof_type = 1;
|
|
fixup_array_fun = NULL;
|
|
data_type = SLANG_UCHAR_TYPE;
|
|
break;
|
|
|
|
default:
|
|
SLang_verror (SL_Read_Error, "Unsupported PNG color-type");
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
*color_typep = color_type;
|
|
|
|
/* Use the high-level interface */
|
|
rowbytes = png_get_rowbytes (png, info);
|
|
if (rowbytes > width * sizeof_type)
|
|
{
|
|
SLang_verror (SL_INTERNAL_ERROR, "Unexpected value returned from png_get_rowbytes");
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == (data = (png_byte *) SLmalloc (height * width * sizeof_type)))
|
|
{
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == (image_pointers = allocate_image_pointers (height, data, width * sizeof_type, flip)))
|
|
{
|
|
SLfree ((char *) data);
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
png_read_image(png, image_pointers);
|
|
|
|
dims[0] = height;
|
|
dims[1] = width;
|
|
|
|
if (NULL == (at = SLang_create_array (data_type, 0, (VOID_STAR) data, dims, 2)))
|
|
{
|
|
SLfree ((char *) data);
|
|
free_image_pointers (image_pointers);
|
|
free_png_type (p);
|
|
return NULL;
|
|
}
|
|
free_png_type (p);
|
|
free_image_pointers (image_pointers);
|
|
if (fixup_array_fun != NULL)
|
|
(*fixup_array_fun) (at);
|
|
return at;
|
|
}
|
|
|
|
static void read_image (int flipped)
|
|
{
|
|
int color_type;
|
|
char *file;
|
|
SLang_Ref_Type *ref = NULL;
|
|
SLang_Array_Type *at;
|
|
|
|
if ((SLang_Num_Function_Args == 2)
|
|
&& (-1 == SLang_pop_ref (&ref)))
|
|
return;
|
|
|
|
if (-1 == SLang_pop_slstring (&file))
|
|
{
|
|
file = NULL;
|
|
goto free_return;
|
|
}
|
|
|
|
if (NULL == (at = read_image_internal (file, flipped, &color_type)))
|
|
goto free_return;
|
|
|
|
if ((ref != NULL)
|
|
&& (-1 == SLang_assign_to_ref (ref, SLANG_INT_TYPE, &color_type)))
|
|
{
|
|
SLang_free_array (at);
|
|
goto free_return;
|
|
}
|
|
|
|
(void) SLang_push_array (at, 1);
|
|
|
|
free_return:
|
|
SLang_free_slstring (file);
|
|
if (ref != NULL)
|
|
SLang_free_ref (ref);
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
static void write_gray_to_gray (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
(void) num_cols;
|
|
(void) tmpbuf;
|
|
png_write_row (png, data);
|
|
}
|
|
|
|
static void write_gray_to_gray_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
SLindex_Type i, j;
|
|
|
|
j = 0;
|
|
for (i = 0; i < num_cols; i++)
|
|
{
|
|
tmpbuf[j] = data[i];
|
|
tmpbuf[j+1] = 0xFF;
|
|
j += 2;
|
|
}
|
|
png_write_row (png, tmpbuf);
|
|
}
|
|
|
|
static void write_gray_alpha_to_gray (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
SLindex_Type i;
|
|
|
|
if (Is_Little_Endian == 0)
|
|
data++; /* AGAGAG... -> GAGAGA... */
|
|
|
|
for (i = 0; i < num_cols; i++)
|
|
{
|
|
tmpbuf[i] = *data;
|
|
data += 2;
|
|
}
|
|
png_write_row (png, tmpbuf);
|
|
}
|
|
|
|
static void write_gray_alpha_to_gray_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
if (Is_Little_Endian == 0)
|
|
{
|
|
png_write_row (png, data);
|
|
return;
|
|
}
|
|
|
|
byte_swap16 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
|
|
png_write_row (png, tmpbuf);
|
|
}
|
|
|
|
static void write_rgb_alpha_to_rgb_alpha (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
unsigned char *data_max;
|
|
unsigned char *p;
|
|
|
|
if (Is_Little_Endian)
|
|
{
|
|
byte_swap32 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
|
|
data = tmpbuf;
|
|
}
|
|
data_max = data + 4 * num_cols;
|
|
p = tmpbuf;
|
|
/* Change ARGBARGB... to RGBARGBA... */
|
|
while (data < data_max)
|
|
{
|
|
unsigned char a = data[0];
|
|
p[0] = data[1];
|
|
p[1] = data[2];
|
|
p[2] = data[3];
|
|
p[3] = a;
|
|
data += 4;
|
|
p += 4;
|
|
}
|
|
png_write_row (png, tmpbuf);
|
|
}
|
|
|
|
static void write_rgb_to_rgb (png_struct *png, png_byte *data, SLindex_Type num_cols, png_byte *tmpbuf)
|
|
{
|
|
SLindex_Type i;
|
|
png_byte *p, *q;
|
|
|
|
if (Is_Little_Endian)
|
|
{
|
|
byte_swap32 ((unsigned char *) data, (unsigned char *) tmpbuf, num_cols);
|
|
p = tmpbuf;
|
|
}
|
|
else p = data;
|
|
|
|
/* ARGBARGB... -> RGBRGBRGB */
|
|
q = tmpbuf;
|
|
for (i = 0; i < num_cols; i++)
|
|
{
|
|
p++;
|
|
*q++ = *p++;
|
|
*q++ = *p++;
|
|
*q++ = *p++;
|
|
}
|
|
png_write_row (png, tmpbuf);
|
|
}
|
|
|
|
static int 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)
|
|
{
|
|
int num_pass;
|
|
SLindex_Type i;
|
|
|
|
num_pass = png_set_interlace_handling(png);
|
|
while (num_pass > 0)
|
|
{
|
|
num_pass--;
|
|
for (i = 0; i < num_rows; i++)
|
|
(*write_row_func) (png, image_pointers[i], num_cols, tmpbuf);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int 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)
|
|
{
|
|
FILE *fp;
|
|
Png_Type *p = NULL;
|
|
png_struct *png;
|
|
png_info *info;
|
|
SLindex_Type width, height;
|
|
png_byte **image_pointers;
|
|
int bit_depth;
|
|
int status = -1;
|
|
png_byte *tmpbuf;
|
|
|
|
bit_depth = 8;
|
|
|
|
height = at->dims[0];
|
|
width = at->dims[1];
|
|
|
|
if (NULL == (image_pointers = allocate_image_pointers (height, (png_byte *)at->data, width * at->sizeof_type, flip)))
|
|
return -1;
|
|
|
|
if (NULL == (tmpbuf = (png_byte *)SLmalloc (4*width)))
|
|
{
|
|
free_image_pointers (image_pointers);
|
|
return -1;
|
|
}
|
|
|
|
if (NULL == (fp = fopen (file, "wb")))
|
|
{
|
|
(void)SLerrno_set_errno (errno);
|
|
SLang_verror (SL_Open_Error, "Unable to open %s", file);
|
|
goto return_error;
|
|
}
|
|
|
|
if (NULL == (p = alloc_png_type ('w')))
|
|
goto return_error;
|
|
|
|
p->fp = fp;
|
|
|
|
if (NULL == (p->png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
|
|
{
|
|
SLang_verror (SL_Open_Error, "png_create_write_struct failed");
|
|
goto return_error;
|
|
}
|
|
png = p->png;
|
|
if (NULL == (p->info = png_create_info_struct (png)))
|
|
{
|
|
SLang_verror (SL_Open_Error, "png_create_info_struct failed");
|
|
goto return_error;
|
|
}
|
|
info = p->info;
|
|
if (setjmp(png_jmpbuf(png)))
|
|
{
|
|
SLang_verror (SL_Write_Error, "PNG I/O error");
|
|
goto return_error;
|
|
}
|
|
png_init_io(png, fp);
|
|
|
|
if ((compress_level >= 0) && (compress_level <= 9))
|
|
png_set_compression_level (png, compress_level);
|
|
|
|
png_set_IHDR (png, info, width, height,
|
|
bit_depth, color_type, PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
|
png_write_info(png, info);
|
|
|
|
if (-1 == write_array (png, image_pointers, height, width, write_fun, tmpbuf))
|
|
goto return_error;
|
|
|
|
png_write_end(png, NULL);
|
|
if (EOF == fclose (p->fp))
|
|
{
|
|
SLang_verror (SL_Write_Error, "Error closing %s", file);
|
|
SLerrno_set_errno (errno);
|
|
}
|
|
else status = 0;
|
|
|
|
p->fp = NULL;
|
|
/* drop */
|
|
return_error:
|
|
if (tmpbuf != NULL)
|
|
SLfree ((char *) tmpbuf);
|
|
free_image_pointers (image_pointers);
|
|
if (p != NULL)
|
|
free_png_type (p);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void write_image (int flip)
|
|
{
|
|
char *file;
|
|
SLang_Array_Type *at;
|
|
int with_alpha = 0;
|
|
int has_with_alpha = 0;
|
|
int compress_level;
|
|
int color_type;
|
|
void (*write_fun) (png_struct *, png_byte *, SLindex_Type, png_byte *);
|
|
|
|
if (SLang_Num_Function_Args == 3)
|
|
{
|
|
if (-1 == SLang_pop_int (&with_alpha))
|
|
return;
|
|
has_with_alpha = 1;
|
|
}
|
|
|
|
if (-1 == SLang_get_int_qualifier ("compress", &compress_level, -1))
|
|
return;
|
|
|
|
if (-1 == SLang_pop_array (&at, 0))
|
|
return;
|
|
|
|
if (at->num_dims != 2)
|
|
{
|
|
SLang_verror (SL_InvalidParm_Error, "Expecting a 2-d array");
|
|
SLang_free_array (at);
|
|
return;
|
|
}
|
|
|
|
switch (SLang_get_int_size (at->data_type))
|
|
{
|
|
case -8:
|
|
case 8:
|
|
if (with_alpha)
|
|
{
|
|
write_fun = write_gray_to_gray_alpha;
|
|
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
|
}
|
|
else
|
|
{
|
|
write_fun = write_gray_to_gray;
|
|
color_type = PNG_COLOR_TYPE_GRAY;
|
|
}
|
|
break;
|
|
case -16:
|
|
case 16:
|
|
if (has_with_alpha && (with_alpha == 0))
|
|
{
|
|
write_fun = write_gray_alpha_to_gray;
|
|
color_type = PNG_COLOR_TYPE_GRAY;
|
|
}
|
|
else
|
|
{
|
|
write_fun = write_gray_alpha_to_gray_alpha;
|
|
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
|
}
|
|
break;
|
|
case -32:
|
|
case 32:
|
|
if (with_alpha)
|
|
{
|
|
write_fun = write_rgb_alpha_to_rgb_alpha;
|
|
color_type = PNG_COLOR_TYPE_RGBA;
|
|
}
|
|
else
|
|
{
|
|
write_fun = write_rgb_to_rgb;
|
|
color_type = PNG_COLOR_TYPE_RGB;
|
|
}
|
|
break;
|
|
default:
|
|
SLang_verror (SL_InvalidParm_Error, "Expecting an 8, 16, or 32 bit integer array");
|
|
SLang_free_array (at);
|
|
return;
|
|
}
|
|
|
|
if (-1 == SLang_pop_slstring (&file))
|
|
{
|
|
SLang_free_array (at);
|
|
return;
|
|
}
|
|
(void) write_image_internal (file, at, color_type, write_fun, flip, compress_level);
|
|
SLang_free_slstring (file);
|
|
SLang_free_array (at);
|
|
}
|
|
|
|
static void read_intrin (void)
|
|
{
|
|
read_image (0);
|
|
}
|
|
static void read_flipped_intrin (void)
|
|
{
|
|
read_image (1);
|
|
}
|
|
|
|
static void write_intrin (void)
|
|
{
|
|
write_image (0);
|
|
}
|
|
static void write_flipped_intrin (void)
|
|
{
|
|
write_image (1);
|
|
}
|
|
|
|
static SLang_Intrin_Fun_Type Module_Intrinsics [] =
|
|
{
|
|
MAKE_INTRINSIC_0("png_read", read_intrin, SLANG_VOID_TYPE),
|
|
MAKE_INTRINSIC_0("png_read_flipped", read_flipped_intrin, SLANG_VOID_TYPE),
|
|
MAKE_INTRINSIC_0("png_write", write_intrin, SLANG_VOID_TYPE),
|
|
MAKE_INTRINSIC_0("png_write_flipped", write_flipped_intrin, SLANG_VOID_TYPE),
|
|
SLANG_END_INTRIN_FUN_TABLE
|
|
};
|
|
|
|
static SLang_Intrin_Var_Type Module_Variables [] =
|
|
{
|
|
MAKE_VARIABLE("_png_module_version_string", &Module_Version_String, SLANG_STRING_TYPE, 1),
|
|
SLANG_END_INTRIN_VAR_TABLE
|
|
};
|
|
|
|
static SLang_IConstant_Type Module_IConstants [] =
|
|
{
|
|
MAKE_ICONSTANT("PNG_COLOR_TYPE_GRAY", PNG_COLOR_TYPE_GRAY),
|
|
MAKE_ICONSTANT("PNG_COLOR_TYPE_GRAY_ALPHA", PNG_COLOR_TYPE_GRAY_ALPHA),
|
|
MAKE_ICONSTANT("PNG_COLOR_TYPE_RGB", PNG_COLOR_TYPE_RGB),
|
|
MAKE_ICONSTANT("PNG_COLOR_TYPE_RGBA", PNG_COLOR_TYPE_RGBA),
|
|
|
|
MAKE_ICONSTANT("_png_module_version", MODULE_VERSION_NUMBER),
|
|
SLANG_END_ICONST_TABLE
|
|
};
|
|
|
|
int init_png_module_ns (char *ns_name)
|
|
{
|
|
unsigned short x;
|
|
|
|
SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
|
|
if (ns == NULL)
|
|
return -1;
|
|
|
|
x = 0xFF;
|
|
Is_Little_Endian = (*(unsigned char *)&x == 0xFF);
|
|
|
|
if (
|
|
(-1 == SLns_add_intrin_var_table (ns, Module_Variables, NULL))
|
|
|| (-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
|
|
|| (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL))
|
|
)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This function is optional */
|
|
void deinit_png_module (void)
|
|
{
|
|
}
|