Skip to content
Browse files

- Finished/rewrote Arnar's old SGI RGB file format support, so Imager

   now has full SGI RGB image format, including RLE and 16-bit/sample
   images.
   https://rt.cpan.org/Ticket/Display.html?id=8666

 - logging functions are now available in the API

 - the convert() method now returns an image of the same sample size as
   the source image.
   https://rt.cpan.org/Ticket/Display.html?id=28492
  • Loading branch information...
1 parent e92cd50 commit d5477d3d0bc40d154ff61827dbc68f2343171772 Tony Cook committed
View
11 Changes
@@ -3,6 +3,13 @@ Imager release history. Older releases can be found in Changes.old
Imager 0.60
===========
+ - Finished/rewrote Arnar's old SGI RGB file format support, so Imager
+ now has full SGI RGB image format, including RLE and 16-bit/sample
+ images.
+ https://rt.cpan.org/Ticket/Display.html?id=8666
+
+ - logging functions are now available in the API
+
Bug fixes:
- in some cases it's possible for giflib/libungif to return color
@@ -18,6 +25,10 @@ Bug fixes:
and i_glinf() API functions which continue to not set the unused
channels.
+ - the convert() method now returns an image of the same sample size as
+ the source image.
+ https://rt.cpan.org/Ticket/Display.html?id=28492
+
Imager 0.59 - 14 June 2007
===========
View
26 Imager.pm
@@ -1378,16 +1378,6 @@ sub read {
$self->{DEBUG} && print "loading a tga file\n";
}
- if ( $input{'type'} eq 'rgb' ) {
- $self->{IMG}=i_readrgb_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
- if ( !defined($self->{IMG}) ) {
- $self->{ERRSTR}=$self->_error_as_msg();
- return undef;
- }
- $self->{DEBUG} && print "loading a tga file\n";
- }
-
-
if ( $input{'type'} eq 'raw' ) {
my %params=(datachannels=>3,storechannels=>3,interleave=>1,%input);
@@ -3155,9 +3145,9 @@ sub convert {
$matrix = $opts{matrix};
}
- my $new = Imager->new();
- $new->{IMG} = i_img_new();
- unless (i_convert($new->{IMG}, $self->{IMG}, $matrix)) {
+ my $new = Imager->new;
+ $new->{IMG} = i_convert($self->{IMG}, $matrix);
+ unless ($new->{IMG}) {
# most likely a bad matrix
$self->{ERRSTR} = _error_as_msg();
return undef;
@@ -3409,7 +3399,7 @@ sub def_guess_type {
return 'png' if ($ext eq "png");
return 'bmp' if ($ext eq "bmp" || $ext eq "dib");
return 'tga' if ($ext eq "tga");
- return 'rgb' if ($ext eq "rgb");
+ return 'sgi' if ($ext eq "rgb" || $ext eq "bw" || $ext eq "sgi" || $ext eq "rgba");
return 'gif' if ($ext eq "gif");
return 'raw' if ($ext eq "raw");
return lc $ext; # best guess
@@ -3888,6 +3878,8 @@ convolution - L<Imager::Filter/conv>
cropping - L<Imager::Transformations/crop>
+CUR files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
+
C<diff> images - L<Imager::Filter/"Image Difference">
dpi - L<Imager::ImageTypes/i_xres>,
@@ -3938,6 +3930,8 @@ guassian blur - L<Imager::Filter/guassian>
hatch fills - L<Imager::Fill/"Hatched fills">
+ICO files - L<Imager::Files/"ICO (Microsoft Windows Icon) and CUR (Microsoft Windows Cursor)">
+
invert image - L<Imager::Filter/hardinvert>
JPEG - L<Imager::Files/"JPEG">
@@ -3976,10 +3970,14 @@ rectangles, drawing - L<Imager::Draw/box>
resizing an image - L<Imager::Transformations/scale>,
L<Imager::Transformations/crop>
+RGB (SGI) files - L<Imager::Files/"SGI (RGB, BW)">
+
saving an image - L<Imager::Files>
scaling - L<Imager::Transformations/scale>
+SGI files - L<Imager::Files/"SGI (RGB, BW)">
+
sharpen - L<Imager::Filters/unsharpmask>, L<Imager::Filters/conv>
size, image - L<Imager::ImageTypes/getwidth>,
View
33 Imager.xs
@@ -1731,23 +1731,19 @@ i_conv(im,pcoef)
i_conv(im,coeff,len);
myfree(coeff);
-undef_int
-i_convert(im, src, coeff)
- Imager::ImgRaw im
+Imager::ImgRaw
+i_convert(src, avmain)
Imager::ImgRaw src
+ AV *avmain
PREINIT:
float *coeff;
int outchan;
int inchan;
- AV *avmain;
SV **temp;
AV *avsub;
int len;
int i, j;
CODE:
- if (!SvROK(ST(2)) || SvTYPE(SvRV(ST(2))) != SVt_PVAV)
- croak("i_convert: parameter 3 must be an arrayref\n");
- avmain = (AV*)SvRV(ST(2));
outchan = av_len(avmain)+1;
/* find the biggest */
inchan = 0;
@@ -1774,7 +1770,7 @@ i_convert(im, src, coeff)
while (i < inchan)
coeff[i++ + j*inchan] = 0;
}
- RETVAL = i_convert(im, src, coeff, outchan, inchan);
+ RETVAL = i_convert(src, coeff, outchan, inchan);
myfree(coeff);
OUTPUT:
RETVAL
@@ -2941,27 +2937,6 @@ i_readtga_wiol(ig, length)
int length
-undef_int
-i_writergb_wiol(im,ig, wierdpack, compress, idstring)
- Imager::ImgRaw im
- Imager::IO ig
- int wierdpack
- int compress
- char* idstring
- PREINIT:
- int idlen;
- CODE:
- idlen = SvCUR(ST(4));
- RETVAL = i_writergb_wiol(im, ig, wierdpack, compress, idstring, idlen);
- OUTPUT:
- RETVAL
-
-
-Imager::ImgRaw
-i_readrgb_wiol(ig, length)
- Imager::IO ig
- int length
-
Imager::ImgRaw
View
8 MANIFEST
@@ -54,6 +54,13 @@ Mandelbrot/mandel.c
Mandelbrot/t/t00mandel.t
Makefile.PL
README
+SGI/Makefile.PL
+SGI/SGI.pm
+SGI/SGI.xs
+SGI/imsgi.c
+SGI/t/00load.t
+SGI/t/10read.t
+SGI/t/20write.t
apidocs.perl Build lib/Imager/APIRef.pm
bigtest.perl Library selection tester
bmp.c Reading and writing Windows BMP files
@@ -177,7 +184,6 @@ regmach.h
regops.perl
render.im
rendert.h Buffer rendering engine types
-rgb.c Reading and writing SGI rgb files
rotate.c
rubthru.im
samples/README
View
2 Makefile.PL
@@ -155,7 +155,7 @@ my @objs = qw(Imager.o draw.o polygon.o image.o io.o iolayer.o
filters.o dynaload.o stackmach.o datatypes.o
regmach.o trans2.o quant.o error.o convert.o
map.o tags.o palimg.o maskimg.o img16.o rotate.o
- bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o hlines.o
+ bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o
imext.o scale.o rubthru.o render.o);
$Recommends{Imager} =
View
20 SGI/Makefile.PL
@@ -0,0 +1,20 @@
+#!perl -w
+use strict;
+use ExtUtils::MakeMaker;
+
+my %opts =
+ (
+ NAME => 'Imager::File::SGI',
+ VERSION_FROM => 'SGI.pm',
+ OBJECT => 'SGI.o imsgi.o',
+ INC => '-I..'
+ );
+my $MM_ver = eval $ExtUtils::MakeMaker::VERSION;
+if ($MM_ver > 6.06) {
+ $opts{AUTHOR} = 'Tony Cook <tony@imager.perl.org>';
+ $opts{ABSTRACT} = 'SGI Image file support';
+}
+
+WriteMakefile(%opts);
+
+
View
89 SGI/SGI.pm
@@ -0,0 +1,89 @@
+package Imager::File::SGI;
+use strict;
+use Imager;
+use vars qw($VERSION @ISA);
+
+BEGIN {
+ $VERSION = "0.01";
+
+ eval {
+ require XSLoader;
+ XSLoader::load('Imager::File::SGI', $VERSION);
+ 1;
+ } or do {
+ require DynaLoader;
+ push @ISA, 'DynaLoader';
+ bootstrap Imager::File::SGI $VERSION;
+ };
+}
+
+Imager->register_reader
+ (
+ type=>'sgi',
+ single =>
+ sub {
+ my ($im, $io, %hsh) = @_;
+ $im->{IMG} = i_readsgi_wiol($io, $hsh{page} || 0);
+
+ unless ($im->{IMG}) {
+ $im->_set_error(Imager->_error_as_msg);
+ return;
+ }
+ return $im;
+ },
+ );
+
+Imager->register_writer
+ (
+ type=>'sgi',
+ single =>
+ sub {
+ my ($im, $io, %hsh) = @_;
+
+ $im->_set_opts(\%hsh, "i_", $im);
+ $im->_set_opts(\%hsh, "sgi_", $im);
+
+ unless (i_writesgi_wiol($io, $im->{IMG})) {
+ $im->_set_error(Imager->_error_as_msg);
+ return;
+ }
+ return $im;
+ },
+ );
+
+__END__
+
+=head1 NAME
+
+Imager::File::ICO - read MS Icon files
+
+=head1 SYNOPSIS
+
+ use Imager;
+
+ my $img = Imager->new;
+ $img->read(file=>"foo.ico")
+ or die $img->errstr;
+
+ my @imgs = Imager->read_multi(file => "foo.ico")
+ or die Imager->errstr;
+
+ $img->write(file => "foo.ico")
+ or die $img->errstr;
+
+ Imager->write_multi({ file => "foo.ico" }, @imgs)
+ or die Imager->errstr;
+
+=head1 DESCRIPTION
+
+Imager's MS Icon support is documented in L<Imager::Files>.
+
+=head1 AUTHOR
+
+Tony Cook <tony@imager.perl.org>
+
+=head1 SEE ALSO
+
+Imager, Imager::Files.
+
+=cut
View
26 SGI/SGI.xs
@@ -0,0 +1,26 @@
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "imext.h"
+#include "imperl.h"
+#include "imsgi.h"
+#include "ppport.h"
+
+DEFINE_IMAGER_CALLBACKS;
+
+MODULE = Imager::File::SGI PACKAGE = Imager::File::SGI
+
+PROTOTYPES: DISABLE
+
+Imager::ImgRaw
+i_readsgi_wiol(ig, partial)
+ Imager::IO ig
+ int partial
+
+int
+i_writesgi_wiol(ig, im)
+ Imager::IO ig
+ Imager::ImgRaw im
+
+BOOT:
+ PERL_INITIALIZE_IMAGER_CALLBACKS;
View
1,200 SGI/imsgi.c
@@ -0,0 +1,1200 @@
+#include "imsgi.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+/* value for imagic */
+#define SGI_MAGIC 474
+
+/* values for the storage field */
+#define SGI_STORAGE_VERBATIM 0
+#define SGI_STORAGE_RLE 1
+
+/* values for the colormap field */
+#define SGI_COLORMAP_NORMAL 0
+#define SGI_COLORMAP_DITHERED 1
+#define SGI_COLORMAP_SCREEN 2
+#define SGI_COLORMAP_COLORMAP 3
+
+/* we add that little bit to avoid rounding issues */
+#define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01))
+
+typedef struct {
+ unsigned short imagic;
+ unsigned char storagetype;
+ unsigned char BPC;
+ unsigned short dimensions;
+ unsigned short xsize, ysize, zsize;
+ unsigned int pixmin, pixmax;
+ char name[80];
+ unsigned int colormap;
+} rgb_header;
+
+static i_img *
+read_rgb_8_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
+static i_img *
+read_rgb_8_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
+static i_img *
+read_rgb_16_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
+static i_img *
+read_rgb_16_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
+static int
+write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2);
+static int
+write_sgi_8_rle(i_img *img, io_glue *ig);
+static int
+write_sgi_8_verb(i_img *img, io_glue *ig);
+static int
+write_sgi_16_rle(i_img *img, io_glue *ig);
+static int
+write_sgi_16_verb(i_img *img, io_glue *ig);
+
+#define Sample16ToF(num) ((num) / 65535.0)
+
+#define _STRING(x) #x
+#define STRING(x) _STRING(x)
+
+/*
+=head1 NAME
+
+rgb.c - implements reading and writing sgi image files, uses io layer.
+
+=head1 SYNOPSIS
+
+ io_glue *ig = io_new_fd( fd );
+ i_img *im = i_readrgb_wiol(ig, 0); // disallow partial reads
+ // or
+ io_glue *ig = io_new_fd( fd );
+ return_code = i_writergb_wiol(im, ig);
+
+=head1 DESCRIPTION
+
+imsgi.c implements the basic functions to read and write portable SGI
+files. It uses the iolayer and needs either a seekable source or an
+entire memory mapped buffer.
+
+=head1 FUNCTION REFERENCE
+
+Some of these functions are internal.
+
+=over
+
+=cut
+*/
+
+/*
+=item rgb_header_unpack(header, headbuf)
+
+Unpacks the header structure into from buffer and stores
+in the header structure.
+
+ header - header structure
+ headbuf - buffer to unpack from
+
+=cut
+*/
+
+
+static
+void
+rgb_header_unpack(rgb_header *header, const unsigned char *headbuf) {
+ header->imagic = (headbuf[0]<<8) + headbuf[1];
+ header->storagetype = headbuf[2];
+ header->BPC = headbuf[3];
+ header->dimensions = (headbuf[4]<<8) + headbuf[5];
+ header->xsize = (headbuf[6]<<8) + headbuf[7];
+ header->ysize = (headbuf[8]<<8) + headbuf[9];
+ header->zsize = (headbuf[10]<<8) + headbuf[11];
+ header->pixmin = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15];
+ header->pixmax = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19];
+ memcpy(header->name,headbuf+24,80);
+ header->name[79] = '\0';
+ header->colormap = (headbuf[104]<<24) + (headbuf[105]<<16)+(headbuf[106]<<8)+headbuf[107];
+}
+
+/* don't make this a macro */
+static void
+store_16(unsigned char *buf, unsigned short value) {
+ buf[0] = value >> 8;
+ buf[1] = value & 0xFF;
+}
+
+static void
+store_32(unsigned char *buf, unsigned short value) {
+ buf[0] = value >> 24;
+ buf[1] = (value >> 16) & 0xFF;
+ buf[2] = (value >> 8) & 0xFF;
+ buf[3] = value & 0xFF;
+}
+
+/*
+=item rgb_header_pack(header, headbuf)
+
+Packs header structure into buffer for writing.
+
+ header - header structure
+ headbuf - buffer to pack into
+
+=cut
+*/
+
+static
+void
+rgb_header_pack(const rgb_header *header, unsigned char headbuf[512]) {
+ memset(headbuf, 0, 512);
+ store_16(headbuf, header->imagic);
+ headbuf[2] = header->storagetype;
+ headbuf[3] = header->BPC;
+ store_16(headbuf+4, header->dimensions);
+ store_16(headbuf+6, header->xsize);
+ store_16(headbuf+8, header->ysize);
+ store_16(headbuf+10, header->zsize);
+ store_32(headbuf+12, header->pixmin);
+ store_32(headbuf+16, header->pixmax);
+ memccpy(headbuf+24, header->name, '\0', 80);
+ store_32(headbuf+104, header->colormap);
+}
+
+/*
+=item i_readsgi_wiol(ig, partial)
+
+Read in an image from the iolayer data source and return the image structure to it.
+Returns NULL on error.
+
+ ig - io_glue object
+ length - maximum length to read from data source, before closing it -1
+ signifies no limit.
+
+=cut
+*/
+
+i_img *
+i_readsgi_wiol(io_glue *ig, int partial) {
+ i_img *img = NULL;
+ int width, height, channels;
+ rgb_header header;
+ unsigned char headbuf[512];
+
+ mm_log((1,"i_readsgi(ig %p, partial %d)\n", ig, partial));
+ i_clear_error();
+
+ if (ig->readcb(ig, headbuf, 512) != 512) {
+ i_push_error(errno, "SGI image: could not read header");
+ return NULL;
+ }
+
+ rgb_header_unpack(&header, headbuf);
+
+ if (header.imagic != SGI_MAGIC) {
+ i_push_error(0, "SGI image: invalid magic number");
+ return NULL;
+ }
+
+ mm_log((1,"imagic: %d\n", header.imagic));
+ mm_log((1,"storagetype: %d\n", header.storagetype));
+ mm_log((1,"BPC: %d\n", header.BPC));
+ mm_log((1,"dimensions: %d\n", header.dimensions));
+ mm_log((1,"xsize: %d\n", header.xsize));
+ mm_log((1,"ysize: %d\n", header.ysize));
+ mm_log((1,"zsize: %d\n", header.zsize));
+ mm_log((1,"min: %d\n", header.pixmin));
+ mm_log((1,"max: %d\n", header.pixmax));
+ mm_log((1,"name [skipped]\n"));
+ mm_log((1,"colormap: %d\n", header.colormap));
+
+ if (header.colormap != SGI_COLORMAP_NORMAL) {
+ i_push_errorf(0, "SGI image: invalid value for colormap (%d)", header.colormap);
+ return NULL;
+ }
+
+ if (header.BPC != 1 && header.BPC != 2) {
+ i_push_errorf(0, "SGI image: invalid value for BPC (%d)", header.BPC);
+ return NULL;
+ }
+
+ if (header.storagetype != SGI_STORAGE_VERBATIM
+ && header.storagetype != SGI_STORAGE_RLE) {
+ i_push_error(0, "SGI image: invalid storage type field");
+ return NULL;
+ }
+
+ if (header.pixmin >= header.pixmax) {
+ i_push_error(0, "SGI image: invalid pixmin >= pixmax");
+ return NULL;
+ }
+
+ width = header.xsize;
+ height = header.ysize;
+ channels = header.zsize;
+
+ switch (header.dimensions) {
+ case 1:
+ channels = 1;
+ height = 1;
+ break;
+
+ case 2:
+ channels = 1;
+ break;
+
+ case 3:
+ /* fall through and use all of the dimensions */
+ break;
+
+ default:
+ i_push_error(0, "SGI image: invalid dimension field");
+ return NULL;
+ }
+
+ if (!i_int_check_image_file_limits(width, height, channels, header.BPC)) {
+ mm_log((1, "i_readsgi_wiol: image size exceeds limits\n"));
+ return NULL;
+ }
+
+ if (header.BPC == 1) {
+ img = i_img_8_new(width, height, channels);
+ if (!img)
+ goto ErrorReturn;
+
+ switch (header.storagetype) {
+ case SGI_STORAGE_VERBATIM:
+ img = read_rgb_8_verbatim(img, ig, &header);
+ break;
+
+ case SGI_STORAGE_RLE:
+ img = read_rgb_8_rle(img, ig, &header);
+ break;
+
+ default:
+ goto ErrorReturn;
+ }
+ }
+ else {
+ img = i_img_16_new(width, height, channels);
+ if (!img)
+ goto ErrorReturn;
+
+ switch (header.storagetype) {
+ case SGI_STORAGE_VERBATIM:
+ img = read_rgb_16_verbatim(img, ig, &header);
+ break;
+
+ case SGI_STORAGE_RLE:
+ img = read_rgb_16_rle(img, ig, &header);
+ break;
+
+ default:
+ goto ErrorReturn;
+ }
+ }
+
+ if (!img)
+ goto ErrorReturn;
+
+ if (*header.name)
+ i_tags_set(&img->tags, "i_comment", header.name, -1);
+ i_tags_setn(&img->tags, "sgi_pixmin", header.pixmin);
+ i_tags_setn(&img->tags, "sgi_pixmax", header.pixmax);
+ i_tags_setn(&img->tags, "sgi_bpc", header.BPC);
+ i_tags_setn(&img->tags, "sgi_rle", header.storagetype == SGI_STORAGE_RLE);
+ i_tags_set(&img->tags, "i_format", "sgi", -1);
+
+ return img;
+
+ ErrorReturn:
+ if (img) i_img_destroy(img);
+ return NULL;
+}
+
+/*
+=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 (!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 (ig->readcb(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 (ig->readcb(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] = (databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
+ (databuf[i*4+2] << 8) | (databuf[i*4+3]);
+
+
+ /* Read length table */
+ if (ig->readcb(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] = (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: %d/%d\n", i, start_tab[i], length_tab[i]));
+
+ *pstart_tab = start_tab;
+ *plength_tab = length_tab;
+ *pmax_length = max_length;
+
+ myfree(databuf);
+
+ return 1;
+
+ ErrorReturn:
+ myfree(databuf);
+ myfree(start_tab);
+ myfree(length_tab);
+
+ return 0;
+}
+
+static i_img *
+read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
+ i_color *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: %d\n", max_length));
+
+ if (max_length > (img->xsize + 1) * 2) {
+ i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
+ goto ErrorReturn;
+ }
+
+ linebuf = mymalloc(width*sizeof(i_color)); /* 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_color *outp;
+ int data_left = datalen;
+ int pixels_left = width;
+ i_sample_t sample;
+
+ if (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
+ i_push_error(0, "SGI image: cannot seek to RLE data");
+ goto ErrorReturn;
+ }
+ if (ig->readcb(ig, databuf, datalen) != datalen) {
+ i_push_error(0, "SGI image: cannot read RLE data");
+ goto ErrorReturn;
+ }
+
+ inp = databuf;
+ outp = linebuf;
+ while (data_left) {
+ int code = *inp++;
+ int count = code & 0x7f;
+ --data_left;
+
+ if (count == 0)
+ break;
+ if (code & 0x80) {
+ /* literal run */
+ /* sanity checks */
+ if (count > pixels_left) {
+ i_push_error(0, "SGI image: literal run overflows scanline");
+ goto ErrorReturn;
+ }
+ if (count > data_left) {
+ i_push_error(0, "SGI image: literal run consumes more data than available");
+ goto ErrorReturn;
+ }
+ /* copy the run */
+ pixels_left -= count;
+ data_left -= count;
+ if (pixmin == 0 && pixmax == 255) {
+ while (count-- > 0) {
+ outp->channel[c] = *inp++;
+ ++outp;
+ }
+ }
+ else {
+ while (count-- > 0) {
+ int sample = *inp++;
+ if (sample < pixmin)
+ sample = 0;
+ else if (sample > pixmax)
+ sample = outmax;
+ else
+ sample -= pixmin;
+ outp->channel[c] = sample * 255 / outmax;
+ ++outp;
+ }
+ }
+ }
+ else {
+ /* RLE run */
+ if (count > pixels_left) {
+ i_push_error(0, "SGI image: RLE run overflows scanline");
+ mm_log((2, "RLE run overflows scanline (y %d chan %d offset %ld len %ld)\n", y, c, start_tab[ci], length_tab[ci]));
+ goto ErrorReturn;
+ }
+ if (data_left < 1) {
+ i_push_error(0, "SGI image: RLE run has no data for pixel");
+ goto ErrorReturn;
+ }
+ sample = *inp++;
+ if (pixmin != 0 || pixmax != 255) {
+ if (sample < pixmin)
+ sample = 0;
+ else if (sample > pixmax)
+ sample = outmax;
+ else
+ sample -= pixmin;
+ sample = sample * 255 / outmax;
+ }
+ --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 (ig->readcb(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 (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
+ i_push_error(0, "SGI image: cannot seek to RLE data");
+ goto ErrorReturn;
+ }
+ if (ig->readcb(ig, databuf, datalen) != datalen) {
+ i_push_error(0, "SGI image: cannot read RLE data");
+ goto ErrorReturn;
+ }
+
+ inp = databuf;
+ outp = linebuf;
+ while (data_left > 0) {
+ int code = inp[0] * 256 + inp[1];
+ int count = code & 0x7f;
+ inp += 2;
+ data_left -= 2;
+
+ if (count == 0)
+ break;
+ if (code & 0x80) {
+ /* literal run */
+ /* sanity checks */
+ if (count > pixels_left) {
+ i_push_error(0, "SGI image: literal run overflows scanline");
+ goto ErrorReturn;
+ }
+ if (count > data_left) {
+ i_push_error(0, "SGI image: literal run consumes more data than available");
+ goto ErrorReturn;
+ }
+ /* copy the run */
+ pixels_left -= count;
+ data_left -= count * 2;
+ if (pixmin == 0 && pixmax == 65535) {
+ while (count-- > 0) {
+ outp->channel[c] = (inp[0] * 256 + inp[1]) / 65535.0;
+ inp += 2;
+ ++outp;
+ }
+ }
+ else {
+ while (count-- > 0) {
+ int sample = inp[0] * 256 + inp[1];
+ if (sample < pixmin)
+ sample = 0;
+ else if (sample > pixmax)
+ sample = outmax;
+ else
+ sample -= pixmin;
+ outp->channel[c] = (double)sample / outmax;
+ ++outp;
+ inp += 2;
+ }
+ }
+ }
+ else {
+ double fsample;
+ /* RLE run */
+ if (count > pixels_left) {
+ i_push_error(0, "SGI image: RLE run overflows scanline");
+ goto ErrorReturn;
+ }
+ if (data_left < 2) {
+ i_push_error(0, "SGI image: RLE run has no data for pixel");
+ goto ErrorReturn;
+ }
+ sample = inp[0] * 256 + inp[1];
+ inp += 2;
+ data_left -= 2;
+ if (pixmin != 0 || pixmax != 65535) {
+ if (sample < pixmin)
+ sample = 0;
+ else if (sample > pixmax)
+ sample = outmax;
+ else
+ sample -= pixmin;
+ fsample = (double)sample / outmax;
+ }
+ else {
+ fsample = (double)sample / 65535.0;
+ }
+ pixels_left -= count;
+ while (count-- > 0) {
+ outp->channel[c] = fsample;
+ ++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_plinf(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 int
+write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2) {
+ rgb_header header;
+ unsigned char headbuf[512] = { 0 };
+
+ header.imagic = SGI_MAGIC;
+ if (!i_tags_get_int(&img->tags, "sgi_rle", 0, rle))
+ *rle = 0;
+ header.storagetype = *rle ? SGI_STORAGE_RLE : SGI_STORAGE_VERBATIM;
+ header.pixmin = 0;
+ header.colormap = SGI_COLORMAP_NORMAL;
+ *bpc2 = img->bits > 8;
+ if (*bpc2) {
+ header.BPC = 2;
+ header.pixmax = 65535;
+ }
+ else {
+ header.BPC = 1;
+ header.pixmax = 255;
+ }
+ if (img->channels == 1) {
+ header.dimensions = 2;
+ }
+ else {
+ header.dimensions = 3;
+ }
+ header.xsize = img->xsize;
+ header.ysize = img->ysize;
+ header.zsize = img->channels;
+ memset(header.name, 0, sizeof(header.name));
+ i_tags_get_string(&img->tags, "i_comment", 0,
+ header.name, sizeof(header.name));
+
+ rgb_header_pack(&header, headbuf);
+
+ if (i_io_write(ig, headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
+ i_push_error(0, "SGI image: cannot write header");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+write_sgi_8_verb(i_img *img, io_glue *ig) {
+ i_sample_t *linebuf;
+ i_img_dim width = img->xsize;
+ int c;
+ i_img_dim y;
+
+ linebuf = mymalloc(width); /* checked 31Jul07 TonyC */
+ for (c = 0; c < img->channels; ++c) {
+ for (y = img->ysize - 1; y >= 0; --y) {
+ i_gsamp(img, 0, width, y, linebuf, &c, 1);
+ if (ig->writecb(ig, linebuf, width) != width) {
+ i_push_error(errno, "SGI image: error writing image data");
+ myfree(linebuf);
+ return 0;
+ }
+ }
+ }
+ myfree(linebuf);
+
+ return 1;
+}
+
+static int
+write_sgi_8_rle(i_img *img, io_glue *ig) {
+ i_sample_t *linebuf;
+ unsigned char *comp_buf;
+ i_img_dim width = img->xsize;
+ int c;
+ i_img_dim y;
+ unsigned char *offsets;
+ unsigned char *lengths;
+ int offset_pos = 0;
+ size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
+ unsigned long start_offset = 512 + offsets_size;
+ unsigned long current_offset = start_offset;
+ int in_left;
+ unsigned char *outp;
+ i_sample_t *inp;
+ size_t comp_size;
+
+ if (offsets_size / 2 / 4 / img->channels != img->ysize) {
+ i_push_error(0, "SGI image: integer overflow calculating allocation size");
+ return 0;
+ }
+
+ linebuf = mymalloc(width); /* checked 31Jul07 TonyC */
+ comp_buf = mymalloc((width + 1) * 2); /* checked 31Jul07 TonyC */
+ offsets = mymalloc(offsets_size);
+ memset(offsets, 0, offsets_size);
+ if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
+ i_push_error(errno, "SGI image: error writing offsets/lengths");
+ goto Error;
+ }
+ lengths = offsets + img->ysize * img->channels * 4;
+ for (c = 0; c < img->channels; ++c) {
+ for (y = img->ysize - 1; y >= 0; --y) {
+ i_gsamp(img, 0, width, y, linebuf, &c, 1);
+ in_left = width;
+ outp = comp_buf;
+ inp = linebuf;
+ while (in_left) {
+ unsigned char *run_start = inp;
+
+ /* first try for an RLE run */
+ int run_length = 1;
+ while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ if (run_length > 2) {
+ *outp++ = run_length;
+ *outp++ = inp[0];
+ inp++;
+ in_left -= run_length;
+ }
+ else {
+ inp = run_start;
+
+ /* scan for a literal run */
+ run_length = 1;
+ run_start = inp;
+ while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ ++inp;
+
+ /* fill out the run if 2 or less samples left and there's space */
+ if (in_left - run_length <= 2
+ && run_length + in_left - run_length <= 127) {
+ run_length += in_left;
+ in_left = 0;
+ }
+ in_left -= run_length;
+ *outp++ = run_length | 0x80;
+ while (run_length--) {
+ *outp++ = *run_start++;
+ }
+ }
+ }
+ *outp++ = 0;
+ comp_size = outp - comp_buf;
+ store_32(offsets + offset_pos, current_offset);
+ store_32(lengths + offset_pos, comp_size);
+ offset_pos += 4;
+ current_offset += comp_size;
+ if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
+ i_push_error(errno, "SGI image: error writing RLE data");
+ goto Error;
+ }
+ }
+ }
+
+ /* seek back to store the offsets and lengths */
+ if (i_io_seek(ig, 512, SEEK_SET) != 512) {
+ i_push_error(errno, "SGI image: cannot seek to RLE table");
+ goto Error;
+ }
+
+ if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
+ i_push_error(errno, "SGI image: cannot write final RLE table");
+ goto Error;
+ }
+
+ myfree(offsets);
+ myfree(comp_buf);
+ myfree(linebuf);
+
+ return 1;
+
+ Error:
+ myfree(offsets);
+ myfree(comp_buf);
+ myfree(linebuf);
+ return 0;
+}
+
+static int
+write_sgi_16_verb(i_img *img, io_glue *ig) {
+ i_fsample_t *linebuf;
+ unsigned char *encbuf;
+ unsigned char *outp;
+ i_img_dim width = img->xsize;
+ int c;
+ i_img_dim x;
+ i_img_dim y;
+
+ linebuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */
+ encbuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */
+ for (c = 0; c < img->channels; ++c) {
+ for (y = img->ysize - 1; y >= 0; --y) {
+ i_gsampf(img, 0, width, y, linebuf, &c, 1);
+ for (x = 0, outp = encbuf; x < width; ++x, outp+=2) {
+ unsigned short samp16 = SampleFTo16(linebuf[x]);
+ store_16(outp, samp16);
+ }
+ if (ig->writecb(ig, encbuf, width * 2) != width * 2) {
+ i_push_error(errno, "SGI image: error writing image data");
+ myfree(linebuf);
+ myfree(encbuf);
+ return 0;
+ }
+ }
+ }
+ myfree(linebuf);
+ myfree(encbuf);
+
+ return 1;
+}
+
+static int
+write_sgi_16_rle(i_img *img, io_glue *ig) {
+ i_fsample_t *sampbuf;
+ unsigned short *linebuf;
+ unsigned char *comp_buf;
+ i_img_dim width = img->xsize;
+ int c;
+ i_img_dim y;
+ unsigned char *offsets;
+ unsigned char *lengths;
+ int offset_pos = 0;
+ size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
+ unsigned long start_offset = 512 + offsets_size;
+ unsigned long current_offset = start_offset;
+ int in_left;
+ unsigned char *outp;
+ unsigned short *inp;
+ size_t comp_size;
+ i_img_dim x;
+
+ if (offsets_size / 4 / 2 / img->channels != img->ysize) {
+ i_push_error(0, "SGI image: integer overflow calculating allocation size");
+ return 0;
+ }
+
+ sampbuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */
+ linebuf = mymalloc(width * sizeof(unsigned short)); /* checked 31Jul07 TonyC */
+ comp_buf = mymalloc((width + 1) * 2 * 2); /* checked 31Jul07 TonyC */
+ offsets = mymalloc(offsets_size);
+ memset(offsets, 0, offsets_size);
+ if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
+ i_push_error(errno, "SGI image: error writing offsets/lengths");
+ goto Error;
+ }
+ lengths = offsets + img->ysize * img->channels * 4;
+ for (c = 0; c < img->channels; ++c) {
+ for (y = img->ysize - 1; y >= 0; --y) {
+ i_gsampf(img, 0, width, y, sampbuf, &c, 1);
+ for (x = 0; x < width; ++x)
+ linebuf[x] = (unsigned short)(SampleFTo16(sampbuf[x]));
+ in_left = width;
+ outp = comp_buf;
+ inp = linebuf;
+ while (in_left) {
+ unsigned short *run_start = inp;
+
+ /* first try for an RLE run */
+ int run_length = 1;
+ while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ if (run_length > 2) {
+ store_16(outp, run_length);
+ store_16(outp+2, inp[0]);
+ outp += 4;
+ inp++;
+ in_left -= run_length;
+ }
+ else {
+ inp = run_start;
+
+ /* scan for a literal run */
+ run_length = 1;
+ run_start = inp;
+ while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
+ ++run_length;
+ ++inp;
+ }
+ ++inp;
+
+ /* fill out the run if 2 or less samples left and there's space */
+ if (in_left - run_length <= 2
+ && run_length + in_left - run_length <= 127) {
+ run_length += in_left;
+ in_left = 0;
+ }
+ in_left -= run_length;
+ store_16(outp, run_length | 0x80);
+ outp += 2;
+ while (run_length--) {
+ store_16(outp, *run_start++);
+ outp += 2;
+ }
+ }
+ }
+ store_16(outp, 0);
+ outp += 2;
+ comp_size = outp - comp_buf;
+ store_32(offsets + offset_pos, current_offset);
+ store_32(lengths + offset_pos, comp_size);
+ offset_pos += 4;
+ current_offset += comp_size;
+ if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
+ i_push_error(errno, "SGI image: error writing RLE data");
+ goto Error;
+ }
+ }
+ }
+
+ /* seek back to store the offsets and lengths */
+ if (i_io_seek(ig, 512, SEEK_SET) != 512) {
+ i_push_error(errno, "SGI image: cannot seek to RLE table");
+ goto Error;
+ }
+
+ if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
+ i_push_error(errno, "SGI image: cannot write final RLE table");
+ goto Error;
+ }
+
+ myfree(offsets);
+ myfree(comp_buf);
+ myfree(linebuf);
+ myfree(sampbuf);
+
+ return 1;
+
+ Error:
+ myfree(offsets);
+ myfree(comp_buf);
+ myfree(linebuf);
+ myfree(sampbuf);
+
+ return 0;
+}
View
12 SGI/imsgi.h
@@ -0,0 +1,12 @@
+#ifndef IMAGER_IMICON_H
+#define IMAGER_IMICON_H
+
+#include "imext.h"
+
+extern i_img *
+i_readsgi_wiol(io_glue *ig, int partial);
+
+extern int
+i_writesgi_wiol(i_io_glue_t *ig, i_img *im);
+
+#endif
View
5 SGI/t/00load.t
@@ -0,0 +1,5 @@
+#!perl -w
+use strict;
+use Test::More tests => 1;
+
+use_ok('Imager::File::SGI');
View
318 SGI/t/10read.t
@@ -0,0 +1,318 @@
+#!perl -w
+use strict;
+use Imager;
+use Imager::Test qw(is_image is_color3);
+use Test::More tests => 103;
+
+-d 'testout' or mkdir 'testout';
+
+Imager::init_log('testout/10read.log', 2);
+
+{
+ my $im_verb = Imager->new;
+ ok($im_verb->read(file => 'testimg/verb.rgb'), "read verbatim")
+ or print "# ", $im_verb->errstr, "\n";
+ is($im_verb->getchannels, 3, "check channels");
+ is($im_verb->getwidth, 20, "check width");
+ is($im_verb->getheight, 20, "check height");
+ is_color3($im_verb->getpixel(x => 0, 'y' => 0), 255, 0, 0, "check 0,0");
+ is_color3($im_verb->getpixel(x => 1, 'y' => 2), 255, 255, 0, "check 0,2");
+ is_color3($im_verb->getpixel(x => 2, 'y' => 4), 0, 255, 255, "check 2,5");
+ is($im_verb->tags(name => 'i_format'), 'sgi', "check i_format tag");
+ is($im_verb->tags(name => 'sgi_rle'), 0, "check sgi_rgb");
+ is($im_verb->tags(name => 'sgi_pixmin'), 0, "check pixmin");
+ is($im_verb->tags(name => 'sgi_pixmax'), 255, "check pixmax");
+ is($im_verb->tags(name => 'sgi_bpc'), 1, "check bpc");
+ is($im_verb->tags(name => 'i_comment'), 'test image',
+ "check name string");
+
+ my $im_rle = Imager->new;
+ ok($im_rle->read(file => 'testimg/rle.rgb'), "read rle")
+ or print "# ", $im_rle->errstr, "\n";
+ is($im_rle->tags(name => 'sgi_rle'), 1, "check sgi_rgb");
+
+ my $im_rleagr = Imager->new;
+ ok($im_rleagr->read(file => 'testimg/rleagr.rgb'), "read rleagr")
+ or print "# ", $im_rleagr->errstr, "\n";
+
+ my $im6 = Imager->new;
+ ok($im6->read(file => 'testimg/verb6.rgb'), "read verbatim 6-bit")
+ or print "# ", $im6->errstr, "\n";
+ is($im6->tags(name => 'sgi_pixmax'), 63, "check pixmax");
+
+ is_image($im_verb, $im_rle, "compare verbatim to rle");
+ is_image($im_verb, $im_rleagr, "compare verbatim to rleagr");
+ is_image($im_verb, $im6, "compare verbatim to verb 6-bit");
+
+ my $im_verb12 = Imager->new;
+ ok($im_verb12->read(file => 'testimg/verb12.rgb'), "read verbatim 12")
+ or print "# ", $im_verb12->errstr, "\n";
+ is($im_verb12->bits, 16, "check bits on verb12");
+ is($im_verb12->tags(name => 'sgi_pixmax'), 4095, "check pixmax");
+
+ my $im_verb16 = Imager->new;
+ ok($im_verb16->read(file => 'testimg/verb16.rgb'), "read verbatim 16")
+ or print "# ", $im_verb16->errstr, "\n";
+ is($im_verb16->bits, 16, "check bits on verb16");
+ is($im_verb16->tags(name => 'sgi_pixmax'), 65535, "check pixmax");
+
+ is_image($im_verb, $im_verb12, "compare verbatim to verb12");
+ is_image($im_verb, $im_verb16, "compare verbatim to verb16");
+
+ my $im_rle6 = Imager->new;
+ ok($im_rle6->read(file => 'testimg/rle6.rgb'), "read rle 6 bit");
+ is($im_rle6->tags(name => 'sgi_pixmax'), 63, 'check pixmax');
+ is_image($im_verb, $im_rle6, 'compare verbatim to rle6');
+
+ my $im_rle12 = Imager->new;
+ ok($im_rle12->read(file => 'testimg/rle12.rgb'), 'read rle 12 bit')
+ or print "# ", $im_rle12->errstr, "\n";
+ is($im_rle12->tags(name => 'sgi_pixmax'), 4095, 'check pixmax');
+ is_image($im_verb, $im_rle12, 'compare verbatim to rle12');
+
+ my $im_rle16 = Imager->new;
+ ok($im_rle16->read(file => 'testimg/rle16.rgb'), 'read rle 16 bit')
+ or print "# ", $im_rle16->errstr, "\n";
+ is($im_rle16->tags(name => 'sgi_pixmax'), 65535, 'check pixmax');
+ is($im_rle16->tags(name => 'sgi_bpc'), 2, "check bpc");
+ is_image($im_verb, $im_rle16, 'compare verbatim to rle16');
+}
+
+{
+ # short read tests, each is source file, limit, match, description
+ my @tests =
+ (
+ [
+ 'verb.rgb', 100,
+ 'SGI image: could not read header', 'header',
+ ],
+ [
+ 'verb.rgb', 512,
+ 'SGI image: cannot read image data',
+ 'verbatim image data'
+ ],
+ [
+ 'rle.rgb', 512,
+ 'SGI image: short read reading RLE start table',
+ 'rle start table'
+ ],
+ [
+ 'rle.rgb', 752,
+ 'SGI image: short read reading RLE length table',
+ 'rle length table'
+ ],
+ [
+ 'rle.rgb', 0x510,
+ "SGI image: cannot read RLE data",
+ 'read rle data'
+ ],
+ [
+ 'rle.rgb', 0x50E,
+ "SGI image: cannot seek to RLE data",
+ 'seek rle data'
+ ],
+ [
+ 'verb16.rgb', 512,
+ 'SGI image: cannot read image data',
+ 'read image data (16-bit)'
+ ],
+ [
+ 'rle16.rgb', 512,
+ 'SGI image: short read reading RLE start table',
+ 'rle start table (16-bit)',
+ ],
+ [
+ 'rle16.rgb', 0x42f,
+ 'SGI image: cannot seek to RLE data',
+ 'seek RLE data (16-bit)'
+ ],
+ [
+ 'rle16.rgb', 0x64A,
+ 'SGI image: cannot read RLE data',
+ 'read rle image data (16-bit)'
+ ],
+ );
+ for my $test (@tests) {
+ my ($src, $size, $match, $desc) = @$test;
+ open SRC, "< testimg/$src"
+ or die "Cannot open testimg/$src: $!";
+ binmode SRC;
+ my $data;
+ read(SRC, $data, $size) == $size
+ or die "Could not read $size bytes from $src";
+ close SRC;
+ my $im = Imager->new;
+ ok(!$im->read(data => $data, type => 'sgi'),
+ "read: $desc");
+ is($im->errstr, $match, "error match: $desc");
+ }
+}
+
+{
+ # each entry is: source file, patches, expected error, description
+ my @tests =
+ (
+ [
+ 'verb.rgb',
+ { 0 => '00 00' },
+ 'SGI image: invalid magic number',
+ 'bad magic',
+ ],
+ [
+ 'verb.rgb',
+ { 104 => '00 00 00 01' },
+ 'SGI image: invalid value for colormap (1)',
+ 'invalid colormap field',
+ ],
+ [
+ 'verb.rgb',
+ { 3 => '03' },
+ 'SGI image: invalid value for BPC (3)',
+ 'invalid bpc field',
+ ],
+ [
+ 'verb.rgb',
+ { 2 => '03' },
+ 'SGI image: invalid storage type field',
+ 'invalid storage type field',
+ ],
+ [
+ 'verb.rgb',
+ { 4 => '00 04' },
+ 'SGI image: invalid dimension field',
+ 'invalid dimension field',
+ ],
+ [
+ 'rle.rgb',
+ { 0x2f0 => '00 00 00 2b' },
+ 'SGI image: ridiculous RLE line length 43',
+ 'invalid rle length',
+ ],
+ [
+ 'rle.rgb',
+ { 0x3E0 => '95' },
+ 'SGI image: literal run overflows scanline',
+ 'literal run overflow scanline',
+ ],
+ [
+ 'rle.rgb',
+ { 0x3E0 => '87' },
+ 'SGI image: literal run consumes more data than available',
+ 'literal run consuming too much data',
+ ],
+ [
+ 'rle.rgb',
+ { 0x3E0 => '15' },
+ 'SGI image: RLE run overflows scanline',
+ 'RLE run overflows scanline',
+ ],
+ [
+ 'rle.rgb',
+ { 0x3E0 => '81 FF 12 00 01' },
+ 'SGI image: RLE run has no data for pixel',
+ 'RLE run has no data for pixel',
+ ],
+ [
+ 'rle.rgb',
+ { 0x3E0 => '81 FF 12 00' },
+ 'SGI image: incomplete RLE scanline',
+ 'incomplete RLE scanline',
+ ],
+ [
+ 'rle.rgb',
+ { 0x2F0 => '00 00 00 06' },
+ 'SGI image: unused RLE data',
+ 'unused RLE data',
+ ],
+ [
+ 'verb.rgb',
+ { 0x0c => '00 00 00 FF 00 00 00 00' },
+ 'SGI image: invalid pixmin >= pixmax',
+ 'bad pixmin/pixmax',
+ ],
+ [
+ 'rle16.rgb',
+ { 0x2f0 => '00 00 00 0B' },
+ 'SGI image: invalid RLE length value for BPC=2',
+ 'bad RLE table (length) (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x2f0 => '00 00 00 53' },
+ 'SGI image: ridiculous RLE line length 83',
+ 'way too big RLE line length (16-bit)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x426 => '00 95' },
+ 'SGI image: literal run overflows scanline',
+ 'literal overflow scanline (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x426 => '00 93' },
+ 'SGI image: literal run consumes more data than available',
+ 'literal overflow data (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x3EA => '00 15' },
+ 'SGI image: RLE run overflows scanline',
+ 'rle overflow scanline (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x3EA => '00 15' },
+ 'SGI image: RLE run overflows scanline',
+ 'rle overflow scanline (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x3EA => '00 83 ff ff ff ff ff ff 00 01' },
+ 'SGI image: RLE run has no data for pixel',
+ 'rle code no argument (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x3EA => '00 14 ff ff 00 00' },
+ 'SGI image: unused RLE data',
+ 'unused RLE data (bpc=2)'
+ ],
+ [
+ 'rle16.rgb',
+ { 0x3EA => '00 12 ff ff' },
+ 'SGI image: incomplete RLE scanline',
+ 'incomplete rle scanline (bpc=2)'
+ ],
+ );
+
+ # invalid file tests - take our original files and patch them a
+ # little to make them invalid
+ my $test_index = 0;
+ for my $test (@tests) {
+ my ($filename, $patches, $error, $desc) = @$test;
+
+ my $data = load_patched_file("testimg/$filename", $patches);
+ my $im = Imager->new;
+ ok(!$im->read(data => $data, type=>'sgi'),
+ "$test_index - $desc:should fail to read");
+ is($im->errstr, $error, "$test_index - $desc:check message");
+ ++$test_index;
+ }
+}
+
+sub load_patched_file {
+ my ($filename, $patches) = @_;
+
+ open IMDATA, "< $filename"
+ or die "Cannot open $filename: $!";
+ binmode IMDATA;
+ my $data = do { local $/; <IMDATA> };
+ for my $offset (keys %$patches) {
+ (my $hdata = $patches->{$offset}) =~ tr/ //d;
+ my $pdata = pack("H*", $hdata);
+ substr($data, $offset, length $pdata) = $pdata;
+ }
+
+ return $data;
+}
View
197 SGI/t/20write.t
@@ -0,0 +1,197 @@
+#!perl -w
+use strict;
+use Imager;
+use Test::More tests => 51;
+use Imager::Test qw(test_image test_image_16 is_image);
+use Fcntl ':seek';
+
+-d 'testout' or mkdir 'testout';
+
+Imager::init_log('testout/20write.log', 2);
+
+{
+ my $im = test_image();
+ ok($im->write(file => 'testout/20verb.rgb'), "write 8-bit verbatim")
+ or print "# ", $im->errstr, "\n";
+ my $im2 = Imager->new;
+ ok($im2->read(file => 'testout/20verb.rgb'), "read it back")
+ or print "# ", $im2->errstr, "\n";
+ is_image($im, $im2, "compare");
+ is($im2->tags(name => 'sgi_rle'), 0, "check not rle");
+ is($im2->tags(name => 'sgi_bpc'), 1, "check bpc");
+ is($im2->tags(name => 'i_comment'), undef, "no namestr");
+
+ ok($im->write(file => 'testout/20rle.rgb',
+ sgi_rle => 1,
+ i_comment => "test"), "write 8-bit rle")
+ or print "# ", $im->errstr, "\n";
+ my $im3 = Imager->new;
+ ok($im3->read(file => 'testout/20rle.rgb'), "read it back")
+ or print "# ", $im3->errstr, "\n";
+ is_image($im, $im3, "compare");
+ is($im3->tags(name => 'sgi_rle'), 1, "check not rle");
+ is($im3->tags(name => 'sgi_bpc'), 1, "check bpc");
+ is($im3->tags(name => 'i_comment'), 'test', "check i_comment set");
+}
+
+{
+ my $im = test_image_16();
+ ok($im->write(file => 'testout/20verb16.rgb'), "write 16-bit verbatim")
+ or print "# ", $im->errstr, "\n";
+ my $im2 = Imager->new;
+ ok($im2->read(file => 'testout/20verb16.rgb'), "read it back")
+ or print "# ", $im2->errstr, "\n";
+ is_image($im, $im2, "compare");
+ is($im2->tags(name => 'sgi_rle'), 0, "check not rle");
+ is($im2->tags(name => 'sgi_bpc'), 2, "check bpc");
+ is($im2->tags(name => 'i_comment'), undef, "no namestr");
+
+ ok($im->write(file => 'testout/20rle16.rgb',
+ sgi_rle => 1,
+ i_comment => "test"), "write 16-bit rle")
+ or print "# ", $im->errstr, "\n";
+ my $im3 = Imager->new;
+ ok($im3->read(file => 'testout/20rle16.rgb'), "read it back")
+ or print "# ", $im3->errstr, "\n";
+ is_image($im, $im3, "compare");
+ is($im3->tags(name => 'sgi_rle'), 1, "check not rle");
+ is($im3->tags(name => 'sgi_bpc'), 2, "check bpc");
+ is($im3->tags(name => 'i_comment'), 'test', "check i_comment set");
+}
+
+{
+ # grey scale check
+ my $im = test_image()->convert(preset=>'grey');
+ ok($im->write(file => 'testout/20vgray8.bw'), "write 8-bit verbatim grey")
+ or print "# ", $im->errstr, "\n";
+ my $im2 = Imager->new;
+ ok($im2->read(file => 'testout/20vgray8.bw'), "read it back")
+ or print "# ", $im2->errstr, "\n";
+ is_image($im, $im2, "compare");
+ is($im2->tags(name => 'i_format'), 'sgi', "check we saved as SGI");
+ is($im2->tags(name => 'sgi_rle'), 0, "check not rle");
+ is($im2->tags(name => 'sgi_bpc'), 1, "check bpc");
+ is($im2->tags(name => 'i_comment'), undef, "no namestr");
+}
+
+{
+ # write failure tests
+ my $rgb8 = test_image();
+ my $rgb16 = test_image_16();
+ my $rgb8rle = $rgb8->copy;
+ $rgb8rle->settag(name => 'sgi_rle', value => 1);
+ my $grey8 = $rgb8->convert(preset => 'grey');
+ my $grey16 = $rgb16->convert(preset => 'grey');
+ my $grey16rle = $grey16->copy;
+ $grey16rle->settag(name => 'sgi_rle', value => 1);
+
+ my @tests =
+ (
+ # each entry is: image, limit, expected msg, description
+ [
+ $rgb8, 500,
+ 'SGI image: cannot write header',
+ 'writing header'
+ ],
+ [
+ $rgb8, 1024,
+ 'SGI image: error writing image data',
+ '8-bit image data'
+ ],
+ [
+ $grey8, 513,
+ 'SGI image: error writing image data',
+ '8-bit image data (grey)'
+ ],
+ [
+ $rgb8rle, 513,
+ 'SGI image: error writing offsets/lengths',
+ 'rle tables, 8 bit',
+ ],
+ [
+ $rgb8rle, 4112,
+ 'SGI image: error writing RLE data',
+ '8-bit rle data',
+ ],
+ [
+ $rgb8rle, 14707,
+ 'SGI image: cannot write final RLE table',
+ '8-bit rewrite RLE table',
+ ],
+ [
+ $rgb16, 513,
+ 'SGI image: error writing image data',
+ '16-bit image data',
+ ],
+ [
+ $grey16rle, 513,
+ 'SGI image: error writing offsets/lengths',
+ 'rle tables, 16 bit',
+ ],
+ [
+ $grey16rle, 1713,
+ 'SGI image: error writing RLE data',
+ '16-bit rle data',
+ ],
+ [
+ $grey16rle, 10871,
+ 'SGI image: cannot write final RLE table',
+ '16-bit rewrite RLE table',
+ ],
+ );
+ for my $test (@tests) {
+ my ($im, $limit, $expected_msg, $desc) = @$test;
+ my ($writecb, $seekcb) = limited_write($limit);
+ ok(!$im->write(type => 'sgi', writecb => $writecb,
+ seekcb => $seekcb, maxbuffer => 1),
+ "write should fail - $desc");
+ is($im->errstr, "$expected_msg: limit reached", "check error - $desc");
+ }
+}
+
+sub limited_write {
+ my ($limit) = @_;
+
+ my $pos = 0;
+ my $written = 0;
+ return
+ (
+ # write callback
+ sub {
+ my ($data) = @_;
+ # limit total written so we can fail the offset table write for RLE
+ $written += length $data;
+ if ($written <= $limit) {
+ $pos += length $data;
+ print "# write of ", length $data, " bytes successful (",
+ $limit - $written, " left)\n";
+ return 1;
+ }
+ else {
+ print "# write of ", length $data, " bytes failed\n";
+ Imager::i_push_error(0, "limit reached");
+ return;
+ }
+ },
+ # seek cb
+ sub {
+ my ($position, $whence) = @_;
+
+ if ($whence == SEEK_SET) {
+ $pos = $position;
+ print "# seek to $pos\n";
+ }
+ elsif ($whence == SEEK_END) {
+ die "SEEK_END not supported\n";
+ }
+ elsif ($whence == SEEK_CUR) {
+ die "SEEK_CUR not supported\n";
+ }
+ else {
+ die "Invalid seek whence $whence";
+ }
+
+ $pos;
+ }
+ )
+}
View
BIN SGI/testimg/rle.rgb
Binary file not shown.
View
BIN SGI/testimg/rle12.rgb
Binary file not shown.
View
BIN SGI/testimg/rle16.rgb
Binary file not shown.
View
BIN SGI/testimg/rle6.rgb
Binary file not shown.
View
BIN SGI/testimg/rleagr.rgb
Binary file not shown.
View
BIN SGI/testimg/verb.rgb
Binary file not shown.
View
BIN SGI/testimg/verb12.rgb
Binary file not shown.
View
BIN SGI/testimg/verb16.rgb
Binary file not shown.
View
BIN SGI/testimg/verb6.rgb
Binary file not shown.
View
32 convert.c
@@ -21,7 +21,7 @@ converting from RGBA to greyscale and back.
/*
-=item i_convert(im, src, coeff, outchan, inchan)
+=item i_convert(src, coeff, outchan, inchan)
Converts the image src into another image.
@@ -40,14 +40,15 @@ Now handles images with more than 8-bits/sample.
=cut
*/
-int
-i_convert(i_img *im, i_img *src, const float *coeff, int outchan, int inchan) {
+i_img *
+i_convert(i_img *src, const float *coeff, int outchan, int inchan) {
int x, y;
int i, j;
int ilimit;
double work[MAXCHANNELS];
+ i_img *im = NULL;
- mm_log((1,"i_convert(im %p, src, %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
+ mm_log((1,"i_convert(src %p, coeff %p,outchan %d, inchan %d)\n",im,src, coeff,outchan, inchan));
i_clear_error();
@@ -59,14 +60,9 @@ i_convert(i_img *im, i_img *src, const float *coeff, int outchan, int inchan) {
return 0;
}
- if (im->type == i_direct_type || src->type == i_direct_type) {
- /* first check the output image */
- if (im->channels != outchan || im->xsize != src->xsize
- || im->ysize != src->ysize) {
- i_img_exorcise(im);
- i_img_empty_ch(im, src->xsize, src->ysize, outchan);
- }
- if (im->bits == i_8_bits && src->bits == i_8_bits) {
+ if (src->type == i_direct_type) {
+ im = i_sametype_chans(src, src->xsize, src->ysize, outchan);
+ if (src->bits == i_8_bits) {
i_color *vals;
/* we can always allocate a single scanline of i_color */
@@ -135,13 +131,9 @@ i_convert(i_img *im, i_img *src, const float *coeff, int outchan, int inchan) {
i_color *colors;
i_palidx *vals;
- if (im->channels != outchan || im->xsize != src->xsize
- || im->ysize != src->ysize
- || i_maxcolors(im) < i_colorcount(src)) {
- i_img_exorcise(im);
- i_img_pal_new_low(im, src->xsize, src->ysize, outchan,
- i_maxcolors(src));
- }
+ im = i_img_pal_new(src->xsize, src->ysize, outchan,
+ i_maxcolors(src));
+
/* just translate the color table */
count = i_colorcount(src);
outcount = i_colorcount(im);
@@ -187,7 +179,7 @@ i_convert(i_img *im, i_img *src, const float *coeff, int outchan, int inchan) {
myfree(colors);
}
- return 1;
+ return im;
}
/*
View
1 feat.h
@@ -29,7 +29,6 @@ static char *i_format_list[]={
"pnm",
"bmp",
"tga",
- "rgb",
"ifs",
NULL};
View
41 image.c
@@ -481,6 +481,9 @@ i_img_info(i_img *im,int *info) {
/*
=item i_img_setmask(im, ch_mask)
+=synopsis // only channel 0 writeable
+=synopsis i_img_setmask(img, 0x01);
+
Set the image channel mask for I<im> to I<ch_mask>.
=cut
@@ -492,6 +495,8 @@ i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
/*
=item i_img_getmask(im)
+=synopsis mask = i_img_getmask(img);
+
Get the image channel mask for I<im>.
=cut
@@ -502,6 +507,8 @@ i_img_getmask(i_img *im) { return im->ch_mask; }
/*
=item i_img_getchannels(im)
+=synopsis channels = i_img_getchannels(img);
+
Get the number of channels in I<im>.
=cut
@@ -509,7 +516,33 @@ Get the number of channels in I<im>.
int
i_img_getchannels(i_img *im) { return im->channels; }
+/*
+=item i_img_get_width(im)
+
+=synopsis width = i_img_get_width(im);
+Returns the width in pixels of the image.
+
+=cut
+*/
+i_img_dim
+i_img_get_width(i_img *im) {
+ return im->xsize;
+}
+
+/*
+=item i_img_get_height(im)
+
+=synopsis height = i_img_get_height(im);
+
+Returns the height in pixels of the image.
+
+=cut
+*/
+i_img_dim
+i_img_get_height(i_img *im) {
+ return im->ysize;
+}
/*
=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
@@ -2079,10 +2112,10 @@ i_test_format_probe(io_glue *data, int length) {
on similar files
values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
*/
- FORMAT_ENTRY("\x01\xDA\x00\x01", "rgb"),
- FORMAT_ENTRY("\x01\xDA\x00\x02", "rgb"),
- FORMAT_ENTRY("\x01\xDA\x01\x01", "rgb"),
- FORMAT_ENTRY("\x01\xDA\x01\x02", "rgb"),
+ FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
+ FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
+ FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
+ FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
View
4 imager.h
@@ -69,6 +69,8 @@ i_img *i_img_pal_new(int x, int y, int ch, int maxpal);
void i_img_setmask (i_img *im,int ch_mask);
int i_img_getmask (i_img *im);
int i_img_getchannels(i_img *im);
+i_img_dim i_img_get_width(i_img *im);
+i_img_dim i_img_get_height(i_img *im);
/* Base functions */
@@ -192,7 +194,7 @@ void i_conv (i_img *im,const float *coeff,int len);
void i_unsharp_mask(i_img *im, double stddev, double scale);
/* colour manipulation */
-extern int i_convert(i_img *im, i_img *src, const float *coeff, int outchan, int inchan);
+extern i_img *i_convert(i_img *src, const float *coeff, i