1 /*$
2  Copyright (C) 2016-2020 Azel.
3 
4  This file is part of AzPainterB.
5 
6  AzPainterB 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  AzPainterB 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  * ImageBuf24
22  *
23  * 24bit RGB イメージ
24  *****************************************/
25 /*
26  * - "R-G-B" のバイト順で並んでいる。
27  * - レイヤ合成後のイメージなどで使われる。
28  */
29 
30 #include <string.h>
31 
32 #include "mDef.h"
33 #include "mLoadImage.h"
34 
35 #include "ImageBuf24.h"
36 
37 
38 
39 /** 32bit カラー値から ImageBuf24Pix に変換 */
40 
ImageBuf24_coltopix(ImageBuf24Pix * dst,uint32_t col)41 void ImageBuf24_coltopix(ImageBuf24Pix *dst,uint32_t col)
42 {
43 	dst->r = (uint8_t)(col >> 16);
44 	dst->g = (uint8_t)(col >> 8);
45 	dst->b = (uint8_t)col;
46 }
47 
48 /** 解放 */
49 
ImageBuf24_free(ImageBuf24 * p)50 void ImageBuf24_free(ImageBuf24 *p)
51 {
52 	if(p)
53 	{
54 		mFree(p->buf);
55 		mFree(p);
56 	}
57 }
58 
59 /** 作成 */
60 
ImageBuf24_new(int w,int h)61 ImageBuf24 *ImageBuf24_new(int w,int h)
62 {
63 	ImageBuf24 *p;
64 
65 	p = (ImageBuf24 *)mMalloc(sizeof(ImageBuf24), TRUE);
66 	if(!p) return NULL;
67 
68 	p->w = w;
69 	p->h = h;
70 	p->pitch = w * 3;
71 
72 	//バッファ確保
73 
74 	p->buf = (uint8_t *)mMalloc(w * h * 3, FALSE);
75 	if(!p->buf)
76 	{
77 		mFree(p);
78 		return NULL;
79 	}
80 
81 	return p;
82 }
83 
84 /** 指定位置のポインタを取得
85  *
86  * @return NULL で範囲外 */
87 
ImageBuf24_getPixelBuf(ImageBuf24 * p,int x,int y)88 uint8_t *ImageBuf24_getPixelBuf(ImageBuf24 *p,int x,int y)
89 {
90 	if(x < 0 || y < 0 || x >= p->w || y >= p->h)
91 		return NULL;
92 	else
93 		return p->buf + y * p->pitch + x * 3;
94 }
95 
96 /** 全体を指定色で埋める */
97 
ImageBuf24_fill(ImageBuf24 * p,uint32_t col)98 void ImageBuf24_fill(ImageBuf24 *p,uint32_t col)
99 {
100 	uint8_t *pd;
101 	ImageBuf24Pix pix;
102 	int i,pitch;
103 
104 	ImageBuf24_coltopix(&pix, col);
105 
106 	//Y1列分を埋める
107 
108 	pd = p->buf;
109 
110 	for(i = p->w; i > 0; i--, pd += 3)
111 	{
112 		pd[0] = pix.r;
113 		pd[1] = pix.g;
114 		pd[2] = pix.b;
115 	}
116 
117 	//残りは、前の列をコピー
118 
119 	pitch = p->pitch;
120 	pd = p->buf + pitch;
121 
122 	for(i = p->h - 1; i > 0; i--, pd += pitch)
123 		memcpy(pd, pd - pitch, pitch);
124 }
125 
126 /** 白色で全体を埋める */
127 
ImageBuf24_fillWhite(ImageBuf24 * p)128 void ImageBuf24_fillWhite(ImageBuf24 *p)
129 {
130 	memset(p->buf, 255, p->pitch * p->h);
131 }
132 
133 /** 範囲を指定色で埋める */
134 
ImageBuf24_fillBox(ImageBuf24 * p,mBox * box,uint32_t col)135 void ImageBuf24_fillBox(ImageBuf24 *p,mBox *box,uint32_t col)
136 {
137 	uint8_t *pd;
138 	ImageBuf24Pix pix;
139 	int i,pitch,wsize;
140 
141 	ImageBuf24_coltopix(&pix, col);
142 
143 	pitch = p->pitch;
144 	wsize = box->w * 3;
145 
146 	//Y1列分を埋める
147 
148 	pd = p->buf + box->y * pitch + box->x * 3;
149 
150 	for(i = box->w; i > 0; i--, pd += 3)
151 	{
152 		pd[0] = pix.r;
153 		pd[1] = pix.g;
154 		pd[2] = pix.b;
155 	}
156 
157 	//前の列をコピー
158 
159 	pd -= wsize;
160 
161 	for(i = box->h - 1; i > 0; i--, pd += pitch)
162 		memcpy(pd + pitch, pd, wsize);
163 }
164 
165 /** チェック柄で範囲を埋める */
166 
ImageBuf24_fillPlaid_box(ImageBuf24 * p,mBox * box,uint32_t col1,uint32_t col2)167 void ImageBuf24_fillPlaid_box(ImageBuf24 *p,mBox *box,uint32_t col1,uint32_t col2)
168 {
169 	ImageBuf24Pix *pd,pix[2];
170 	uint8_t *bufd,*bufs;
171 	int ix,iy,pitch,xx,yy,fy;
172 
173 	ImageBuf24_coltopix(pix, col1);
174 	ImageBuf24_coltopix(pix + 1, col2);
175 
176 	//高さを 16px まで埋める
177 
178 	pd = (ImageBuf24Pix *)(p->buf + box->y * p->pitch + box->x * 3);
179 	pitch = p->w - box->w;
180 
181 	yy = box->y & 15;
182 
183 	for(iy = (box->h > 16)? 16: box->h; iy > 0; iy--)
184 	{
185 		xx = box->x & 15;
186 		fy = yy >> 3;
187 
188 		for(ix = box->w; ix > 0; ix--)
189 		{
190 			*(pd++) = pix[fy ^ (xx >> 3)];
191 
192 			xx = (xx + 1) & 15;
193 		}
194 
195 		pd += pitch;
196 		yy = (yy + 1) & 15;
197 	}
198 
199 	//残りの高さをコピーして埋める
200 
201 	if(box->h > 16)
202 	{
203 		pitch = p->pitch;
204 		bufd = (uint8_t *)pd;
205 		bufs = bufd - (pitch << 4);
206 
207 		xx = box->w * 3;
208 
209 		for(iy = box->h - 16; iy > 0; iy--)
210 		{
211 			memcpy(bufd, bufs, xx);
212 
213 			bufd += pitch;
214 			bufs += pitch;
215 		}
216 	}
217 }
218 
219 /** パレット取得 (最大256色)
220  *
221  * @param tpindex  透過色を入れておく。透過色のインデックス番号が入る。
222  * @return 確保されたバッファ (R-G-B-A)。256色より多い場合は NULL */
223 
ImageBuf24_getPalette(ImageBuf24 * p,int * pnum,int * tpcol)224 uint8_t *ImageBuf24_getPalette(ImageBuf24 *p,int *pnum,int *tpcol)
225 {
226 	uint8_t *palbuf,*ps,*ppal,tr,tg,tb;
227 	uint32_t i;
228 	int j,cnt = 0,settp;
229 
230 	//バッファ確保
231 
232 	palbuf = (uint8_t *)mMalloc(256 * 4, FALSE);
233 	if(!palbuf) return NULL;
234 
235 	//透過色 RGB
236 
237 	if(*tpcol < 0)
238 		settp = FALSE;
239 	else
240 	{
241 		tr = M_GET_R(*tpcol);
242 		tg = M_GET_G(*tpcol);
243 		tb = M_GET_B(*tpcol);
244 		settp = TRUE;
245 	}
246 
247 	//
248 
249 	ps = p->buf;
250 
251 	for(i = p->w * p->h; i; i--, ps += 3)
252 	{
253 		//すでに存在する色か
254 
255 		for(j = 0, ppal = palbuf; j < cnt; j++, ppal += 4)
256 		{
257 			if(ps[0] == ppal[0] && ps[1] == ppal[1] && ps[2] == ppal[2])
258 				break;
259 		}
260 
261 		//追加
262 
263 		if(j == cnt)
264 		{
265 			//256色を超えた
266 
267 			if(cnt == 256)
268 			{
269 				mFree(palbuf);
270 				return NULL;
271 			}
272 
273 			//透過色のインデックスセット
274 
275 			if(settp && ps[0] == tr && ps[1] == tg && ps[2] == tb)
276 			{
277 				*tpcol = cnt;
278 				settp = FALSE;
279 			}
280 
281 			//
282 
283 			ppal[0] = ps[0];
284 			ppal[1] = ps[1];
285 			ppal[2] = ps[2];
286 			ppal[3] = 0;
287 
288 			cnt++;
289 		}
290 	}
291 
292 	*pnum = cnt;
293 
294 	return palbuf;
295 }
296 
297 /** パレットイメージ保存用、Y1行セット */
298 
ImageBuf24_setRow_forPalette(ImageBuf24 * p,uint8_t * dst,uint8_t * src,uint8_t * palbuf,int palnum)299 void ImageBuf24_setRow_forPalette(ImageBuf24 *p,uint8_t *dst,uint8_t *src,uint8_t *palbuf,int palnum)
300 {
301 	uint8_t *ppal;
302 	int i,j;
303 
304 	for(i = p->w; i; i--, src += 3)
305 	{
306 		//パレットから検索
307 
308 		for(j = 0, ppal = palbuf; j < palnum; j++, ppal += 4)
309 		{
310 			if(src[0] == ppal[0] && src[1] == ppal[1] && src[2] == ppal[2])
311 				break;
312 		}
313 
314 		if(j == palnum) j = 0;
315 
316 		*(dst++) = j;
317 	}
318 }
319 
320 
321 //==============================
322 // 画像読み込み
323 //==============================
324 
325 
326 typedef struct
327 {
328 	mLoadImage base;
329 	ImageBuf24 *img;
330 	uint8_t *dstbuf;
331 	ImageBuf24Pix bgpix;
332 }_loadimageinfo;
333 
334 
335 /** 情報取得 */
336 
_loadfile_getinfo(mLoadImage * param,mLoadImageInfo * info)337 static int _loadfile_getinfo(mLoadImage *param,mLoadImageInfo *info)
338 {
339 	_loadimageinfo *p = (_loadimageinfo *)param;
340 
341 	//作成
342 
343 	p->img = ImageBuf24_new(info->width, info->height);
344 	if(!p->img) return MLOADIMAGE_ERR_ALLOC;
345 
346 	p->dstbuf = p->img->buf;
347 	if(info->bottomup) p->dstbuf += (info->height - 1) * p->img->pitch;
348 
349 	return MLOADIMAGE_ERR_OK;
350 }
351 
352 /** Y1行取得 */
353 
_loadfile_getrow(mLoadImage * param,uint8_t * buf,int pitch)354 static int _loadfile_getrow(mLoadImage *param,uint8_t *buf,int pitch)
355 {
356 	_loadimageinfo *p = (_loadimageinfo *)param;
357 	int i,a;
358 	uint8_t *pd;
359 	ImageBuf24Pix pix;
360 
361 	pd = p->dstbuf;
362 	pix = p->bgpix;
363 
364 	for(i = param->info.width; i > 0; i--, buf += 4, pd += 3)
365 	{
366 		a = buf[3];
367 
368 		if(a == 255)
369 			pd[0] = buf[0], pd[1] = buf[1], pd[2] = buf[2];
370 		else if(a == 0)
371 			pd[0] = pix.r, pd[1] = pix.g, pd[2] = pix.b;
372 		else
373 		{
374 			pd[0] = (buf[0] - pix.r) * a / 255 + pix.r;
375 			pd[1] = (buf[1] - pix.g) * a / 255 + pix.g;
376 			pd[2] = (buf[2] - pix.b) * a / 255 + pix.b;
377 		}
378 	}
379 
380 	p->dstbuf += (param->info.bottomup)? -(p->img->pitch): p->img->pitch;
381 
382 	return MLOADIMAGE_ERR_OK;
383 }
384 
385 /** 画像ファイルを読み込み (BMP/PNG/GIF/JPEG)
386  *
387  * @param bkgndcol アルファ値または透過色がある場合は、この背景色と合成される */
388 
ImageBuf24_loadFile(const char * filename,uint32_t bkgndcol)389 ImageBuf24 *ImageBuf24_loadFile(const char *filename,uint32_t bkgndcol)
390 {
391 	_loadimageinfo *p;
392 	mLoadImageFunc func;
393 	ImageBuf24 *img = NULL;
394 
395 	p = (_loadimageinfo *)mLoadImage_create(sizeof(_loadimageinfo));
396 	if(!p) return NULL;
397 
398 	ImageBuf24_coltopix(&p->bgpix, bkgndcol);
399 
400 	p->base.format = MLOADIMAGE_FORMAT_RGBA;
401 	p->base.src.type = MLOADIMAGE_SOURCE_TYPE_PATH;
402 	p->base.src.filename = filename;
403 	p->base.getinfo = _loadfile_getinfo;
404 	p->base.getrow = _loadfile_getrow;
405 
406 	//実行
407 
408 	if(mLoadImage_checkFormat(&p->base.src, &func, MLOADIMAGE_CHECKFORMAT_F_ALL))
409 	{
410 		if((func)(M_LOADIMAGE(p)))
411 			img = p->img;
412 		else
413 			ImageBuf24_free(p->img);
414 	}
415 
416 	mLoadImage_free(M_LOADIMAGE(p));
417 
418 	return img;
419 }
420 
421