1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * PNG 保存
22 *****************************************/
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <png.h>
27
28 #include "mDef.h"
29 #include "mSaveImage.h"
30
31
32 //--------------------
33
34 typedef struct
35 {
36 mSaveImage *param;
37
38 png_struct *png;
39 png_info *pnginfo;
40
41 FILE *fp;
42 uint8_t *rowbuf,
43 *palbuf;
44
45 mBool start_image;
46 }SAVEPNG;
47
48 //--------------------
49
50
51
52 //=======================
53 // sub
54 //=======================
55
56
57 /** PNG エラー関数 */
58
_png_error_func(png_struct * png,png_const_charp mes)59 static void _png_error_func(png_struct *png,png_const_charp mes)
60 {
61 mSaveImage_setMessage((mSaveImage *)png_get_error_ptr(png), mes);
62
63 longjmp(png_jmpbuf(png), 1);
64 }
65
66 /** PNG 警告関数 */
67
_png_warn_func(png_struct * png,png_const_charp mes)68 static void _png_warn_func(png_struct *png,png_const_charp mes)
69 {
70
71 }
72
73
74 //===========================
75 // 書き込みセット
76 //===========================
77
78
79 /** ヘッダ */
80
_set_header(SAVEPNG * p,mSaveImage * param)81 static void _set_header(SAVEPNG *p,mSaveImage *param)
82 {
83 int type,bits;
84
85 bits = param->sample_bits;
86
87 //カラータイプ
88
89 switch(param->coltype)
90 {
91 case MSAVEIMAGE_COLTYPE_PALETTE:
92 type = PNG_COLOR_TYPE_PALETTE;
93 bits = param->bits;
94 break;
95 case MSAVEIMAGE_COLTYPE_RGBA:
96 type = PNG_COLOR_TYPE_RGB_ALPHA;
97 break;
98 case MSAVEIMAGE_COLTYPE_GRAY:
99 type = PNG_COLOR_TYPE_GRAY;
100 break;
101 case MSAVEIMAGE_COLTYPE_GRAY_ALPHA:
102 type = PNG_COLOR_TYPE_GRAY_ALPHA;
103 break;
104 default:
105 type = PNG_COLOR_TYPE_RGB;
106 break;
107 }
108
109 png_set_IHDR(p->png, p->pnginfo,
110 param->width, param->height, bits, type,
111 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
112 }
113
114 /** パレット */
115
_set_palette(SAVEPNG * p)116 static int _set_palette(SAVEPNG *p)
117 {
118 p->palbuf = mSaveImage_convertPalette_RGB(p->param);
119 if(!p->palbuf) return MSAVEIMAGE_ERR_ALLOC;
120
121 png_set_PLTE(p->png, p->pnginfo, (png_colorp)p->palbuf, p->param->palette_num);
122
123 return 0;
124 }
125
126
127 //===========================
128 // main
129 //===========================
130
131
132 /** 初期化 */
133
_init(SAVEPNG * p)134 static int _init(SAVEPNG *p)
135 {
136 png_struct *png;
137 png_info *pnginfo;
138
139 //png_struct
140
141 png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
142 p->param, _png_error_func, _png_warn_func);
143 if(!png) return MSAVEIMAGE_ERR_ALLOC;
144
145 p->png = png;
146
147 //png_info
148
149 pnginfo = png_create_info_struct(png);
150 if(!pnginfo) return MSAVEIMAGE_ERR_ALLOC;
151
152 p->pnginfo = pnginfo;
153
154 //エラー時
155
156 if(setjmp(png_jmpbuf(png)))
157 return -1;
158
159 //出力
160
161 p->fp = mSaveImage_openFILE(&p->param->output);
162 if(!p->fp) return MSAVEIMAGE_ERR_OPENFILE;
163
164 png_init_io(png, p->fp);
165
166 return 0;
167 }
168
169 /** イメージ前処理 */
170
_before_image(SAVEPNG * p)171 static int _before_image(SAVEPNG *p)
172 {
173 int ret,h,v;
174
175 //IHDR
176
177 _set_header(p, p->param);
178
179 //パレット
180
181 if(p->param->coltype == MSAVEIMAGE_COLTYPE_PALETTE)
182 {
183 if((ret = _set_palette(p)))
184 return ret;
185 }
186
187 //解像度 (dpi or dpm)
188
189 if(mSaveImage_getResolution_dpm(p->param, &h, &v))
190 png_set_pHYs(p->png, p->pnginfo, h, v, PNG_RESOLUTION_METER);
191
192 //他設定
193
194 if(p->param->set_option)
195 {
196 if((ret = (p->param->set_option)(p->param)))
197 return ret;
198 }
199
200 //書き込み
201
202 png_write_info(p->png, p->pnginfo);
203
204 return 0;
205 }
206
207 /** メイン処理 */
208
_main_proc(SAVEPNG * p)209 static int _main_proc(SAVEPNG *p)
210 {
211 mSaveImage *param = p->param;
212 int ret,i,pitch;
213
214 //初期化
215
216 if((ret = _init(p)))
217 return ret;
218
219 //イメージ前の処理
220
221 if((ret = _before_image(p)))
222 return ret;
223
224 //Y1行バッファ確保
225
226 pitch = png_get_rowbytes(p->png, p->pnginfo);
227
228 p->rowbuf = (uint8_t *)mMalloc(pitch, FALSE);
229 if(!p->rowbuf) return MSAVEIMAGE_ERR_ALLOC;
230
231 //イメージ書き込み
232
233 p->start_image = TRUE;
234
235 for(i = param->height; i > 0; i--)
236 {
237 //取得
238
239 ret = (param->send_row)(param, p->rowbuf, pitch);
240 if(ret) return ret;
241
242 //書き込み
243
244 png_write_row(p->png, (png_bytep)p->rowbuf);
245 }
246
247 return 0;
248 }
249
250 /** 解放 */
251
_png_free(SAVEPNG * p)252 static void _png_free(SAVEPNG *p)
253 {
254 if(p->png)
255 {
256 //イメージ書き込み終了
257
258 if(p->start_image)
259 png_write_end(p->png, NULL);
260
261 //png_struct,png_info 削除
262
263 png_destroy_write_struct(&p->png, (p->pnginfo)? &p->pnginfo: NULL);
264 }
265
266 if(p->fp)
267 {
268 if(p->param->output.type == MSAVEIMAGE_OUTPUT_TYPE_PATH)
269 fclose(p->fp);
270 else
271 fflush(p->fp);
272 }
273
274 mFree(p->rowbuf);
275 mFree(p->palbuf);
276 mFree(p);
277 }
278
279
280 //===================
281
282
283 /**
284
285 @addtogroup saveimage
286 @{
287
288 */
289
290
291 /** PNG ファイルに保存 */
292
mSaveImagePNG(mSaveImage * param)293 mBool mSaveImagePNG(mSaveImage *param)
294 {
295 SAVEPNG *p;
296 int ret;
297
298 //確保
299
300 p = (SAVEPNG *)mMalloc(sizeof(SAVEPNG), TRUE);
301 if(!p) return FALSE;
302
303 p->param = param;
304 param->internal = p;
305
306 //処理
307
308 ret = _main_proc(p);
309
310 if(ret)
311 {
312 if(ret > 0)
313 mSaveImage_setMessage_errno(param, ret);
314 }
315
316 //解放
317
318 _png_free(p);
319
320 return (ret == 0);
321 }
322
323 /** PNG 圧縮レベル設定 */
324
mSaveImagePNG_setCompressionLevel(mSaveImage * p,int level)325 void mSaveImagePNG_setCompressionLevel(mSaveImage *p,int level)
326 {
327 png_set_compression_level(((SAVEPNG *)p->internal)->png, level);
328 }
329
330 /** PNG 透過色セット
331 *
332 * パレットカラー、グレイスケール、RGB [8bit] 用 */
333
mSaveImagePNG_setTransparent_8bit(mSaveImage * p,uint32_t col)334 void mSaveImagePNG_setTransparent_8bit(mSaveImage *p,uint32_t col)
335 {
336 SAVEPNG *pp = (SAVEPNG *)p->internal;
337 uint8_t r,g,b,*trbuf,*ps;
338 png_color_16 pngcol;
339 int i,pnum;
340
341 r = M_GET_R(col);
342 g = M_GET_G(col);
343 b = M_GET_B(col);
344
345 switch(pp->param->coltype)
346 {
347 //RGB
348 case MSAVEIMAGE_COLTYPE_RGB:
349 pngcol.red = r;
350 pngcol.green = g;
351 pngcol.blue = b;
352
353 png_set_tRNS(pp->png, pp->pnginfo, NULL, 0, &pngcol);
354 break;
355 //グレイスケール
356 case MSAVEIMAGE_COLTYPE_GRAY:
357 pngcol.gray = r;
358 png_set_tRNS(pp->png, pp->pnginfo, NULL, 0, &pngcol);
359 break;
360 //パレット
361 case MSAVEIMAGE_COLTYPE_PALETTE:
362 pnum = pp->param->palette_num;
363
364 trbuf = (uint8_t *)mMalloc(pnum, FALSE);
365 if(!trbuf) return;
366
367 memset(trbuf, 255, pnum);
368
369 ps = pp->param->palette_buf;
370
371 for(i = 0; i < pnum && !(ps[0] == r && ps[1] == g && ps[2] == b); i++, ps += 4);
372
373 if(i < pnum)
374 {
375 trbuf[i] = 0;
376 png_set_tRNS(pp->png, pp->pnginfo, trbuf, i + 1, 0);
377 }
378
379 mFree(trbuf);
380 break;
381 }
382 }
383
384 /* @} */
385