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