Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mgd.c
4 : Created by: Thomas Boutell (http://www.boutell.com/boutell/)
5 :
6 : with the help of
7 :
8 : David Rowley <mgardi@watdscu.waterloo.edu>
9 : David Koblas <koblas@netcom.com>
10 :
11 : modified by
12 :
13 : Stefan Ritt <Stefan.Ritt@psi.ch>
14 :
15 : For further copywright notices see:
16 :
17 : http://www.boutell.com/gd/
18 :
19 : Contents: GD graphics library to create Web images
20 :
21 : $Id:$
22 :
23 : \********************************************************************/
24 :
25 : #include <stdio.h>
26 : #include <math.h>
27 : #include <string.h>
28 : #include <stdlib.h>
29 : #include <midas.h>
30 : #include "mgd.h"
31 :
32 : int gdFontGiantData[] = {
33 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 : 0, 0, 0, 0, 0, 48, 120, 252, 510, 252, 120, 48, 0, 0, 0,
35 : 0, 0, 0, 0, 0, 438, 204, 438, 204, 438, 204, 438, 0, 0, 0,
36 : 0, 0, 0, 102, 102, 126, 102, 102, 0, 504, 96, 96, 96, 96, 0,
37 : 0, 0, 0, 62, 6, 30, 6, 6, 0, 496, 48, 240, 48, 48, 0,
38 : 0, 0, 0, 124, 70, 6, 70, 124, 0, 248, 408, 248, 408, 408, 0,
39 : 0, 0, 0, 6, 6, 6, 6, 62, 0, 496, 48, 240, 48, 48, 0,
40 : 0, 0, 0, 0, 0, 120, 204, 204, 120, 0, 0, 0, 0, 0, 0,
41 : 0, 0, 48, 48, 48, 510, 510, 48, 48, 48, 0, 510, 510, 0, 0,
42 : 0, 0, 0, 102, 110, 126, 118, 102, 0, 48, 48, 48, 48, 496, 0,
43 : 0, 0, 0, 102, 102, 102, 60, 24, 0, 504, 96, 96, 96, 96, 0,
44 : 48, 48, 48, 48, 48, 48, 48, 63, 63, 0, 0, 0, 0, 0, 0,
45 : 0, 0, 0, 0, 0, 0, 0, 63, 63, 48, 48, 48, 48, 48, 48,
46 : 0, 0, 0, 0, 0, 0, 0, 496, 496, 48, 48, 48, 48, 48, 48,
47 : 48, 48, 48, 48, 48, 48, 48, 496, 496, 0, 0, 0, 0, 0, 0,
48 : 48, 48, 48, 48, 48, 48, 48, 511, 511, 48, 48, 48, 48, 48, 48,
49 : 0, 0, 0, 511, 511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 : 0, 0, 0, 0, 0, 511, 511, 0, 0, 0, 0, 0, 0, 0, 0,
51 : 0, 0, 0, 0, 0, 0, 0, 511, 511, 0, 0, 0, 0, 0, 0,
52 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 511, 511, 0, 0, 0, 0,
53 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 511, 511, 0, 0,
54 : 48, 48, 48, 48, 48, 48, 48, 496, 496, 48, 48, 48, 48, 48, 48,
55 : 48, 48, 48, 48, 48, 48, 48, 63, 63, 48, 48, 48, 48, 48, 48,
56 : 48, 48, 48, 48, 48, 48, 48, 511, 511, 0, 0, 0, 0, 0, 0,
57 : 0, 0, 0, 0, 0, 0, 0, 511, 511, 48, 48, 48, 48, 48, 48,
58 : 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
59 : 0, 0, 0, 448, 112, 28, 6, 28, 112, 448, 0, 510, 510, 0, 0,
60 : 0, 0, 0, 14, 56, 224, 384, 224, 56, 14, 0, 510, 510, 0, 0,
61 : 0, 0, 0, 0, 0, 510, 510, 200, 200, 200, 206, 206, 0, 0, 0,
62 : 0, 0, 0, 384, 192, 510, 510, 48, 510, 510, 12, 6, 0, 0, 0,
63 : 0, 0, 0, 240, 408, 24, 24, 252, 24, 24, 62, 506, 14, 0, 0,
64 : 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0,
65 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 : 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 0, 0, 0,
67 : 0, 0, 216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68 : 0, 0, 0, 108, 108, 254, 108, 108, 254, 108, 108, 0, 0, 0, 0,
69 : 0, 0, 32, 248, 428, 44, 60, 248, 480, 416, 428, 248, 32, 0, 0,
70 : 0, 0, 396, 222, 222, 108, 48, 48, 216, 492, 492, 198, 0, 0, 0,
71 : 0, 0, 60, 102, 102, 102, 60, 102, 486, 198, 230, 444, 0, 0, 0,
72 : 0, 0, 240, 112, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 : 0, 96, 48, 24, 24, 12, 12, 12, 12, 24, 24, 48, 96, 0, 0,
74 : 0, 12, 24, 48, 48, 96, 96, 96, 96, 48, 48, 24, 12, 0, 0,
75 : 0, 0, 0, 16, 214, 124, 56, 238, 56, 124, 214, 16, 0, 0, 0,
76 : 0, 0, 0, 0, 48, 48, 48, 510, 48, 48, 48, 0, 0, 0, 0,
77 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 56, 12, 0, 0,
78 : 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 0,
79 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 120, 48, 0, 0,
80 : 0, 0, 384, 192, 192, 96, 48, 48, 24, 12, 12, 6, 0, 0, 0,
81 : 0, 0, 120, 204, 390, 390, 390, 390, 390, 390, 204, 120, 0, 0, 0,
82 : 0, 0, 48, 56, 60, 48, 48, 48, 48, 48, 48, 252, 0, 0, 0,
83 : 0, 0, 252, 390, 390, 384, 192, 96, 56, 12, 6, 510, 0, 0, 0,
84 : 0, 0, 510, 384, 192, 96, 240, 384, 384, 384, 390, 252, 0, 0, 0,
85 : 0, 0, 192, 224, 240, 216, 204, 198, 510, 192, 192, 192, 0, 0, 0,
86 : 0, 0, 510, 6, 6, 254, 398, 384, 384, 384, 390, 252, 0, 0, 0,
87 : 0, 0, 248, 12, 6, 6, 254, 398, 390, 390, 390, 252, 0, 0, 0,
88 : 0, 0, 510, 384, 384, 192, 96, 48, 24, 24, 12, 12, 0, 0, 0,
89 : 0, 0, 252, 390, 390, 390, 252, 390, 390, 390, 390, 252, 0, 0, 0,
90 : 0, 0, 252, 390, 390, 390, 454, 508, 384, 384, 192, 124, 0, 0, 0,
91 : 0, 0, 0, 0, 0, 48, 120, 48, 0, 0, 48, 120, 48, 0, 0,
92 : 0, 0, 0, 0, 0, 48, 120, 48, 0, 0, 120, 56, 12, 0, 0,
93 : 0, 0, 192, 96, 48, 24, 12, 12, 24, 48, 96, 192, 0, 0, 0,
94 : 0, 0, 0, 0, 0, 0, 510, 0, 0, 510, 0, 0, 0, 0, 0,
95 : 0, 0, 12, 24, 48, 96, 192, 192, 96, 48, 24, 12, 0, 0, 0,
96 : 0, 0, 252, 390, 390, 384, 192, 96, 48, 48, 0, 48, 0, 0, 0,
97 : 0, 0, 252, 390, 390, 502, 414, 478, 502, 6, 6, 252, 0, 0, 0,
98 : 0, 0, 48, 120, 204, 390, 390, 390, 510, 390, 390, 390, 0, 0, 0,
99 : 0, 0, 254, 396, 396, 396, 252, 396, 396, 396, 396, 254, 0, 0, 0,
100 : 0, 0, 252, 390, 6, 6, 6, 6, 6, 6, 390, 252, 0, 0, 0,
101 : 0, 0, 254, 396, 396, 396, 396, 396, 396, 396, 396, 254, 0, 0, 0,
102 : 0, 0, 510, 12, 12, 12, 124, 12, 12, 12, 12, 510, 0, 0, 0,
103 : 0, 0, 510, 12, 12, 12, 124, 12, 12, 12, 12, 12, 0, 0, 0,
104 : 0, 0, 252, 390, 6, 6, 6, 486, 390, 390, 390, 252, 0, 0, 0,
105 : 0, 0, 390, 390, 390, 390, 510, 390, 390, 390, 390, 390, 0, 0, 0,
106 : 0, 0, 252, 48, 48, 48, 48, 48, 48, 48, 48, 252, 0, 0, 0,
107 : 0, 0, 496, 192, 192, 192, 192, 192, 192, 192, 198, 124, 0, 0, 0,
108 : 0, 0, 390, 198, 102, 54, 30, 30, 54, 102, 198, 390, 0, 0, 0,
109 : 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 510, 0, 0, 0,
110 : 0, 0, 390, 390, 462, 510, 510, 438, 438, 390, 390, 390, 0, 0, 0,
111 : 0, 0, 390, 390, 398, 414, 438, 486, 454, 390, 390, 390, 0, 0, 0,
112 : 0, 0, 252, 390, 390, 390, 390, 390, 390, 390, 390, 252, 0, 0, 0,
113 : 0, 0, 254, 390, 390, 390, 254, 6, 6, 6, 6, 6, 0, 0, 0,
114 : 0, 0, 252, 390, 390, 390, 390, 390, 390, 438, 486, 252, 384, 0, 0,
115 : 0, 0, 254, 390, 390, 390, 254, 54, 102, 198, 390, 390, 0, 0, 0,
116 : 0, 0, 252, 390, 6, 6, 252, 384, 384, 384, 390, 252, 0, 0, 0,
117 : 0, 0, 510, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0,
118 : 0, 0, 390, 390, 390, 390, 390, 390, 390, 390, 390, 252, 0, 0, 0,
119 : 0, 0, 390, 390, 390, 204, 204, 204, 120, 120, 120, 48, 0, 0, 0,
120 : 0, 0, 390, 390, 390, 390, 438, 438, 438, 438, 510, 204, 0, 0, 0,
121 : 0, 0, 390, 390, 204, 120, 48, 48, 120, 204, 390, 390, 0, 0, 0,
122 : 0, 0, 390, 390, 204, 120, 48, 48, 48, 48, 48, 48, 0, 0, 0,
123 : 0, 0, 510, 384, 192, 96, 48, 24, 12, 6, 6, 510, 0, 0, 0,
124 : 0, 0, 248, 24, 24, 24, 24, 24, 24, 24, 24, 248, 0, 0, 0,
125 : 0, 0, 6, 12, 12, 24, 48, 48, 96, 192, 192, 384, 0, 0, 0,
126 : 0, 0, 124, 96, 96, 96, 96, 96, 96, 96, 96, 124, 0, 0, 0,
127 : 0, 0, 48, 120, 204, 390, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 511, 0, 0,
129 : 0, 0, 60, 56, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130 : 0, 0, 0, 0, 0, 252, 384, 384, 508, 390, 454, 508, 0, 0, 0,
131 : 0, 0, 6, 6, 6, 254, 398, 390, 390, 390, 398, 254, 0, 0, 0,
132 : 0, 0, 0, 0, 0, 252, 390, 6, 6, 6, 390, 252, 0, 0, 0,
133 : 0, 0, 384, 384, 384, 508, 454, 390, 390, 390, 454, 508, 0, 0, 0,
134 : 0, 0, 0, 0, 0, 252, 390, 390, 510, 6, 6, 252, 0, 0, 0,
135 : 0, 0, 240, 408, 408, 24, 24, 126, 24, 24, 24, 24, 0, 0, 0,
136 : 0, 0, 0, 0, 0, 508, 198, 198, 198, 124, 6, 252, 390, 390, 252,
137 : 0, 0, 6, 6, 6, 254, 398, 390, 390, 390, 390, 390, 0, 0, 0,
138 : 0, 0, 0, 48, 0, 56, 48, 48, 48, 48, 48, 252, 0, 0, 0,
139 : 0, 0, 0, 192, 0, 240, 192, 192, 192, 192, 192, 198, 198, 198, 124,
140 : 0, 0, 6, 6, 6, 390, 230, 62, 14, 62, 230, 390, 0, 0, 0,
141 : 0, 0, 56, 48, 48, 48, 48, 48, 48, 48, 48, 252, 0, 0, 0,
142 : 0, 0, 0, 0, 0, 254, 438, 438, 438, 438, 438, 390, 0, 0, 0,
143 : 0, 0, 0, 0, 0, 254, 398, 390, 390, 390, 390, 390, 0, 0, 0,
144 : 0, 0, 0, 0, 0, 252, 390, 390, 390, 390, 390, 252, 0, 0, 0,
145 : 0, 0, 0, 0, 0, 254, 398, 390, 390, 390, 398, 254, 6, 6, 6,
146 : 0, 0, 0, 0, 0, 508, 454, 390, 390, 390, 454, 508, 384, 384, 384,
147 : 0, 0, 0, 0, 0, 246, 412, 396, 12, 12, 12, 12, 0, 0, 0,
148 : 0, 0, 0, 0, 0, 252, 390, 6, 252, 384, 390, 252, 0, 0, 0,
149 : 0, 0, 0, 24, 24, 254, 24, 24, 24, 24, 408, 240, 0, 0, 0,
150 : 0, 0, 0, 0, 0, 198, 198, 198, 198, 198, 198, 508, 0, 0, 0,
151 : 0, 0, 0, 0, 0, 390, 390, 204, 204, 120, 120, 48, 0, 0, 0,
152 : 0, 0, 0, 0, 0, 390, 390, 438, 438, 438, 510, 204, 0, 0, 0,
153 : 0, 0, 0, 0, 0, 390, 204, 120, 48, 120, 204, 390, 0, 0, 0,
154 : 0, 0, 0, 0, 0, 198, 198, 198, 198, 198, 230, 252, 192, 198, 124,
155 : 0, 0, 0, 0, 0, 510, 192, 96, 48, 24, 12, 510, 0, 0, 0,
156 : 0, 0, 480, 48, 48, 96, 56, 56, 96, 48, 48, 480, 0, 0, 0,
157 : 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0,
158 : 0, 0, 30, 48, 48, 24, 112, 112, 24, 48, 48, 30, 0, 0, 0,
159 : 0, 0, 412, 438, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161 : };
162 :
163 : int gdFontMediumBoldData[] = {
164 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165 : 0, 0, 0, 0, 0, 12, 30, 63, 30, 12, 0, 0, 0,
166 : 0, 0, 0, 51, 51, 12, 51, 51, 12, 51, 51, 0, 0,
167 : 0, 27, 27, 31, 27, 27, 0, 60, 24, 24, 24, 24, 0,
168 : 0, 15, 3, 7, 3, 3, 0, 60, 12, 28, 12, 12, 0,
169 : 0, 14, 3, 3, 3, 14, 0, 28, 44, 28, 44, 44, 0,
170 : 0, 3, 3, 3, 3, 15, 0, 60, 12, 28, 12, 12, 0,
171 : 0, 0, 30, 51, 51, 30, 0, 0, 0, 0, 0, 0, 0,
172 : 0, 0, 12, 12, 63, 63, 12, 12, 0, 63, 63, 0, 0,
173 : 0, 51, 55, 63, 59, 51, 0, 12, 12, 12, 12, 60, 0,
174 : 0, 51, 51, 18, 30, 12, 0, 60, 24, 24, 24, 24, 0,
175 : 12, 12, 12, 12, 12, 12, 15, 15, 0, 0, 0, 0, 0,
176 : 0, 0, 0, 0, 0, 0, 15, 15, 12, 12, 12, 12, 12,
177 : 0, 0, 0, 0, 0, 0, 124, 124, 12, 12, 12, 12, 12,
178 : 12, 12, 12, 12, 12, 12, 124, 124, 0, 0, 0, 0, 0,
179 : 12, 12, 12, 12, 12, 12, 127, 127, 12, 12, 12, 12, 12,
180 : 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181 : 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 0, 0,
182 : 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0,
183 : 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0,
184 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 0,
185 : 12, 12, 12, 12, 12, 12, 124, 124, 12, 12, 12, 12, 12,
186 : 12, 12, 12, 12, 12, 12, 15, 15, 12, 12, 12, 12, 12,
187 : 12, 12, 12, 12, 12, 12, 127, 127, 0, 0, 0, 0, 0,
188 : 0, 0, 0, 0, 0, 0, 127, 127, 12, 12, 12, 12, 12,
189 : 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
190 : 0, 0, 48, 24, 6, 3, 6, 24, 48, 63, 63, 0, 0,
191 : 0, 0, 3, 6, 24, 48, 24, 6, 3, 63, 63, 0, 0,
192 : 0, 0, 0, 0, 0, 63, 54, 54, 54, 55, 51, 0, 0,
193 : 0, 0, 32, 48, 63, 63, 12, 63, 63, 3, 1, 0, 0,
194 : 0, 0, 28, 54, 6, 6, 15, 6, 6, 54, 29, 0, 0,
195 : 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0,
196 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197 : 0, 0, 12, 12, 12, 12, 12, 12, 0, 12, 12, 0, 0,
198 : 0, 0, 54, 54, 54, 0, 0, 0, 0, 0, 0, 0, 0,
199 : 0, 0, 20, 20, 62, 62, 20, 62, 62, 20, 20, 0, 0,
200 : 0, 0, 12, 30, 45, 13, 30, 44, 45, 30, 12, 0, 0,
201 : 0, 0, 39, 53, 23, 24, 12, 6, 58, 43, 57, 0, 0,
202 : 0, 0, 14, 27, 27, 27, 14, 43, 59, 27, 46, 0, 0,
203 : 0, 0, 28, 28, 12, 6, 0, 0, 0, 0, 0, 0, 0,
204 : 0, 0, 24, 12, 12, 6, 6, 6, 12, 12, 24, 0, 0,
205 : 0, 0, 6, 12, 12, 24, 24, 24, 12, 12, 6, 0, 0,
206 : 0, 0, 0, 0, 18, 12, 63, 63, 12, 18, 0, 0, 0,
207 : 0, 0, 0, 0, 12, 12, 63, 63, 12, 12, 0, 0, 0,
208 : 0, 0, 0, 0, 0, 0, 0, 0, 28, 28, 12, 6, 0,
209 : 0, 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0,
210 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 30, 12, 0,
211 : 0, 0, 48, 48, 24, 24, 12, 6, 6, 3, 3, 0, 0,
212 : 0, 0, 12, 18, 51, 51, 51, 51, 51, 18, 12, 0, 0,
213 : 0, 0, 12, 14, 13, 12, 12, 12, 12, 12, 63, 0, 0,
214 : 0, 0, 30, 51, 51, 48, 28, 6, 3, 3, 63, 0, 0,
215 : 0, 0, 30, 51, 48, 48, 28, 48, 48, 51, 30, 0, 0,
216 : 0, 0, 48, 56, 60, 54, 51, 51, 63, 48, 48, 0, 0,
217 : 0, 0, 63, 3, 3, 31, 51, 48, 48, 51, 30, 0, 0,
218 : 0, 0, 30, 51, 3, 3, 31, 51, 51, 51, 30, 0, 0,
219 : 0, 0, 63, 48, 48, 24, 24, 12, 12, 6, 6, 0, 0,
220 : 0, 0, 30, 51, 51, 51, 30, 51, 51, 51, 30, 0, 0,
221 : 0, 0, 30, 51, 51, 51, 62, 48, 48, 51, 30, 0, 0,
222 : 0, 0, 0, 0, 12, 30, 12, 0, 0, 12, 30, 12, 0,
223 : 0, 0, 0, 0, 12, 30, 12, 0, 28, 28, 12, 6, 0,
224 : 0, 0, 48, 24, 12, 6, 3, 6, 12, 24, 48, 0, 0,
225 : 0, 0, 0, 0, 63, 63, 0, 63, 63, 0, 0, 0, 0,
226 : 0, 0, 3, 6, 12, 24, 48, 24, 12, 6, 3, 0, 0,
227 : 0, 0, 30, 51, 51, 48, 28, 12, 0, 12, 12, 0, 0,
228 : 0, 0, 30, 49, 49, 61, 53, 61, 1, 49, 30, 0, 0,
229 : 0, 0, 30, 51, 51, 51, 63, 51, 51, 51, 51, 0, 0,
230 : 0, 0, 31, 51, 51, 51, 31, 51, 51, 51, 31, 0, 0,
231 : 0, 0, 30, 51, 3, 3, 3, 3, 3, 51, 30, 0, 0,
232 : 0, 0, 31, 51, 51, 51, 51, 51, 51, 51, 31, 0, 0,
233 : 0, 0, 63, 3, 3, 3, 31, 3, 3, 3, 63, 0, 0,
234 : 0, 0, 63, 3, 3, 3, 31, 3, 3, 3, 3, 0, 0,
235 : 0, 0, 30, 51, 3, 3, 59, 51, 51, 51, 62, 0, 0,
236 : 0, 0, 51, 51, 51, 51, 63, 51, 51, 51, 51, 0, 0,
237 : 0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0,
238 : 0, 0, 48, 48, 48, 48, 48, 48, 48, 51, 30, 0, 0,
239 : 0, 0, 35, 51, 27, 15, 7, 15, 27, 51, 35, 0, 0,
240 : 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 63, 0, 0,
241 : 0, 0, 33, 51, 63, 63, 51, 51, 51, 51, 51, 0, 0,
242 : 0, 0, 51, 51, 55, 55, 63, 59, 59, 51, 51, 0, 0,
243 : 0, 0, 30, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0,
244 : 0, 0, 31, 51, 51, 51, 31, 3, 3, 3, 3, 0, 0,
245 : 0, 0, 30, 51, 51, 51, 51, 51, 55, 59, 30, 48, 0,
246 : 0, 0, 31, 51, 51, 51, 31, 15, 27, 51, 35, 0, 0,
247 : 0, 0, 30, 51, 3, 3, 30, 48, 48, 51, 30, 0, 0,
248 : 0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0,
249 : 0, 0, 51, 51, 51, 51, 51, 51, 51, 51, 30, 0, 0,
250 : 0, 0, 51, 51, 51, 18, 18, 30, 12, 12, 12, 0, 0,
251 : 0, 0, 51, 51, 51, 51, 51, 63, 63, 51, 33, 0, 0,
252 : 0, 0, 33, 51, 18, 30, 12, 30, 18, 51, 33, 0, 0,
253 : 0, 0, 51, 51, 30, 30, 12, 12, 12, 12, 12, 0, 0,
254 : 0, 0, 63, 48, 48, 24, 12, 6, 3, 3, 63, 0, 0,
255 : 0, 0, 30, 6, 6, 6, 6, 6, 6, 6, 30, 0, 0,
256 : 0, 0, 3, 3, 6, 6, 12, 24, 24, 48, 48, 0, 0,
257 : 0, 0, 30, 24, 24, 24, 24, 24, 24, 24, 30, 0, 0,
258 : 0, 0, 12, 30, 51, 33, 0, 0, 0, 0, 0, 0, 0,
259 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 63, 0,
260 : 0, 0, 14, 14, 12, 24, 0, 0, 0, 0, 0, 0, 0,
261 : 0, 0, 0, 0, 0, 30, 48, 62, 51, 51, 62, 0, 0,
262 : 0, 0, 3, 3, 3, 31, 51, 51, 51, 51, 31, 0, 0,
263 : 0, 0, 0, 0, 0, 30, 51, 3, 3, 51, 30, 0, 0,
264 : 0, 0, 48, 48, 48, 62, 51, 51, 51, 51, 62, 0, 0,
265 : 0, 0, 0, 0, 0, 30, 51, 63, 3, 51, 30, 0, 0,
266 : 0, 0, 28, 54, 6, 6, 15, 6, 6, 6, 6, 0, 0,
267 : 0, 0, 0, 0, 0, 46, 51, 51, 30, 3, 30, 51, 30,
268 : 0, 0, 3, 3, 3, 31, 51, 51, 51, 51, 51, 0, 0,
269 : 0, 0, 12, 12, 0, 14, 12, 12, 12, 12, 63, 0, 0,
270 : 0, 0, 48, 48, 0, 48, 48, 48, 48, 48, 48, 51, 30,
271 : 0, 0, 3, 3, 3, 51, 27, 15, 15, 27, 51, 0, 0,
272 : 0, 0, 14, 12, 12, 12, 12, 12, 12, 12, 63, 0, 0,
273 : 0, 0, 0, 0, 0, 27, 63, 63, 51, 51, 51, 0, 0,
274 : 0, 0, 0, 0, 0, 31, 51, 51, 51, 51, 51, 0, 0,
275 : 0, 0, 0, 0, 0, 30, 51, 51, 51, 51, 30, 0, 0,
276 : 0, 0, 0, 0, 0, 31, 51, 51, 51, 31, 3, 3, 3,
277 : 0, 0, 0, 0, 0, 62, 51, 51, 51, 62, 48, 48, 48,
278 : 0, 0, 0, 0, 0, 31, 51, 3, 3, 3, 3, 0, 0,
279 : 0, 0, 0, 0, 0, 30, 51, 6, 24, 51, 30, 0, 0,
280 : 0, 0, 0, 3, 3, 15, 3, 3, 3, 51, 30, 0, 0,
281 : 0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 62, 0, 0,
282 : 0, 0, 0, 0, 0, 51, 51, 51, 30, 30, 12, 0, 0,
283 : 0, 0, 0, 0, 0, 51, 51, 51, 63, 63, 18, 0, 0,
284 : 0, 0, 0, 0, 0, 51, 51, 30, 30, 51, 51, 0, 0,
285 : 0, 0, 0, 0, 0, 51, 51, 51, 51, 62, 48, 51, 30,
286 : 0, 0, 0, 0, 0, 63, 48, 24, 6, 3, 63, 0, 0,
287 : 0, 0, 28, 6, 6, 12, 6, 12, 6, 6, 28, 0, 0,
288 : 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0,
289 : 0, 0, 14, 24, 24, 12, 24, 12, 24, 24, 14, 0, 0,
290 : 0, 0, 38, 63, 25, 0, 0, 0, 0, 0, 0, 0, 0,
291 : 42, 20, 42, 20, 42, 20, 42, 20, 42, 20, 42, 20, 42,
292 : };
293 :
294 : int gdFontSmallData[] = {
295 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296 : 0, 0, 4, 4, 4, 4, 4, 0, 4, 0, 0, 0,
297 : 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0,
298 : 0, 0, 0, 10, 31, 10, 10, 31, 10, 0, 0, 0,
299 : 0, 4, 14, 21, 5, 14, 20, 21, 14, 4, 0, 0,
300 : 0, 0, 31, 19, 8, 4, 2, 25, 25, 0, 0, 0,
301 : 0, 0, 2, 5, 5, 2, 21, 9, 22, 0, 0, 0,
302 : 0, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0,
303 : 0, 0, 16, 8, 4, 4, 4, 8, 16, 0, 0, 0,
304 : 0, 0, 1, 2, 4, 4, 4, 2, 1, 0, 0, 0,
305 : 0, 0, 4, 21, 14, 4, 14, 21, 4, 0, 0, 0,
306 : 0, 0, 0, 4, 4, 31, 4, 4, 0, 0, 0, 0,
307 : 0, 0, 0, 0, 0, 0, 0, 6, 6, 3, 0, 0,
308 : 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0,
309 : 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0,
310 : 0, 0, 0, 16, 8, 4, 2, 1, 0, 0, 0, 0,
311 : 0, 0, 14, 17, 25, 21, 19, 17, 14, 0, 0, 0,
312 : 0, 0, 4, 6, 4, 4, 4, 4, 14, 0, 0, 0,
313 : 0, 0, 14, 17, 16, 8, 4, 2, 31, 0, 0, 0,
314 : 0, 0, 14, 17, 16, 12, 16, 17, 14, 0, 0, 0,
315 : 0, 0, 8, 12, 10, 9, 31, 8, 8, 0, 0, 0,
316 : 0, 0, 31, 1, 15, 16, 16, 17, 14, 0, 0, 0,
317 : 0, 0, 12, 2, 1, 15, 17, 17, 14, 0, 0, 0,
318 : 0, 0, 31, 16, 8, 8, 4, 4, 4, 0, 0, 0,
319 : 0, 0, 14, 17, 17, 14, 17, 17, 14, 0, 0, 0,
320 : 0, 0, 14, 17, 17, 30, 16, 8, 6, 0, 0, 0,
321 : 0, 0, 0, 0, 6, 6, 0, 6, 6, 0, 0, 0,
322 : 0, 0, 0, 0, 6, 6, 0, 6, 6, 3, 0, 0,
323 : 0, 0, 0, 8, 4, 2, 4, 8, 0, 0, 0, 0,
324 : 0, 0, 0, 0, 31, 0, 31, 0, 0, 0, 0, 0,
325 : 0, 0, 0, 2, 4, 8, 4, 2, 0, 0, 0, 0,
326 : 0, 0, 14, 17, 8, 4, 4, 0, 4, 0, 0, 0,
327 : 0, 0, 14, 17, 29, 21, 29, 1, 14, 0, 0, 0,
328 : 0, 0, 14, 17, 17, 31, 17, 17, 17, 0, 0, 0,
329 : 0, 0, 15, 17, 17, 15, 17, 17, 15, 0, 0, 0,
330 : 0, 0, 14, 17, 1, 1, 1, 17, 14, 0, 0, 0,
331 : 0, 0, 15, 18, 18, 18, 18, 18, 15, 0, 0, 0,
332 : 0, 0, 31, 1, 1, 15, 1, 1, 31, 0, 0, 0,
333 : 0, 0, 31, 1, 1, 15, 1, 1, 1, 0, 0, 0,
334 : 0, 0, 14, 17, 1, 1, 25, 17, 14, 0, 0, 0,
335 : 0, 0, 17, 17, 17, 31, 17, 17, 17, 0, 0, 0,
336 : 0, 0, 14, 4, 4, 4, 4, 4, 14, 0, 0, 0,
337 : 0, 0, 16, 16, 16, 16, 16, 17, 14, 0, 0, 0,
338 : 0, 0, 17, 9, 5, 3, 5, 9, 17, 0, 0, 0,
339 : 0, 0, 1, 1, 1, 1, 1, 1, 31, 0, 0, 0,
340 : 0, 0, 17, 27, 21, 17, 17, 17, 17, 0, 0, 0,
341 : 0, 0, 17, 17, 19, 21, 25, 17, 17, 0, 0, 0,
342 : 0, 0, 14, 17, 17, 17, 17, 17, 14, 0, 0, 0,
343 : 0, 0, 15, 17, 17, 15, 1, 1, 1, 0, 0, 0,
344 : 0, 0, 14, 17, 17, 17, 21, 9, 22, 0, 0, 0,
345 : 0, 0, 15, 17, 17, 15, 5, 9, 17, 0, 0, 0,
346 : 0, 0, 14, 17, 1, 14, 16, 17, 14, 0, 0, 0,
347 : 0, 0, 31, 4, 4, 4, 4, 4, 4, 0, 0, 0,
348 : 0, 0, 17, 17, 17, 17, 17, 17, 14, 0, 0, 0,
349 : 0, 0, 17, 17, 17, 17, 10, 10, 4, 0, 0, 0,
350 : 0, 0, 17, 17, 17, 17, 21, 27, 17, 0, 0, 0,
351 : 0, 0, 17, 17, 10, 4, 10, 17, 17, 0, 0, 0,
352 : 0, 0, 17, 17, 10, 4, 4, 4, 4, 0, 0, 0,
353 : 0, 0, 31, 16, 8, 31, 2, 1, 31, 0, 0, 0,
354 : 0, 28, 4, 4, 4, 4, 4, 4, 4, 28, 0, 0,
355 : 0, 0, 0, 1, 2, 4, 8, 16, 0, 0, 0, 0,
356 : 0, 7, 4, 4, 4, 4, 4, 4, 4, 7, 0, 0,
357 : 0, 4, 10, 17, 0, 0, 0, 0, 0, 0, 0, 0,
358 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0,
359 : 0, 12, 12, 24, 0, 0, 0, 0, 0, 0, 0, 0,
360 : 0, 0, 0, 0, 14, 16, 30, 17, 30, 0, 0, 0,
361 : 0, 0, 1, 1, 15, 17, 17, 17, 15, 0, 0, 0,
362 : 0, 0, 0, 0, 14, 17, 1, 1, 30, 0, 0, 0,
363 : 0, 0, 16, 16, 30, 17, 17, 17, 30, 0, 0, 0,
364 : 0, 0, 0, 0, 14, 17, 15, 1, 14, 0, 0, 0,
365 : 0, 0, 12, 18, 2, 7, 2, 2, 2, 0, 0, 0,
366 : 0, 0, 0, 0, 14, 17, 17, 17, 30, 16, 14, 0,
367 : 0, 0, 1, 1, 15, 17, 17, 17, 17, 0, 0, 0,
368 : 0, 0, 0, 4, 0, 4, 4, 4, 4, 0, 0, 0,
369 : 0, 0, 0, 16, 0, 16, 16, 16, 16, 17, 14, 0,
370 : 0, 0, 1, 1, 17, 9, 7, 9, 17, 0, 0, 0,
371 : 0, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0,
372 : 0, 0, 0, 0, 11, 21, 21, 21, 21, 0, 0, 0,
373 : 0, 0, 0, 0, 13, 19, 17, 17, 17, 0, 0, 0,
374 : 0, 0, 0, 0, 14, 17, 17, 17, 14, 0, 0, 0,
375 : 0, 0, 0, 0, 15, 17, 17, 17, 15, 1, 1, 0,
376 : 0, 0, 0, 0, 14, 17, 17, 17, 30, 16, 16, 0,
377 : 0, 0, 0, 0, 13, 19, 1, 1, 1, 0, 0, 0,
378 : 0, 0, 0, 0, 30, 1, 14, 16, 15, 0, 0, 0,
379 : 0, 0, 4, 4, 31, 4, 4, 4, 24, 0, 0, 0,
380 : 0, 0, 0, 0, 17, 17, 17, 17, 14, 0, 0, 0,
381 : 0, 0, 0, 0, 17, 17, 17, 10, 4, 0, 0, 0,
382 : 0, 0, 0, 0, 17, 17, 21, 21, 10, 0, 0, 0,
383 : 0, 0, 0, 0, 17, 10, 4, 10, 17, 0, 0, 0,
384 : 0, 0, 0, 0, 17, 17, 17, 10, 4, 2, 1, 0,
385 : 0, 0, 0, 0, 31, 8, 14, 2, 31, 0, 0, 0,
386 : 0, 16, 8, 8, 8, 4, 8, 8, 8, 16, 0, 0,
387 : 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0,
388 : 0, 1, 2, 2, 2, 4, 2, 2, 2, 1, 0, 0,
389 : 0, 22, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390 : 0, 0, 1, 1, 15, 17, 17, 17, 15, 0, 0, 0,
391 : };
392 :
393 : gdFont gdFontGiantRep = {
394 : 128, 0, 9, 15,
395 : gdFontGiantData
396 : };
397 :
398 : gdFont gdFontMediumBoldRep = {
399 : 128, 0, 7, 13,
400 : gdFontMediumBoldData
401 : };
402 :
403 : gdFont gdFontSmallRep = {
404 : 96, 32, 6, 12,
405 : gdFontSmallData
406 : };
407 :
408 : gdFontPtr gdFontMediumBold = &gdFontMediumBoldRep;
409 : gdFontPtr gdFontGiant = &gdFontGiantRep;
410 : gdFontPtr gdFontSmall = &gdFontSmallRep;
411 :
412 : /*------------------------------------------------------------------*/
413 :
414 : static void gdImageBrushApply(gdImagePtr im, int x, int y);
415 : static void gdImageTileApply(gdImagePtr im, int x, int y);
416 :
417 0 : gdImagePtr gdImageCreate(int sx, int sy)
418 : {
419 : int i;
420 : gdImagePtr im;
421 0 : im = (gdImage *) M_MALLOC(sizeof(gdImage));
422 0 : im->pixels = (unsigned char **) M_MALLOC(sizeof(unsigned char *) * sx);
423 0 : im->polyInts = 0;
424 0 : im->polyAllocated = 0;
425 0 : im->brush = 0;
426 0 : im->tile = 0;
427 0 : im->style = 0;
428 0 : for (i = 0; (i < sx); i++) {
429 0 : im->pixels[i] = (unsigned char *) M_CALLOC(sy, sizeof(unsigned char));
430 : }
431 0 : im->sx = sx;
432 0 : im->sy = sy;
433 0 : im->colorsTotal = 0;
434 0 : im->transparent = (-1);
435 0 : im->interlace = 0;
436 0 : return im;
437 : }
438 :
439 0 : void gdImageDestroy(gdImagePtr im)
440 : {
441 : int i;
442 0 : for (i = 0; (i < im->sx); i++) {
443 0 : M_FREE(im->pixels[i]);
444 : }
445 0 : M_FREE(im->pixels);
446 0 : if (im->polyInts) {
447 0 : M_FREE(im->polyInts);
448 : }
449 0 : if (im->style) {
450 0 : M_FREE(im->style);
451 : }
452 0 : M_FREE(im);
453 0 : }
454 :
455 0 : int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
456 : {
457 : int i;
458 : long rd, gd, bd;
459 0 : int ct = (-1);
460 0 : long mindist = 0;
461 0 : for (i = 0; (i < (im->colorsTotal)); i++) {
462 : long dist;
463 0 : if (im->open[i]) {
464 0 : continue;
465 : }
466 0 : rd = (im->red[i] - r);
467 0 : gd = (im->green[i] - g);
468 0 : bd = (im->blue[i] - b);
469 0 : dist = rd * rd + gd * gd + bd * bd;
470 0 : if ((i == 0) || (dist < mindist)) {
471 0 : mindist = dist;
472 0 : ct = i;
473 : }
474 : }
475 0 : return ct;
476 : }
477 :
478 0 : int gdImageColorExact(gdImagePtr im, int r, int g, int b)
479 : {
480 : int i;
481 0 : for (i = 0; (i < (im->colorsTotal)); i++) {
482 0 : if (im->open[i]) {
483 0 : continue;
484 : }
485 0 : if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b)) {
486 0 : return i;
487 : }
488 : }
489 0 : return -1;
490 : }
491 :
492 0 : int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
493 : {
494 : int i;
495 0 : int ct = (-1);
496 :
497 : /* check if color exists already */
498 0 : for (i = 0; (i < (im->colorsTotal)); i++) {
499 0 : if (!im->open[i] &&
500 0 : im->red[i] == r &&
501 0 : im->green[i] == g &&
502 0 : im->blue[i] == b) {
503 0 : return i;
504 : }
505 : }
506 :
507 0 : for (i = 0; (i < (im->colorsTotal)); i++) {
508 0 : if (im->open[i]) {
509 0 : ct = i;
510 0 : break;
511 : }
512 : }
513 0 : if (ct == (-1)) {
514 0 : ct = im->colorsTotal;
515 0 : if (ct == gdMaxColors) {
516 0 : return -1;
517 : }
518 0 : im->colorsTotal++;
519 : }
520 0 : im->red[ct] = r;
521 0 : im->green[ct] = g;
522 0 : im->blue[ct] = b;
523 0 : im->open[ct] = 0;
524 0 : return ct;
525 : }
526 :
527 0 : void gdImageColorDeallocate(gdImagePtr im, int color)
528 : {
529 : /* Mark it open. */
530 0 : im->open[color] = 1;
531 0 : }
532 :
533 0 : void gdImageColorTransparent(gdImagePtr im, int color)
534 : {
535 0 : im->transparent = color;
536 0 : }
537 :
538 0 : void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
539 : {
540 : int p;
541 0 : switch (color) {
542 0 : case gdStyled:
543 0 : if (!im->style) {
544 : /* Refuse to draw if no style is set. */
545 0 : return;
546 : } else {
547 0 : p = im->style[im->stylePos++];
548 : }
549 0 : if (p != (gdTransparent)) {
550 0 : gdImageSetPixel(im, x, y, p);
551 : }
552 0 : im->stylePos = im->stylePos % im->styleLength;
553 0 : break;
554 0 : case gdStyledBrushed:
555 0 : if (!im->style) {
556 : /* Refuse to draw if no style is set. */
557 0 : return;
558 : }
559 0 : p = im->style[im->stylePos++];
560 0 : if ((p != gdTransparent) && (p != 0)) {
561 0 : gdImageSetPixel(im, x, y, gdBrushed);
562 : }
563 0 : im->stylePos = im->stylePos % im->styleLength;
564 0 : break;
565 0 : case gdBrushed:
566 0 : gdImageBrushApply(im, x, y);
567 0 : break;
568 0 : case gdTiled:
569 0 : gdImageTileApply(im, x, y);
570 0 : break;
571 0 : default:
572 0 : if (gdImageBoundsSafe(im, x, y)) {
573 0 : im->pixels[x][y] = color;
574 : }
575 0 : break;
576 : }
577 : }
578 :
579 0 : static void gdImageBrushApply(gdImagePtr im, int x, int y)
580 : {
581 : int lx, ly;
582 : int hy;
583 : int hx;
584 : int x1, y1, x2, y2;
585 : int srcx, srcy;
586 0 : if (!im->brush) {
587 0 : return;
588 : }
589 0 : hy = gdImageSY(im->brush) / 2;
590 0 : y1 = y - hy;
591 0 : y2 = y1 + gdImageSY(im->brush);
592 0 : hx = gdImageSX(im->brush) / 2;
593 0 : x1 = x - hx;
594 0 : x2 = x1 + gdImageSX(im->brush);
595 0 : srcy = 0;
596 0 : for (ly = y1; (ly < y2); ly++) {
597 0 : srcx = 0;
598 0 : for (lx = x1; (lx < x2); lx++) {
599 : int p;
600 0 : p = gdImageGetPixel(im->brush, srcx, srcy);
601 : /* Allow for non-square brushes! */
602 0 : if (p != gdImageGetTransparent(im->brush)) {
603 0 : gdImageSetPixel(im, lx, ly, im->brushColorMap[p]);
604 : }
605 0 : srcx++;
606 : }
607 0 : srcy++;
608 : }
609 : }
610 :
611 0 : static void gdImageTileApply(gdImagePtr im, int x, int y)
612 : {
613 : int srcx, srcy;
614 : int p;
615 0 : if (!im->tile) {
616 0 : return;
617 : }
618 0 : srcx = x % gdImageSX(im->tile);
619 0 : srcy = y % gdImageSY(im->tile);
620 0 : p = gdImageGetPixel(im->tile, srcx, srcy);
621 : /* Allow for transparency */
622 0 : if (p != gdImageGetTransparent(im->tile)) {
623 0 : gdImageSetPixel(im, x, y, im->tileColorMap[p]);
624 : }
625 : }
626 :
627 0 : int gdImageGetPixel(gdImagePtr im, int x, int y)
628 : {
629 0 : if (gdImageBoundsSafe(im, x, y)) {
630 0 : return im->pixels[x][y];
631 : } else {
632 0 : return 0;
633 : }
634 : }
635 :
636 : /* Bresenham as presented in Foley & Van Dam */
637 :
638 0 : void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
639 : {
640 : int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
641 0 : dx = abs(x2 - x1);
642 0 : dy = abs(y2 - y1);
643 0 : if (dy <= dx) {
644 0 : d = 2 * dy - dx;
645 0 : incr1 = 2 * dy;
646 0 : incr2 = 2 * (dy - dx);
647 0 : if (x1 > x2) {
648 0 : x = x2;
649 0 : y = y2;
650 0 : ydirflag = (-1);
651 0 : xend = x1;
652 : } else {
653 0 : x = x1;
654 0 : y = y1;
655 0 : ydirflag = 1;
656 0 : xend = x2;
657 : }
658 0 : gdImageSetPixel(im, x, y, color);
659 0 : if (((y2 - y1) * ydirflag) > 0) {
660 0 : while (x < xend) {
661 0 : x++;
662 0 : if (d < 0) {
663 0 : d += incr1;
664 : } else {
665 0 : y++;
666 0 : d += incr2;
667 : }
668 0 : gdImageSetPixel(im, x, y, color);
669 : }
670 : } else {
671 0 : while (x < xend) {
672 0 : x++;
673 0 : if (d < 0) {
674 0 : d += incr1;
675 : } else {
676 0 : y--;
677 0 : d += incr2;
678 : }
679 0 : gdImageSetPixel(im, x, y, color);
680 : }
681 : }
682 : } else {
683 0 : d = 2 * dx - dy;
684 0 : incr1 = 2 * dx;
685 0 : incr2 = 2 * (dx - dy);
686 0 : if (y1 > y2) {
687 0 : y = y2;
688 0 : x = x2;
689 0 : yend = y1;
690 0 : xdirflag = (-1);
691 : } else {
692 0 : y = y1;
693 0 : x = x1;
694 0 : yend = y2;
695 0 : xdirflag = 1;
696 : }
697 0 : gdImageSetPixel(im, x, y, color);
698 0 : if (((x2 - x1) * xdirflag) > 0) {
699 0 : while (y < yend) {
700 0 : y++;
701 0 : if (d < 0) {
702 0 : d += incr1;
703 : } else {
704 0 : x++;
705 0 : d += incr2;
706 : }
707 0 : gdImageSetPixel(im, x, y, color);
708 : }
709 : } else {
710 0 : while (y < yend) {
711 0 : y++;
712 0 : if (d < 0) {
713 0 : d += incr1;
714 : } else {
715 0 : x--;
716 0 : d += incr2;
717 : }
718 0 : gdImageSetPixel(im, x, y, color);
719 : }
720 : }
721 : }
722 0 : }
723 :
724 : /* As above, plus dashing */
725 :
726 : #define dashedSet \
727 : { \
728 : dashStep++; \
729 : if (dashStep == gdDashSize) { \
730 : dashStep = 0; \
731 : on = !on; \
732 : } \
733 : if (on) { \
734 : gdImageSetPixel(im, x, y, color); \
735 : } \
736 : }
737 :
738 0 : void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
739 : {
740 : int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
741 0 : int dashStep = 0;
742 0 : int on = 1;
743 0 : dx = abs(x2 - x1);
744 0 : dy = abs(y2 - y1);
745 0 : if (dy <= dx) {
746 0 : d = 2 * dy - dx;
747 0 : incr1 = 2 * dy;
748 0 : incr2 = 2 * (dy - dx);
749 0 : if (x1 > x2) {
750 0 : x = x2;
751 0 : y = y2;
752 0 : ydirflag = (-1);
753 0 : xend = x1;
754 : } else {
755 0 : x = x1;
756 0 : y = y1;
757 0 : ydirflag = 1;
758 0 : xend = x2;
759 : }
760 0 : dashedSet;
761 0 : if (((y2 - y1) * ydirflag) > 0) {
762 0 : while (x < xend) {
763 0 : x++;
764 0 : if (d < 0) {
765 0 : d += incr1;
766 : } else {
767 0 : y++;
768 0 : d += incr2;
769 : }
770 0 : dashedSet;
771 : }
772 : } else {
773 0 : while (x < xend) {
774 0 : x++;
775 0 : if (d < 0) {
776 0 : d += incr1;
777 : } else {
778 0 : y--;
779 0 : d += incr2;
780 : }
781 0 : dashedSet;
782 : }
783 : }
784 : } else {
785 0 : d = 2 * dx - dy;
786 0 : incr1 = 2 * dx;
787 0 : incr2 = 2 * (dx - dy);
788 0 : if (y1 > y2) {
789 0 : y = y2;
790 0 : x = x2;
791 0 : yend = y1;
792 0 : xdirflag = (-1);
793 : } else {
794 0 : y = y1;
795 0 : x = x1;
796 0 : yend = y2;
797 0 : xdirflag = 1;
798 : }
799 0 : dashedSet;
800 0 : if (((x2 - x1) * xdirflag) > 0) {
801 0 : while (y < yend) {
802 0 : y++;
803 0 : if (d < 0) {
804 0 : d += incr1;
805 : } else {
806 0 : x++;
807 0 : d += incr2;
808 : }
809 0 : dashedSet;
810 : }
811 : } else {
812 0 : while (y < yend) {
813 0 : y++;
814 0 : if (d < 0) {
815 0 : d += incr1;
816 : } else {
817 0 : x--;
818 0 : d += incr2;
819 : }
820 0 : dashedSet;
821 : }
822 : }
823 : }
824 0 : }
825 :
826 0 : int gdImageBoundsSafe(gdImagePtr im, int x, int y)
827 : {
828 0 : return (!(((y < 0) || (y >= im->sy)) || ((x < 0) || (x >= im->sx))));
829 : }
830 :
831 0 : void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
832 : {
833 : int cx, cy;
834 : int px, py;
835 : int fline;
836 0 : cx = 0;
837 0 : cy = 0;
838 0 : if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
839 0 : return;
840 : }
841 0 : fline = (c - f->offset) * f->h;
842 0 : for (py = y; (py < (y + f->h)); py++) {
843 0 : for (px = x; (px < (x + f->w)); px++) {
844 0 : if (f->data[fline + cy] & (1 << cx)) {
845 0 : gdImageSetPixel(im, px, py, color);
846 : }
847 0 : cx++;
848 : }
849 0 : cx = 0;
850 0 : cy++;
851 : }
852 : }
853 :
854 0 : void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, char c, int color)
855 : {
856 : int cx, cy;
857 : int px, py;
858 : int fline;
859 0 : cx = 0;
860 0 : cy = 0;
861 0 : if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
862 0 : return;
863 : }
864 0 : fline = (c - f->offset) * f->h;
865 0 : for (py = y; (py > (y - f->w)); py--) {
866 0 : for (px = x; (px < (x + f->h)); px++) {
867 0 : if (f->data[fline + cy] & (1 << cx)) {
868 0 : gdImageSetPixel(im, px, py, color);
869 : }
870 0 : cy++;
871 : }
872 0 : cy = 0;
873 0 : cx++;
874 : }
875 : }
876 :
877 0 : void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, const char *s, int color)
878 : {
879 : int i;
880 : int l;
881 0 : l = strlen(s);
882 0 : for (i = 0; (i < l); i++) {
883 0 : gdImageChar(im, f, x, y, s[i], color);
884 0 : x += f->w;
885 : }
886 0 : }
887 :
888 0 : void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, const char *s, int color)
889 : {
890 : int i;
891 : int l;
892 0 : l = strlen(s);
893 0 : for (i = 0; (i < l); i++) {
894 0 : gdImageCharUp(im, f, x, y, s[i], color);
895 0 : y -= f->w;
896 : }
897 0 : }
898 :
899 0 : void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
900 : {
901 : int lastBorder;
902 : /* Seek left */
903 : int leftLimit, rightLimit;
904 : int i;
905 0 : leftLimit = (-1);
906 0 : if (border < 0) {
907 : /* Refuse to fill to a non-solid border */
908 0 : return;
909 : }
910 0 : for (i = x; (i >= 0); i--) {
911 0 : if (gdImageGetPixel(im, i, y) == border) {
912 0 : break;
913 : }
914 0 : gdImageSetPixel(im, i, y, color);
915 0 : leftLimit = i;
916 : }
917 0 : if (leftLimit == (-1)) {
918 0 : return;
919 : }
920 : /* Seek right */
921 0 : rightLimit = x;
922 0 : for (i = (x + 1); (i < im->sx); i++) {
923 0 : if (gdImageGetPixel(im, i, y) == border) {
924 0 : break;
925 : }
926 0 : gdImageSetPixel(im, i, y, color);
927 0 : rightLimit = i;
928 : }
929 : /* Look at lines above and below and start paints */
930 : /* Above */
931 0 : if (y > 0) {
932 0 : lastBorder = 1;
933 0 : for (i = leftLimit; (i <= rightLimit); i++) {
934 : int c;
935 0 : c = gdImageGetPixel(im, i, y - 1);
936 0 : if (lastBorder) {
937 0 : if ((c != border) && (c != color)) {
938 0 : gdImageFillToBorder(im, i, y - 1, border, color);
939 0 : lastBorder = 0;
940 : }
941 0 : } else if ((c == border) || (c == color)) {
942 0 : lastBorder = 1;
943 : }
944 : }
945 : }
946 : /* Below */
947 0 : if (y < ((im->sy) - 1)) {
948 0 : lastBorder = 1;
949 0 : for (i = leftLimit; (i <= rightLimit); i++) {
950 : int c;
951 0 : c = gdImageGetPixel(im, i, y + 1);
952 0 : if (lastBorder) {
953 0 : if ((c != border) && (c != color)) {
954 0 : gdImageFillToBorder(im, i, y + 1, border, color);
955 0 : lastBorder = 0;
956 : }
957 0 : } else if ((c == border) || (c == color)) {
958 0 : lastBorder = 1;
959 : }
960 : }
961 : }
962 : }
963 :
964 0 : void gdImageFill(gdImagePtr im, int x, int y, int color)
965 : {
966 : int lastBorder;
967 : int old;
968 : int leftLimit, rightLimit;
969 : int i;
970 0 : old = gdImageGetPixel(im, x, y);
971 0 : if (color == gdTiled) {
972 : /* Tile fill -- got to watch out! */
973 : int p, tileColor;
974 : int srcx, srcy;
975 0 : if (!im->tile) {
976 0 : return;
977 : }
978 : /* Refuse to flood-fill with a transparent pattern --
979 : I can't do it without allocating another image */
980 0 : if (gdImageGetTransparent(im->tile) != (-1)) {
981 0 : return;
982 : }
983 0 : srcx = x % gdImageSX(im->tile);
984 0 : srcy = y % gdImageSY(im->tile);
985 0 : p = gdImageGetPixel(im->tile, srcx, srcy);
986 0 : tileColor = im->tileColorMap[p];
987 0 : if (old == tileColor) {
988 : /* Nothing to be done */
989 0 : return;
990 : }
991 : } else {
992 0 : if (old == color) {
993 : /* Nothing to be done */
994 0 : return;
995 : }
996 : }
997 : /* Seek left */
998 0 : leftLimit = (-1);
999 0 : for (i = x; (i >= 0); i--) {
1000 0 : if (gdImageGetPixel(im, i, y) != old) {
1001 0 : break;
1002 : }
1003 0 : gdImageSetPixel(im, i, y, color);
1004 0 : leftLimit = i;
1005 : }
1006 0 : if (leftLimit == (-1)) {
1007 0 : return;
1008 : }
1009 : /* Seek right */
1010 0 : rightLimit = x;
1011 0 : for (i = (x + 1); (i < im->sx); i++) {
1012 0 : if (gdImageGetPixel(im, i, y) != old) {
1013 0 : break;
1014 : }
1015 0 : gdImageSetPixel(im, i, y, color);
1016 0 : rightLimit = i;
1017 : }
1018 : /* Look at lines above and below and start paints */
1019 : /* Above */
1020 0 : if (y > 0) {
1021 0 : lastBorder = 1;
1022 0 : for (i = leftLimit; (i <= rightLimit); i++) {
1023 : int c;
1024 0 : c = gdImageGetPixel(im, i, y - 1);
1025 0 : if (lastBorder) {
1026 0 : if (c == old) {
1027 0 : gdImageFill(im, i, y - 1, color);
1028 0 : lastBorder = 0;
1029 : }
1030 0 : } else if (c != old) {
1031 0 : lastBorder = 1;
1032 : }
1033 : }
1034 : }
1035 : /* Below */
1036 0 : if (y < ((im->sy) - 1)) {
1037 0 : lastBorder = 1;
1038 0 : for (i = leftLimit; (i <= rightLimit); i++) {
1039 : int c;
1040 0 : c = gdImageGetPixel(im, i, y + 1);
1041 0 : if (lastBorder) {
1042 0 : if (c == old) {
1043 0 : gdImageFill(im, i, y + 1, color);
1044 0 : lastBorder = 0;
1045 : }
1046 0 : } else if (c != old) {
1047 0 : lastBorder = 1;
1048 : }
1049 : }
1050 : }
1051 : }
1052 :
1053 : #ifdef TEST_CODE
1054 : void gdImageDump(gdImagePtr im)
1055 : {
1056 : int i, j;
1057 : for (i = 0; (i < im->sy); i++) {
1058 : for (j = 0; (j < im->sx); j++) {
1059 : printf("%d", im->pixels[j][i]);
1060 : }
1061 : printf("\n");
1062 : }
1063 : }
1064 : #endif
1065 :
1066 : /* Code drawn from ppmtogif.c, from the pbmplus package
1067 : **
1068 : ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
1069 : ** Lempel-Zim compression based on "compress".
1070 : **
1071 : ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
1072 : **
1073 : ** Copyright (C) 1989 by Jef Poskanzer.
1074 : **
1075 : ** Permission to use, copy, modify, and distribute this software and its
1076 : ** documentation for any purpose and without fee is hereby granted, provided
1077 : ** that the above copyright notice appear in all copies and that both that
1078 : ** copyright notice and this permission notice appear in supporting
1079 : ** documentation. This software is provided "as is" without express or
1080 : ** implied warranty.
1081 : **
1082 : ** The Graphics Interchange Format(c) is the Copyright property of
1083 : ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
1084 : ** CompuServe Incorporated.
1085 : */
1086 :
1087 : /*
1088 : * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
1089 : */
1090 : typedef int code_int;
1091 :
1092 : #ifdef SIGNED_COMPARE_SLOW
1093 : typedef unsigned long int count_int;
1094 : typedef unsigned short int count_short;
1095 : #else /*SIGNED_COMPARE_SLOW */
1096 : typedef long int count_int;
1097 : #endif /*SIGNED_COMPARE_SLOW */
1098 :
1099 : static int colorstobpp(int colors);
1100 : static void BumpPixel(void);
1101 : static int GIFNextPixel(gdImagePtr im);
1102 : static void GIFEncode(gdGifBuffer * buffer, int GWidth, int GHeight, int GInterlace,
1103 : int Background, int Transparent, int BitsPerPixel, int *Red,
1104 : int *Green, int *Blue, gdImagePtr im);
1105 : static void Putword(int w, gdGifBuffer * buffer);
1106 : static void compress(int init_bits, gdGifBuffer * buffer, gdImagePtr im);
1107 : static void output(code_int code);
1108 : static void cl_block(void);
1109 : static void cl_hash(count_int hsize);
1110 : static void char_init(void);
1111 : static void char_out(int c);
1112 : static void flush_char(void);
1113 : /* Allows for reuse */
1114 : static void init_statics(void);
1115 :
1116 : static char gif_buffer[500000];
1117 :
1118 0 : void gdImageGif(gdImagePtr im, gdGifBuffer * buffer)
1119 : {
1120 : int interlace, transparent, BitsPerPixel;
1121 0 : interlace = im->interlace;
1122 0 : transparent = im->transparent;
1123 :
1124 : /* allocate buffer */
1125 0 : buffer->size = 0;
1126 0 : buffer->data = gif_buffer;
1127 :
1128 0 : BitsPerPixel = colorstobpp(im->colorsTotal);
1129 : /* Clear any old values in statics strewn through the GIF code */
1130 0 : init_statics();
1131 : /* All set, let's do it. */
1132 0 : GIFEncode(buffer, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
1133 0 : im->red, im->green, im->blue, im);
1134 0 : }
1135 :
1136 0 : static int colorstobpp(int colors)
1137 : {
1138 0 : int bpp = 0;
1139 :
1140 0 : if (colors <= 2)
1141 0 : bpp = 1;
1142 0 : else if (colors <= 4)
1143 0 : bpp = 2;
1144 0 : else if (colors <= 8)
1145 0 : bpp = 3;
1146 0 : else if (colors <= 16)
1147 0 : bpp = 4;
1148 0 : else if (colors <= 32)
1149 0 : bpp = 5;
1150 0 : else if (colors <= 64)
1151 0 : bpp = 6;
1152 0 : else if (colors <= 128)
1153 0 : bpp = 7;
1154 0 : else if (colors <= 256)
1155 0 : bpp = 8;
1156 0 : return bpp;
1157 : }
1158 :
1159 : /*****************************************************************************
1160 : *
1161 : * GIFENCODE.C - GIF Image compression interface
1162 : *
1163 : * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
1164 : * BitsPerPixel, Red, Green, Blue, gdImagePtr )
1165 : *
1166 : *****************************************************************************/
1167 :
1168 : #define TRUE 1
1169 : #define FALSE 0
1170 :
1171 : static int Width, Height;
1172 : static int curx, cury;
1173 : static long CountDown;
1174 : static int Pass = 0;
1175 : static int Interlace;
1176 :
1177 : /*
1178 : * Bump the 'curx' and 'cury' to point to the next pixel
1179 : */
1180 0 : static void BumpPixel(void)
1181 : {
1182 : /*
1183 : * Bump the current X position
1184 : */
1185 0 : ++curx;
1186 :
1187 : /*
1188 : * If we are at the end of a scan line, set curx back to the beginning
1189 : * If we are interlaced, bump the cury to the appropriate spot,
1190 : * otherwise, just increment it.
1191 : */
1192 0 : if (curx == Width) {
1193 0 : curx = 0;
1194 :
1195 0 : if (!Interlace)
1196 0 : ++cury;
1197 : else {
1198 0 : switch (Pass) {
1199 :
1200 0 : case 0:
1201 0 : cury += 8;
1202 0 : if (cury >= Height) {
1203 0 : ++Pass;
1204 0 : cury = 4;
1205 : }
1206 0 : break;
1207 :
1208 0 : case 1:
1209 0 : cury += 8;
1210 0 : if (cury >= Height) {
1211 0 : ++Pass;
1212 0 : cury = 2;
1213 : }
1214 0 : break;
1215 :
1216 0 : case 2:
1217 0 : cury += 4;
1218 0 : if (cury >= Height) {
1219 0 : ++Pass;
1220 0 : cury = 1;
1221 : }
1222 0 : break;
1223 :
1224 0 : case 3:
1225 0 : cury += 2;
1226 0 : break;
1227 : }
1228 : }
1229 : }
1230 0 : }
1231 :
1232 : /*
1233 : * Return the next pixel from the image
1234 : */
1235 0 : static int GIFNextPixel(gdImagePtr im)
1236 : {
1237 : int r;
1238 :
1239 0 : if (CountDown == 0)
1240 0 : return EOF;
1241 :
1242 0 : --CountDown;
1243 :
1244 0 : r = gdImageGetPixel(im, curx, cury);
1245 :
1246 0 : BumpPixel();
1247 :
1248 0 : return r;
1249 : }
1250 :
1251 : /* public */
1252 :
1253 0 : void bputc(int c, gdGifBuffer * buffer)
1254 : {
1255 0 : buffer->data[buffer->size++] = (unsigned char) c;
1256 0 : }
1257 :
1258 : static void
1259 0 : GIFEncode(gdGifBuffer * buffer, int GWidth, int GHeight, int GInterlace, int Background,
1260 : int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue,
1261 : gdImagePtr im)
1262 : {
1263 : int B;
1264 : int RWidth, RHeight;
1265 : int LeftOfs, TopOfs;
1266 : int Resolution;
1267 : int ColorMapSize;
1268 : int InitCodeSize;
1269 : int i;
1270 :
1271 0 : Interlace = GInterlace;
1272 :
1273 0 : ColorMapSize = 1 << BitsPerPixel;
1274 :
1275 0 : RWidth = Width = GWidth;
1276 0 : RHeight = Height = GHeight;
1277 0 : LeftOfs = TopOfs = 0;
1278 :
1279 0 : Resolution = BitsPerPixel;
1280 :
1281 : /*
1282 : * Calculate number of bits we are expecting
1283 : */
1284 0 : CountDown = (long) Width *(long) Height;
1285 :
1286 : /*
1287 : * Indicate which pass we are on (if interlace)
1288 : */
1289 0 : Pass = 0;
1290 :
1291 : /*
1292 : * The initial code size
1293 : */
1294 0 : if (BitsPerPixel <= 1)
1295 0 : InitCodeSize = 2;
1296 : else
1297 0 : InitCodeSize = BitsPerPixel;
1298 :
1299 : /*
1300 : * Set up the current x and y position
1301 : */
1302 0 : curx = cury = 0;
1303 :
1304 : /*
1305 : * Write the Magic header
1306 : */
1307 0 : memcpy(buffer->data + buffer->size, Transparent < 0 ? "GIF87a" : "GIF89a", 6);
1308 0 : buffer->size += 6;
1309 :
1310 : /*
1311 : * Write out the screen width and height
1312 : */
1313 0 : Putword(RWidth, buffer);
1314 0 : Putword(RHeight, buffer);
1315 :
1316 : /*
1317 : * Indicate that there is a global color map
1318 : */
1319 0 : B = 0x80; /* Yes, there is a color map */
1320 :
1321 : /*
1322 : * OR in the resolution
1323 : */
1324 0 : B |= (Resolution - 1) << 5;
1325 :
1326 : /*
1327 : * OR in the Bits per Pixel
1328 : */
1329 0 : B |= (BitsPerPixel - 1);
1330 :
1331 : /*
1332 : * Write it out
1333 : */
1334 0 : bputc(B, buffer);
1335 :
1336 : /*
1337 : * Write out the Background color
1338 : */
1339 0 : bputc(Background, buffer);
1340 :
1341 : /*
1342 : * Byte of 0's (future expansion)
1343 : */
1344 0 : bputc(0, buffer);
1345 :
1346 : /*
1347 : * Write out the Global Color Map
1348 : */
1349 0 : for (i = 0; i < ColorMapSize; ++i) {
1350 0 : bputc(Red[i], buffer);
1351 0 : bputc(Green[i], buffer);
1352 0 : bputc(Blue[i], buffer);
1353 : }
1354 :
1355 : /*
1356 : * Write out extension for transparent color index, if necessary.
1357 : */
1358 0 : if (Transparent >= 0) {
1359 0 : bputc('!', buffer);
1360 0 : bputc(0xf9, buffer);
1361 0 : bputc(4, buffer);
1362 0 : bputc(1, buffer);
1363 0 : bputc(0, buffer);
1364 0 : bputc(0, buffer);
1365 0 : bputc((unsigned char) Transparent, buffer);
1366 0 : bputc(0, buffer);
1367 : }
1368 :
1369 : /*
1370 : * Write an Image separator
1371 : */
1372 0 : bputc(',', buffer);
1373 :
1374 : /*
1375 : * Write the Image header
1376 : */
1377 :
1378 0 : Putword(LeftOfs, buffer);
1379 0 : Putword(TopOfs, buffer);
1380 0 : Putword(Width, buffer);
1381 0 : Putword(Height, buffer);
1382 :
1383 : /*
1384 : * Write out whether or not the image is interlaced
1385 : */
1386 0 : if (Interlace)
1387 0 : bputc(0x40, buffer);
1388 : else
1389 0 : bputc(0x00, buffer);
1390 :
1391 : /*
1392 : * Write out the initial code size
1393 : */
1394 0 : bputc(InitCodeSize, buffer);
1395 :
1396 : /*
1397 : * Go and actually compress the data
1398 : */
1399 0 : compress(InitCodeSize + 1, buffer, im);
1400 :
1401 : /*
1402 : * Write out a Zero-length packet (to end the series)
1403 : */
1404 0 : bputc(0, buffer);
1405 :
1406 : /*
1407 : * Write the GIF file terminator
1408 : */
1409 0 : bputc(';', buffer);
1410 0 : }
1411 :
1412 : /*
1413 : * Write out a word to the GIF file
1414 : */
1415 0 : static void Putword(int w, gdGifBuffer * buffer)
1416 : {
1417 0 : buffer->data[buffer->size++] = (unsigned char) (w & 0xff);
1418 0 : buffer->data[buffer->size++] = (unsigned char) ((w / 256) & 0xff);
1419 0 : }
1420 :
1421 :
1422 : /***************************************************************************
1423 : *
1424 : * GIFCOMPR.C - GIF Image compression routines
1425 : *
1426 : * Lempel-Ziv compression based on 'compress'. GIF modifications by
1427 : * David Rowley (mgardi@watdcsu.waterloo.edu)
1428 : *
1429 : ***************************************************************************/
1430 :
1431 : /*
1432 : * General DEFINEs
1433 : */
1434 :
1435 : #define GIFBITS 12
1436 :
1437 : #define HSIZE 5003 /* 80% occupancy */
1438 :
1439 : #ifdef NO_UCHAR
1440 : typedef char char_type;
1441 : #else /*NO_UCHAR */
1442 : typedef unsigned char char_type;
1443 : #endif /*NO_UCHAR */
1444 :
1445 : /*
1446 : *
1447 : * GIF Image compression - modified 'compress'
1448 : *
1449 : * Based on: compress.c - File compression ala IEEE Computer, June 1984.
1450 : *
1451 : * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
1452 : * Jim McKie (decvax!mcvax!jim)
1453 : * Steve Davies (decvax!vax135!petsd!peora!srd)
1454 : * Ken Turkowski (decvax!decwrl!turtlevax!ken)
1455 : * James A. Woods (decvax!ihnp4!ames!jaw)
1456 : * Joe Orost (decvax!vax135!petsd!joe)
1457 : *
1458 : */
1459 : #include <ctype.h>
1460 :
1461 : #define ARGVAL() (*++(*argv) || (--argc && *++argv))
1462 :
1463 : static int n_bits; /* number of bits/code */
1464 : static int maxbits = GIFBITS; /* user settable max # bits/code */
1465 : static code_int maxcode; /* maximum code, given n_bits */
1466 : static code_int maxmaxcode = (code_int) 1 << GIFBITS; /* should NEVER generate this code */
1467 : #ifdef COMPATIBLE /* But wrong! */
1468 : # define MAXCODE(n_bits) ((code_int) 1 << (n_bits) - 1)
1469 : #else /*COMPATIBLE*/
1470 : # define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
1471 : #endif /*COMPATIBLE*/
1472 : static count_int htab[HSIZE];
1473 : static unsigned short codetab[HSIZE];
1474 : #define HashTabOf(i) htab[i]
1475 : #define CodeTabOf(i) codetab[i]
1476 :
1477 : static code_int hsize = HSIZE; /* for dynamic table sizing */
1478 :
1479 : /*
1480 : * To save much memory, we overlay the table used by compress() with those
1481 : * used by decompress(). The tab_prefix table is the same size and type
1482 : * as the codetab. The tab_suffix table needs 2**GIFBITS characters. We
1483 : * get this from the beginning of htab. The output stack uses the rest
1484 : * of htab, and contains characters. There is plenty of room for any
1485 : * possible stack (stack used to be 8000 characters).
1486 : */
1487 :
1488 : #define tab_prefixof(i) CodeTabOf(i)
1489 : #define tab_suffixof(i) ((char_type*)(htab))[i]
1490 : #define de_stack ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
1491 :
1492 : static code_int free_ent = 0; /* first unused entry */
1493 :
1494 : /*
1495 : * block compression parameters -- after all codes are used up,
1496 : * and compression rate changes, start over.
1497 : */
1498 : static int clear_flg = 0;
1499 :
1500 : static int offset;
1501 : static long int in_count = 1; /* length of input */
1502 : static long int out_count = 0; /* # of codes output (for debugging) */
1503 :
1504 : /*
1505 : * compress stdin to stdout
1506 : *
1507 : * Algorithm: use open addressing double hashing (no chaining) on the
1508 : * prefix code / next character combination. We do a variant of Knuth's
1509 : * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1510 : * secondary probe. Here, the modular division first probe is gives way
1511 : * to a faster exclusive-or manipulation. Also do block compression with
1512 : * an adaptive reset, whereby the code table is cleared when the compression
1513 : * ratio decreases, but after the table fills. The variable-length output
1514 : * codes are re-sized at this point, and a special CLEAR code is generated
1515 : * for the decompressor. Late addition: construct the table according to
1516 : * file size for noticeable speed improvement on small files. Please direct
1517 : * questions about this implementation to ames!jaw.
1518 : */
1519 :
1520 : static int g_init_bits;
1521 : static gdGifBuffer *g_outbuffer;
1522 :
1523 : static int ClearCode;
1524 : static int EOFCode;
1525 :
1526 0 : static void compress(int init_bits, gdGifBuffer * buffer, gdImagePtr im)
1527 : {
1528 : long fcode;
1529 : code_int i /* = 0 */ ;
1530 : int c;
1531 : code_int ent;
1532 : code_int disp;
1533 : code_int hsize_reg;
1534 : int hshift;
1535 :
1536 : /*
1537 : * Set up the globals: g_init_bits - initial number of bits
1538 : * g_outbuffer - pointer to output file
1539 : */
1540 0 : g_init_bits = init_bits;
1541 0 : g_outbuffer = buffer;
1542 :
1543 : /*
1544 : * Set up the necessary values
1545 : */
1546 0 : offset = 0;
1547 0 : out_count = 0;
1548 0 : clear_flg = 0;
1549 0 : in_count = 1;
1550 0 : maxcode = MAXCODE(n_bits = g_init_bits);
1551 :
1552 0 : ClearCode = (1 << (init_bits - 1));
1553 0 : EOFCode = ClearCode + 1;
1554 0 : free_ent = ClearCode + 2;
1555 :
1556 0 : char_init();
1557 :
1558 0 : ent = GIFNextPixel(im);
1559 :
1560 0 : hshift = 0;
1561 0 : for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
1562 0 : ++hshift;
1563 0 : hshift = 8 - hshift; /* set hash code range bound */
1564 :
1565 0 : hsize_reg = hsize;
1566 0 : cl_hash((count_int) hsize_reg); /* clear hash table */
1567 :
1568 0 : output((code_int) ClearCode);
1569 :
1570 : #ifdef SIGNED_COMPARE_SLOW
1571 : while ((c = GIFNextPixel(im)) != (unsigned) EOF) {
1572 : #else /*SIGNED_COMPARE_SLOW */
1573 0 : while ((c = GIFNextPixel(im)) != EOF) { /* } */
1574 : #endif /*SIGNED_COMPARE_SLOW */
1575 :
1576 0 : ++in_count;
1577 :
1578 0 : fcode = (long) (((long) c << maxbits) + ent);
1579 0 : i = (((code_int) c << hshift) ^ ent); /* xor hashing */
1580 :
1581 0 : if (HashTabOf(i) == fcode) {
1582 0 : ent = CodeTabOf(i);
1583 0 : continue;
1584 0 : } else if ((long) HashTabOf(i) < 0) /* empty slot */
1585 0 : goto nomatch;
1586 0 : disp = hsize_reg - i; /* secondary hash (after G. Knott) */
1587 0 : if (i == 0)
1588 0 : disp = 1;
1589 0 : probe:
1590 0 : if ((i -= disp) < 0)
1591 0 : i += hsize_reg;
1592 :
1593 0 : if (HashTabOf(i) == fcode) {
1594 0 : ent = CodeTabOf(i);
1595 0 : continue;
1596 : }
1597 0 : if ((long) HashTabOf(i) > 0)
1598 0 : goto probe;
1599 0 : nomatch:
1600 0 : output((code_int) ent);
1601 0 : ++out_count;
1602 0 : ent = c;
1603 : #ifdef SIGNED_COMPARE_SLOW
1604 : if ((unsigned) free_ent < (unsigned) maxmaxcode) {
1605 : #else /*SIGNED_COMPARE_SLOW */
1606 0 : if (free_ent < maxmaxcode) { /* } */
1607 : #endif /*SIGNED_COMPARE_SLOW */
1608 0 : CodeTabOf(i) = free_ent++; /* code -> hashtable */
1609 0 : HashTabOf(i) = fcode;
1610 : } else
1611 0 : cl_block();
1612 : }
1613 : /*
1614 : * Put out the final code.
1615 : */
1616 0 : output((code_int) ent);
1617 0 : ++out_count;
1618 0 : output((code_int) EOFCode);
1619 0 : }
1620 :
1621 : /*****************************************************************
1622 : * TAG( output )
1623 : *
1624 : * Output the given code.
1625 : * Inputs:
1626 : * code: A n_bits-bit integer. If == -1, then EOF. This assumes
1627 : * that n_bits =< (long)wordsize - 1.
1628 : * Outputs:
1629 : * Outputs code to the file.
1630 : * Assumptions:
1631 : * Chars are 8 bits long.
1632 : * Algorithm:
1633 : * Maintain a GIFBITS character long buffer (so that 8 codes will
1634 : * fit in it exactly). Use the VAX insv instruction to insert each
1635 : * code in turn. When the buffer fills up empty it and start over.
1636 : */
1637 :
1638 : static unsigned long cur_accum = 0;
1639 : static int cur_bits = 0;
1640 :
1641 : static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
1642 : 0x001F, 0x003F, 0x007F, 0x00FF,
1643 : 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
1644 : 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
1645 : };
1646 :
1647 0 : static void output(code_int code)
1648 : {
1649 0 : cur_accum &= masks[cur_bits];
1650 :
1651 0 : if (cur_bits > 0)
1652 0 : cur_accum |= ((long) code << cur_bits);
1653 : else
1654 0 : cur_accum = code;
1655 :
1656 0 : cur_bits += n_bits;
1657 :
1658 0 : while (cur_bits >= 8) {
1659 0 : char_out((unsigned int) (cur_accum & 0xff));
1660 0 : cur_accum >>= 8;
1661 0 : cur_bits -= 8;
1662 : }
1663 :
1664 : /*
1665 : * If the next entry is going to be too big for the code size,
1666 : * then increase it, if possible.
1667 : */
1668 0 : if (free_ent > maxcode || clear_flg) {
1669 :
1670 0 : if (clear_flg) {
1671 :
1672 0 : maxcode = MAXCODE(n_bits = g_init_bits);
1673 0 : clear_flg = 0;
1674 :
1675 : } else {
1676 :
1677 0 : ++n_bits;
1678 0 : if (n_bits == maxbits)
1679 0 : maxcode = maxmaxcode;
1680 : else
1681 0 : maxcode = MAXCODE(n_bits);
1682 : }
1683 : }
1684 :
1685 0 : if (code == EOFCode) {
1686 : /*
1687 : * At EOF, write the rest of the buffer.
1688 : */
1689 0 : while (cur_bits > 0) {
1690 0 : char_out((unsigned int) (cur_accum & 0xff));
1691 0 : cur_accum >>= 8;
1692 0 : cur_bits -= 8;
1693 : }
1694 :
1695 0 : flush_char();
1696 :
1697 : }
1698 0 : }
1699 :
1700 : /*
1701 : * Clear out the hash table
1702 : */
1703 0 : static void cl_block(void)
1704 : { /* table clear for block compress */
1705 :
1706 0 : cl_hash((count_int) hsize);
1707 0 : free_ent = ClearCode + 2;
1708 0 : clear_flg = 1;
1709 :
1710 0 : output((code_int) ClearCode);
1711 0 : }
1712 :
1713 0 : static void cl_hash(count_int hsize)
1714 : { /* reset code table */
1715 :
1716 0 : count_int *htab_p = htab + hsize;
1717 :
1718 : long i;
1719 0 : long m1 = -1;
1720 :
1721 0 : i = hsize - 16;
1722 : do { /* might use Sys V memset(3) here */
1723 0 : *(htab_p - 16) = m1;
1724 0 : *(htab_p - 15) = m1;
1725 0 : *(htab_p - 14) = m1;
1726 0 : *(htab_p - 13) = m1;
1727 0 : *(htab_p - 12) = m1;
1728 0 : *(htab_p - 11) = m1;
1729 0 : *(htab_p - 10) = m1;
1730 0 : *(htab_p - 9) = m1;
1731 0 : *(htab_p - 8) = m1;
1732 0 : *(htab_p - 7) = m1;
1733 0 : *(htab_p - 6) = m1;
1734 0 : *(htab_p - 5) = m1;
1735 0 : *(htab_p - 4) = m1;
1736 0 : *(htab_p - 3) = m1;
1737 0 : *(htab_p - 2) = m1;
1738 0 : *(htab_p - 1) = m1;
1739 0 : htab_p -= 16;
1740 0 : } while ((i -= 16) >= 0);
1741 :
1742 0 : for (i += 16; i > 0; --i)
1743 0 : *--htab_p = m1;
1744 0 : }
1745 :
1746 : /******************************************************************************
1747 : *
1748 : * GIF Specific routines
1749 : *
1750 : ******************************************************************************/
1751 :
1752 : /*
1753 : * Number of characters so far in this 'packet'
1754 : */
1755 : static int a_count;
1756 :
1757 : /*
1758 : * Set up the 'byte output' routine
1759 : */
1760 0 : static void char_init(void)
1761 : {
1762 0 : a_count = 0;
1763 0 : }
1764 :
1765 : /*
1766 : * Define the storage for the packet accumulator
1767 : */
1768 : static char accum[256];
1769 :
1770 : /*
1771 : * Add a character to the end of the current packet, and if it is 254
1772 : * characters, flush the packet to disk.
1773 : */
1774 0 : static void char_out(int c)
1775 : {
1776 0 : accum[a_count++] = c;
1777 0 : if (a_count >= 254)
1778 0 : flush_char();
1779 0 : }
1780 :
1781 : /*
1782 : * Flush the packet to disk, and reset the accumulator
1783 : */
1784 0 : static void flush_char(void)
1785 : {
1786 0 : if (a_count > 0) {
1787 0 : bputc(a_count, g_outbuffer);
1788 0 : memcpy(g_outbuffer->data + g_outbuffer->size, accum, a_count);
1789 0 : g_outbuffer->size += a_count;
1790 0 : a_count = 0;
1791 : }
1792 0 : }
1793 :
1794 0 : static void init_statics(void)
1795 : {
1796 : /* Some of these are properly initialized later. What I'm doing
1797 : here is making sure code that depends on C's initialization
1798 : of statics doesn't break when the code gets called more
1799 : than once. */
1800 0 : Width = 0;
1801 0 : Height = 0;
1802 0 : curx = 0;
1803 0 : cury = 0;
1804 0 : CountDown = 0;
1805 0 : Pass = 0;
1806 0 : Interlace = 0;
1807 0 : a_count = 0;
1808 0 : cur_accum = 0;
1809 0 : cur_bits = 0;
1810 0 : g_init_bits = 0;
1811 0 : g_outbuffer = 0;
1812 0 : ClearCode = 0;
1813 0 : EOFCode = 0;
1814 0 : free_ent = 0;
1815 0 : clear_flg = 0;
1816 0 : offset = 0;
1817 0 : in_count = 1;
1818 0 : out_count = 0;
1819 0 : hsize = HSIZE;
1820 0 : n_bits = 0;
1821 0 : maxbits = GIFBITS;
1822 0 : maxcode = 0;
1823 0 : maxmaxcode = (code_int) 1 << GIFBITS;
1824 0 : }
1825 :
1826 :
1827 : /* +-------------------------------------------------------------------+ */
1828 : /* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
1829 : /* | Permission to use, copy, modify, and distribute this software | */
1830 : /* | and its documentation for any purpose and without fee is hereby | */
1831 : /* | granted, provided that the above copyright notice appear in all | */
1832 : /* | copies and that both that copyright notice and this permission | */
1833 : /* | notice appear in supporting documentation. This software is | */
1834 : /* | provided "as is" without express or implied warranty. | */
1835 : /* +-------------------------------------------------------------------+ */
1836 :
1837 :
1838 : #define MAXCOLORMAPSIZE 256
1839 :
1840 : #define TRUE 1
1841 : #define FALSE 0
1842 :
1843 : #define CM_RED 0
1844 : #define CM_GREEN 1
1845 : #define CM_BLUE 2
1846 :
1847 : #define MAX_LWZ_BITS 12
1848 :
1849 : #define INTERLACE 0x40
1850 : #define LOCALCOLORMAP 0x80
1851 : #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
1852 :
1853 : #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
1854 :
1855 : #define LM_to_uint(a,b) (((b)<<8)|(a))
1856 :
1857 : /* We may eventually want to use this information, but def it out for now */
1858 : #if 0
1859 : static struct {
1860 : unsigned int Width;
1861 : unsigned int Height;
1862 : unsigned char ColorMap[3][MAXCOLORMAPSIZE];
1863 : unsigned int BitPixel;
1864 : unsigned int ColorResolution;
1865 : unsigned int Background;
1866 : unsigned int AspectRatio;
1867 : } GifScreen;
1868 : #endif
1869 :
1870 : static struct {
1871 : int transparent;
1872 : int delayTime;
1873 : int inputFlag;
1874 : int disposal;
1875 : } Gif89 = {
1876 : -1, -1, -1, 0};
1877 :
1878 : static int ReadColorMap(FILE * fd, int number, unsigned char (*buffer)[256]);
1879 : static int DoExtension(FILE * fd, int label, int *Transparent);
1880 : static int GetDataBlock(FILE * fd, unsigned char *buf);
1881 : static int GetCode(FILE * fd, int code_size, int flag);
1882 : static int LWZReadByte(FILE * fd, int flag, int input_code_size);
1883 : static void ReadImage(gdImagePtr im, FILE * fd, int len, int height,
1884 : unsigned char (*cmap)[256], int interlace, int ignore);
1885 :
1886 : int ZeroDataBlock;
1887 :
1888 0 : gdImagePtr gdImageCreateFromGif(FILE * fd)
1889 : {
1890 : int imageNumber;
1891 : int BitPixel;
1892 : //int ColorResolution;
1893 : //int Background;
1894 : //int AspectRatio;
1895 0 : int Transparent = (-1);
1896 : unsigned char buf[16];
1897 : unsigned char c;
1898 : unsigned char ColorMap[3][MAXCOLORMAPSIZE];
1899 : unsigned char localColorMap[3][MAXCOLORMAPSIZE];
1900 : int imw, imh;
1901 : int useGlobalColormap;
1902 : int bitPixel;
1903 0 : int imageCount = 0;
1904 : char version[4];
1905 0 : gdImagePtr im = 0;
1906 0 : ZeroDataBlock = FALSE;
1907 :
1908 0 : imageNumber = 1;
1909 0 : if (!ReadOK(fd, buf, 6)) {
1910 0 : return 0;
1911 : }
1912 0 : if (strncmp((char *) buf, "GIF", 3) != 0) {
1913 0 : return 0;
1914 : }
1915 0 : strncpy(version, (char *) buf + 3, 3);
1916 0 : version[3] = '\0';
1917 :
1918 0 : if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
1919 0 : return 0;
1920 : }
1921 0 : if (!ReadOK(fd, buf, 7)) {
1922 0 : return 0;
1923 : }
1924 0 : BitPixel = 2 << (buf[4] & 0x07);
1925 : //ColorResolution = (int) (((buf[4] & 0x70) >> 3) + 1);
1926 : //Background = buf[5];
1927 : //AspectRatio = buf[6];
1928 :
1929 0 : if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
1930 0 : if (ReadColorMap(fd, BitPixel, ColorMap)) {
1931 0 : return 0;
1932 : }
1933 : }
1934 : for (;;) {
1935 0 : if (!ReadOK(fd, &c, 1)) {
1936 0 : return 0;
1937 : }
1938 0 : if (c == ';') { /* GIF terminator */
1939 : int i;
1940 0 : if (imageCount < imageNumber) {
1941 0 : return 0;
1942 : }
1943 : /* Terminator before any image was declared! */
1944 0 : if (!im) {
1945 0 : return 0;
1946 : }
1947 : /* Check for open colors at the end, so
1948 : we can reduce colorsTotal and ultimately
1949 : BitsPerPixel */
1950 0 : for (i = ((im->colorsTotal - 1)); (i >= 0); i--) {
1951 0 : if (im->open[i]) {
1952 0 : im->colorsTotal--;
1953 : } else {
1954 0 : break;
1955 : }
1956 : }
1957 0 : return im;
1958 : }
1959 :
1960 0 : if (c == '!') { /* Extension */
1961 0 : if (!ReadOK(fd, &c, 1)) {
1962 0 : return 0;
1963 : }
1964 0 : DoExtension(fd, c, &Transparent);
1965 0 : continue;
1966 : }
1967 :
1968 0 : if (c != ',') { /* Not a valid start character */
1969 0 : continue;
1970 : }
1971 :
1972 0 : ++imageCount;
1973 :
1974 0 : if (!ReadOK(fd, buf, 9)) {
1975 0 : return 0;
1976 : }
1977 :
1978 0 : useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
1979 :
1980 0 : bitPixel = 1 << ((buf[8] & 0x07) + 1);
1981 :
1982 0 : imw = LM_to_uint(buf[4], buf[5]);
1983 0 : imh = LM_to_uint(buf[6], buf[7]);
1984 0 : if (!(im = gdImageCreate(imw, imh))) {
1985 0 : return 0;
1986 : }
1987 0 : im->interlace = BitSet(buf[8], INTERLACE);
1988 0 : if (!useGlobalColormap) {
1989 0 : if (ReadColorMap(fd, bitPixel, localColorMap)) {
1990 0 : return 0;
1991 : }
1992 0 : ReadImage(im, fd, imw, imh, localColorMap,
1993 0 : BitSet(buf[8], INTERLACE), imageCount != imageNumber);
1994 : } else {
1995 0 : ReadImage(im, fd, imw, imh,
1996 0 : ColorMap, BitSet(buf[8], INTERLACE), imageCount != imageNumber);
1997 : }
1998 0 : if (Transparent != (-1)) {
1999 0 : gdImageColorTransparent(im, Transparent);
2000 : }
2001 0 : }
2002 : }
2003 :
2004 0 : static int ReadColorMap(FILE * fd, int number, unsigned char (*buffer)[256])
2005 : {
2006 : int i;
2007 : unsigned char rgb[3];
2008 :
2009 :
2010 0 : for (i = 0; i < number; ++i) {
2011 0 : if (!ReadOK(fd, rgb, sizeof(rgb))) {
2012 0 : return TRUE;
2013 : }
2014 0 : buffer[CM_RED][i] = rgb[0];
2015 0 : buffer[CM_GREEN][i] = rgb[1];
2016 0 : buffer[CM_BLUE][i] = rgb[2];
2017 : }
2018 :
2019 :
2020 0 : return FALSE;
2021 : }
2022 :
2023 0 : static int DoExtension(FILE * fd, int label, int *Transparent)
2024 : {
2025 : static unsigned char buf[256];
2026 :
2027 0 : switch (label) {
2028 0 : case 0xf9: /* Graphic Control Extension */
2029 0 : (void) GetDataBlock(fd, (unsigned char *) buf);
2030 0 : Gif89.disposal = (buf[0] >> 2) & 0x7;
2031 0 : Gif89.inputFlag = (buf[0] >> 1) & 0x1;
2032 0 : Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
2033 0 : if ((buf[0] & 0x1) != 0)
2034 0 : *Transparent = buf[3];
2035 :
2036 0 : while (GetDataBlock(fd, (unsigned char *) buf) != 0);
2037 0 : return FALSE;
2038 0 : default:
2039 0 : break;
2040 : }
2041 0 : while (GetDataBlock(fd, (unsigned char *) buf) != 0);
2042 :
2043 0 : return FALSE;
2044 : }
2045 :
2046 0 : static int GetDataBlock(FILE * fd, unsigned char *buf)
2047 : {
2048 : unsigned char count;
2049 :
2050 0 : if (!ReadOK(fd, &count, 1)) {
2051 0 : return -1;
2052 : }
2053 :
2054 0 : ZeroDataBlock = count == 0;
2055 :
2056 0 : if ((count != 0) && (!ReadOK(fd, buf, count))) {
2057 0 : return -1;
2058 : }
2059 :
2060 0 : return count;
2061 : }
2062 :
2063 0 : static int GetCode(FILE * fd, int code_size, int flag)
2064 : {
2065 : static unsigned char buf[280];
2066 : static int curbit, lastbit, done, last_byte;
2067 : int i, j, ret;
2068 : unsigned char count;
2069 :
2070 0 : if (flag) {
2071 0 : curbit = 0;
2072 0 : lastbit = 0;
2073 0 : done = FALSE;
2074 0 : return 0;
2075 : }
2076 :
2077 0 : if ((curbit + code_size) >= lastbit) {
2078 0 : if (done) {
2079 0 : if (curbit >= lastbit) {
2080 : /* Oh well */
2081 : }
2082 0 : return -1;
2083 : }
2084 0 : buf[0] = buf[last_byte - 2];
2085 0 : buf[1] = buf[last_byte - 1];
2086 :
2087 0 : if ((count = GetDataBlock(fd, &buf[2])) == 0)
2088 0 : done = TRUE;
2089 :
2090 0 : last_byte = 2 + count;
2091 0 : curbit = (curbit - lastbit) + 16;
2092 0 : lastbit = (2 + count) * 8;
2093 : }
2094 :
2095 0 : ret = 0;
2096 0 : for (i = curbit, j = 0; j < code_size; ++i, ++j)
2097 0 : ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
2098 :
2099 0 : curbit += code_size;
2100 :
2101 0 : return ret;
2102 : }
2103 :
2104 0 : static int LWZReadByte(FILE * fd, int flag, int input_code_size)
2105 : {
2106 : static int fresh = FALSE;
2107 : int code, incode;
2108 : static int code_size, set_code_size;
2109 : static int max_code, max_code_size;
2110 : static int firstcode, oldcode;
2111 : static int clear_code, end_code;
2112 : static int table[2][(1 << MAX_LWZ_BITS)];
2113 : static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
2114 : int i;
2115 :
2116 0 : if (flag) {
2117 0 : set_code_size = input_code_size;
2118 0 : code_size = set_code_size + 1;
2119 0 : clear_code = 1 << set_code_size;
2120 0 : end_code = clear_code + 1;
2121 0 : max_code_size = 2 * clear_code;
2122 0 : max_code = clear_code + 2;
2123 :
2124 0 : GetCode(fd, 0, TRUE);
2125 :
2126 0 : fresh = TRUE;
2127 :
2128 0 : for (i = 0; i < clear_code; ++i) {
2129 0 : table[0][i] = 0;
2130 0 : table[1][i] = i;
2131 : }
2132 0 : for (; i < (1 << MAX_LWZ_BITS); ++i)
2133 0 : table[0][i] = table[1][0] = 0;
2134 :
2135 0 : sp = stack;
2136 :
2137 0 : return 0;
2138 0 : } else if (fresh) {
2139 0 : fresh = FALSE;
2140 : do {
2141 0 : firstcode = oldcode = GetCode(fd, code_size, FALSE);
2142 0 : } while (firstcode == clear_code);
2143 0 : return firstcode;
2144 : }
2145 :
2146 0 : if (sp > stack)
2147 0 : return *--sp;
2148 :
2149 0 : while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
2150 0 : if (code == clear_code) {
2151 0 : for (i = 0; i < clear_code; ++i) {
2152 0 : table[0][i] = 0;
2153 0 : table[1][i] = i;
2154 : }
2155 0 : for (; i < (1 << MAX_LWZ_BITS); ++i)
2156 0 : table[0][i] = table[1][i] = 0;
2157 0 : code_size = set_code_size + 1;
2158 0 : max_code_size = 2 * clear_code;
2159 0 : max_code = clear_code + 2;
2160 0 : sp = stack;
2161 0 : firstcode = oldcode = GetCode(fd, code_size, FALSE);
2162 0 : return firstcode;
2163 0 : } else if (code == end_code) {
2164 : int count;
2165 : unsigned char buf[260];
2166 :
2167 0 : if (ZeroDataBlock)
2168 0 : return -2;
2169 :
2170 0 : while ((count = GetDataBlock(fd, buf)) > 0);
2171 :
2172 0 : if (count != 0)
2173 0 : return -2;
2174 : }
2175 :
2176 0 : incode = code;
2177 :
2178 0 : if (code >= max_code) {
2179 0 : *sp++ = firstcode;
2180 0 : code = oldcode;
2181 : }
2182 :
2183 0 : while (code >= clear_code) {
2184 0 : *sp++ = table[1][code];
2185 0 : if (code == table[0][code]) {
2186 : /* Oh well */
2187 : }
2188 0 : code = table[0][code];
2189 : }
2190 :
2191 0 : *sp++ = firstcode = table[1][code];
2192 :
2193 0 : if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
2194 0 : table[0][code] = oldcode;
2195 0 : table[1][code] = firstcode;
2196 0 : ++max_code;
2197 0 : if ((max_code >= max_code_size) && (max_code_size < (1 << MAX_LWZ_BITS))) {
2198 0 : max_code_size *= 2;
2199 0 : ++code_size;
2200 : }
2201 : }
2202 :
2203 0 : oldcode = incode;
2204 :
2205 0 : if (sp > stack)
2206 0 : return *--sp;
2207 : }
2208 0 : return code;
2209 : }
2210 :
2211 : static void
2212 0 : ReadImage(gdImagePtr im, FILE * fd, int len, int height, unsigned char (*cmap)[256],
2213 : int interlace, int ignore)
2214 : {
2215 : unsigned char c;
2216 : int v;
2217 0 : int xpos = 0, ypos = 0, pass = 0;
2218 : int i;
2219 : /* Stash the color map into the image */
2220 0 : for (i = 0; (i < gdMaxColors); i++) {
2221 0 : im->red[i] = cmap[CM_RED][i];
2222 0 : im->green[i] = cmap[CM_GREEN][i];
2223 0 : im->blue[i] = cmap[CM_BLUE][i];
2224 0 : im->open[i] = 1;
2225 : }
2226 : /* Many (perhaps most) of these colors will remain marked open. */
2227 0 : im->colorsTotal = gdMaxColors;
2228 : /*
2229 : ** Initialize the Compression routines
2230 : */
2231 0 : if (!ReadOK(fd, &c, 1)) {
2232 0 : return;
2233 : }
2234 0 : if (LWZReadByte(fd, TRUE, c) < 0) {
2235 0 : return;
2236 : }
2237 :
2238 : /*
2239 : ** If this is an "uninteresting picture" ignore it.
2240 : */
2241 0 : if (ignore) {
2242 0 : while (LWZReadByte(fd, FALSE, c) >= 0);
2243 0 : return;
2244 : }
2245 :
2246 0 : while ((v = LWZReadByte(fd, FALSE, c)) >= 0) {
2247 : /* This how we recognize which colors are actually used. */
2248 0 : if (im->open[v]) {
2249 0 : im->open[v] = 0;
2250 : }
2251 0 : gdImageSetPixel(im, xpos, ypos, v);
2252 0 : ++xpos;
2253 0 : if (xpos == len) {
2254 0 : xpos = 0;
2255 0 : if (interlace) {
2256 0 : switch (pass) {
2257 0 : case 0:
2258 : case 1:
2259 0 : ypos += 8;
2260 0 : break;
2261 0 : case 2:
2262 0 : ypos += 4;
2263 0 : break;
2264 0 : case 3:
2265 0 : ypos += 2;
2266 0 : break;
2267 : }
2268 :
2269 0 : if (ypos >= height) {
2270 0 : ++pass;
2271 0 : switch (pass) {
2272 0 : case 1:
2273 0 : ypos = 4;
2274 0 : break;
2275 0 : case 2:
2276 0 : ypos = 2;
2277 0 : break;
2278 0 : case 3:
2279 0 : ypos = 1;
2280 0 : break;
2281 0 : default:
2282 0 : goto fini;
2283 : }
2284 : }
2285 : } else {
2286 0 : ++ypos;
2287 : }
2288 : }
2289 0 : if (ypos >= height)
2290 0 : break;
2291 : }
2292 :
2293 0 : fini:
2294 0 : if (LWZReadByte(fd, FALSE, c) >= 0) {
2295 : /* Ignore extra */
2296 : }
2297 : }
2298 :
2299 0 : void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2300 : {
2301 0 : gdImageLine(im, x1, y1, x2, y1, color);
2302 0 : gdImageLine(im, x1, y2, x2, y2, color);
2303 0 : gdImageLine(im, x1, y1, x1, y2, color);
2304 0 : gdImageLine(im, x2, y1, x2, y2, color);
2305 0 : }
2306 :
2307 0 : void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2308 : {
2309 : int x, y;
2310 0 : for (y = y1; (y <= y2); y++) {
2311 0 : for (x = x1; (x <= x2); x++) {
2312 0 : gdImageSetPixel(im, x, y, color);
2313 : }
2314 : }
2315 0 : }
2316 :
2317 0 : void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY,
2318 : int w, int h)
2319 : {
2320 : int c;
2321 : int x, y;
2322 : int tox, toy;
2323 : int i;
2324 : int colorMap[gdMaxColors];
2325 0 : for (i = 0; (i < gdMaxColors); i++) {
2326 0 : colorMap[i] = (-1);
2327 : }
2328 0 : toy = dstY;
2329 0 : for (y = srcY; (y < (srcY + h)); y++) {
2330 0 : tox = dstX;
2331 0 : for (x = srcX; (x < (srcX + w)); x++) {
2332 : int nc;
2333 0 : c = gdImageGetPixel(src, x, y);
2334 : /* Added 7/24/95: support transparent copies */
2335 0 : if (gdImageGetTransparent(src) == c) {
2336 0 : tox++;
2337 0 : continue;
2338 : }
2339 : /* Have we established a mapping for this color? */
2340 0 : if (colorMap[c] == (-1)) {
2341 : /* If it's the same image, mapping is trivial */
2342 0 : if (dst == src) {
2343 0 : nc = c;
2344 : } else {
2345 : /* First look for an exact match */
2346 0 : nc = gdImageColorExact(dst, src->red[c], src->green[c], src->blue[c]);
2347 : }
2348 0 : if (nc == (-1)) {
2349 : /* No, so try to allocate it */
2350 0 : nc = gdImageColorAllocate(dst, src->red[c], src->green[c], src->blue[c]);
2351 : /* If we're out of colors, go for the
2352 : closest color */
2353 0 : if (nc == (-1)) {
2354 0 : nc = gdImageColorClosest(dst, src->red[c], src->green[c], src->blue[c]);
2355 : }
2356 : }
2357 0 : colorMap[c] = nc;
2358 : }
2359 0 : gdImageSetPixel(dst, tox, toy, colorMap[c]);
2360 0 : tox++;
2361 : }
2362 0 : toy++;
2363 : }
2364 0 : }
2365 :
2366 0 : void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
2367 : int srcY, int dstW, int dstH, int srcW, int srcH)
2368 : {
2369 : int c;
2370 : int x, y;
2371 : int tox, toy;
2372 : int ydest;
2373 : int i;
2374 : int colorMap[gdMaxColors];
2375 : /* Stretch vectors */
2376 : int *stx;
2377 : int *sty;
2378 : /* We only need to use floating point to determine the correct
2379 : stretch vector for one line's worth. */
2380 : double accum;
2381 0 : stx = (int *) M_MALLOC(sizeof(int) * srcW);
2382 0 : sty = (int *) M_MALLOC(sizeof(int) * srcH);
2383 0 : accum = 0;
2384 0 : for (i = 0; (i < srcW); i++) {
2385 : int got;
2386 0 : accum += (double) dstW / (double) srcW;
2387 0 : got = (int) floor(accum);
2388 0 : stx[i] = got;
2389 0 : accum -= got;
2390 : }
2391 0 : accum = 0;
2392 0 : for (i = 0; (i < srcH); i++) {
2393 : int got;
2394 0 : accum += (double) dstH / (double) srcH;
2395 0 : got = (int) floor(accum);
2396 0 : sty[i] = got;
2397 0 : accum -= got;
2398 : }
2399 0 : for (i = 0; (i < gdMaxColors); i++) {
2400 0 : colorMap[i] = (-1);
2401 : }
2402 0 : toy = dstY;
2403 0 : for (y = srcY; (y < (srcY + srcH)); y++) {
2404 0 : for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
2405 0 : tox = dstX;
2406 0 : for (x = srcX; (x < (srcX + srcW)); x++) {
2407 : int nc;
2408 0 : if (!stx[x - srcX]) {
2409 0 : continue;
2410 : }
2411 0 : c = gdImageGetPixel(src, x, y);
2412 : /* Added 7/24/95: support transparent copies */
2413 0 : if (gdImageGetTransparent(src) == c) {
2414 0 : tox += stx[x - srcX];
2415 0 : continue;
2416 : }
2417 : /* Have we established a mapping for this color? */
2418 0 : if (colorMap[c] == (-1)) {
2419 : /* If it's the same image, mapping is trivial */
2420 0 : if (dst == src) {
2421 0 : nc = c;
2422 : } else {
2423 : /* First look for an exact match */
2424 0 : nc = gdImageColorExact(dst, src->red[c], src->green[c], src->blue[c]);
2425 : }
2426 0 : if (nc == (-1)) {
2427 : /* No, so try to allocate it */
2428 0 : nc = gdImageColorAllocate(dst,
2429 : src->red[c], src->green[c], src->blue[c]);
2430 : /* If we're out of colors, go for the
2431 : closest color */
2432 0 : if (nc == (-1)) {
2433 0 : nc = gdImageColorClosest(dst,
2434 : src->red[c], src->green[c], src->blue[c]);
2435 : }
2436 : }
2437 0 : colorMap[c] = nc;
2438 : }
2439 0 : for (i = 0; (i < stx[x - srcX]); i++) {
2440 0 : gdImageSetPixel(dst, tox, toy, colorMap[c]);
2441 0 : tox++;
2442 : }
2443 : }
2444 0 : toy++;
2445 : }
2446 : }
2447 0 : M_FREE(stx);
2448 0 : M_FREE(sty);
2449 0 : }
2450 :
2451 0 : void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2452 : {
2453 : int i;
2454 : int lx, ly;
2455 0 : if (!n) {
2456 0 : return;
2457 : }
2458 0 : lx = p->x;
2459 0 : ly = p->y;
2460 0 : gdImageLine(im, lx, ly, p[n - 1].x, p[n - 1].y, c);
2461 0 : for (i = 1; (i < n); i++) {
2462 0 : p++;
2463 0 : gdImageLine(im, lx, ly, p->x, p->y, c);
2464 0 : lx = p->x;
2465 0 : ly = p->y;
2466 : }
2467 : }
2468 :
2469 : int gdCompareInt(const void *a, const void *b);
2470 :
2471 0 : void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2472 : {
2473 : int i;
2474 : int y;
2475 : int y1, y2;
2476 : int ints;
2477 0 : if (!n) {
2478 0 : return;
2479 : }
2480 0 : if (!im->polyAllocated) {
2481 0 : im->polyInts = (int *) M_MALLOC(sizeof(int) * n);
2482 0 : im->polyAllocated = n;
2483 : }
2484 0 : if (im->polyAllocated < n) {
2485 0 : while (im->polyAllocated < n) {
2486 0 : im->polyAllocated *= 2;
2487 : }
2488 0 : im->polyInts = (int *) realloc(im->polyInts, sizeof(int) * im->polyAllocated);
2489 : }
2490 0 : y1 = p[0].y;
2491 0 : y2 = p[0].y;
2492 0 : for (i = 1; (i < n); i++) {
2493 0 : if (p[i].y < y1) {
2494 0 : y1 = p[i].y;
2495 : }
2496 0 : if (p[i].y > y2) {
2497 0 : y2 = p[i].y;
2498 : }
2499 : }
2500 0 : for (y = y1; (y <= y2); y++) {
2501 0 : int interLast = 0;
2502 0 : int dirLast = 0;
2503 0 : int interFirst = 1;
2504 0 : ints = 0;
2505 0 : for (i = 0; (i <= n); i++) {
2506 : int x1, x2;
2507 : int y1, y2;
2508 : int dir;
2509 : int ind1, ind2;
2510 0 : int lastInd1 = 0;
2511 0 : if ((i == n) || (!i)) {
2512 0 : ind1 = n - 1;
2513 0 : ind2 = 0;
2514 : } else {
2515 0 : ind1 = i - 1;
2516 0 : ind2 = i;
2517 : }
2518 0 : y1 = p[ind1].y;
2519 0 : y2 = p[ind2].y;
2520 0 : if (y1 < y2) {
2521 0 : y1 = p[ind1].y;
2522 0 : y2 = p[ind2].y;
2523 0 : x1 = p[ind1].x;
2524 0 : x2 = p[ind2].x;
2525 0 : dir = -1;
2526 0 : } else if (y1 > y2) {
2527 0 : y2 = p[ind1].y;
2528 0 : y1 = p[ind2].y;
2529 0 : x2 = p[ind1].x;
2530 0 : x1 = p[ind2].x;
2531 0 : dir = 1;
2532 : } else {
2533 : /* Horizontal; just draw it */
2534 0 : gdImageLine(im, p[ind1].x, y1, p[ind2].x, y1, c);
2535 0 : continue;
2536 : }
2537 0 : if ((y >= y1) && (y <= y2)) {
2538 0 : int inter = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
2539 : /* Only count intersections once
2540 : except at maxima and minima. Also,
2541 : if two consecutive intersections are
2542 : endpoints of the same horizontal line
2543 : that is not at a maxima or minima,
2544 : discard the leftmost of the two. */
2545 0 : if (!interFirst) {
2546 0 : if ((p[ind1].y == p[lastInd1].y) && (p[ind1].x != p[lastInd1].x)) {
2547 0 : if (dir == dirLast) {
2548 0 : if (inter > interLast) {
2549 : /* Replace the old one */
2550 0 : im->polyInts[ints] = inter;
2551 : } else {
2552 : /* Discard this one */
2553 : }
2554 0 : continue;
2555 : }
2556 : }
2557 0 : if (inter == interLast) {
2558 0 : if (dir == dirLast) {
2559 0 : continue;
2560 : }
2561 : }
2562 : }
2563 0 : if (i > 0) {
2564 0 : im->polyInts[ints++] = inter;
2565 : }
2566 0 : lastInd1 = i;
2567 0 : dirLast = dir;
2568 0 : interLast = inter;
2569 0 : interFirst = 0;
2570 : }
2571 : }
2572 0 : qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2573 0 : for (i = 0; (i < (ints - 1)); i += 2) {
2574 0 : gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, c);
2575 : }
2576 : }
2577 : }
2578 :
2579 0 : int gdCompareInt(const void *a, const void *b)
2580 : {
2581 0 : return (*(const int *) a) - (*(const int *) b);
2582 : }
2583 :
2584 0 : void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
2585 : {
2586 0 : if (im->style) {
2587 0 : M_FREE(im->style);
2588 : }
2589 0 : im->style = (int *)
2590 0 : M_MALLOC(sizeof(int) * noOfPixels);
2591 0 : memcpy(im->style, style, sizeof(int) * noOfPixels);
2592 0 : im->styleLength = noOfPixels;
2593 0 : im->stylePos = 0;
2594 0 : }
2595 :
2596 0 : void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
2597 : {
2598 : int i;
2599 0 : im->brush = brush;
2600 0 : for (i = 0; (i < gdImageColorsTotal(brush)); i++) {
2601 : int index;
2602 0 : index = gdImageColorExact(im,
2603 : gdImageRed(brush, i),
2604 : gdImageGreen(brush, i), gdImageBlue(brush, i));
2605 0 : if (index == (-1)) {
2606 0 : index = gdImageColorAllocate(im,
2607 : gdImageRed(brush, i),
2608 : gdImageGreen(brush, i), gdImageBlue(brush, i));
2609 0 : if (index == (-1)) {
2610 0 : index = gdImageColorClosest(im,
2611 : gdImageRed(brush, i),
2612 : gdImageGreen(brush, i), gdImageBlue(brush, i));
2613 : }
2614 : }
2615 0 : im->brushColorMap[i] = index;
2616 : }
2617 0 : }
2618 :
2619 0 : void gdImageInterlace(gdImagePtr im, int interlaceArg)
2620 : {
2621 0 : im->interlace = interlaceArg;
2622 0 : }
|