Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /* 2013jan18..22, several fixes + interlacing, Jose Da Silva */
3 : /*
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions are met:
6 :
7 : * Redistributions of source code must retain the above copyright notice, this
8 : * list of conditions and the following disclaimer.
9 :
10 : * Redistributions in binary form must reproduce the above copyright notice,
11 : * this list of conditions and the following disclaimer in the documentation
12 : * and/or other materials provided with the distribution.
13 :
14 : * The name of the author may not be used to endorse or promote products
15 : * derived from this software without specific prior written permission.
16 :
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : */
28 :
29 : #include <fontforge-config.h>
30 :
31 : #ifdef _NO_LIBUNGIF
32 :
33 : static int a_file_must_define_something=0; /* ANSI says so */
34 :
35 : #else /* We can build with gif_lib - therefore import gif files */
36 :
37 : #include <basics.h>
38 : #include <string.h>
39 : #include "gimage.h"
40 : #include <gif_lib.h>
41 :
42 : #if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) && ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5)
43 : #define _GIFLIB_51PLUS
44 : #endif
45 :
46 0 : static GImage *ProcessSavedImage(GifFileType *gif,struct SavedImage *si,int il) {
47 : /* Process each gif image into an internal FF format. Return NULL if error */
48 : GImage *ret;
49 : struct _GImage *base;
50 0 : ColorMapObject *m = gif->SColorMap; /* gif_lib.h, NULL if not exists. */
51 0 : int i,j,k,*id = NULL;
52 : long l;
53 0 : uint8 *d,*iv = NULL;
54 :
55 : /* Create memory to hold image, exit with NULL if not enough memory */
56 0 : if ( si->ImageDesc.ColorMap!=NULL ) m=si->ImageDesc.ColorMap;
57 0 : if ( m==NULL )
58 0 : return( NULL );
59 0 : if ( m->BitsPerPixel==1 ) {
60 0 : if ( (ret=GImageCreate(it_bitmap,si->ImageDesc.Width,si->ImageDesc.Height))==NULL )
61 0 : return( NULL );
62 0 : if ( m->ColorCount==2 &&
63 0 : m->Colors[0].Red==0 && m->Colors[0].Green==0 && m->Colors[0].Blue==0 &&
64 0 : m->Colors[1].Red==255 && m->Colors[1].Green==255 && m->Colors[1].Blue==255 )
65 : /* Don't need a clut */;
66 : else
67 0 : if ( (ret->u.image->clut = (GClut *) calloc(1,sizeof(GClut)))==NULL ) {
68 0 : free(ret);
69 0 : NoMoreMemMessage();
70 0 : return( NULL );
71 : }
72 : } else
73 0 : if ( (ret=GImageCreate(it_index,si->ImageDesc.Width,si->ImageDesc.Height))==NULL )
74 0 : return( NULL );
75 0 : if ( il && ((id=(int *) malloc(si->ImageDesc.Height*sizeof(int)))==NULL || \
76 0 : (iv=(uint8 *) malloc(si->ImageDesc.Height*sizeof(uint8)))==NULL) ) {
77 0 : free(ret->u.image->clut);
78 0 : free(ret);
79 0 : free(id);
80 0 : free(iv);
81 0 : NoMoreMemMessage();
82 0 : return( NULL );
83 : }
84 :
85 : /* Process gif image into an internal FF usable format */
86 0 : base = ret->u.image;
87 0 : if ( base->clut!=NULL ) {
88 0 : base->clut->clut_len = m->ColorCount;
89 0 : for ( i=0; i<m->ColorCount; ++i )
90 0 : base->clut->clut[i] = COLOR_CREATE(m->Colors[i].Red,m->Colors[i].Green,m->Colors[i].Blue);
91 : }
92 0 : if ( m->BitsPerPixel!=1 )
93 0 : memcpy(base->data,si->RasterBits,base->width*base->height);
94 0 : else if ( m->BitsPerPixel==1 ) {
95 0 : l=0;
96 0 : for ( i=0; i<base->height; ++i ) {
97 0 : d = (base->data + i*base->bytes_per_line);
98 0 : memset(d,'\0',base->bytes_per_line);
99 0 : for ( j=0; j<base->width; ++j ) {
100 0 : if ( si->RasterBits[l] )
101 0 : d[j>>3] |= (1<<(7-(j&7)));
102 0 : ++l;
103 : }
104 : }
105 : }
106 0 : if ( il ) {
107 : /* Convert interlaced image into a sequential image */
108 0 : j=0; k=0;
109 0 : for ( i=0; i<base->height; ++i ) {
110 0 : id[i]=k;
111 0 : if ( j==0 ) {
112 0 : k += 8;
113 0 : if ( k>=base->height ) {
114 0 : j++; k=4;
115 : }
116 0 : } else if ( j==1 ) {
117 0 : k += 8;
118 0 : if ( k>=base->height ) {
119 0 : j++; k=2;
120 : }
121 0 : } else if ( j==2 ) {
122 0 : k += 4;
123 0 : if ( k>=base->height ) {
124 0 : j++; k=1;
125 : }
126 : } else
127 0 : k += 2;
128 : }
129 0 : for ( j=0; j<base->bytes_per_line; ++j ) {
130 0 : for ( i=1; i<base->height; ++i )
131 0 : iv[id[i]]=base->data[i*base->bytes_per_line+j];
132 0 : for ( i=1; i<base->height; ++i )
133 0 : base->data[i*base->bytes_per_line+j]=iv[i];
134 : }
135 0 : free(id);
136 0 : free(iv);
137 : }
138 0 : for ( i=0; i<si->ExtensionBlockCount; ++i ) {
139 0 : if ( si->ExtensionBlocks[i].Function==0xf9 &&
140 0 : si->ExtensionBlocks[i].ByteCount>=4 ) {
141 0 : base->delay = (si->ExtensionBlocks[i].Bytes[2]<<8) |
142 0 : (si->ExtensionBlocks[i].Bytes[2]&0xff);
143 0 : if ( si->ExtensionBlocks[i].Bytes[0]&1 ) {
144 0 : base->trans = (unsigned char) si->ExtensionBlocks[i].Bytes[3];
145 0 : if ( base->clut!=NULL )
146 0 : base->clut->trans_index = base->trans;
147 : }
148 : }
149 : }
150 0 : return( ret );
151 : }
152 :
153 0 : GImage *GImageReadGif(char *filename) {
154 : /* Import a gif image (or gif animation), else return NULL if error */
155 : GImage *ret, **images;
156 : GifFileType *gif;
157 : int i,il;
158 :
159 : //
160 : // MIQ: As at mid 2013 giflib version 4 is still the current
161 : // version in some environments. Given that this function call
162 : // seems to be the only incompatible change in what FontForge uses
163 : // as at that time, I added a smoother macro here to allow v4 to
164 : // still work OK for the time being.
165 : //
166 : #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 || defined(_GIFLIB_5PLUS)
167 : if ( (gif=DGifOpenFileName(filename,NULL))==NULL ) {
168 : #else
169 0 : if ( (gif=DGifOpenFileName(filename))==NULL ) {
170 : #endif
171 0 : fprintf( stderr,"Can't open \"%s\"\n",filename );
172 0 : return( NULL );
173 : }
174 :
175 0 : if ( DGifSlurp(gif)!=GIF_OK ) {
176 0 : fprintf(stderr,"Bad input file \"%s\"\n",filename );
177 : #ifdef _GIFLIB_51PLUS
178 : DGifCloseFile(gif, NULL);
179 : #else
180 0 : DGifCloseFile(gif);
181 : #endif
182 0 : return( NULL );
183 : }
184 :
185 : /* Process each image so that it/they can be imported into FF. */
186 0 : if ( (images=(GImage **) malloc(gif->ImageCount*sizeof(GImage *)))==NULL ) {
187 : #ifdef _GIFLIB_51PLUS
188 : DGifCloseFile(gif, NULL);
189 : #else
190 0 : DGifCloseFile(gif);
191 : #endif
192 0 : NoMoreMemMessage();
193 0 : return( NULL );
194 : }
195 0 : il=gif->SavedImages[0].ImageDesc.Interlace;
196 0 : for ( i=0; i<gif->ImageCount; ++i ) {
197 0 : if ( (images[i]=ProcessSavedImage(gif,&gif->SavedImages[i],il))==NULL ) {
198 0 : while ( --i>=0 ) free(images[i]);
199 0 : free(images);
200 : #ifdef _GIFLIB_51PLUS
201 : DGifCloseFile(gif, NULL);
202 : #else
203 0 : DGifCloseFile(gif);
204 : #endif
205 0 : return( NULL );
206 : }
207 : }
208 :
209 : /* All okay if you reached here. We have 1 image or several images */
210 0 : if ( gif->ImageCount==1 )
211 0 : ret = images[0];
212 : else
213 0 : ret = GImageCreateAnimation(images,gif->ImageCount);
214 : #ifdef _GIFLIB_51PLUS
215 : DGifCloseFile(gif, NULL);
216 : #else
217 0 : DGifCloseFile(gif);
218 : #endif
219 0 : free(images);
220 0 : return( ret );
221 : }
222 :
223 : #endif /* ! _NO_LIBUNGIF */
|