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