Permalink
Browse files

PNG re-work: handle writing bilevel files

  • Loading branch information...
1 parent 21c6936 commit b8961d05343f807ec877638a873e9b07e5a91fdc @tonycoz committed Apr 12, 2012
Showing with 59 additions and 60 deletions.
  1. +42 −58 PNG/impng.c
  2. +17 −2 PNG/t/10png.t
View
@@ -27,9 +27,8 @@ write_direct8(png_structp png_ptr, png_infop info_ptr, i_img *im);
static int
write_paletted(png_structp png_ptr, png_infop info_ptr, i_img *im, int bits);
-static void
-pack_to_bits(unsigned char *dest, const unsigned char *src, size_t count,
- int bits);
+static int
+write_bilevel(png_structp png_ptr, png_infop info_ptr, i_img *im);
unsigned
i_png_lib_version(void) {
@@ -90,6 +89,7 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
unsigned char *data;
unsigned char * volatile vdata = NULL;
int bits;
+ int is_bilevel = 0, zero_is_white;
mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig));
@@ -120,15 +120,21 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
channels=im->channels;
- if (im->type == i_palette_type) {
+ if (i_img_is_monochrome(im, &zero_is_white)) {
+ is_bilevel = 1;
+ bits = 1;
+ cspace = PNG_COLOR_TYPE_GRAY;
+ mm_log((1, "i_writepng: bilevel output\n"));
+ }
+ else if (im->type == i_palette_type) {
int colors = i_colorcount(im);
cspace = PNG_COLOR_TYPE_PALETTE;
bits = 1;
while ((1 << bits) < colors) {
bits += bits;
}
- mm_log((1, "paletted output\n"));
+ mm_log((1, "i_writepng: paletted output\n"));
}
else {
switch (channels) {
@@ -149,10 +155,10 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
abort();
}
bits = 8;
- mm_log((1, "direct output\n"));
+ mm_log((1, "i_writepng: direct output\n"));
}
- mm_log((1,"cspace=%d, bits=%d\n",cspace, bits));
+ mm_log((1,"i_writepng: cspace=%d, bits=%d\n",cspace, bits));
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
@@ -229,7 +235,13 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
}
- if (im->type == i_palette_type) {
+ if (is_bilevel) {
+ if (!write_bilevel(png_ptr, info_ptr, im)) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 0;
+ }
+ }
+ else if (im->type == i_palette_type) {
if (!write_paletted(png_ptr, info_ptr, im, bits)) {
png_destroy_write_struct(&png_ptr, &info_ptr);
return 0;
@@ -875,59 +887,31 @@ write_paletted(png_structp png_ptr, png_infop info_ptr, i_img *im, int bits) {
return 1;
}
-#if 0
-/* the source size is required to be rounded up to a number of samples
- per byte bounday */
-static void
-pack_to_bits(unsigned char *dest, const unsigned char *src, size_t count,
- int bits) {
- ptr_diff_t out_count;
- switch (bits) {
- case 1:
- out_count = (count + 7) / 8;
- while (out_count > 0) {
- unsigned mask = 0x80;
- unsigned out = 0;
- while (mask) {
- if (*src++)
- out |= mask;
- mask >>= 1;
- }
- *dest++ = out;
- --out_count;
- }
- break;
-
- case 2:
- out_count = (count + 3) / 4;
- while (out_count > 0) {
- int shift = 6;
- unsigned out = 0;
- while (shift >= 0) {
- out |= *src << shift;
- ++src;
- shift -= 2;
- }
- *dest++ = out;
- --out_count;
- }
- break;
-
- case 4:
- out_count = (count + 1) / 2;
- while (out_count > 0) {
- *dest++ = (src[0] << 4) | src[1];
- src += 2;
- --out_count;
- }
- break
+static int
+write_bilevel(png_structp png_ptr, png_infop info_ptr, i_img *im) {
+ unsigned char *data, *volatile vdata = NULL;
+ i_img_dim y;
- case 8:
- break;
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ if (vdata)
+ myfree(vdata);
+
+ return 0;
}
-}
-#endif
+ png_write_info(png_ptr, info_ptr);
+
+ png_set_packing(png_ptr);
+
+ vdata = data = mymalloc(im->xsize);
+ for (y = 0; y < im->ysize; y++) {
+ i_gsamp(im, 0, im->xsize, y, data, NULL, 1);
+ png_write_row(png_ptr, (png_bytep)data);
+ }
+ myfree(data);
+
+ return 1;
+}
static void
read_warn_handler(png_structp png_ptr, png_const_charp msg) {
View
@@ -10,7 +10,7 @@ my $debug_writes = 1;
init_log("testout/t102png.log",1);
-plan tests => 187;
+plan tests => 192;
# this loads Imager::File::PNG too
ok($Imager::formats{"png"}, "must have png format");
@@ -511,7 +511,7 @@ SKIP:
or diag("Cannot save testout/pal2.png: ".$pim->errstr);
my $in = Imager->new(file => "testout/pal2.png");
ok($in, "read it back in")
- or diag("Cann't read pal1.png back: " . Imager->errstr);
+ or diag("Can't read pal1.png back: " . Imager->errstr);
# PNG doesn't have a paletted greyscale type, so it's written as
# paletted color, convert our source image for the comparison
my $cmpim = $pim->convert(preset => "rgb");
@@ -520,6 +520,21 @@ SKIP:
is($in->tags(name => "png_bits"), 2, "2 bit representation");
}
+{
+ my $imbase = test_image();
+ my $mono = $imbase->convert(preset => "gray")
+ ->to_paletted(make_colors => "mono", translate => "errdiff");
+
+ ok($mono->write(file => "testout/bilevel.png"),
+ "write bilevel.png");
+ my $in = Imager->new(file => "testout/bilevel.png");
+ ok($in, "read it back in")
+ or diag("Can't read bilevel.png: " . Imager->errstr);
+ is_image($in, $mono, "check it matches");
+ is($in->type, "paletted", "make sure the result is paletted");
+ is($in->tags(name => "png_bits"), 1, "1 bit representation");
+}
+
sub limited_write {
my ($limit) = @_;

0 comments on commit b8961d0

Please sign in to comment.