with the i_background tag/parameter.
https://rt.cpan.org/Ticket/Display.html?id=29876
+ - writing a 2 or 4 channel image to a PGM/PPM will now write that
+ image as if composited against a background, black by default,
+ overridable with the i_background tag/parameter.
+ http://rt.cpan.org/Ticket/Display.html?id=30074
+
Bug fixes:
- Imager::Matrix2d->translate() now only requires one of the x or y
static void ft2_push_message(int code);
-static ft2_initialized = 0;
+static int ft2_initialized = 0;
static FT_Library library;
/*
bg->channel[3] = 255;
}
+/*
+=item i_get_file_backgroundf(im, &bg)
+
+Retrieve the file write background color tag from the image as a
+floating point color.
+
+Implemented in terms of i_get_file_background().
+
+If not present, returns black.
+
+=cut
+*/
+
+void
+i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
+ i_color bg;
+
+ i_get_file_background(im, &bg);
+ fbg->rgba.r = Sample8ToF(bg.rgba.r);
+ fbg->rgba.g = Sample8ToF(bg.rgba.g);
+ fbg->rgba.b = Sample8ToF(bg.rgba.b);
+ fbg->rgba.a = 1.0;
+}
+
/*
=back
extern int i_img_is_monochrome(i_img *im, int *zero_is_white);
extern void i_get_file_background(i_img *im, i_color *bg);
+extern void i_get_file_backgroundf(i_img *im, i_fcolor *bg);
const char * i_test_format_probe(io_glue *data, int length);
i_adapt_fcolors(int dest_channels, int src_channels, i_fcolor *colors,
size_t count);
+extern void
+i_adapt_colors_bg(int dest_channels, int src_channels, i_color *colors,
+ size_t count, i_color const *bg);
+extern void
+i_adapt_fcolors_bg(int dest_channels, int src_channels, i_fcolor *colors,
+ size_t count, i_fcolor const *bg);
+
#endif
static
int
-write_ppm_data_8(i_img *im, io_glue *ig) {
- int write_size = im->xsize * im->channels;
+write_ppm_data_8(i_img *im, io_glue *ig, int want_channels) {
+ int write_size = im->xsize * want_channels;
+ i_color *line_buf = mymalloc(sizeof(i_color) * im->xsize);
unsigned char *data = mymalloc(write_size);
int y = 0;
+ int x;
+ int ch;
int rc = 1;
+ i_color bg;
+ i_get_file_background(im, &bg);
while (y < im->ysize && rc >= 0) {
- i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
+ i_color *linep = line_buf;
+ unsigned char *datap = data;
+
+ i_glin(im, 0, im->xsize, y, line_buf);
+ i_adapt_colors_bg(want_channels, im->channels, line_buf, im->xsize, &bg);
+ for (x = 0; x < im->xsize; ++x) {
+ for (ch = 0; ch < want_channels; ++ch) {
+ *datap++ = linep->channel[ch];
+ }
+ ++linep;
+ }
if (i_io_write(ig, data, write_size) != write_size) {
i_push_error(errno, "could not write ppm data");
+ myfree(data);
+ myfree(line_buf);
rc = 0;
break;
}
++y;
}
myfree(data);
+ myfree(line_buf);
return rc;
}
static
int
-write_ppm_data_16(i_img *im, io_glue *ig) {
- int sample_count = im->channels * im->xsize;
+write_ppm_data_16(i_img *im, io_glue *ig, int want_channels) {
+ int sample_count = want_channels * im->xsize;
int write_size = sample_count * 2;
- int line_size = sample_count * sizeof(i_fsample_t);
- i_fsample_t *line_buf = mymalloc(line_size);
- i_fsample_t *samplep;
+ i_fcolor *line_buf = mymalloc(sizeof(i_fcolor) * im->xsize);
unsigned char *write_buf = mymalloc(write_size);
- unsigned char *writep;
- int sample_num;
int y = 0;
+ int x, ch;
int rc = 1;
+ i_fcolor bg;
+
+ i_get_file_backgroundf(im, &bg);
while (y < im->ysize) {
- i_gsampf(im, 0, im->xsize, y, line_buf, NULL, im->channels);
- samplep = line_buf;
- writep = write_buf;
- for (sample_num = 0; sample_num < sample_count; ++sample_num) {
- unsigned sample16 = SampleFTo16(*samplep++);
- *writep++ = sample16 >> 8;
- *writep++ = sample16 & 0xFF;
+ i_fcolor *linep = line_buf;
+ unsigned char *writep = write_buf;
+
+ i_glinf(im, 0, im->xsize, y, line_buf);
+ i_adapt_fcolors_bg(want_channels, im->channels, line_buf, im->xsize, &bg);
+ for (x = 0; x < im->xsize; ++x) {
+ for (ch = 0; ch < want_channels; ++ch) {
+ unsigned sample16 = SampleFTo16(linep->channel[ch]);
+ *writep++ = sample16 >> 8;
+ *writep++ = sample16 & 0xFF;
+ }
+ ++linep;
}
+
if (i_io_write(ig, write_buf, write_size) != write_size) {
i_push_error(errno, "could not write ppm data");
rc = 0;
else {
int type;
int maxval;
+ int want_channels = im->channels;
+
+ if (want_channels == 2 || want_channels == 4)
+ --want_channels;
if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data))
wide_data = 0;
- if (im->channels == 3) {
+ if (want_channels == 3) {
type = 6;
}
- else if (im->channels == 1) {
+ else if (want_channels == 1) {
type = 5;
}
else {
return(0);
}
- if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
+ if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type
+ && im->channels == want_channels) {
if (ig->writecb(ig,im->idata,im->bytes) != im->bytes) {
i_push_error(errno, "could not write ppm data");
return 0;
}
}
else if (maxval == 255) {
- if (!write_ppm_data_8(im, ig))
+ if (!write_ppm_data_8(im, ig, want_channels))
return 0;
}
else {
- if (!write_ppm_data_16(im, ig))
+ if (!write_ppm_data_16(im, ig, want_channels))
return 0;
}
}
#!perl -w
use Imager ':all';
-use Test::More tests => 153;
+use Test::More tests => 173;
use strict;
use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image);
}
{ # check error messages set correctly
- my $im = Imager->new(xsize=>100, ysize=>100, channels=>4);
- ok(!$im->write(file=>"testout/t104_fail.ppm", type=>'pnm'),
- "should fail to write 4 channel image");
- is($im->errstr, 'can only save 1 or 3 channel images to pnm',
- "check error message");
+ my $im = Imager->new;
ok(!$im->read(file=>'t/t104ppm.t', type=>'pnm'),
'should fail to read script as an image file');
is($im->errstr, 'unable to read pnm image: bad header magic, not a PNM file',
"check error message");
}
+{
+ # RT #30074
+ # give 4/2 channel images a background color when saving to pnm
+ my $im = Imager->new(xsize=>16, ysize=>16, channels=>4);
+ $im->box(filled => 1, xmin => 8, color => '#FFE0C0');
+ $im->box(filled => 1, color => NC(0, 192, 192, 128),
+ ymin => 8, xmax => 7);
+ ok($im->write(file=>"testout/t104_alpha.ppm", type=>'pnm'),
+ "should succeed writing 4 channel image");
+ my $imread = Imager->new;
+ ok($imread->read(file => 'testout/t104_alpha.ppm'), "read it back");
+ is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0,
+ "check transparent became black");
+ is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
+ "check color came through");
+ is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96,
+ "check translucent came through");
+ my $data;
+ ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000'),
+ "write with red background");
+ ok($imread->read(data => $data, type => 'pnm'),
+ "read it back");
+ is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0,
+ "check transparent became red");
+ is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
+ "check color came through");
+ is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96,
+ "check translucent came through");
+}
+
+{
+ # more RT #30074 - 16 bit images
+ my $im = Imager->new(xsize=>16, ysize=>16, channels=>4, bits => 16);
+ $im->box(filled => 1, xmin => 8, color => '#FFE0C0');
+ $im->box(filled => 1, color => NC(0, 192, 192, 128),
+ ymin => 8, xmax => 7);
+ ok($im->write(file=>"testout/t104_alp16.ppm", type=>'pnm',
+ pnm_write_wide_data => 1),
+ "should succeed writing 4 channel image");
+ my $imread = Imager->new;
+ ok($imread->read(file => 'testout/t104_alp16.ppm'), "read it back");
+ is($imread->bits, 16, "check we did produce a 16 bit image");
+ is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0,
+ "check transparent became black");
+ is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
+ "check color came through");
+ is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96,
+ "check translucent came through");
+ my $data;
+ ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000',
+ pnm_write_wide_data => 1),
+ "write with red background");
+ ok($imread->read(data => $data, type => 'pnm'),
+ "read it back");
+ is($imread->bits, 16, "check it's 16-bit");
+ is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0,
+ "check transparent became red");
+ is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
+ "check color came through");
+ is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96,
+ "check translucent came through");
+}
+
# various bad input files
print "# check error handling\n";
{