/src/giflib-code/gif_font.c
Line | Count | Source |
1 | | /**************************************************************************** |
2 | | |
3 | | gif_font.c - utility font handling and simple drawing for the GIF library |
4 | | |
5 | | ****************************************************************************/ |
6 | | // SPDX-License-Identifier: MIT |
7 | | // SPDX-File-Copyright-Txt: (C) Eric S. Raymond <esr@thyrsus.com> |
8 | | |
9 | | #include <limits.h> |
10 | | #include <stdint.h> |
11 | | #include <stdlib.h> |
12 | | #include <string.h> |
13 | | |
14 | | #include "gif_lib.h" |
15 | | |
16 | | /**************************************************************************** |
17 | | Ascii 8 by 8 regular font - only first 128 characters are supported. |
18 | | *****************************************************************************/ |
19 | | |
20 | | /* |
21 | | * Each array entry holds the bits for 8 horizontal scan lines, topmost |
22 | | * first. The most significant bit of each constant is the leftmost bit of |
23 | | * the scan line. |
24 | | */ |
25 | | /*@+charint@*/ |
26 | | const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH] = { |
27 | | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* Ascii 0 */ |
28 | | {0x3c, 0x42, 0xa5, 0x81, 0xbd, 0x42, 0x3c, 0x00}, /* Ascii 1 */ |
29 | | {0x3c, 0x7e, 0xdb, 0xff, 0xc3, 0x7e, 0x3c, 0x00}, /* Ascii 2 */ |
30 | | {0x00, 0xee, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 3 */ |
31 | | {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 4 */ |
32 | | {0x00, 0x3c, 0x18, 0xff, 0xff, 0x08, 0x18, 0x00}, /* Ascii 5 */ |
33 | | {0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x10, 0x38, 0x00}, /* Ascii 6 */ |
34 | | {0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, 0x00, 0x00}, /* Ascii 7 */ |
35 | | {0xff, 0xff, 0xe7, 0xc3, 0xe7, 0xff, 0xff, 0xff}, /* Ascii 8 */ |
36 | | {0x00, 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c, 0x00}, /* Ascii 9 */ |
37 | | {0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0xbd, 0xc3, 0xff}, /* Ascii 10 */ |
38 | | {0x1f, 0x07, 0x0d, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* Ascii 11 */ |
39 | | {0x00, 0x7e, 0xc3, 0xc3, 0x7e, 0x18, 0x7e, 0x18}, /* Ascii 12 */ |
40 | | {0x04, 0x06, 0x07, 0x04, 0x04, 0xfc, 0xf8, 0x00}, /* Ascii 13 */ |
41 | | {0x0c, 0x0a, 0x0d, 0x0b, 0xf9, 0xf9, 0x1f, 0x1f}, /* Ascii 14 */ |
42 | | {0x00, 0x92, 0x7c, 0x44, 0xc6, 0x7c, 0x92, 0x00}, /* Ascii 15 */ |
43 | | {0x00, 0x00, 0x60, 0x78, 0x7e, 0x78, 0x60, 0x00}, /* Ascii 16 */ |
44 | | {0x00, 0x00, 0x06, 0x1e, 0x7e, 0x1e, 0x06, 0x00}, /* Ascii 17 */ |
45 | | {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18}, /* Ascii 18 */ |
46 | | {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, /* Ascii 19 */ |
47 | | {0xff, 0xb6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x00}, /* Ascii 20 */ |
48 | | {0x7e, 0xc1, 0xdc, 0x22, 0x22, 0x1f, 0x83, 0x7e}, /* Ascii 21 */ |
49 | | {0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}, /* Ascii 22 */ |
50 | | {0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x00, 0xff}, /* Ascii 23 */ |
51 | | {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* Ascii 24 */ |
52 | | {0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x00}, /* Ascii 25 */ |
53 | | {0x00, 0x04, 0x06, 0xff, 0x06, 0x04, 0x00, 0x00}, /* Ascii 26 */ |
54 | | {0x00, 0x20, 0x60, 0xff, 0x60, 0x20, 0x00, 0x00}, /* Ascii 27 */ |
55 | | {0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xff, 0x00}, /* Ascii 28 */ |
56 | | {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, /* Ascii 29 */ |
57 | | {0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00}, /* Ascii 30 */ |
58 | | {0x00, 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 31 */ |
59 | | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */ |
60 | | {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00}, /* ! */ |
61 | | {0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */ |
62 | | {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, /* # */ |
63 | | {0x10, 0x7c, 0xd2, 0x7c, 0x86, 0x7c, 0x10, 0x00}, /* $ */ |
64 | | {0xf0, 0x96, 0xfc, 0x18, 0x3e, 0x72, 0xde, 0x00}, /* % */ |
65 | | {0x30, 0x48, 0x30, 0x78, 0xce, 0xcc, 0x78, 0x00}, /* & */ |
66 | | {0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */ |
67 | | {0x10, 0x60, 0xc0, 0xc0, 0xc0, 0x60, 0x10, 0x00}, /* ( */ |
68 | | {0x10, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x10, 0x00}, /* ) */ |
69 | | {0x00, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x00, 0x00}, /* * */ |
70 | | {0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00}, /* + */ |
71 | | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x70}, /* , */ |
72 | | {0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}, /* - */ |
73 | | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00}, /* . */ |
74 | | {0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00}, /* / */ |
75 | | {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* 0 */ |
76 | | {0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* 1 */ |
77 | | {0x7c, 0xc6, 0x06, 0x0c, 0x30, 0x60, 0xfe, 0x00}, /* 2 */ |
78 | | {0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00}, /* 3 */ |
79 | | {0x0e, 0x1e, 0x36, 0x66, 0xfe, 0x06, 0x06, 0x00}, /* 4 */ |
80 | | {0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xfc, 0x00}, /* 5 */ |
81 | | {0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00}, /* 6 */ |
82 | | {0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00}, /* 7 */ |
83 | | {0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* 8 */ |
84 | | {0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00}, /* 9 */ |
85 | | {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}, /* : */ |
86 | | {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00}, /* }, */ |
87 | | {0x00, 0x1c, 0x30, 0x60, 0x30, 0x1c, 0x00, 0x00}, /* < */ |
88 | | {0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}, /* = */ |
89 | | {0x00, 0x70, 0x18, 0x0c, 0x18, 0x70, 0x00, 0x00}, /* > */ |
90 | | {0x7c, 0xc6, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, /* ? */ |
91 | | {0x7c, 0x82, 0x9a, 0xaa, 0xaa, 0x9e, 0x7c, 0x00}, /* @ */ |
92 | | {0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, /* A */ |
93 | | {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x00}, /* B */ |
94 | | {0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00}, /* C */ |
95 | | {0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00}, /* D */ |
96 | | {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xfe, 0x00}, /* E */ |
97 | | {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* F */ |
98 | | {0x7c, 0xc6, 0xc0, 0xce, 0xc6, 0xc6, 0x7e, 0x00}, /* G */ |
99 | | {0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00}, /* H */ |
100 | | {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, /* I */ |
101 | | {0x1e, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00}, /* J */ |
102 | | {0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x00}, /* K */ |
103 | | {0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00}, /* L */ |
104 | | {0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00}, /* M */ |
105 | | {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, /* N */ |
106 | | {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* O */ |
107 | | {0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* P */ |
108 | | {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x06}, /* Q */ |
109 | | {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0x00}, /* R */ |
110 | | {0x78, 0xcc, 0x60, 0x30, 0x18, 0xcc, 0x78, 0x00}, /* S */ |
111 | | {0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, /* T */ |
112 | | {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* U */ |
113 | | {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* V */ |
114 | | {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, /* W */ |
115 | | {0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00}, /* X */ |
116 | | {0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00}, /* Y */ |
117 | | {0xfe, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00}, /* Z */ |
118 | | {0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00}, /* [ */ |
119 | | {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x00}, /* \ */ |
120 | | {0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00}, /* ] */ |
121 | | {0x00, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, /* ^ */ |
122 | | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /* _ */ |
123 | | {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */ |
124 | | {0x00, 0x00, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00}, /* a */ |
125 | | {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0x00}, /* b */ |
126 | | {0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0x7e, 0x00}, /* c */ |
127 | | {0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x00}, /* d */ |
128 | | {0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7e, 0x00}, /* e */ |
129 | | {0x1e, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x00}, /* f */ |
130 | | {0x00, 0x00, 0x7e, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* g */ |
131 | | {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* */ |
132 | | {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* i */ |
133 | | {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0xf0}, /* j */ |
134 | | {0xc0, 0xc0, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0x00}, /* k */ |
135 | | {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* l */ |
136 | | {0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, /* m */ |
137 | | {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* n */ |
138 | | {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* o */ |
139 | | {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0xc0}, /* p */ |
140 | | {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x06}, /* q */ |
141 | | {0x00, 0x00, 0x6e, 0x70, 0x60, 0x60, 0x60, 0x00}, /* r */ |
142 | | {0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00}, /* s */ |
143 | | {0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x1c, 0x00}, /* t */ |
144 | | {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00}, /* u */ |
145 | | {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* v */ |
146 | | {0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x00}, /* w */ |
147 | | {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, /* x */ |
148 | | {0x00, 0x00, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* y */ |
149 | | {0x00, 0x00, 0xfc, 0x18, 0x30, 0x60, 0xfc, 0x00}, /* z */ |
150 | | {0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00}, /* { */ |
151 | | {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */ |
152 | | {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, /* } */ |
153 | | {0x00, 0x00, 0x70, 0x9a, 0x0e, 0x00, 0x00, 0x00}, /* ~ */ |
154 | | {0x00, 0x00, 0x18, 0x3c, 0x66, 0xff, 0x00, 0x00} /* Ascii 127 */ |
155 | | }; |
156 | | /*@=charint@*/ |
157 | | |
158 | | static bool GifImageGetGeometry(const SavedImage *Image, |
159 | | size_t *width, |
160 | | size_t *height, |
161 | | size_t *pixels) |
162 | 0 | { |
163 | 0 | size_t w, h; |
164 | |
|
165 | 0 | if (Image == NULL || Image->RasterBits == NULL) { |
166 | 0 | return false; |
167 | 0 | } |
168 | 0 | if (Image->ImageDesc.Width <= 0 || Image->ImageDesc.Height <= 0) { |
169 | 0 | return false; |
170 | 0 | } |
171 | | |
172 | 0 | w = (size_t)Image->ImageDesc.Width; |
173 | 0 | h = (size_t)Image->ImageDesc.Height; |
174 | 0 | if (w > SIZE_MAX / h) { |
175 | 0 | return false; |
176 | 0 | } |
177 | | |
178 | 0 | if (width != NULL) { |
179 | 0 | *width = w; |
180 | 0 | } |
181 | 0 | if (height != NULL) { |
182 | 0 | *height = h; |
183 | 0 | } |
184 | 0 | if (pixels != NULL) { |
185 | 0 | *pixels = w * h; |
186 | 0 | } |
187 | 0 | return true; |
188 | 0 | } |
189 | | |
190 | | static void GifPutPixelClipped(SavedImage *Image, int x, int y, GifPixelType color) |
191 | 0 | { |
192 | 0 | size_t width, height; |
193 | |
|
194 | 0 | if (!GifImageGetGeometry(Image, &width, &height, NULL)) { |
195 | 0 | return; |
196 | 0 | } |
197 | 0 | if (x < 0 || y < 0) { |
198 | 0 | return; |
199 | 0 | } |
200 | 0 | if ((size_t)x >= width || (size_t)y >= height) { |
201 | 0 | return; |
202 | 0 | } |
203 | | |
204 | 0 | Image->RasterBits[(size_t)y * width + (size_t)x] = color; |
205 | 0 | } |
206 | | |
207 | | void GifDrawText8x8(SavedImage *Image, const int x, const int y, |
208 | | const char *legend, const int color) |
209 | 0 | { |
210 | 0 | int i; |
211 | 0 | const unsigned char *cp; |
212 | |
|
213 | 0 | if (legend == NULL) { |
214 | 0 | return; |
215 | 0 | } |
216 | | |
217 | 0 | for (i = 0; i < GIF_FONT_HEIGHT; i++) { |
218 | 0 | int row_y = y + i; |
219 | |
|
220 | 0 | if (row_y < 0 || row_y > INT_MAX) { |
221 | 0 | continue; |
222 | 0 | } |
223 | | |
224 | 0 | for (cp = (const unsigned char *)legend; *cp != '\0'; cp++) { |
225 | 0 | size_t char_index = (size_t)(cp - (const unsigned char *)legend); |
226 | 0 | size_t j; |
227 | 0 | int glyph_x; |
228 | 0 | unsigned int glyph; |
229 | |
|
230 | 0 | if (*cp >= 128) { |
231 | 0 | continue; |
232 | 0 | } |
233 | 0 | if (char_index > (size_t)(INT_MAX / GIF_FONT_WIDTH)) { |
234 | 0 | break; |
235 | 0 | } |
236 | | |
237 | 0 | glyph_x = x + (int)(char_index * GIF_FONT_WIDTH); |
238 | 0 | glyph = GifAsciiTable8x8[*cp][i]; |
239 | 0 | for (j = 0; j < GIF_FONT_WIDTH; j++) { |
240 | 0 | if ((glyph & (1U << (GIF_FONT_WIDTH - 1 - j))) != 0U) { |
241 | 0 | if (glyph_x <= INT_MAX - (int)j) { |
242 | 0 | GifPutPixelClipped(Image, glyph_x + (int)j, row_y, |
243 | 0 | (GifPixelType)color); |
244 | 0 | } |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | void GifDrawBox(SavedImage *Image, const int x, const int y, const int w, |
252 | | const int d, const int color) |
253 | 0 | { |
254 | 0 | int j; |
255 | |
|
256 | 0 | if (w < 0 || d < 0) { |
257 | 0 | return; |
258 | 0 | } |
259 | | |
260 | 0 | for (j = 0; j <= w; j++) { |
261 | 0 | if (x <= INT_MAX - j) { |
262 | 0 | GifPutPixelClipped(Image, x + j, y, (GifPixelType)color); |
263 | 0 | if (y <= INT_MAX - d) { |
264 | 0 | GifPutPixelClipped(Image, x + j, y + d, |
265 | 0 | (GifPixelType)color); |
266 | 0 | } |
267 | 0 | } |
268 | 0 | } |
269 | |
|
270 | 0 | for (j = 0; j <= d; j++) { |
271 | 0 | if (y <= INT_MAX - j) { |
272 | 0 | GifPutPixelClipped(Image, x, y + j, (GifPixelType)color); |
273 | 0 | if (x <= INT_MAX - w) { |
274 | 0 | GifPutPixelClipped(Image, x + w, y + j, |
275 | 0 | (GifPixelType)color); |
276 | 0 | } |
277 | 0 | } |
278 | 0 | } |
279 | 0 | } |
280 | | |
281 | | void GifDrawRectangle(SavedImage *Image, const int x, const int y, const int w, |
282 | | const int d, const int color) |
283 | 0 | { |
284 | 0 | size_t width, height; |
285 | 0 | size_t row; |
286 | 0 | size_t x0, y0, x1, y1; |
287 | |
|
288 | 0 | if (!GifImageGetGeometry(Image, &width, &height, NULL)) { |
289 | 0 | return; |
290 | 0 | } |
291 | 0 | if (w <= 0 || d <= 0) { |
292 | 0 | return; |
293 | 0 | } |
294 | | |
295 | 0 | x0 = (x <= 0) ? 0U : (size_t)x; |
296 | 0 | y0 = (y <= 0) ? 0U : (size_t)y; |
297 | |
|
298 | 0 | if (x >= 0 && (size_t)x < width) { |
299 | 0 | size_t rw = (size_t)w; |
300 | 0 | x1 = rw > width - (size_t)x ? width : (size_t)x + rw; |
301 | 0 | } else if (x < 0) { |
302 | 0 | size_t rw = (size_t)w; |
303 | 0 | size_t start = (size_t)(-x); |
304 | 0 | if (rw <= start) { |
305 | 0 | return; |
306 | 0 | } |
307 | 0 | x1 = rw - start; |
308 | 0 | if (x1 > width) { |
309 | 0 | x1 = width; |
310 | 0 | } |
311 | 0 | } else { |
312 | 0 | return; |
313 | 0 | } |
314 | | |
315 | 0 | if (y >= 0 && (size_t)y < height) { |
316 | 0 | size_t rh = (size_t)d; |
317 | 0 | y1 = rh > height - (size_t)y ? height : (size_t)y + rh; |
318 | 0 | } else if (y < 0) { |
319 | 0 | size_t rh = (size_t)d; |
320 | 0 | size_t start = (size_t)(-y); |
321 | 0 | if (rh <= start) { |
322 | 0 | return; |
323 | 0 | } |
324 | 0 | y1 = rh - start; |
325 | 0 | if (y1 > height) { |
326 | 0 | y1 = height; |
327 | 0 | } |
328 | 0 | } else { |
329 | 0 | return; |
330 | 0 | } |
331 | | |
332 | 0 | if (x0 >= x1 || y0 >= y1) { |
333 | 0 | return; |
334 | 0 | } |
335 | | |
336 | 0 | for (row = y0; row < y1; row++) { |
337 | 0 | memset(Image->RasterBits + row * width + x0, (GifPixelType)color, |
338 | 0 | x1 - x0); |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | | void GifDrawBoxedText8x8(SavedImage *Image, const int x, const int y, |
343 | | const char *legend, const int border, const int bg, |
344 | | const int fg) |
345 | 0 | { |
346 | 0 | size_t j = 0, LineCount = 0, TextWidth = 0; |
347 | 0 | const char *cp; |
348 | 0 | char *dup; |
349 | 0 | size_t legend_len; |
350 | |
|
351 | 0 | if (legend == NULL || border < 0) { |
352 | 0 | return; |
353 | 0 | } |
354 | | |
355 | | /* compute size of text to box */ |
356 | 0 | for (cp = legend; *cp != '\0'; cp++) { |
357 | 0 | if (*cp == '\r' || *cp == '\n') { |
358 | 0 | if (j > TextWidth) { |
359 | 0 | TextWidth = j; |
360 | 0 | } |
361 | 0 | j = 0; |
362 | 0 | LineCount++; |
363 | 0 | } else if (*cp != '\t') { |
364 | 0 | ++j; |
365 | 0 | } |
366 | 0 | } |
367 | 0 | LineCount++; /* count last line */ |
368 | 0 | if (j > TextWidth) { /* last line might be longer than any previous */ |
369 | 0 | TextWidth = j; |
370 | 0 | } |
371 | |
|
372 | 0 | legend_len = strlen(legend); |
373 | 0 | dup = malloc(legend_len + 1); |
374 | | /* FIXME: should return bad status, but that would require API change */ |
375 | 0 | if (dup != NULL) { |
376 | 0 | size_t fill_w = 0, fill_h = 0, box_w = 0, box_h = 0; |
377 | 0 | int i = 0; |
378 | 0 | char *line, *next; |
379 | |
|
380 | 0 | if (TextWidth <= (SIZE_MAX - (size_t)(2 * border)) / GIF_FONT_WIDTH) { |
381 | 0 | box_w = (size_t)(2 * border) + TextWidth * GIF_FONT_WIDTH; |
382 | 0 | if (box_w > 0) { |
383 | 0 | fill_w = box_w - 1; |
384 | 0 | } |
385 | 0 | } |
386 | 0 | if (LineCount <= (SIZE_MAX - (size_t)(2 * border)) / GIF_FONT_HEIGHT) { |
387 | 0 | box_h = (size_t)(2 * border) + LineCount * GIF_FONT_HEIGHT; |
388 | 0 | if (box_h > 0) { |
389 | 0 | fill_h = box_h - 1; |
390 | 0 | } |
391 | 0 | } |
392 | |
|
393 | 0 | if (fill_w > (size_t)INT_MAX) { |
394 | 0 | fill_w = (size_t)INT_MAX; |
395 | 0 | } |
396 | 0 | if (fill_h > (size_t)INT_MAX) { |
397 | 0 | fill_h = (size_t)INT_MAX; |
398 | 0 | } |
399 | 0 | if (box_w > (size_t)INT_MAX) { |
400 | 0 | box_w = (size_t)INT_MAX; |
401 | 0 | } |
402 | 0 | if (box_h > (size_t)INT_MAX) { |
403 | 0 | box_h = (size_t)INT_MAX; |
404 | 0 | } |
405 | | |
406 | | /* fill the box */ |
407 | 0 | GifDrawRectangle(Image, x + 1, y + 1, (int)fill_w, (int)fill_h, |
408 | 0 | bg); |
409 | 0 | memcpy(dup, legend, legend_len + 1); |
410 | |
|
411 | 0 | for (line = dup; line != NULL; line = next) { |
412 | 0 | size_t leadspace = 0; |
413 | 0 | char *eol = strpbrk(line, "\r\n"); |
414 | |
|
415 | 0 | next = NULL; |
416 | 0 | if (eol != NULL) { |
417 | 0 | next = eol + 1; |
418 | 0 | if ((*eol == '\r' && *next == '\n') || |
419 | 0 | (*eol == '\n' && *next == '\r')) { |
420 | 0 | ++next; |
421 | 0 | } |
422 | 0 | *eol = '\0'; |
423 | 0 | } |
424 | |
|
425 | 0 | if (line[0] == '\t') { |
426 | 0 | size_t linelen = strlen(line + 1); |
427 | 0 | if (linelen < TextWidth) { |
428 | 0 | leadspace = (TextWidth - linelen) / 2; |
429 | 0 | } |
430 | 0 | ++line; |
431 | 0 | } |
432 | |
|
433 | 0 | if ((size_t)i <= (size_t)(INT_MAX / GIF_FONT_HEIGHT)) { |
434 | 0 | int text_x = x + border; |
435 | 0 | int text_y = y + border + (GIF_FONT_HEIGHT * i++); |
436 | |
|
437 | 0 | if (leadspace <= (size_t)(INT_MAX / GIF_FONT_WIDTH) && |
438 | 0 | text_x <= INT_MAX - (int)(leadspace * GIF_FONT_WIDTH)) { |
439 | 0 | text_x += (int)(leadspace * GIF_FONT_WIDTH); |
440 | 0 | } |
441 | 0 | GifDrawText8x8(Image, text_x, text_y, line, fg); |
442 | 0 | } |
443 | 0 | } |
444 | 0 | free(dup); |
445 | | |
446 | | /* outline the box */ |
447 | 0 | GifDrawBox(Image, x, y, (int)box_w, (int)box_h, fg); |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | /* end */ |