Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "gdrawP.h"
28 : #include <string.h>
29 :
30 0 : void _GDraw_getimageclut(struct _GImage *base, struct gcol *clut) {
31 : int i, cnt;
32 : long col;
33 :
34 0 : if ( base->clut==NULL ) {
35 0 : clut->red = clut->green = clut->blue = 0;
36 0 : ++clut;
37 0 : clut->red = clut->green = clut->blue = 0xff;
38 0 : ++clut;
39 0 : i = 2;
40 : } else {
41 0 : cnt= base->clut->clut_len;
42 0 : for ( i=0; i<cnt; ++i, ++clut ) {
43 0 : col = base->clut->clut[i];
44 0 : clut->red = (col>>16)&0xff;
45 0 : clut->green = (col>>8)&0xff;
46 0 : clut->blue = (col&0xff);
47 : }
48 : }
49 0 : for ( ; i<256; ++i, ++clut ) {
50 0 : clut->red = clut->green = clut->blue = 0xff;
51 0 : clut->pixel = 0;
52 : }
53 0 : }
54 :
55 0 : static int MonoCols(GClut *clut, int *dark, int *bright_col, int *dark_col) {
56 : int bright;
57 :
58 0 : if ( clut==NULL ) {
59 0 : bright = 1; *bright_col = 3*255;
60 0 : *dark = 0; *dark_col = 0;
61 : } else {
62 0 : Color col0 = clut->clut[0], col1 = clut->clut[1];
63 0 : int g0 = COLOR_RED(col0)+COLOR_GREEN(col0)+COLOR_BLUE(col0),
64 0 : g1 = COLOR_RED(col1)+COLOR_GREEN(col1)+COLOR_BLUE(col1);
65 0 : if ( g1>g0 ) {
66 0 : bright = 1; *bright_col = g1;
67 0 : *dark = 0; *dark_col = g0;
68 : } else {
69 0 : bright = 0; *bright_col = g0;
70 0 : *dark = 1; *dark_col = g1;
71 : }
72 : }
73 0 : return( bright );
74 : }
75 :
76 0 : static GImage *GImage1to32(struct _GImage *base,GRect *src) {
77 : GImage *ret;
78 : struct _GImage *rbase;
79 : register Color *clut;
80 : Color fake[2];
81 : uint8 *pt;
82 : uint32 *ipt;
83 : int bit, i,j;
84 :
85 0 : if ( base->clut==NULL ) {
86 0 : fake[0] = COLOR_CREATE(0,0,0);
87 0 : fake[1] = COLOR_CREATE(0xff,0xff,0xff);
88 0 : clut = fake;
89 : } else
90 0 : clut = base->clut->clut;
91 0 : ret = GImageCreate(it_true,src->width,src->height);
92 0 : rbase = ret->u.image;
93 0 : rbase->trans = base->clut==NULL || base->trans==COLOR_UNKNOWN?COLOR_UNKNOWN:
94 0 : clut[base->trans];
95 :
96 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
97 0 : pt = (uint8 *) (base->data) + i*base->bytes_per_line + (src->x>>3);
98 0 : ipt = (uint32 *) (rbase->data + (i-src->y)*rbase->bytes_per_line);
99 0 : bit = 0x80>>(src->x&7);
100 0 : for ( j=src->width-1; j>=0; --j ) {
101 0 : if ( *pt&bit )
102 0 : *ipt++ = clut[1];
103 : else
104 0 : *ipt++ = clut[0];
105 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt;};
106 : }
107 : }
108 0 : return( ret );
109 : }
110 :
111 0 : static GImage *GImage8to32(struct _GImage *base,GRect *src) {
112 : GImage *ret;
113 : struct _GImage *rbase;
114 0 : register Color *clut = base->clut->clut;
115 : uint8 *pt;
116 : uint32 *ipt;
117 : int i,j;
118 :
119 0 : ret = GImageCreate(it_true,src->width,src->height);
120 0 : rbase = ret->u.image;
121 0 : rbase->trans = base->trans==COLOR_UNKNOWN?COLOR_UNKNOWN:
122 0 : clut[base->trans];
123 :
124 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
125 0 : pt = (uint8 *) (base->data) + i*base->bytes_per_line + src->x;
126 0 : ipt = (uint32 *) (rbase->data + (i-src->y)*rbase->bytes_per_line);
127 0 : for ( j=src->width-1; j>=0; --j )
128 0 : *ipt++ = clut[ *pt++ ];
129 : }
130 0 : return( ret );
131 : }
132 :
133 0 : static GImage *GImage32to32(struct _GImage *base,GRect *src) {
134 : GImage *ret;
135 : struct _GImage *rbase;
136 : uint32 *pt;
137 : uint32 *ipt;
138 : int i;
139 :
140 0 : ret = GImageCreate(it_true,src->width,src->height);
141 0 : rbase = ret->u.image;
142 0 : rbase->trans = base->trans;
143 :
144 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
145 0 : pt = ((uint32 *) (base->data + i*base->bytes_per_line)) + src->x;
146 0 : ipt = (uint32 *) (rbase->data + (i-src->y)*rbase->bytes_per_line);
147 0 : memcpy(ipt,pt,(src->width)*sizeof(uint32));
148 : }
149 0 : return( ret );
150 : }
151 :
152 0 : static GImage *GImage1to8(struct _GImage *base,GRect *src, GClut *nclut, RevCMap *rev) {
153 : GImage *ret;
154 : struct _GImage *rbase;
155 : register Color *clut; Color fake[2];
156 : uint8 *pt;
157 : uint8 *ipt;
158 : int bit;
159 : uint8 ones, zeros;
160 : int i,j;
161 : const struct gcol *stupid_gcc;
162 :
163 0 : if ( base->clut==NULL ) {
164 0 : fake[0] = COLOR_CREATE(0,0,0);
165 0 : fake[1] = COLOR_CREATE(0xff,0xff,0xff);
166 0 : clut = fake;
167 : } else
168 0 : clut = base->clut->clut;
169 0 : ones = _GImage_GetIndexedPixelPrecise(clut[1],rev)->pixel;
170 0 : stupid_gcc = _GImage_GetIndexedPixelPrecise(clut[0],rev);
171 0 : zeros = stupid_gcc->pixel;
172 0 : if ( base->clut!=NULL && nclut->trans_index!=COLOR_UNKNOWN ) {
173 0 : if ( base->trans==0 )
174 0 : zeros = nclut->trans_index;
175 0 : else if ( base->trans==1 )
176 0 : ones = nclut->trans_index;
177 : }
178 :
179 0 : ret = GImageCreate(it_index,src->width,src->height);
180 0 : rbase = ret->u.image;
181 0 : *rbase->clut = *nclut;
182 0 : rbase->trans = nclut->trans_index;
183 :
184 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
185 0 : pt = (uint8 *) (base->data) + i*base->bytes_per_line + (src->x>>3);
186 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
187 0 : bit = 0x80>>(src->x&7);
188 0 : for ( j=src->width-1; j>=0; --j ) {
189 0 : if ( *pt&bit )
190 0 : *ipt++ = ones;
191 : else
192 0 : *ipt++ = zeros;
193 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt;};
194 : }
195 : }
196 0 : return( ret );
197 : }
198 :
199 0 : static GImage *GImage8to8(struct _GImage *base,GRect *src, GClut *nclut, RevCMap *rev) {
200 : GImage *ret;
201 : struct _GImage *rbase;
202 : uint8 *pt;
203 : uint8 *ipt;
204 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
205 : int i,j;
206 :
207 0 : to_trans = nclut->trans_index;
208 0 : if ( to_trans!=COLOR_UNKNOWN )
209 0 : from_trans = base->trans;
210 0 : ret = GImageCreate(it_index,src->width,src->height);
211 0 : rbase = ret->u.image;
212 0 : *rbase->clut = *nclut;
213 0 : rbase->trans = nclut->trans_index;
214 0 : if ( nclut==base->clut || GImageSameClut(base->clut,nclut) ) {
215 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
216 0 : pt = (uint8 *) (base->data) + i*base->bytes_per_line + src->x;
217 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
218 0 : memcpy(ipt,pt,src->width);
219 : }
220 : } else {
221 : struct gcol gclut[256];
222 : short *red_dith, *green_dith, *blue_dith;
223 : short *r_d, *g_d, *b_d;
224 : register int rd, gd, bd;
225 : int index;
226 : const struct gcol *pos;
227 :
228 0 : _GDraw_getimageclut(base,gclut);
229 0 : red_dith = calloc(src->width,sizeof(short));
230 0 : green_dith = calloc(src->width,sizeof(short));
231 0 : blue_dith = calloc(src->width,sizeof(short));
232 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
233 0 : pt = (uint8 *) (base->data + i*base->bytes_per_line) + src->x;
234 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
235 0 : rd = gd = bd = 0;
236 0 : r_d = red_dith; g_d = green_dith; b_d = blue_dith;
237 0 : for ( j=src->width-1; j>=0; --j ) {
238 0 : index = *pt++;
239 0 : if ( index==from_trans ) {
240 0 : *ipt++ = to_trans;
241 0 : ++r_d; ++g_d; ++b_d;
242 : } else {
243 0 : pos = &gclut[index];
244 0 : rd += *r_d + pos->red; if ( rd<0 ) rd=0; else if ( rd>255 ) rd = 255;
245 0 : gd += *g_d + pos->green; if ( gd<0 ) gd=0; else if ( gd>255 ) gd = 255;
246 0 : bd += *b_d + pos->blue; if ( bd<0 ) bd=0; else if ( bd>255 ) bd = 255;
247 0 : pos = _GImage_GetIndexedPixelPrecise(COLOR_CREATE(rd,gd,bd),rev);
248 0 : *ipt++ = pos->pixel;
249 0 : *r_d++ = rd = (rd - pos->red)/2;
250 0 : *g_d++ = gd = (gd - pos->green)/2;
251 0 : *b_d++ = bd = (bd - pos->blue)/2;
252 : }
253 : }
254 : }
255 0 : free(red_dith); free(green_dith); free(blue_dith);
256 : }
257 0 : return( ret );
258 : }
259 :
260 0 : static GImage *GImage32to8(struct _GImage *base,GRect *src, GClut *nclut, RevCMap *rev) {
261 : GImage *ret;
262 : struct _GImage *rbase;
263 : uint32 *pt;
264 : uint8 *ipt;
265 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
266 : int i,j;
267 : short *red_dith, *green_dith, *blue_dith;
268 : short *r_d, *g_d, *b_d;
269 : register int rd, gd, bd;
270 : int index;
271 : const struct gcol *pos;
272 :
273 0 : to_trans = nclut->trans_index;
274 0 : if ( to_trans!=COLOR_UNKNOWN )
275 0 : from_trans = base->trans;
276 0 : ret = GImageCreate(it_index,src->width,src->height);
277 0 : rbase = ret->u.image;
278 0 : *rbase->clut = *nclut;
279 0 : rbase->trans = nclut->trans_index;
280 :
281 0 : red_dith = calloc(src->width,sizeof(short));
282 0 : green_dith = calloc(src->width,sizeof(short));
283 0 : blue_dith = calloc(src->width,sizeof(short));
284 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
285 0 : pt = (uint32 *) (base->data + i*base->bytes_per_line) + src->x;
286 0 : ipt = (uint8 *) (ret->u.image->data) + (i-src->y)*ret->u.image->bytes_per_line;
287 0 : rd = gd = bd = 0;
288 0 : r_d = red_dith; g_d = green_dith; b_d = blue_dith;
289 0 : for ( j=src->width-1; j>=0; --j ) {
290 0 : index = *pt++;
291 0 : if ( index==from_trans ) {
292 0 : *ipt++ = to_trans;
293 0 : ++r_d; ++g_d; ++b_d;
294 : } else {
295 0 : rd += *r_d + COLOR_RED(index); if ( rd<0 ) rd=0; else if ( rd>255 ) rd = 255;
296 0 : gd += *g_d + COLOR_GREEN(index); if ( gd<0 ) gd=0; else if ( gd>255 ) gd = 255;
297 0 : bd += *b_d + COLOR_BLUE(index); if ( bd<0 ) bd=0; else if ( bd>255 ) bd = 255;
298 0 : pos = _GImage_GetIndexedPixelPrecise(COLOR_CREATE(rd,gd,bd),rev);
299 0 : *ipt++ = pos->pixel;
300 0 : *r_d++ = rd = (rd - pos->red)/2;
301 0 : *g_d++ = gd = (gd - pos->green)/2;
302 0 : *b_d++ = bd = (bd - pos->blue)/2;
303 : }
304 : }
305 : }
306 0 : free(red_dith); free(green_dith); free(blue_dith);
307 0 : return( ret );
308 : }
309 :
310 0 : static GImage *GImage1to1(struct _GImage *base,GRect *src, GClut *nclut) {
311 : GImage *ret;
312 : struct _GImage *rbase;
313 : uint8 *pt;
314 : uint8 *ipt;
315 : int bit, ibit;
316 : uint8 ones, zeros;
317 : int i,j;
318 :
319 : {
320 : register Color *clut; Color fake[2];
321 : int bright, dark, bright_col, dark_col;
322 0 : if ( base->clut==NULL ) {
323 0 : fake[0] = COLOR_CREATE(0,0,0);
324 0 : fake[1] = COLOR_CREATE(0xff,0xff,0xff);
325 0 : clut = fake;
326 : } else
327 0 : clut = base->clut->clut;
328 0 : bright = MonoCols(nclut,&dark,&bright_col,&dark_col);
329 0 : if ( COLOR_RED(clut[0])+COLOR_GREEN(clut[0])+COLOR_BLUE(clut[0]) >
330 0 : COLOR_RED(clut[1])+COLOR_GREEN(clut[1])+COLOR_BLUE(clut[1]) ) {
331 0 : zeros = bright;
332 0 : ones = dark;
333 : } else {
334 0 : zeros = dark;
335 0 : ones = bright;
336 : }
337 : }
338 0 : if ( base->clut!=NULL && nclut!=NULL && nclut->trans_index!=COLOR_UNKNOWN ) {
339 0 : if ( base->trans==0 ) {
340 0 : zeros = nclut->trans_index;
341 0 : ones = !zeros;
342 0 : } else if ( base->trans==1 ) {
343 0 : ones = nclut->trans_index;
344 0 : zeros = !ones;
345 : }
346 : }
347 :
348 0 : ret = GImageCreate(it_mono,src->width,src->height);
349 0 : rbase = ret->u.image;
350 0 : if ( nclut!=NULL ) {
351 0 : rbase->clut = calloc(1,sizeof(GClut));
352 0 : *rbase->clut = *nclut;
353 0 : rbase->trans = nclut->trans_index;
354 : }
355 :
356 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
357 0 : pt = (uint8 *) (base->data) + i*base->bytes_per_line + (src->x>>3);
358 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
359 0 : bit = 0x80>>(src->x&7);
360 0 : ibit = 0x80;
361 0 : if ( ones==0 ) {
362 0 : for ( j=src->width-1; j>=0; --j ) {
363 0 : if ( *pt&bit )
364 0 : *ipt &= ~ibit;
365 : else
366 0 : *ipt |= ibit;
367 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt;};
368 0 : if (( ibit>>=1 )==0 ) {ibit=0x80; ++ipt;};
369 : }
370 : } else {
371 0 : for ( j=src->width-1; j>=0; --j ) {
372 0 : if ( *pt&bit )
373 0 : *ipt |= ibit;
374 : else
375 0 : *ipt &= ~ibit;
376 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt;};
377 0 : if (( ibit>>=1 )==0 ) {ibit=0x80; ++ipt;};
378 : }
379 : }
380 : }
381 0 : return( ret );
382 : }
383 :
384 0 : static GImage *GImage8to1(struct _GImage *base,GRect *src, GClut *nclut) {
385 : GImage *ret;
386 : struct _GImage *rbase;
387 : uint8 *pt;
388 : uint8 *ipt;
389 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
390 : struct gcol gclut[256];
391 : int bit;
392 : short *grey_dith;
393 : short *g_d;
394 : register int gd;
395 : int bright, dark;
396 : int bright_col, dark_col;
397 : int i,j;
398 : int index;
399 : const struct gcol *pos;
400 :
401 0 : to_trans = COLOR_UNKNOWN;
402 0 : if ( nclut!=NULL )
403 0 : to_trans = nclut->trans_index;
404 0 : if ( to_trans!=COLOR_UNKNOWN )
405 0 : from_trans = base->trans;
406 :
407 0 : ret = GImageCreate(it_mono,src->width,src->height);
408 0 : rbase = ret->u.image;
409 0 : if ( nclut!=NULL ) {
410 0 : rbase->clut = calloc(1,sizeof(GClut));
411 0 : *rbase->clut = *nclut;
412 0 : rbase->trans = nclut->trans_index;
413 : }
414 :
415 0 : _GDraw_getimageclut(base,gclut);
416 0 : bright = MonoCols(nclut, &dark,&bright_col,&dark_col);
417 :
418 0 : grey_dith = calloc(src->width,sizeof(short));
419 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
420 0 : pt = (uint8 *) (base->data + i*base->bytes_per_line) + src->x;
421 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
422 0 : bit = 0x80;
423 0 : gd = 0;
424 0 : g_d = grey_dith;
425 0 : for ( j=src->width-1; j>=0; --j ) {
426 0 : index = *pt++;
427 0 : if ( index==from_trans ) {
428 0 : *ipt++ = to_trans;
429 0 : ++g_d;
430 : } else {
431 0 : pos = &gclut[index];
432 0 : gd += *g_d + pos->red+pos->green+pos->blue;
433 0 : if (( gd<3*128 && dark) || (gd>=3*128 && bright))
434 0 : *ipt |= bit;
435 : else
436 0 : *ipt &= ~bit;
437 0 : if ( gd<0 ) gd=0; else if ( gd>3*255 ) gd = 3*255;
438 0 : if ( gd<3*128 )
439 0 : *g_d++ = gd = (gd-dark_col)/2;
440 : else
441 0 : *g_d++ = gd = (gd-bright_col)/2;
442 : }
443 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++ipt;};
444 : }
445 : }
446 0 : free(grey_dith);
447 0 : return( ret );
448 : }
449 :
450 0 : static GImage *GImage32to1(struct _GImage *base,GRect *src, GClut *nclut) {
451 : GImage *ret;
452 : struct _GImage *rbase;
453 : uint32 *pt;
454 : uint8 *ipt;
455 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
456 : int bit;
457 : short *grey_dith;
458 : short *g_d;
459 : register int gd;
460 : int bright, dark, bright_col, dark_col;
461 : int i,j, index;
462 :
463 0 : to_trans = COLOR_UNKNOWN;
464 0 : if ( nclut!=NULL )
465 0 : to_trans = nclut->trans_index;
466 0 : if ( to_trans!=COLOR_UNKNOWN )
467 0 : from_trans = base->trans;
468 :
469 0 : ret = GImageCreate(it_mono,src->width,src->height);
470 0 : rbase = ret->u.image;
471 0 : if ( nclut!=NULL ) {
472 0 : rbase->clut = calloc(1,sizeof(GClut));
473 0 : *rbase->clut = *nclut;
474 0 : rbase->trans = nclut->trans_index;
475 : }
476 0 : bright = MonoCols(nclut,&dark,&bright_col,&dark_col);
477 :
478 0 : grey_dith = calloc(src->width,sizeof(short));
479 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
480 0 : pt = (uint32 *) (base->data + i*base->bytes_per_line) + src->x;
481 0 : ipt = (uint8 *) (rbase->data) + (i-src->y)*rbase->bytes_per_line;
482 0 : bit = 0x80;
483 0 : gd = 0;
484 0 : g_d = grey_dith;
485 0 : for ( j=src->width-1; j>=0; --j ) {
486 0 : index = *pt++;
487 0 : if ( index==from_trans ) {
488 0 : if ( to_trans ) *ipt |= bit; else *ipt &= ~bit;
489 0 : ++g_d;
490 : } else {
491 0 : gd += *g_d + COLOR_RED(index) + COLOR_GREEN(index) + COLOR_BLUE(index);
492 0 : if (( gd<3*128 && dark) || (gd>=3*128 && bright))
493 0 : *ipt |= bit;
494 : else
495 0 : *ipt &= ~bit;
496 0 : if ( gd<0 ) gd=0; else if ( gd>3*255 ) gd = 3*255;
497 0 : if ( gd<3*128 )
498 0 : *g_d++ = gd = (gd-dark_col)/2;
499 : else
500 0 : *g_d++ = gd = (gd-bright_col)/2;
501 : }
502 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++ipt;}
503 : }
504 : }
505 0 : free(grey_dith);
506 0 : return( ret );
507 : }
508 :
509 0 : GImage *GImageBaseGetSub(struct _GImage *base, enum image_type it, GRect *src, GClut *nclut, RevCMap *rev) {
510 0 : RevCMap *oldrev = rev;
511 0 : GImage *ret = NULL;
512 : GRect temp;
513 :
514 0 : if ( src==NULL ) {
515 0 : src = &temp;
516 0 : temp.x = temp.y = 0;
517 0 : temp.width = base->width;
518 0 : temp.height = base->height;
519 : }
520 :
521 0 : if ( src->width<0 || src->height<0 ) {
522 0 : GDrawIError("Invalid rectangle in GImageGetSub");
523 0 : return( NULL );
524 : }
525 0 : switch ( it ) {
526 : case it_mono:
527 0 : switch ( base->image_type ) {
528 : case it_mono:
529 0 : return( GImage1to1(base,src,nclut));
530 : case it_index:
531 0 : return( GImage8to1(base,src,nclut));
532 : case it_true:
533 0 : return( GImage32to1(base,src,nclut));
534 : default:
535 0 : GDrawIError("Bad image type %d", base->image_type);
536 0 : return( NULL );
537 : }
538 : case it_index:
539 0 : if ( rev==NULL )
540 0 : rev = GClutReverse(nclut,8);
541 0 : switch ( base->image_type ) {
542 : case it_mono:
543 0 : ret = GImage1to8(base,src,nclut,rev);
544 0 : break;
545 : case it_index:
546 0 : ret = GImage8to8(base,src,nclut,rev);
547 0 : break;
548 : case it_true:
549 0 : ret = GImage32to8(base,src,nclut,rev);
550 0 : break;
551 : default:
552 0 : GDrawIError("Bad image type %d", base->image_type);
553 0 : ret = NULL;
554 0 : break;
555 : }
556 0 : if ( oldrev==NULL )
557 0 : GClut_RevCMapFree(rev);
558 0 : return( ret );
559 : case it_true:
560 0 : switch ( base->image_type ) {
561 : case it_mono:
562 0 : return( GImage1to32(base,src));
563 : case it_index:
564 0 : return( GImage8to32(base,src));
565 : case it_true:
566 0 : return( GImage32to32(base,src));
567 : default:
568 0 : GDrawIError("Bad image type %d", base->image_type);
569 0 : return( NULL );
570 : }
571 : default:
572 0 : GDrawIError("Bad image type %d", it);
573 0 : return( NULL );
574 : }
575 : }
576 :
577 0 : GImage *GImageGetSub(GImage *image,enum image_type it, GRect *src, GClut *nclut, RevCMap *rev) {
578 :
579 0 : if ( image->list_len ) {
580 0 : GDrawIError( "Attempt to get a subimage from an image list" );
581 0 : return( NULL );
582 : }
583 0 : return( GImageBaseGetSub( image->u.image, it, src, nclut, rev));
584 : }
585 :
586 0 : static void GImageInsert1to1(GImage *from,struct _GImage *tobase, GRect *src,
587 : int to_x, int to_y, enum pastetrans_type ptt) {
588 0 : struct _GImage *fbase = from->u.image;
589 : uint8 *pt;
590 : uint8 *ipt;
591 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
592 : uint8 ones, zeros;
593 : int i,j, bit, ibit, index;
594 :
595 0 : to_trans = tobase->trans;
596 0 : if ( to_trans!=COLOR_UNKNOWN || ptt==ptt_old_shines_through )
597 0 : from_trans = fbase->trans;
598 :
599 : {
600 : register Color *clut; Color fake[2];
601 : int bright, dark, bright_col, dark_col;
602 0 : clut = fbase->clut->clut;
603 0 : if ( clut==NULL ) {
604 0 : fake[0] = COLOR_CREATE(0,0,0);
605 0 : fake[1] = COLOR_CREATE(0xff,0xff,0xff);
606 0 : clut = fake;
607 : }
608 :
609 0 : bright = MonoCols(tobase->clut,&dark,&bright_col,&dark_col);
610 0 : if ( COLOR_RED(clut[0])+COLOR_GREEN(clut[0])+COLOR_BLUE(clut[0]) >
611 0 : COLOR_RED(clut[1])+COLOR_GREEN(clut[1])+COLOR_BLUE(clut[1]) ) {
612 0 : zeros = bright;
613 0 : ones = dark;
614 : } else {
615 0 : zeros = dark;
616 0 : ones = bright;
617 : }
618 : }
619 :
620 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
621 0 : pt = (uint8 *) (fbase->data) + i*fbase->bytes_per_line + (src->x>>3);
622 0 : ipt = (uint8 *) (tobase->data) + (i-src->y+to_y)*tobase->bytes_per_line+(to_x>>3);
623 0 : bit = 0x80>>(src->x&7);
624 0 : ibit = 0x80>>(to_x&7);
625 0 : for ( j=src->width-1; j>=0; --j ) {
626 0 : index = *pt&bit;
627 0 : if (( index && from_trans ) || (!index && !from_trans) ) {
628 0 : if ( ptt== ptt_old_shines_through )
629 : /* Do Nothing */;
630 0 : else if ( to_trans ) *ipt |= ibit; else *ipt &= ~ibit;
631 0 : } else if ( (index && ones) || (!index && zeros) ) {
632 0 : *ipt |= ibit;
633 : } else {
634 0 : *ipt &= ~ibit;
635 : }
636 0 : if (( ibit>>=1 )==0 ) {ibit=0x80; ++ipt;}
637 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt;}
638 : }
639 : }
640 0 : }
641 :
642 0 : static void GImageInsert8to8(GImage *from,struct _GImage *tobase, GRect *src, RevCMap *rev,
643 : int to_x, int to_y, enum pastetrans_type ptt) {
644 0 : struct _GImage *fbase = from->u.image;
645 0 : register Color *clut = from->u.image->clut->clut;
646 : uint8 *pt;
647 : uint8 *ipt;
648 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
649 : struct gcol gclut[256];
650 : short *red_dith, *green_dith, *blue_dith;
651 : short *r_d, *g_d, *b_d;
652 : register int rd, gd, bd;
653 : int i,j,index;
654 : const struct gcol *pos;
655 : Color col;
656 :
657 0 : to_trans = tobase->trans;
658 0 : if ( to_trans!=COLOR_UNKNOWN || ptt==ptt_old_shines_through )
659 0 : from_trans = fbase->trans;
660 :
661 0 : _GDraw_getimageclut(tobase,gclut);
662 0 : red_dith = calloc(src->width,sizeof(short));
663 0 : green_dith = calloc(src->width,sizeof(short));
664 0 : blue_dith = calloc(src->width,sizeof(short));
665 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
666 0 : pt = (uint8 *) (fbase->data + i*fbase->bytes_per_line) + src->x;
667 0 : ipt = (uint8 *) (tobase->data) + (i-src->y+to_y)*tobase->bytes_per_line+to_x;
668 0 : rd = gd = bd = 0;
669 0 : r_d = red_dith; g_d = green_dith; b_d = blue_dith;
670 0 : for ( j=src->width-1; j>=0; --j ) {
671 0 : index = *pt++;
672 0 : if ( index==from_trans ) {
673 0 : if ( ptt==ptt_old_shines_through )
674 0 : ++ipt;
675 : else
676 0 : *ipt++ = to_trans;
677 0 : ++r_d; ++g_d; ++b_d;
678 : } else {
679 0 : col = clut[index];
680 0 : rd += *r_d + COLOR_RED(col); if ( rd<0 ) rd=0; else if ( rd>255 ) rd = 255;
681 0 : gd += *g_d + COLOR_GREEN(col); if ( gd<0 ) gd=0; else if ( gd>255 ) gd = 255;
682 0 : bd += *b_d + COLOR_BLUE(col); if ( bd<0 ) bd=0; else if ( bd>255 ) bd = 255;
683 0 : pos = _GImage_GetIndexedPixelPrecise(COLOR_CREATE(rd,gd,bd),rev);
684 0 : *ipt++ = pos->pixel;
685 0 : *r_d++ = rd = (rd - pos->red)/2;
686 0 : *g_d++ = gd = (gd - pos->green)/2;
687 0 : *b_d++ = bd = (bd - pos->blue)/2;
688 : }
689 : }
690 : }
691 0 : free(red_dith); free(green_dith); free(blue_dith);
692 0 : }
693 :
694 0 : static void GImageInsert32to32(GImage *from,struct _GImage *tobase, GRect *src,
695 : int to_x, int to_y, enum pastetrans_type ptt) {
696 0 : struct _GImage *fbase = from->u.image;
697 : uint32 *pt;
698 : uint32 *ipt;
699 0 : uint32 from_trans=COLOR_UNKNOWN, to_trans;
700 : int i,j,index;
701 :
702 0 : to_trans = tobase->trans;
703 0 : if ( to_trans!=COLOR_UNKNOWN || ptt==ptt_old_shines_through )
704 0 : from_trans = fbase->trans;
705 :
706 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
707 0 : pt = (uint32 *) (fbase->data + i*fbase->bytes_per_line) + src->x;
708 0 : ipt = (uint32 *) (tobase->data + (i-src->y+to_y)*tobase->bytes_per_line)+to_x;
709 0 : for ( j=src->width-1; j>=0; --j ) {
710 0 : index = *pt++;
711 0 : if ( index==from_trans ) {
712 0 : if ( ptt==ptt_old_shines_through )
713 0 : ++ipt;
714 : else
715 0 : *ipt++ = to_trans;
716 : } else {
717 0 : *ipt++ = index;
718 : }
719 : }
720 : }
721 0 : }
722 :
723 : /* When pasting a transparent color, this routine pastes it as transparent. */
724 : /* It does not allow the old color to shine through! */
725 0 : int GImageInsertToBase(struct _GImage *tobase, GImage *from, GRect *src, RevCMap *rev,
726 : int to_x, int to_y, enum pastetrans_type ptt ) {
727 :
728 0 : if ( from->list_len ) {
729 0 : GDrawIError( "Attempt to paste from an image list" );
730 0 : return( false );
731 : }
732 0 : if ( src->width<=0 || src->height<=0 || src->x<0 || src->y<0 ) {
733 0 : GDrawIError("Invalid rectangle in GImageInsert");
734 0 : return( false );
735 : }
736 0 : if ( src->x+src->width > from->u.image->width || src->y+src->height > from->u.image->height ||
737 0 : to_x+src->width > tobase->width ||
738 0 : to_y+src->height > tobase->height ||
739 0 : to_x<0 || to_y<0 ) {
740 0 : GDrawIError("Bad size to GImageInsert");
741 0 : return( false );
742 : }
743 0 : if ( from->u.image->image_type != tobase->image_type ) {
744 0 : GDrawIError("Image type mismatch in GImageInsert");
745 0 : return( false );
746 : }
747 :
748 0 : if ( (from->u.image->trans==COLOR_UNKNOWN || tobase->trans==COLOR_UNKNOWN ) ||
749 0 : (from->u.image->trans==tobase->trans && ptt==ptt_paste_trans_to_trans)) {
750 0 : int i, size=4;
751 0 : if ( tobase->image_type == it_index ) size = 1;
752 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
753 0 : uint8 *fpt = (uint8 *) (from->u.image + i*from->u.image->bytes_per_line + size*src->x);
754 0 : uint8 *tpt = (uint8 *) (from->u.image + (i-src->y+to_y)*from->u.image->bytes_per_line + size*to_x);
755 0 : memcpy(tpt,fpt,(src->width)*size);
756 : }
757 0 : } else if ( tobase->image_type==it_mono && (src->x&7)==(to_x&7) &&
758 0 : GImageSameClut(from->u.image->clut,tobase->clut) &&
759 0 : from->u.image->trans==COLOR_UNKNOWN ) {
760 : int i, mask1, mask2, size;
761 0 : int end = src->x+src->width-1;
762 0 : mask1 = -1<<(src->x&7);
763 0 : mask2 = ~(-1<<(end&7));
764 0 : size = (end>>3) - (src->x>>3)-2;
765 0 : if ( mask1==-1 && size!=-2 ) { ++size; }
766 0 : if ( mask2==255 && size!=-2 ) { ++size; }
767 0 : for ( i=src->y; i<src->y+src->height; ++i ) {
768 0 : uint8 *fpt = (uint8 *) (from->u.image->data + i*from->u.image->bytes_per_line + (src->x>>3));
769 0 : uint8 *tpt = (uint8 *) (tobase->data + (i-src->y+to_y)*tobase->bytes_per_line + (to_x>>3));
770 0 : if ( size==-2 ) {
771 : /* all bits in same byte */
772 0 : *tpt = (*fpt&mask1&mask2) | (*tpt&~(mask1&mask2));
773 : } else {
774 0 : if ( mask1!=-1 ) {
775 0 : *tpt = (*fpt++&mask1) | (*tpt&~mask1);
776 0 : ++tpt;
777 : }
778 0 : if ( size!=0 )
779 0 : memcpy(tpt,fpt,size);
780 0 : if ( mask2!=255 )
781 0 : tpt[size] |= fpt[size]&mask1;
782 : }
783 : }
784 0 : } else if ( tobase->image_type==it_mono ) {
785 0 : GImageInsert1to1(from, tobase, src, to_x, to_y, ptt);
786 0 : } else if ( tobase->image_type==it_true ) {
787 0 : GImageInsert32to32(from, tobase, src, to_x, to_y, ptt);
788 : } else /*if ( tobase->image_type==it_index )*/ {
789 0 : RevCMap *oldrev = rev;
790 0 : if ( rev==NULL )
791 0 : rev = GClutReverse(tobase->clut,8);
792 0 : GImageInsert8to8(from, tobase, src, rev, to_x, to_y, ptt);
793 0 : if ( oldrev==NULL )
794 0 : GClut_RevCMapFree(rev);
795 : }
796 0 : return( true );
797 : }
798 :
799 0 : int GImageInsert(GImage *to, GImage *from, GRect *src, RevCMap *rev,
800 : int to_x, int to_y, enum pastetrans_type ptt ) {
801 :
802 0 : if ( to->list_len ) {
803 0 : GDrawIError( "Attempt to paste to an image list" );
804 0 : return( false );
805 : }
806 0 : GImageInsertToBase(to->u.image,from,src,rev,to_x,to_y,ptt);
807 0 : return( true );
808 : }
809 :
810 : struct bounds {
811 : int start, end;
812 : float start_frac, end_frac;
813 : /* if start==end then start_frac and end_frac should both be start_frac+end_frac-1 */
814 : };
815 :
816 0 : static struct bounds *FillBounds(int src_start, int src_end, int dest_start, int dest_end) {
817 : int i;
818 0 : struct bounds *bounds = malloc((dest_end-dest_start)*sizeof(struct bounds));
819 0 : struct bounds *bpt = bounds;
820 0 : double frac = (src_end-src_start)/(dest_end-dest_start);
821 : double temp;
822 :
823 0 : for ( i=dest_start; i<dest_end; ++i, ++bpt ) {
824 0 : temp = (i-dest_start)*frac + src_start;
825 0 : bpt->start = (int) temp;
826 0 : bpt->start_frac = temp -bpt->start;
827 0 : temp = (i+1-dest_start)*frac + src_start;
828 0 : bpt->end = (int) temp;
829 0 : bpt->end_frac = temp -bpt->start;
830 0 : if ( bpt->end==bpt->start )
831 0 : bpt->start = bpt->end -= bpt->start;
832 : else
833 0 : bpt->start = 1-bpt->start;
834 : }
835 0 : return( bounds );
836 : }
837 :
838 : /* Calculate the pixel value for the thing at (x,y) (in the generated coordinate */
839 : /* system */
840 : extern Color _GImageGetPixelColor(struct _GImage *base,int x, int y);
841 :
842 0 : static Color CalculatePixel(struct _GImage *base, int x, int y, struct bounds *xb,
843 : struct bounds *yb, int do_trans) {
844 0 : float red=0, green=0, blue=0, tot=0, trans_tot=0, factx, facty;
845 : Color pix;
846 : int i,j;
847 :
848 0 : for ( i=xb->start; i<=xb->end; ++i ) {
849 0 : if ( i==xb->start ) factx = xb->start_frac;
850 0 : else if ( i==xb->end ) factx = xb->end_frac;
851 0 : else factx = 1;
852 0 : for ( j = yb->start; j<=yb->end; ++j ) {
853 0 : if ( j==yb->start ) facty = yb->start_frac;
854 0 : else if ( j==yb->end ) facty = yb->end_frac;
855 0 : else facty = 1;
856 0 : facty *= factx;
857 0 : pix = _GImageGetPixelColor(base,i,j);
858 : if ( pix<0 && !do_trans ) pix = ~pix;
859 : if ( pix<0 )
860 : trans_tot += facty;
861 : else {
862 0 : red += facty*COLOR_RED(pix);
863 0 : green += facty*COLOR_GREEN(pix);
864 0 : blue += facty*COLOR_BLUE(pix);
865 0 : tot += facty;
866 : }
867 : }
868 : }
869 0 : if ( trans_tot>tot )
870 0 : return( COLOR_UNKNOWN );
871 0 : if ( tot==0 )
872 0 : return( COLOR_CREATE(0,0,0) );
873 0 : red /= tot; green /= tot; blue /= tot;
874 0 : return( COLOR_CREATE( (int) (red+.5), (int) (green+.5), (int) (blue+.5) ));
875 : }
876 :
877 0 : void GImageResize(struct _GImage *tobase, struct _GImage *fbase,
878 : GRect *src, RevCMap *rev) {
879 : struct bounds *vert, *hor;
880 : int i,j;
881 0 : uint32 *pt32=NULL;
882 0 : uint8 *pt8=NULL;
883 0 : int bit=0;
884 : struct gcol gclut[256];
885 0 : short *red_dith=NULL, *green_dith=NULL, *blue_dith=NULL;
886 0 : short *r_d=NULL, *g_d=NULL, *b_d=NULL;
887 0 : register int rd=0, gd=0, bd=0;
888 : Color pix;
889 0 : RevCMap *oldrev=rev;
890 0 : int bright=0, dark, bright_col, dark_col;
891 0 : Color trans=COLOR_UNKNOWN;
892 : int do_trans;
893 : const struct gcol *pos;
894 :
895 0 : if ( fbase->trans!=COLOR_UNKNOWN ) {
896 0 : trans = tobase->trans;
897 : }
898 0 : do_trans = false;
899 0 : if ( trans!=COLOR_UNKNOWN )
900 0 : do_trans = true;
901 :
902 0 : vert = FillBounds(src->y,src->y+src->height,0,tobase->height);
903 0 : hor = FillBounds(src->x,src->x+src->width,0,tobase->width );
904 :
905 0 : if ( tobase->image_type==it_index ) {
906 0 : _GDraw_getimageclut(tobase,gclut);
907 0 : red_dith = calloc(src->width,sizeof(short));
908 0 : green_dith = calloc(src->width,sizeof(short));
909 0 : blue_dith = calloc(src->width,sizeof(short));
910 0 : if ( rev==NULL )
911 0 : rev = GClutReverse(tobase->clut,8);
912 0 : } else if ( tobase->image_type==it_mono ) {
913 0 : green_dith = calloc(src->width,sizeof(short));
914 0 : bright = MonoCols(tobase->clut,&dark,&bright_col,&dark_col);
915 : }
916 :
917 0 : for ( i=0; i<tobase->height; ++i ) {
918 0 : switch ( tobase->image_type ) {
919 : case it_true:
920 0 : pt32 = (uint32 *) (tobase->data + i*tobase->bytes_per_line);
921 0 : break;
922 : case it_index:
923 0 : pt8 = (uint8 *) (tobase->data + i*tobase->bytes_per_line);
924 0 : rd = gd = bd = 0;
925 0 : r_d = red_dith; g_d = green_dith; b_d = blue_dith;
926 0 : break;
927 : case it_mono:
928 0 : pt8 = (uint8 *) (tobase->data + i*tobase->bytes_per_line);
929 0 : bit = 0x80;
930 0 : gd = 0;
931 0 : g_d = green_dith;
932 0 : break;
933 : }
934 :
935 0 : for ( j=0; j<tobase->width; ++j ) {
936 0 : pix = CalculatePixel(fbase,j,i,hor,vert,do_trans);
937 0 : switch ( tobase->image_type ) {
938 : case it_true:
939 : if ( pix<0 )
940 : *pt32++ = trans;
941 : else
942 0 : *pt32++ = pix;
943 0 : break;
944 : case it_index:
945 : if ( pix<0 ) {
946 : *pt8++ = trans;
947 : ++r_d; ++g_d; ++b_d;
948 : } else {
949 0 : rd += *r_d + COLOR_RED(pix); if ( rd<0 ) rd=0; else if ( rd>255 ) rd = 255;
950 0 : gd += *g_d + COLOR_GREEN(pix); if ( gd<0 ) gd=0; else if ( gd>255 ) gd = 255;
951 0 : bd += *b_d + COLOR_BLUE(pix); if ( bd<0 ) bd=0; else if ( bd>255 ) bd = 255;
952 0 : pos = _GImage_GetIndexedPixelPrecise(COLOR_CREATE(rd,gd,bd),rev);
953 0 : *pt8++ = pos->pixel;
954 0 : *r_d++ = rd = (rd - pos->red)/2;
955 0 : *g_d++ = gd = (gd - pos->green)/2;
956 0 : *b_d++ = bd = (bd - pos->blue)/2;
957 : }
958 0 : break;
959 : case it_mono:
960 : if ( pix<0 ) {
961 : if ( trans ) *pt8 |= bit; else *pt8 &= ~bit;
962 : ++g_d;
963 : } else {
964 0 : gd += *g_d + COLOR_RED(pix) + COLOR_GREEN(pix) + COLOR_BLUE(pix);
965 0 : if (( gd<3*128 && dark) || (gd>=3*128 && bright))
966 0 : *pt8 |= bit;
967 : else
968 0 : *pt8 &= ~bit;
969 0 : if ( gd<0 ) gd=0; else if ( gd>3*255 ) gd = 3*255;
970 0 : if ( gd<3*128 )
971 0 : *g_d++ = gd = (gd-dark_col)/2;
972 : else
973 0 : *g_d++ = gd = (gd-bright_col)/2;
974 : }
975 0 : if (( bit>>=1 )==0 ) {bit=0x80; ++pt8;}
976 0 : break;
977 : }
978 : }}
979 0 : if ( oldrev!=rev )
980 0 : GClut_RevCMapFree(rev);
981 0 : }
982 :
983 0 : GImage *GImageResize32(GImage *from, GRect *src, int width, int height, Color trans) {
984 : GImage *to;
985 :
986 0 : if ( from->list_len ) {
987 0 : GDrawIError( "Attempt to resize an image list" );
988 0 : return( NULL );
989 : }
990 0 : to = GImageCreate(it_true, width, height);
991 0 : to->u.image->trans = trans;
992 0 : GImageResize(to->u.image,from->u.image,src,NULL);
993 0 : return( to );
994 : }
995 :
996 0 : GImage *GImageResizeSame(GImage *from, GRect *src, int width, int height, RevCMap *rev) {
997 : GImage *to;
998 0 : if ( from->list_len ) {
999 0 : GDrawIError( "Attempt to resize an image list" );
1000 0 : return( NULL );
1001 : }
1002 0 : to = GImageCreate(from->u.image->image_type, width, height);
1003 0 : to->u.image->trans = from->u.image->trans;
1004 0 : GImageResize(to->u.image,from->u.image,src,rev);
1005 0 : return( to );
1006 : }
|