--- /dev/null
+/*
+=head1 NAME
+
+imgdouble.c - implements double per sample images
+
+=head1 SYNOPSIS
+
+ i_img *im = i_img_double_new(int x, int y, int channels);
+ # use like a normal image
+
+=head1 DESCRIPTION
+
+Implements double/sample images.
+
+This basic implementation is required so that we have some larger
+sample image type to work with.
+
+=over
+
+=cut
+*/
+
+#include "image.h"
+#include "imagei.h"
+
+static int i_ppix_ddoub(i_img *im, int x, int y, i_color *val);
+static int i_gpix_ddoub(i_img *im, int x, int y, i_color *val);
+static int i_glin_ddoub(i_img *im, int l, int r, int y, i_color *vals);
+static int i_plin_ddoub(i_img *im, int l, int r, int y, i_color *vals);
+static int i_ppixf_ddoub(i_img *im, int x, int y, i_fcolor *val);
+static int i_gpixf_ddoub(i_img *im, int x, int y, i_fcolor *val);
+static int i_glinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals);
+static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals);
+static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps,
+ int *chans, int chan_count);
+static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps,
+ int *chans, int chan_count);
+
+/*
+=item IIM_base_16bit_direct
+
+Base structure used to initialize a 16-bit/sample image.
+
+Internal.
+
+=cut
+*/
+static i_img IIM_base_double_direct =
+{
+ 0, /* channels set */
+ 0, 0, 0, /* xsize, ysize, bytes */
+ ~0, /* ch_mask */
+ i_double_bits, /* bits */
+ i_direct_type, /* type */
+ 0, /* virtual */
+ NULL, /* idata */
+ { 0, 0, NULL }, /* tags */
+ NULL, /* ext_data */
+
+ i_ppix_ddoub, /* i_f_ppix */
+ i_ppixf_ddoub, /* i_f_ppixf */
+ i_plin_ddoub, /* i_f_plin */
+ i_plinf_ddoub, /* i_f_plinf */
+ i_gpix_ddoub, /* i_f_gpix */
+ i_gpixf_ddoub, /* i_f_gpixf */
+ i_glin_ddoub, /* i_f_glin */
+ i_glinf_ddoub, /* i_f_glinf */
+ i_gsamp_ddoub, /* i_f_gsamp */
+ i_gsampf_ddoub, /* i_f_gsampf */
+
+ NULL, /* i_f_gpal */
+ NULL, /* i_f_ppal */
+ NULL, /* i_f_addcolor */
+ NULL, /* i_f_getcolor */
+ NULL, /* i_f_colorcount */
+ NULL, /* i_f_findcolor */
+
+ NULL, /* i_f_destroy */
+};
+
+/*
+=item i_img_double_new(int x, int y, int ch)
+
+Creates a new double per sample image.
+
+=cut
+*/
+i_img *i_img_double_new_low(i_img *im, int x, int y, int ch) {
+ mm_log((1,"i_img_double_new(x %d, y %d, ch %d)\n", x, y, ch));
+
+ *im = IIM_base_double_direct;
+ i_tags_new(&im->tags);
+ im->xsize = x;
+ im->ysize = y;
+ im->channels = ch;
+ im->bytes = x * y * ch * sizeof(double);
+ im->ext_data = NULL;
+ im->idata = mymalloc(im->bytes);
+ if (im->idata) {
+ memset(im->idata, 0, im->bytes);
+ }
+ else {
+ i_tags_destroy(&im->tags);
+ im = NULL;
+ }
+
+ return im;
+}
+
+i_img *i_img_double_new(int x, int y, int ch) {
+ i_img *im;
+
+ im = mymalloc(sizeof(i_img));
+ if (im) {
+ if (!i_img_double_new_low(im, x, y, ch)) {
+ myfree(im);
+ im = NULL;
+ }
+ }
+
+ mm_log((1, "(%p) <- i_img_double_new\n", im));
+
+ return im;
+}
+
+static int i_ppix_ddoub(i_img *im, int x, int y, i_color *val) {
+ int off, ch;
+
+ if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
+ return -1;
+
+ off = (x + y * im->xsize) * im->channels;
+ for (ch = 0; ch < im->channels; ++ch)
+ ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
+
+ return 0;
+}
+
+static int i_gpix_ddoub(i_img *im, int x, int y, i_color *val) {
+ int off, ch;
+
+ if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
+ return -1;
+
+ off = (x + y * im->xsize) * im->channels;
+ for (ch = 0; ch < im->channels; ++ch)
+ val->channel[ch] = SampleFTo8(((double *)im->idata)[off+ch]);
+
+ return 0;
+}
+
+static int i_ppixf_ddoub(i_img *im, int x, int y, i_fcolor *val) {
+ int off, ch;
+
+ if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
+ return -1;
+
+ off = (x + y * im->xsize) * im->channels;
+ for (ch = 0; ch < im->channels; ++ch)
+ ((double *)im->idata)[off+ch] = val->channel[ch];;
+
+ return 0;
+}
+
+static int i_gpixf_ddoub(i_img *im, int x, int y, i_fcolor *val) {
+ int off, ch;
+
+ if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
+ return -1;
+
+ off = (x + y * im->xsize) * im->channels;
+ for (ch = 0; ch < im->channels; ++ch)
+ val->channel[ch] = ((double *)im->idata)[off+ch];
+
+ return 0;
+}
+
+static int i_glin_ddoub(i_img *im, int l, int r, int y, i_color *vals) {
+ int ch, count, i;
+ int off;
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ count = r - l;
+ for (i = 0; i < count; ++i) {
+ for (ch = 0; ch < im->channels; ++ch) {
+ vals[i].channel[ch] = SampleFTo8(((double *)im->idata)[off]);
+ ++off;
+ }
+ }
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int i_plin_ddoub(i_img *im, int l, int r, int y, i_color *vals) {
+ int ch, count, i;
+ int off;
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ count = r - l;
+ for (i = 0; i < count; ++i) {
+ for (ch = 0; ch < im->channels; ++ch) {
+ ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
+ ++off;
+ }
+ }
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int i_glinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals) {
+ int ch, count, i;
+ int off;
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ count = r - l;
+ for (i = 0; i < count; ++i) {
+ for (ch = 0; ch < im->channels; ++ch) {
+ vals[i].channel[ch] = ((double *)im->idata)[off];
+ ++off;
+ }
+ }
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals) {
+ int ch, count, i;
+ int off;
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ count = r - l;
+ for (i = 0; i < count; ++i) {
+ for (ch = 0; ch < im->channels; ++ch) {
+ ((double *)im->idata)[off] = vals[i].channel[ch];
+ ++off;
+ }
+ }
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps,
+ int *chans, int chan_count) {
+ int ch, count, i, w;
+ int off;
+
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ w = r - l;
+ count = 0;
+
+ if (chans) {
+ /* make sure we have good channel numbers */
+ for (ch = 0; ch < chan_count; ++ch) {
+ if (chans[ch] < 0 || chans[ch] >= im->channels) {
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
+ return 0;
+ }
+ }
+ for (i = 0; i < w; ++i) {
+ for (ch = 0; ch < chan_count; ++ch) {
+ *samps++ = SampleFTo8(((double *)im->idata)[off+chans[ch]]);
+ ++count;
+ }
+ off += im->channels;
+ }
+ }
+ else {
+ for (i = 0; i < w; ++i) {
+ for (ch = 0; ch < chan_count; ++ch) {
+ *samps++ = SampleFTo8(((double *)im->idata)[off+ch]);
+ ++count;
+ }
+ off += im->channels;
+ }
+ }
+
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps,
+ int *chans, int chan_count) {
+ int ch, count, i, w;
+ int off;
+
+ if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
+ if (r > im->xsize)
+ r = im->xsize;
+ off = (l+y*im->xsize) * im->channels;
+ w = r - l;
+ count = 0;
+
+ if (chans) {
+ /* make sure we have good channel numbers */
+ for (ch = 0; ch < chan_count; ++ch) {
+ if (chans[ch] < 0 || chans[ch] >= im->channels) {
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
+ return 0;
+ }
+ }
+ for (i = 0; i < w; ++i) {
+ for (ch = 0; ch < chan_count; ++ch) {
+ *samps++ = ((double *)im->idata)[off+chans[ch]];
+ ++count;
+ }
+ off += im->channels;
+ }
+ }
+ else {
+ for (i = 0; i < w; ++i) {
+ for (ch = 0; ch < chan_count; ++ch) {
+ *samps++ = ((double *)im->idata)[off+ch];
+ ++count;
+ }
+ off += im->channels;
+ }
+ }
+
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
--- /dev/null
+#!perl -w
+use strict;
+BEGIN { $| = 1; print "1..29\n"; }
+my $loaded;
+END {print "not ok 1\n" unless $loaded;}
+use Imager qw(:all :handy);
+#use Data::Dumper;
+$loaded = 1;
+print "ok 1\n";
+init_log("testout/t022double.log", 1);
+
+use Imager::Color::Float;
+
+my $im_g = Imager::i_img_double_new(100, 101, 1);
+
+ok(2, Imager::i_img_getchannels($im_g) == 1,
+ "1 channel image channel count mismatch");
+ok(3, Imager::i_img_getmask($im_g) & 1, "1 channel image bad mask");
+ok(4, Imager::i_img_virtual($im_g) == 0,
+ "1 channel image thinks it is virtual");
+my $double_bits = length(pack("d", 1)) * 8;
+ok(5, Imager::i_img_bits($im_g) == $double_bits,
+ "1 channel image has bits != $double_bits");
+ok(6, Imager::i_img_type($im_g) == 0, "1 channel image isn't direct");
+
+my @ginfo = i_img_info($im_g);
+ok(7, $ginfo[0] == 100, "1 channel image width incorrect");
+ok(8, $ginfo[1] == 101, "1 channel image height incorrect");
+
+undef $im_g;
+
+my $im_rgb = Imager::i_img_double_new(100, 101, 3);
+
+ok(9, Imager::i_img_getchannels($im_rgb) == 3,
+ "3 channel image channel count mismatch");
+ok(10, (Imager::i_img_getmask($im_rgb) & 7) == 7, "3 channel image bad mask");
+ok(11, Imager::i_img_bits($im_rgb) == $double_bits,
+ "3 channel image has bits != $double_bits");
+ok(12, Imager::i_img_type($im_rgb) == 0, "3 channel image isn't direct");
+
+my $redf = NCF(1, 0, 0);
+my $greenf = NCF(0, 1, 0);
+my $bluef = NCF(0, 0, 1);
+
+# fill with red
+for my $y (0..101) {
+ Imager::i_plinf($im_rgb, 0, $y, ($redf) x 100);
+}
+print "ok 13\n";
+# basic sanity
+test_colorf_gpix(14, $im_rgb, 0, 0, $redf);
+test_colorf_gpix(16, $im_rgb, 99, 0, $redf);
+test_colorf_gpix(18, $im_rgb, 0, 100, $redf);
+test_colorf_gpix(20, $im_rgb, 99, 100, $redf);
+test_colorf_glin(22, $im_rgb, 0, 0, ($redf) x 100);
+test_colorf_glin(24, $im_rgb, 0, 100, ($redf) x 100);
+
+Imager::i_plinf($im_rgb, 20, 1, ($greenf) x 60);
+test_colorf_glin(26, $im_rgb, 0, 1,
+ ($redf) x 20, ($greenf) x 60, ($redf) x 20);
+
+# basic OO tests
+my $oo16img = Imager->new(xsize=>200, ysize=>201, bits=>16)
+ or print "not ";
+print "ok 28\n";
+$oo16img->bits == 16 or print "not ";
+print "ok 29\n";
+
+
+sub NCF {
+ return Imager::Color::Float->new(@_);
+}
+
+sub test_colorf_gpix {
+ my ($test_base, $im, $x, $y, $expected) = @_;
+ my $c = Imager::i_gpixf($im, $x, $y);
+ $c or print "not ";
+ print "ok ",$test_base++,"\n";
+ colorf_cmp($c, $expected) == 0 or print "not ";
+ print "ok ",$test_base++,"\n";
+}
+
+sub test_colorf_glin {
+ my ($test_base, $im, $x, $y, @pels) = @_;
+
+ my @got = Imager::i_glinf($im, $x, $x+@pels, $y);
+ @got == @pels or print "not ";
+ print "ok ",$test_base++,"\n";
+ grep(colorf_cmp($pels[$_], $got[$_]), 0..$#got) and print "not ";
+ print "ok ",$test_base++,"\n";
+}
+
+sub colorf_cmp {
+ my ($c1, $c2) = @_;
+ my @s1 = map { int($_*65535.99) } $c1->rgba;
+ my @s2 = map { int($_*65535.99) } $c2->rgba;
+
+ # print "# (",join(",", @s1[0..2]),") <=> (",join(",", @s2[0..2]),")\n";
+ return $s1[0] <=> $s2[0]
+ || $s1[1] <=> $s2[1]
+ || $s1[2] <=> $s2[2];
+}
+
+sub ok {
+ my ($test_num, $ok, $comment) = @_;
+
+ if ($ok) {
+ print "ok $test_num\n";
+ }
+ else {
+ print "not ok $test_num # $comment\n";
+ }
+}