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