Code

moving trunk for module inkscape
[inkscape.git] / src / helper / png-write.cpp
1 #define __SP_PNG_WRITE_C__
3 /*
4  * PNG file format utilities
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Whoever wrote this example in libpng documentation
9  *
10  * Copyright (C) 1999-2002 authors
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #include <glib/gmessages.h>
20 #include <png.h>
21 #include "png-write.h"
22 #include "io/sys.h"
24 /* This is an example of how to use libpng to read and write PNG files.
25  * The file libpng.txt is much more verbose then this.  If you have not
26  * read it, do so first.  This was designed to be a starting point of an
27  * implementation.  This is not officially part of libpng, and therefore
28  * does not require a copyright notice.
29  *
30  * This file does not currently compile, because it is missing certain
31  * parts, like allocating memory to hold an image.  You will have to
32  * supply these parts to get it to compile.  For an example of a minimal
33  * working PNG reader/writer, see pngtest.c, included in this distribution.
34  */
36 /* write a png file */
38 typedef struct SPPNGBD {
39         const guchar *px;
40         int rowstride;
41 } SPPNGBD;
43 static int
44 sp_png_get_block_stripe (const guchar **rows, int row, int num_rows, void *data)
45 {
46         SPPNGBD *bd = (SPPNGBD *) data;
48         for (int r = 0; r < num_rows; r++) {
49                 rows[r] = bd->px + (row + r) * bd->rowstride;
50         }
52         return num_rows;
53 }
55 int
56 sp_png_write_rgba (const gchar *filename, const guchar *px, int width, int height, int rowstride)
57 {
58         SPPNGBD bd;
60         bd.px = px;
61         bd.rowstride = rowstride;
63         return sp_png_write_rgba_striped (filename, width, height, sp_png_get_block_stripe, &bd);
64 }
66 int
67 sp_png_write_rgba_striped (const gchar *filename, int width, int height,
68                            int (* get_rows) (const guchar **rows, int row, int num_rows, void *data),
69                            void *data)
70 {
71         FILE *fp;
72         png_structp png_ptr;
73         png_infop info_ptr;
74         png_color_8 sig_bit;
75         png_text text_ptr[3];
76         png_uint_32 r;
78         g_return_val_if_fail (filename != NULL, FALSE);
80         /* open the file */
82         Inkscape::IO::dump_fopen_call(filename, "M");
83         fp = Inkscape::IO::fopen_utf8name(filename, "wb");
84         g_return_val_if_fail (fp != NULL, FALSE);
86         /* Create and initialize the png_struct with the desired error handler
87          * functions.  If you want to use the default stderr and longjump method,
88          * you can supply NULL for the last three parameters.  We also check that
89          * the library version is compatible with the one used at compile time,
90          * in case we are using dynamically linked libraries.  REQUIRED.
91          */
92         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
94         if (png_ptr == NULL) {
95                 fclose(fp);
96                 return FALSE;
97         }
99         /* Allocate/initialize the image information data.  REQUIRED */
100         info_ptr = png_create_info_struct(png_ptr);
101         if (info_ptr == NULL) {
102                 fclose(fp);
103                 png_destroy_write_struct(&png_ptr, NULL);
104                 return FALSE;
105         }
107         /* Set error handling.  REQUIRED if you aren't supplying your own
108          * error hadnling functions in the png_create_write_struct() call.
109          */
110         if (setjmp(png_ptr->jmpbuf)) {
111                 /* If we get here, we had a problem reading the file */
112                 fclose(fp);
113                 png_destroy_write_struct(&png_ptr, &info_ptr);
114                 return FALSE;
115         }
117         /* set up the output control if you are using standard C streams */
118         png_init_io(png_ptr, fp);
120         /* Set the image information here.  Width and height are up to 2^31,
121          * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
122          * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
123          * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
124          * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
125          * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
126          * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
127          */
128         png_set_IHDR(png_ptr, info_ptr,
129                      width,
130                      height,
131                      8, /* bit_depth */
132                      PNG_COLOR_TYPE_RGB_ALPHA,
133                      PNG_INTERLACE_NONE,
134                      PNG_COMPRESSION_TYPE_BASE,
135                      PNG_FILTER_TYPE_BASE);
137         /* otherwise, if we are dealing with a color image then */
138         sig_bit.red = 8;
139         sig_bit.green = 8;
140         sig_bit.blue = 8;
141         /* if the image has an alpha channel then */
142         sig_bit.alpha = 8;
143         png_set_sBIT(png_ptr, info_ptr, &sig_bit);
145         /* Made by Inkscape comment */
146         text_ptr[0].key = "Software";
147         text_ptr[0].text = "www.inkscape.org";
148         text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
149         png_set_text(png_ptr, info_ptr, text_ptr, 1);
151         /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
152         /* note that if sRGB is present the cHRM chunk must be ignored
153          * on read and must be written in accordance with the sRGB profile */
155         /* Write the file header information.  REQUIRED */
156         png_write_info(png_ptr, info_ptr);
158         /* Once we write out the header, the compression type on the text
159          * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
160          * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
161          * at the end.
162          */
164         /* set up the transformations you want.  Note that these are
165          * all optional.  Only call them if you want them.
166          */
168         /* --- CUT --- */
170         /* The easiest way to write the image (you may have a different memory
171          * layout, however, so choose what fits your needs best).  You need to
172          * use the first method if you aren't handling interlacing yourself.
173          */
175         r = 0;
176         while (r < static_cast< png_uint_32 > (height) ) {
177                 png_bytep row_pointers[64];
178                 int h, n;
180                 h = MIN (height - r, 64);
181                 n = get_rows ((const unsigned char **) row_pointers, r, h, data);
182                 if (!n) break;
183                 png_write_rows (png_ptr, row_pointers, n);
184                 r += n;
185         }
187         /* You can write optional chunks like tEXt, zTXt, and tIME at the end
188          * as well.
189          */
191         /* It is REQUIRED to call this to finish writing the rest of the file */
192         png_write_end(png_ptr, info_ptr);
194         /* if you allocated any text comments, free them here */
196         /* clean up after the write, and free any memory allocated */
197         png_destroy_write_struct(&png_ptr, &info_ptr);
199         /* close the file */
200         fclose(fp);
202         /* that's it */
203         return TRUE;