Support all image depths (1-4) in fl_write_png()

This commit is contained in:
Albrecht Schlosser 2021-11-11 20:58:09 +01:00
parent 500e470d39
commit 6d1f5608ba
3 changed files with 52 additions and 20 deletions

View File

@ -39,8 +39,8 @@ private:
// Support functions to write PNG image files (since 1.4.0)
FL_EXPORT int fl_write_png(const char *filename, int w, int h, int d, const unsigned char *pixels);
FL_EXPORT int fl_write_png(const char *filename, Fl_RGB_Image *img);
FL_EXPORT int fl_write_png(const char *filename, const char *pixels, int w, int h, int d=3, int ld=0);
FL_EXPORT int fl_write_png(const char *filename, const unsigned char *pixels, int w, int h, int d=3, int ld=0);
#endif

View File

@ -348,7 +348,7 @@ void save_template_cb(Fl_Widget *, void *) {
strcpy(ext, ".png");
errno = 0;
if (fl_write_png(filename, w, h, 3, pixels) != 0) {
if (fl_write_png(filename, pixels, w, h, 3) != 0) {
delete[] pixels;
fl_alert("Error writing %s: %s", filename, strerror(errno));
return;

View File

@ -1,7 +1,7 @@
//
// Fl_PNG_Image support functions for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 by Bill Spitzak and others.
// Copyright 2005-2021 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@ -42,7 +42,7 @@ extern "C" {
*/
/**
Write a RGB(A) image to a PNG image file.
Write an RGB(A) image to a PNG image file.
This is a very basic and restricted function to create a PNG image file
from an RGB image (Fl_RGB_Image).
@ -53,16 +53,16 @@ extern "C" {
The image file is always written with the original image size data_w()
and data_h(), even if the image has been scaled.
Image depth 3 (RGB) and 4 (RGBA) are supported.
Image depth 1 (gray), 2 (gray + alpha channel), 3 (RGB) and 4 (RGBA)
are supported.
\note Behavior of grayscale images (depth 1 and 2) is currently undefined
and may or may not work. There is no error handling except for opening
the file. This function may be changed in the future.
\note Currently there is no error handling except for errors when opening
the file. This may be changed in the future.
\param[in] filename Output filename, extension should be '.png'
\param[in] img RGB image to be written
\return success (0) or error code
\return success (0) or error code: negative values are errors
\retval 0 success, file has been written
\retval -1 png or zlib library not available
@ -73,8 +73,20 @@ extern "C" {
int fl_write_png(const char *filename, Fl_RGB_Image *img) {
return fl_write_png(filename,
img->data_w(), img->data_h(), img->d(),
(const unsigned char *)img->data()[0]);
img->data()[0],
img->data_w(),
img->data_h(),
img->d(),
img->ld());
}
/**
Write raw image data to a PNG image file.
\see fl_write_png(const char *filename, const char *pixels, int w, int h, int d, int ld)
*/
int fl_write_png(const char *filename, const unsigned char *pixels, int w, int h, int d, int ld) {
return fl_write_png(filename, (const char *)pixels, w, h, d, ld);
}
/**
@ -83,44 +95,64 @@ int fl_write_png(const char *filename, Fl_RGB_Image *img) {
This is a very basic and restricted function to create a PNG image file
from raw image data, e.g. a screenshot.
The image data must be aligned w/o gaps after each row.
The image data must be aligned w/o gaps after each row (ld = 0 or ld = w * d)
or \p ld must be the total length of each row, i.e. w * d + gapsize.
If ld == 0 then ld = w * d is assumed.
The total data size must be (w * d + gapsize) * h = ld' * h
where ld' = w * d if ld == 0.
For further restrictions and return values please see
fl_write_png(const char *filename, Fl_RGB_Image *img).
\param[in] filename Output filename, extension should be '.png'
\param[in] pixels Image data
\param[in] w Image data width
\param[in] h Image data height
\param[in] d Image depth (3 = RGB, 4 = RGBA)
\param[in] pixels Image data (\p w * \p h * \p d bytes)
\param[in] d Image depth: 1 = GRAY, 2 = GRAY + alpha, 3 = RGB, 4 = RGBA
\param[in] ld Line delta: default (0) = w * d
\return success (0) or error code, see ...
\see fl_write_png(const char *filename, Fl_RGB_Image *img)
*/
int fl_write_png(const char *filename, int w, int h, int d, const unsigned char *pixels) {
*/
int fl_write_png(const char *filename, const char *pixels, int w, int h, int d, int ld) {
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
FILE *fp;
int color_type;
if ((fp = fl_fopen(filename, "wb")) == NULL) {
return -2;
}
switch (d) {
case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
case 3: color_type = PNG_COLOR_TYPE_RGB; break;
case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
default: color_type = PNG_COLOR_TYPE_RGB;
}
if (ld == 0)
ld = w * d;
png_structp pptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
png_infop iptr = png_create_info_struct(pptr);
png_bytep ptr = (png_bytep)pixels;
png_init_io(pptr, fp);
png_set_IHDR(pptr, iptr, w, h, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
color_type,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_set_sRGB(pptr, iptr, PNG_sRGB_INTENT_PERCEPTUAL);
png_write_info(pptr, iptr);
for (int i = h; i > 0; i--, ptr += w * d) {
for (int i = 0; i < h; i++, ptr += ld) {
png_write_row(pptr, ptr);
}