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
28 #include <fontforge-config.h>
29
30 #include "basics.h"
31 #include "gimage.h"
32
GImageCreate(enum image_type type,int32 width,int32 height)33 GImage *GImageCreate(enum image_type type, int32 width, int32 height) {
34 /* Prepare to get a bitmap image. Cleanup and return NULL if not enough memory */
35 GImage *gi;
36 struct _GImage *base;
37
38 if ( type<it_mono || type>it_rgba )
39 return( NULL );
40
41 gi = (GImage *) calloc(1,sizeof(GImage));
42 base = (struct _GImage *) malloc(sizeof(struct _GImage));
43 if ( gi==NULL || base==NULL )
44 goto errorGImageCreate;
45
46 gi->u.image = base;
47 base->image_type = type;
48 base->width = width;
49 base->height = height;
50 base->bytes_per_line = (type==it_true || type==it_rgba)?4*width:type==it_index?width:(width+7)/8;
51 base->data = NULL;
52 base->clut = NULL;
53 base->trans = COLOR_UNKNOWN;
54 if ( (base->data = (uint8 *) malloc(height*base->bytes_per_line))==NULL )
55 goto errorGImageCreate;
56 if ( type==it_index ) {
57 if ( (base->clut = (GClut *) calloc(1,sizeof(GClut)))==NULL ) {
58 free(base->data);
59 goto errorGImageCreate;
60 }
61 base->clut->trans_index = COLOR_UNKNOWN;
62 }
63 return( gi );
64
65 errorGImageCreate:
66 free(base);
67 free(gi);
68 NoMoreMemMessage();
69 return( NULL );
70 }
71
72
_GImage_Create(enum image_type type,int32 width,int32 height)73 GImage *_GImage_Create(enum image_type type, int32 width, int32 height) {
74 GImage *gi;
75 struct _GImage *base;
76
77 if ( type<it_mono || type>it_rgba )
78 return( NULL );
79
80 gi = (GImage *) calloc(1,sizeof(GImage));
81 base = (struct _GImage *) malloc(sizeof(struct _GImage));
82 if ( gi==NULL || base==NULL )
83 goto error_GImage_Create;
84
85 gi->u.image = base;
86 base->image_type = type;
87 base->width = width;
88 base->height = height;
89 base->bytes_per_line = (type==it_true || type==it_rgba)?4*width:type==it_index?width:(width+7)/8;
90 base->data = NULL;
91 base->clut = NULL;
92 if ( type==it_index ) {
93 if ( (base->clut = (GClut *) calloc(1,sizeof(GClut)))==NULL )
94 goto error_GImage_Create;
95 }
96 return( gi );
97
98 error_GImage_Create:
99 free(base);
100 free(gi);
101 NoMoreMemMessage();
102 return( NULL );
103 }
104
GImageDestroy(GImage * gi)105 void GImageDestroy(GImage *gi) {
106 /* Free memory (if GImage exists) */
107 int i;
108
109 if (gi!=NULL ) {
110 if ( gi->list_len!=0 ) {
111 for ( i=0; i<gi->list_len; ++i ) {
112 free(gi->u.images[i]->clut);
113 free(gi->u.images[i]->data);
114 free(gi->u.images[i]);
115 }
116 free(gi->u.images);
117 } else {
118 free(gi->u.image->clut);
119 free(gi->u.image->data);
120 free(gi->u.image);
121 }
122 free(gi);
123 }
124 }
125
GImageCreateAnimation(GImage ** images,int n)126 GImage *GImageCreateAnimation(GImage **images, int n) {
127 /* Create an animation using n "images". Return gi and free "images" if */
128 /* okay, else return NULL and keep "images" if memory error occurred, */
129 GImage *gi;
130 struct _GImage **imgs;
131 int i;
132
133 /* Check if "images" are okay to copy before creating an animation. */
134 /* We expect to find single images (not an array). Type must match. */
135 for ( i=0; i<n; ++i ) {
136 if ( images[i]->list_len!=0 || \
137 images[i]->u.image->image_type!=images[0]->u.image->image_type ) {
138 fprintf( stderr, "Images are not compatible to make an Animation\n" );
139 return( NULL );
140 }
141 }
142
143 /* First, create enough memory space to hold the complete animation */
144 gi = (GImage *) calloc(1,sizeof(GImage));
145 imgs = (struct _GImage **) malloc(n*sizeof(struct _GImage *));
146 if ( gi==NULL || imgs==NULL ) {
147 free(gi);
148 free(imgs);
149 NoMoreMemMessage();
150 return( NULL );
151 }
152
153 /* Copy images[i] pointer into 'gi', then release each "images[i]". */
154 gi->list_len = n;
155 gi->u.images = imgs;
156 for ( i=0; i<n; ++i ) {
157 imgs[i] = images[i]->u.image;
158 free(images[i]);
159 }
160 return( gi );
161 }
162
163 /* -1 => add it at the end */
GImageAddImageBefore(GImage * dest,GImage * src,int pos)164 GImage *GImageAddImageBefore(GImage *dest, GImage *src, int pos) {
165 struct _GImage **imgs;
166 int n, i, j;
167 enum image_type it;
168
169 n = (src->list_len==0?1:src->list_len) + (dest->list_len==0?1:dest->list_len);
170 imgs = (struct _GImage **) malloc(n*sizeof(struct _GImage *));
171 if ( imgs==NULL ) {
172 NoMoreMemMessage();
173 return( NULL );
174 }
175
176 i = 0;
177 if ( dest->list_len==0 ) {
178 it = dest->u.image->image_type;
179 if ( pos==-1 ) pos = 1;
180 if ( pos!=0 ) imgs[i++] = dest->u.image;
181 } else {
182 it = dest->u.images[0]->image_type;
183 if ( pos==-1 ) pos = dest->list_len;
184 for ( i=0; i<pos; ++i )
185 imgs[i] = dest->u.images[i];
186 }
187 j = i;
188 if ( src->list_len==0 ) {
189 if ( src->u.image->image_type!=it ) {
190 free(imgs);
191 return( NULL );
192 }
193 imgs[j++] = src->u.image;
194 } else {
195 for ( ; j<i+src->list_len; ++j ) {
196 if ( src->u.images[j-i]->image_type!=it ) {
197 free(imgs);
198 return( NULL );
199 }
200 imgs[j] = src->u.images[j-i];
201 }
202 free(src->u.images);
203 }
204 if ( dest->list_len==0 ) {
205 if ( pos==0 ) imgs[j++] = dest->u.image;
206 } else {
207 for ( ; j<n; ++j )
208 imgs[j] = dest->u.images[i++];
209 }
210 dest->u.images = imgs;
211 dest->list_len = n;
212 free(src);
213 return( dest );
214 }
215
GImageDrawRect(GImage * img,GRect * r,Color col)216 void GImageDrawRect(GImage *img,GRect *r,Color col) {
217 struct _GImage *base;
218 int i;
219
220 base = img->u.image;
221 if ( r->y>=base->height || r->x>=base->width )
222 return;
223
224 for ( i=0; i<r->width; ++i ) {
225 if ( i+r->x>=base->width )
226 break;
227 base->data[r->y*base->bytes_per_line + i + r->x] = col;
228 if ( r->y+r->height-1<base->height )
229 base->data[(r->y+r->height-1)*base->bytes_per_line + i + r->x] = col;
230 }
231 for ( i=0; i<r->height; ++i ) {
232 if ( i+r->y>=base->height )
233 break;
234 base->data[(r->y+i)*base->bytes_per_line + r->x] = col;
235 if ( r->x+r->width-1<base->width )
236 base->data[(r->y+i)*base->bytes_per_line + r->x+r->width-1] = col;
237 }
238 }
239
GImageDrawImage(GImage * dest,GImage * src,GRect * UNUSED (junk),int x,int y)240 void GImageDrawImage(GImage *dest,GImage *src,GRect *UNUSED(junk),int x, int y) {
241 struct _GImage *sbase, *dbase;
242 int i,j, di, sbi, dbi, val, factor, maxpix, sbit;
243
244 /* This is designed to merge images which should be treated as alpha */
245 /* channels. dest must be indexed, src may be either indexed or mono */
246 dbase = dest->u.image;
247 sbase = src->u.image;
248
249 if ( dbase->image_type != it_index ) {
250 fprintf( stderr, "Bad call to GImageMaxImage\n" );
251 return;
252 }
253
254 maxpix = 1;
255 if ( dbase->clut!=NULL )
256 maxpix = dbase->clut->clut_len - 1;
257
258 if ( dbase->clut!=NULL && sbase->clut!=NULL && sbase->clut->clut_len>1 ) {
259 factor = (dbase->clut->clut_len - 1) / (sbase->clut->clut_len - 1);
260 if ( factor==0 ) factor=1;
261 } else
262 factor = 1;
263
264 if ( sbase->image_type == it_index ) {
265 for ( i=0; i<sbase->height; ++i ) {
266 di = y + i;
267 if ( di<0 || di>=dbase->height )
268 continue;
269 sbi = i*sbase->bytes_per_line;
270 dbi = di*dbase->bytes_per_line;
271 for ( j=0; j<sbase->width; ++j ) {
272 if ( x+j<0 || x+j>=dbase->width )
273 continue;
274 val = dbase->data[dbi+x+j] + sbase->data[sbi+j]*factor;
275 if ( val>255 ) val = 255;
276 dbase->data[dbi+x+j] = val;
277 }
278 }
279 } else if ( sbase->image_type == it_mono ) {
280 for ( i=0; i<sbase->height; ++i ) {
281 di = y + i;
282 if ( di<0 || di>=dbase->height )
283 continue;
284 sbi = i*sbase->bytes_per_line;
285 dbi = di*dbase->bytes_per_line;
286 for ( j=0, sbit=0x80; j<sbase->width; ++j ) {
287 if ( x+j<0 || x+j>=dbase->width )
288 continue;
289 if ( sbase->data[sbi+(j>>3)] & sbit )
290 dbase->data[dbi+x+j] = maxpix;
291 if ( (sbit>>=1) == 0 )
292 sbit = 0x80;
293 }
294 }
295 }
296 }
297
298 /* Blends src image with alpha channel over dest. Both images must be */
299 /* 32-bit truecolor. Alpha channel of dest must be all opaque. */
GImageBlendOver(GImage * dest,GImage * src,GRect * from,int x,int y)300 void GImageBlendOver(GImage *dest,GImage *src,GRect *from,int x, int y) {
301 struct _GImage *sbase, *dbase;
302 int i, j, a, r, g, b;
303 uint32 *dpt, *spt;
304
305 dbase = dest->u.image;
306 sbase = src->u.image;
307
308 if ( dbase->image_type != it_true ) {
309 fprintf( stderr, "Bad call to GImageBlendOver\n" );
310 return;
311 }
312
313 if ( sbase->image_type != it_rgba ) {
314 fprintf( stderr, "Bad call to GImageBlendOver\n" );
315 return;
316 }
317
318 for ( i=0; i<from->height; ++i ) {
319 dpt = (uint32 *) (dbase->data + (i+y)*dbase->bytes_per_line + x*sizeof(uint32));
320 spt = (uint32 *) (sbase->data + (i+from->y)*sbase->bytes_per_line + from->x*sizeof(uint32));
321
322 for (j=0; j<from->width; j++) {
323 a = COLOR_ALPHA(*spt);
324 r = ((255-a)*COLOR_RED(*dpt) + a*COLOR_RED(*spt))/255;
325 g = ((255-a)*COLOR_GREEN(*dpt)+ a*COLOR_GREEN(*spt))/255;
326 b = ((255-a)*COLOR_BLUE(*dpt) + a*COLOR_BLUE(*spt))/255;
327 spt++;
328 *dpt++ = 0xff000000 | COLOR_CREATE(r,g,b);
329 }
330 }
331 }
332
GImageGetWidth(GImage * img)333 int GImageGetWidth(GImage *img) {
334 if ( img->list_len==0 ) {
335 return( img->u.image->width );
336 } else {
337 return( img->u.images[0]->width );
338 }
339 }
340
GImageGetHeight(GImage * img)341 int GImageGetHeight(GImage *img) {
342 if ( img->list_len==0 ) {
343 return( img->u.image->height );
344 } else {
345 return( img->u.images[0]->height );
346 }
347 }
348
GImageGetUserData(GImage * img)349 void *GImageGetUserData(GImage *img) {
350 return( img->userdata );
351 }
352
GImageSetUserData(GImage * img,void * userdata)353 void GImageSetUserData(GImage *img,void *userdata) {
354 img->userdata = userdata;
355 }
356
_GImageGetPixelRGBA(struct _GImage * base,int x,int y)357 static Color _GImageGetPixelRGBA(struct _GImage *base,int x, int y) {
358 Color val;
359
360 if ( base->image_type==it_rgba ) {
361 val = ((uint32*) (base->data + y*base->bytes_per_line))[x] ;
362 return( val==base->trans?(val&0xffffff):val );
363 } else if ( base->image_type==it_true ) {
364 val = ((uint32*) (base->data + y*base->bytes_per_line))[x] ;
365 return( val==base->trans?(val&0xffffff):(val|0xff000000) );
366 } else if ( base->image_type==it_index ) {
367 uint8 pixel = ((uint8*) (base->data + y*base->bytes_per_line))[x];
368 val = base->clut->clut[pixel];
369 return( pixel==base->trans?(val&0xffffff):(val|0xff000000) );
370 } else {
371 uint8 pixel = (((uint8*) (base->data + y*base->bytes_per_line))[x>>3]&(1<<(7-(x&7))) )?1:0;
372 if ( base->clut==NULL ) {
373 if ( pixel )
374 val = COLOR_CREATE(0xff,0xff,0xff);
375 else
376 val = COLOR_CREATE(0,0,0);
377 } else
378 val = base->clut->clut[pixel];
379 return( pixel==base->trans?(val&0xffffff):(val|0xff000000) );
380 }
381 }
382
GImageGetPixelRGBA(GImage * image,int x,int y)383 Color GImageGetPixelRGBA(GImage *image,int x, int y) {
384 struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
385 return( _GImageGetPixelRGBA(base,x,y));
386 }
387