Imager
view release on metacpan or search on metacpan
SGI/imsgi.c view on Meta::CPAN
=item i_writergb_wiol(img, ig)
Writes an image in targa format. Returns 0 on error.
img - image to store
ig - io_glue object
=cut
*/
int
i_writesgi_wiol(io_glue *ig, i_img *img) {
int rle;
int bpc2;
i_clear_error();
if (img->xsize > SGI_DIM_LIMIT || img->ysize > SGI_DIM_LIMIT) {
i_push_error(0, "image too large for SGI");
return 0;
}
if (!write_sgi_header(img, ig, &rle, &bpc2))
return 0;
mm_log((1, "format rle %d bpc2 %d\n", rle, bpc2));
if (bpc2) {
if (rle)
return write_sgi_16_rle(img, ig);
else
return write_sgi_16_verb(img, ig);
}
else {
if (rle)
return write_sgi_8_rle(img, ig);
else
return write_sgi_8_verb(img, ig);
}
}
static i_img *
read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
i_color *linebuf;
unsigned char *databuf;
int c, y;
int savemask;
i_img_dim width = i_img_get_width(img);
i_img_dim height = i_img_get_height(img);
int channels = i_img_getchannels(img);
int pixmin = header->pixmin;
int pixmax = header->pixmax;
int outmax = pixmax - pixmin;
linebuf = mymalloc(width * sizeof(i_color)); /* checked 31Jul07 TonyC */
databuf = mymalloc(width); /* checked 31Jul07 TonyC */
savemask = i_img_getmask(img);
for(c = 0; c < channels; c++) {
i_img_setmask(img, 1<<c);
for(y = 0; y < height; y++) {
int x;
if (i_io_read(ig, databuf, width) != width) {
i_push_error(0, "SGI image: cannot read image data");
i_img_destroy(img);
myfree(linebuf);
myfree(databuf);
return NULL;
}
if (pixmin == 0 && pixmax == 255) {
for(x = 0; x < img->xsize; x++)
linebuf[x].channel[c] = databuf[x];
}
else {
for(x = 0; x < img->xsize; x++) {
int sample = databuf[x];
if (sample < pixmin)
sample = 0;
else if (sample > pixmax)
sample = outmax;
else
sample -= pixmin;
linebuf[x].channel[c] = sample * 255 / outmax;
}
}
i_plin(img, 0, width, height-1-y, linebuf);
}
}
i_img_setmask(img, savemask);
myfree(linebuf);
myfree(databuf);
return img;
}
static int
read_rle_tables(io_glue *ig, i_img *img,
unsigned long **pstart_tab, unsigned long **plength_tab,
unsigned long *pmax_length) {
i_img_dim height = i_img_get_height(img);
int channels = i_img_getchannels(img);
unsigned char *databuf;
unsigned long *start_tab, *length_tab;
unsigned long max_length = 0;
int i;
size_t databuf_size = (size_t)height * channels * 4;
size_t tab_size = (size_t)height * channels * sizeof(unsigned long);
/* assumption: that the lengths are in bytes rather than in pixels */
if (databuf_size / height / channels != 4
|| tab_size / height / channels != sizeof(unsigned long)) {
i_push_error(0, "SGI image: integer overflow calculating allocation size");
return 0;
}
databuf = mymalloc(height * channels * 4); /* checked 31Jul07 TonyC */
start_tab = mymalloc(height*channels*sizeof(unsigned long));
length_tab = mymalloc(height*channels*sizeof(unsigned long));
/* Read offset table */
if (i_io_read(ig, databuf, height * channels * 4) != height * channels * 4) {
i_push_error(0, "SGI image: short read reading RLE start table");
goto ErrorReturn;
}
for(i = 0; i < height * channels; i++)
start_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
(databuf[i*4+2] << 8) | (databuf[i*4+3]);
/* Read length table */
if (i_io_read(ig, databuf, height*channels*4) != height*channels*4) {
i_push_error(0, "SGI image: short read reading RLE length table");
goto ErrorReturn;
}
for(i=0; i < height * channels; i++) {
length_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
(databuf[i*4+2] << 8) | (databuf[i*4+3]);
if (length_tab[i] > max_length)
max_length = length_tab[i];
}
mm_log((3, "Offset/length table:\n"));
for(i=0; i < height * channels; i++)
mm_log((3, "%d: %lu/%lu\n", i, start_tab[i], length_tab[i]));
*pstart_tab = start_tab;
*plength_tab = length_tab;
SGI/imsgi.c view on Meta::CPAN
}
--data_left;
pixels_left -= count;
while (count-- > 0) {
outp->channel[c] = sample;
++outp;
}
}
}
/* must have a full scanline */
if (pixels_left) {
i_push_error(0, "SGI image: incomplete RLE scanline");
goto ErrorReturn;
}
/* must have used all of the data */
if (data_left) {
i_push_errorf(0, "SGI image: unused RLE data");
goto ErrorReturn;
}
}
i_plin(img, 0, width, height-1-y, linebuf);
}
myfree(linebuf);
myfree(databuf);
myfree(start_tab);
myfree(length_tab);
return img;
ErrorReturn:
if (linebuf)
myfree(linebuf);
if (databuf)
myfree(databuf);
myfree(start_tab);
myfree(length_tab);
i_img_destroy(img);
return NULL;
}
static i_img *
read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
i_fcolor *linebuf;
unsigned char *databuf;
int c, y;
int savemask;
i_img_dim width = i_img_get_width(img);
i_img_dim height = i_img_get_height(img);
int channels = i_img_getchannels(img);
int pixmin = header->pixmin;
int pixmax = header->pixmax;
int outmax = pixmax - pixmin;
linebuf = mymalloc(width * sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
databuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */
savemask = i_img_getmask(img);
for(c = 0; c < channels; c++) {
i_img_setmask(img, 1<<c);
for(y = 0; y < height; y++) {
int x;
if (i_io_read(ig, databuf, width*2) != width*2) {
i_push_error(0, "SGI image: cannot read image data");
i_img_destroy(img);
myfree(linebuf);
myfree(databuf);
return NULL;
}
if (pixmin == 0 && pixmax == 65535) {
for(x = 0; x < img->xsize; x++)
linebuf[x].channel[c] = (databuf[x*2] * 256 + databuf[x*2+1]) / 65535.0;
}
else {
for(x = 0; x < img->xsize; x++) {
int sample = databuf[x*2] * 256 + databuf[x*2+1];
if (sample < pixmin)
sample = 0;
else if (sample > pixmax)
sample = outmax;
else
sample -= pixmin;
linebuf[x].channel[c] = (double)sample / outmax;
}
}
i_plinf(img, 0, width, height-1-y, linebuf);
}
}
i_img_setmask(img, savemask);
myfree(linebuf);
myfree(databuf);
return img;
}
static i_img *
read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) {
i_fcolor *linebuf = NULL;
unsigned char *databuf = NULL;
unsigned long *start_tab, *length_tab;
unsigned long max_length;
i_img_dim width = i_img_get_width(img);
i_img_dim height = i_img_get_height(img);
int channels = i_img_getchannels(img);
i_img_dim y;
int c;
int pixmin = header->pixmin;
int pixmax = header->pixmax;
int outmax = pixmax - pixmin;
if (!read_rle_tables(ig, img,
&start_tab, &length_tab, &max_length)) {
i_img_destroy(img);
return NULL;
}
mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));
if (max_length > (img->xsize * 2 + 1) * 2) {
i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
goto ErrorReturn;
}
linebuf = mymalloc(width*sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */
for(y = 0; y < img->ysize; y++) {
for(c = 0; c < channels; c++) {
int ci = height * c + y;
int datalen = length_tab[ci];
unsigned char *inp;
i_fcolor *outp;
int data_left = datalen;
int pixels_left = width;
int sample;
if (datalen & 1) {
i_push_error(0, "SGI image: invalid RLE length value for BPC=2");
goto ErrorReturn;
}
if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
i_push_error(0, "SGI image: cannot seek to RLE data");
goto ErrorReturn;
}
if (i_io_read(ig, databuf, datalen) != datalen) {
i_push_error(0, "SGI image: cannot read RLE data");
goto ErrorReturn;
}
( run in 1.027 second using v1.01-cache-2.11-cpan-99c4e6809bf )