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