Initial revision
[blender.git] / source / blender / imbuf / intern / png_encode.c
1 /**
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  * $Id$
31  */
32
33
34 #include "png.h"
35
36 #ifdef WIN32
37 #include "BLI_winstuff.h"
38 #endif
39 #include "BLI_blenlib.h"
40
41 #include "imbuf.h"
42 #include "imbuf_patch.h"
43
44 #include "IMB_imbuf_types.h"
45 #include "IMB_imbuf.h"
46
47 #include "IMB_allocimbuf.h"
48 #include "IMB_cmap.h"
49
50 static void
51 WriteData(
52     png_structp png_ptr,
53     png_bytep data,
54     png_size_t length);
55
56 static void
57 Flush(
58     png_structp png_ptr);
59
60 static void
61 WriteData(
62     png_structp png_ptr,
63     png_bytep data,
64     png_size_t length)
65 {
66         ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr);
67
68         // if buffer is to small increase it.
69         while (ibuf->encodedsize + length > ibuf->encodedbuffersize) {
70                 imb_enlargeencodedbufferImBuf(ibuf);
71         }
72
73         memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length);
74         ibuf->encodedsize += length;
75 }
76
77 static void
78 Flush(
79     png_structp png_ptr)
80 {
81 }
82
83 short IMB_png_encode(struct ImBuf *ibuf, int file, int flags)
84 {
85         png_structp png_ptr;
86         png_infop info_ptr;
87         unsigned char *pixels = 0;
88         unsigned char *from, *to;
89         png_bytepp row_pointers = 0;
90         int i, bytesperpixel, color_type;
91         FILE *fp = 0;
92
93         bytesperpixel = (ibuf->depth + 7) >> 3;
94         if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
95                 printf("imb_png_encode: unsupported bytes per pixel: %d\n", bytesperpixel);
96                 return (0);
97         }
98
99         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
100                 NULL, NULL, NULL);
101         if (png_ptr == NULL) {
102                 printf("Cannot png_create_write_struct\n");
103                 return 0;
104         }
105
106         info_ptr = png_create_info_struct(png_ptr);
107         if (info_ptr == NULL) {
108                 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
109                 printf("Cannot png_create_info_struct\n");
110                 return 0;
111         }
112
113         if (setjmp(png_jmpbuf(png_ptr))) {
114                 png_destroy_write_struct(&png_ptr, &info_ptr);
115                 if (pixels) MEM_freeN(pixels);
116                 if (row_pointers) MEM_freeN(row_pointers);
117                 // printf("Aborting\n");
118                 if (fp) {
119                         fflush(fp);
120                         fclose(fp);
121                 }
122                 return 0;
123         }
124
125         // copy image data
126
127         pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
128         if (pixels == NULL) {
129                 printf("Cannot allocate pixels array\n");
130                 return 0;
131         }
132
133         from = (unsigned char *) ibuf->rect;
134         to = pixels;
135
136         switch (bytesperpixel) {
137         case 4:
138                 color_type = PNG_COLOR_TYPE_RGBA;
139                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
140                         to[0] = from[0];
141                         to[1] = from[1];
142                         to[2] = from[2];
143                         to[3] = from[3];
144                         to += 4; from += 4;
145                 }
146                 break;
147         case 3:
148                 color_type = PNG_COLOR_TYPE_RGB;
149                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
150                         to[0] = from[0];
151                         to[1] = from[1];
152                         to[2] = from[2];
153                         to += 3; from += 4;
154                 }
155                 break;
156         case 1:
157                 color_type = PNG_COLOR_TYPE_GRAY;
158                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
159                         to[0] = from[0];
160                         to++; from += 4;
161                 }
162                 break;
163         }
164
165         if (flags & IB_mem) {
166                 // create image in memory
167                 imb_addencodedbufferImBuf(ibuf);
168                 ibuf->encodedsize = 0;
169
170                 png_set_write_fn(png_ptr,
171                          (png_voidp) ibuf,
172                          WriteData,
173                          Flush);
174         } else {
175                 fp = fdopen(file, "wb");
176                 png_init_io(png_ptr, fp);
177         }
178
179         /*
180         png_set_filter(png_ptr, 0,
181                 PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
182                 PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
183                 PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
184                 PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
185                 PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
186                 PNG_ALL_FILTERS);
187
188         png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
189         */
190
191         // png image settings
192         png_set_IHDR(png_ptr,
193                  info_ptr,
194                  ibuf->x,
195                  ibuf->y,
196                  8,
197                  color_type,
198                  PNG_INTERLACE_NONE,
199                  PNG_COMPRESSION_TYPE_DEFAULT,
200                  PNG_FILTER_TYPE_DEFAULT);
201
202         // write the file header information
203         png_write_info(png_ptr, info_ptr);
204
205         // allocate memory for an array of row-pointers
206         row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
207         if (row_pointers == NULL) {
208                         printf("Cannot allocate row-pointers array\n");
209                         return 0;
210         }
211
212         // set the individual row-pointers to point at the correct offsets
213         for (i = 0; i < ibuf->y; i++) {
214                 row_pointers[ibuf->y-1-i] = (png_bytep)
215                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
216         }
217
218         // write out the entire image data in one call
219         png_write_image(png_ptr, row_pointers);
220
221         // write the additional chunks to the PNG file (not really needed)
222         png_write_end(png_ptr, info_ptr);
223
224         // clean up
225         MEM_freeN(pixels);
226         MEM_freeN(row_pointers);
227         png_destroy_write_struct(&png_ptr, &info_ptr);
228
229         if (fp) {
230                 fflush(fp);
231                 fclose(fp);
232         }
233
234         return(1);
235 }
236