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  * ImageBuf24
22  *
23  * 8bit R-G-B イメージ
24  *****************************************/
25 /*
26  * - [R-G-B] のバイト順で並んでいる。
27  */
28 
29 #include "mDef.h"
30 #include "mLoadImage.h"
31 #include "mPixbuf.h"
32 
33 #include "ImageBuf24.h"
34 
35 
36 
37 /** 解放 */
38 
ImageBuf24_free(ImageBuf24 * p)39 void ImageBuf24_free(ImageBuf24 *p)
40 {
41 	if(p)
42 	{
43 		mFree(p->buf);
44 		mFree(p);
45 	}
46 }
47 
48 /** 作成 */
49 
ImageBuf24_new(int w,int h)50 ImageBuf24 *ImageBuf24_new(int w,int h)
51 {
52 	ImageBuf24 *p;
53 
54 	p = (ImageBuf24 *)mMalloc(sizeof(ImageBuf24), TRUE);
55 	if(!p) return NULL;
56 
57 	p->w = w;
58 	p->h = h;
59 	p->pitch = w * 3;
60 
61 	//バッファ確保
62 
63 	p->buf = (uint8_t *)mMalloc(w * h * 3, FALSE);
64 	if(!p->buf)
65 	{
66 		mFree(p);
67 		return NULL;
68 	}
69 
70 	return p;
71 }
72 
73 /** 指定位置のポインタを取得
74  *
75  * @return NULL で範囲外 */
76 
ImageBuf24_getPixelBuf(ImageBuf24 * p,int x,int y)77 uint8_t *ImageBuf24_getPixelBuf(ImageBuf24 *p,int x,int y)
78 {
79 	if(x < 0 || y < 0 || x >= p->w || y >= p->h)
80 		return NULL;
81 	else
82 		return p->buf + y * p->pitch + x * 3;
83 }
84 
85 
86 //==============================
87 // 画像読み込み
88 //==============================
89 
90 
91 typedef struct
92 {
93 	mLoadImage base;
94 	ImageBuf24 *img;
95 	uint8_t *dstbuf;
96 }_loadimageinfo;
97 
98 
99 /** 情報取得 */
100 
_loadfile_getinfo(mLoadImage * param,mLoadImageInfo * info)101 static int _loadfile_getinfo(mLoadImage *param,mLoadImageInfo *info)
102 {
103 	_loadimageinfo *p = (_loadimageinfo *)param;
104 
105 	//作成
106 
107 	p->img = ImageBuf24_new(info->width, info->height);
108 	if(!p->img) return MLOADIMAGE_ERR_ALLOC;
109 
110 	p->dstbuf = p->img->buf;
111 	if(info->bottomup) p->dstbuf += (info->height - 1) * p->img->pitch;
112 
113 	return MLOADIMAGE_ERR_OK;
114 }
115 
116 /** Y1行取得 */
117 
_loadfile_getrow(mLoadImage * param,uint8_t * buf,int pitch)118 static int _loadfile_getrow(mLoadImage *param,uint8_t *buf,int pitch)
119 {
120 	_loadimageinfo *p = (_loadimageinfo *)param;
121 	int i,a;
122 	uint8_t *pd;
123 
124 	pd = p->dstbuf;
125 
126 	for(i = param->info.width; i > 0; i--, buf += 4, pd += 3)
127 	{
128 		a = buf[3];
129 
130 		if(a == 255)
131 			pd[0] = buf[0], pd[1] = buf[1], pd[2] = buf[2];
132 		else if(a == 0)
133 			pd[0] = pd[1] = pd[2] = 255;
134 		else
135 		{
136 			pd[0] = (buf[0] - 255) * a / 255 + 255;
137 			pd[1] = (buf[1] - 255) * a / 255 + 255;
138 			pd[2] = (buf[2] - 255) * a / 255 + 255;
139 		}
140 	}
141 
142 	p->dstbuf += (param->info.bottomup)? -(p->img->pitch): p->img->pitch;
143 
144 	return MLOADIMAGE_ERR_OK;
145 }
146 
147 /** 画像ファイルを読み込み (BMP/PNG/GIF/JPEG)
148  *
149  * アルファ値または透過色がある場合は、背景が白として合成される */
150 
ImageBuf24_loadFile(const char * filename)151 ImageBuf24 *ImageBuf24_loadFile(const char *filename)
152 {
153 	_loadimageinfo *p;
154 	mLoadImageFunc func;
155 	ImageBuf24 *img = NULL;
156 
157 	p = (_loadimageinfo *)mLoadImage_create(sizeof(_loadimageinfo));
158 	if(!p) return NULL;
159 
160 	p->base.format = MLOADIMAGE_FORMAT_RGBA;
161 	p->base.src.type = MLOADIMAGE_SOURCE_TYPE_PATH;
162 	p->base.src.filename = filename;
163 	p->base.getinfo = _loadfile_getinfo;
164 	p->base.getrow = _loadfile_getrow;
165 
166 	//実行
167 
168 	if(mLoadImage_checkFormat(&p->base.src, &func, MLOADIMAGE_CHECKFORMAT_F_ALL))
169 	{
170 		if((func)(M_LOADIMAGE(p)))
171 			img = p->img;
172 		else
173 			ImageBuf24_free(p->img);
174 	}
175 
176 	mLoadImage_free(M_LOADIMAGE(p));
177 
178 	return img;
179 }
180 
181 
182 //============================================
183 // キャンバス描画 (イメージビューア)
184 //============================================
185 
186 
187 #define FIXF_BIT  28
188 #define FIXF_VAL  ((int64_t)1 << FIXF_BIT)
189 
190 
191 /** キャンバス描画 (ニアレストネイバー) */
192 
ImageBuf24_drawCanvas_nearest(ImageBuf24 * src,mPixbuf * dst,mBox * boxdst,ImageBuf24CanvasInfo * info)193 void ImageBuf24_drawCanvas_nearest(ImageBuf24 *src,mPixbuf *dst,
194 	mBox *boxdst,ImageBuf24CanvasInfo *info)
195 {
196 	int sw,sh,dbpp,pitchd,ix,iy,n;
197 	uint8_t *pd,*psY,*ps;
198 	mPixCol pixbkgnd;
199 	mBox box;
200 	int64_t fincx,fincy,fxleft,fx,fy;
201 	double scale,scalex;
202 
203 	//クリッピング
204 
205 	if(!mPixbufGetClipBox_box(dst, &box, boxdst)) return;
206 
207 	//
208 
209 	sw = src->w, sh = src->h;
210 
211 	pd = mPixbufGetBufPtFast(dst, box.x, box.y);
212 	dbpp = dst->bpp;
213 	pitchd = dst->pitch_dir - box.w * dbpp;
214 	pixbkgnd = mRGBtoPix(info->bkgndcol);
215 
216 	//
217 
218 	scale = scalex = info->scalediv;
219 
220 	fincx = fincy = (int64_t)(scale * FIXF_VAL + 0.5);
221 
222 	if(info->mirror)
223 		fincx = -fincx, scalex = -scalex;
224 
225 	fxleft = (int64_t)((info->scrollx * scalex + info->originx) * FIXF_VAL)
226 		+ box.x * fincx;
227 	fy = (int64_t)((info->scrolly * scale + info->originy) * FIXF_VAL)
228 		+ box.y * fincy;
229 
230 	//
231 
232 	for(iy = box.h; iy > 0; iy--, fy += fincy)
233 	{
234 		n = fy >> FIXF_BIT;
235 
236 		//Yが範囲外
237 
238 		if(fy < 0 || n >= sh)
239 		{
240 			mPixbufRawLineH(dst, pd, box.w, pixbkgnd);
241 
242 			pd += dst->pitch_dir;
243 			continue;
244 		}
245 
246 		//X
247 
248 		psY = src->buf + n * src->pitch;
249 
250 		for(ix = box.w, fx = fxleft; ix > 0; ix--, fx += fincx, pd += dbpp)
251 		{
252 			n = fx >> FIXF_BIT;
253 
254 			if(fx < 0 || n >= sw)
255 				//範囲外
256 				(dst->setbuf)(pd, pixbkgnd);
257 			else
258 			{
259 				ps = psY + n * 3;
260 
261 				(dst->setbuf)(pd, mRGBtoPix2(ps[0], ps[1], ps[2]));
262 			}
263 		}
264 
265 		pd += pitchd;
266 	}
267 }
268 
269 /** キャンバス描画 (8x8 オーバーサンプリング) */
270 
ImageBuf24_drawCanvas_oversamp(ImageBuf24 * src,mPixbuf * dst,mBox * boxdst,ImageBuf24CanvasInfo * info)271 void ImageBuf24_drawCanvas_oversamp(ImageBuf24 *src,mPixbuf *dst,
272 	mBox *boxdst,ImageBuf24CanvasInfo *info)
273 {
274 	int sw,sh,dbpp,pitchd,ix,iy,jx,jy,n,tblX[8],r,g,b;
275 	uint8_t *pd,*tbl_psY[8],*ps;
276 	mPixCol pixbkgnd;
277 	mBox box;
278 	int64_t fincx,fincy,fincx2,fincy2,fxleft,fx,fy,f;
279 	double scale,scalex;
280 
281 	//クリッピング
282 
283 	if(!mPixbufGetClipBox_box(dst, &box, boxdst)) return;
284 
285 	//
286 
287 	sw = src->w, sh = src->h;
288 
289 	pd = mPixbufGetBufPtFast(dst, box.x, box.y);
290 	dbpp = dst->bpp;
291 	pitchd = dst->pitch_dir - box.w * dbpp;
292 	pixbkgnd = mRGBtoPix(info->bkgndcol);
293 
294 	//
295 
296 	scale = scalex = info->scalediv;
297 
298 	fincx = fincy = (int64_t)(scale * FIXF_VAL + 0.5);
299 
300 	if(info->mirror)
301 		fincx = -fincx, scalex = -scalex;
302 
303 	fincx2 = fincx >> 3;
304 	fincy2 = fincy >> 3;
305 
306 	fxleft = (int64_t)((info->scrollx * scalex + info->originx) * FIXF_VAL)
307 		+ box.x * fincx;
308 	fy = (int64_t)((info->scrolly * scale + info->originy) * FIXF_VAL)
309 		+ box.y * fincy;
310 
311 	//
312 
313 	for(iy = box.h; iy > 0; iy--, fy += fincy)
314 	{
315 		n = fy >> FIXF_BIT;
316 
317 		//Yが範囲外
318 
319 		if(n < 0 || n >= sh)
320 		{
321 			mPixbufRawLineH(dst, pd, box.w, pixbkgnd);
322 			pd += dst->pitch_dir;
323 			continue;
324 		}
325 
326 		//Yテーブル
327 
328 		for(jy = 0, f = fy; jy < 8; jy++, f += fincy2)
329 		{
330 			n = f >> FIXF_BIT;
331 			if(n >= sh) n = sh - 1;
332 
333 			tbl_psY[jy] = src->buf + n * src->pitch;
334 		}
335 
336 		//---- X
337 
338 		for(ix = box.w, fx = fxleft; ix > 0; ix--, fx += fincx, pd += dbpp)
339 		{
340 			n = fx >> FIXF_BIT;
341 
342 			if(n < 0 || n >= sw)
343 				//範囲外
344 				(dst->setbuf)(pd, pixbkgnd);
345 			else
346 			{
347 				//X テーブル
348 
349 				for(jx = 0, f = fx; jx < 8; jx++, f += fincx2)
350 				{
351 					n = f >> FIXF_BIT;
352 					if(n >= sw) n = sw - 1;
353 
354 					tblX[jx] = n * 3;
355 				}
356 
357 				//オーバーサンプリング
358 
359 				r = g = b = 0;
360 
361 				for(jy = 0; jy < 8; jy++)
362 				{
363 					for(jx = 0; jx < 8; jx++)
364 					{
365 						ps = tbl_psY[jy] + tblX[jx];
366 
367 						r += ps[0];
368 						g += ps[1];
369 						b += ps[2];
370 					}
371 				}
372 
373 				(dst->setbuf)(pd, mRGBtoPix2(r >> 6, g >> 6, b >> 6));
374 			}
375 		}
376 
377 		pd += pitchd;
378 	}
379 }
380