rgd 0.4.1a → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
File without changes
data/Rakefile CHANGED
@@ -1,48 +1,67 @@
1
- # coding: utf-8
2
-
3
- require 'rubygems'
4
- require 'rake'
5
- require 'rake/clean'
6
- require 'rake/gempackagetask'
7
- require 'rake/rdoctask'
8
- require 'rake/testtask'
9
-
10
- spec = Gem::Specification.new do |s|
11
- s.name = 'rgd'
12
- s.version = '0.4.1a'
13
- s.has_rdoc = true
14
- s.extra_rdoc_files = ['README', 'COPYING']
15
- s.summary = 'libgd binding for Ruby'
16
- s.description = s.summary
17
- s.author = 'oCameLo'
18
- s.email = ''
19
- s.homepage = 'http://otnth.blogspot.com'
20
- # s.executables = ['your_executable_here']
21
- s.files = %w(BSDL COPYING Rakefile README) + Dir.glob("{bin,ext,lib,test}/**/*")
22
- s.require_path = "lib"
23
- s.bindir = "bin"
24
- if $WIN32 then
25
- s.platform = Gem::Platform::CURRENT
26
- else
27
- s.extensions = 'ext/rgd/extconf.rb'
28
- end
29
- end
30
-
31
- Rake::GemPackageTask.new(spec) do |pkg|
32
- pkg.gem_spec = spec
33
- pkg.need_tar = true
34
- pkg.need_zip = true
35
- end
36
-
37
- Rake::RDocTask.new do |rdoc|
38
- files =['README', 'COPYING', 'lib/**/*.rb'] + Dir.glob("ext/**/*.c")
39
- rdoc.rdoc_files.add(files)
40
- rdoc.main = "README" # page to start on
41
- rdoc.title = "RGD Docs"
42
- rdoc.rdoc_dir = 'doc' # rdoc output folder
43
- rdoc.options << '--line-numbers'
44
- end
45
-
46
- Rake::TestTask.new do |t|
47
- t.test_files = FileList['test/main.rb']
48
- end
1
+ # coding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/clean'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/testtask'
9
+
10
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'lib/rgd/version')
11
+
12
+ spec = Gem::Specification.new do |s|
13
+ s.name = 'rgd'
14
+ s.version = RGD::VERSION
15
+ s.has_rdoc = true
16
+ s.extra_rdoc_files = ['README.rdoc', 'COPYING.rdoc']
17
+ s.summary = 'libgd binding for Ruby'
18
+ s.description = s.summary
19
+ s.author = 'oCameLo'
20
+ s.email = ''
21
+ s.homepage = 'https://github.com/oTnTh/rgd'
22
+ # s.executables = ['your_executable_here']
23
+ s.files = %w(BSDL COPYING.rdoc Rakefile README.rdoc) + Dir.glob("{bin,ext,lib,test}/**/*")
24
+ s.require_path = "lib"
25
+ s.bindir = "bin"
26
+ if $WIN32 then
27
+ s.platform = Gem::Platform::CURRENT
28
+ else
29
+ s.extensions = 'ext/rgd/extconf.rb'
30
+ end
31
+ end
32
+
33
+ CLEAN.include ['pkg', '**/*.o', '**/*.log', '**/*.def', '**/Makefile', 'ext/**/*.so']
34
+ task :build => :clean do
35
+ spec.extensions.each do |extconf|
36
+ Dir.chdir(File.dirname(File.expand_path(extconf))) do
37
+ unless sh "ruby #{File.basename(extconf)}"
38
+ $stderr.puts "Failed to run extconf"
39
+ break
40
+ end
41
+
42
+ unless sh "make"
43
+ $stderr.puts "Failed to make"
44
+ break
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Rake::GemPackageTask.new(spec) do |pkg|
51
+ pkg.gem_spec = spec
52
+ pkg.need_tar = true
53
+ pkg.need_zip = true
54
+ end
55
+
56
+ Rake::RDocTask.new do |rdoc|
57
+ files =['README.rdoc', 'COPYING.rdoc', 'lib/**/*.rb'] + Dir.glob("ext/**/*.c")
58
+ rdoc.rdoc_files.add(files)
59
+ rdoc.main = "README.rdoc" # page to start on
60
+ rdoc.title = "RGD Docs"
61
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
62
+ rdoc.options << '--line-numbers'
63
+ end
64
+
65
+ Rake::TestTask.new do |t|
66
+ t.test_files = FileList['test/main.rb']
67
+ end
@@ -1,114 +1,114 @@
1
- /* $Id$ */
2
- #ifdef __cplusplus
3
- extern "C" {
4
- #endif
5
-
6
- /*
7
- gd_bmp.c
8
-
9
- Bitmap format support for libgd
10
-
11
- * Written 2007, Scott MacVicar
12
- ---------------------------------------------------------------------------
13
-
14
- Todo:
15
-
16
- RLE4, RLE8 and Bitfield encoding
17
- Add full support for Windows v4 and Windows v5 header formats
18
-
19
- ----------------------------------------------------------------------------
20
- */
21
-
22
- #ifndef BMP_H
23
- #define BMP_H 1
24
-
25
- #define BMP_PALETTE_3 1
26
- #define BMP_PALETTE_4 2
27
-
28
- #define BMP_WINDOWS_V3 40
29
- #define BMP_OS2_V1 12
30
- #define BMP_OS2_V2 64
31
- #define BMP_WINDOWS_V4 108
32
- #define BMP_WINDOWS_V5 124
33
-
34
- #define BMP_BI_RGB 0
35
- #define BMP_BI_RLE8 1
36
- #define BMP_BI_RLE4 2
37
- #define BMP_BI_BITFIELDS 3
38
- #define BMP_BI_JPEG 4
39
- #define BMP_BI_PNG 5
40
-
41
- #define BMP_RLE_COMMAND 0
42
- #define BMP_RLE_ENDOFLINE 0
43
- #define BMP_RLE_ENDOFBITMAP 1
44
- #define BMP_RLE_DELTA 2
45
-
46
- #define BMP_RLE_TYPE_RAW 0
47
- #define BMP_RLE_TYPE_RLE 1
48
-
49
- /* BMP header. */
50
- typedef struct
51
- {
52
- /* 16 bit - header identifying the type */
53
- signed short int magic;
54
-
55
- /* 32bit - size of the file */
56
- int size;
57
-
58
- /* 16bit - these two are in the spec but "reserved" */
59
- signed short int reserved1;
60
- signed short int reserved2;
61
-
62
- /* 32 bit - offset of the bitmap header from data in bytes */
63
- signed int off;
64
-
65
- } bmp_hdr_t;
66
-
67
- /* BMP info. */
68
- typedef struct
69
- {
70
- /* 16bit - Type, ie Windows or OS/2 for the palette info */
71
- signed short int type;
72
- /* 32bit - The length of the bitmap information header in bytes. */
73
- signed int len;
74
-
75
- /* 32bit - The width of the bitmap in pixels. */
76
- signed int width;
77
-
78
- /* 32bit - The height of the bitmap in pixels. */
79
- signed int height;
80
-
81
- /* 8 bit - The bitmap data is specified in top-down order. */
82
- signed char topdown;
83
-
84
- /* 16 bit - The number of planes. This must be set to a value of one. */
85
- signed short int numplanes;
86
-
87
- /* 16 bit - The number of bits per pixel. */
88
- signed short int depth;
89
-
90
- /* 32bit - The type of compression used. */
91
- signed int enctype;
92
-
93
- /* 32bit - The size of the image in bytes. */
94
- signed int size;
95
-
96
- /* 32bit - The horizontal resolution in pixels/metre. */
97
- signed int hres;
98
-
99
- /* 32bit - The vertical resolution in pixels/metre. */
100
- signed int vres;
101
-
102
- /* 32bit - The number of color indices used by the bitmap. */
103
- signed int numcolors;
104
-
105
- /* 32bit - The number of color indices important for displaying the bitmap. */
106
- signed int mincolors;
107
-
108
- } bmp_info_t;
109
-
110
- #endif
111
-
112
- #ifdef __cplusplus
113
- }
114
- #endif
1
+ /* $Id$ */
2
+ #ifdef __cplusplus
3
+ extern "C" {
4
+ #endif
5
+
6
+ /*
7
+ gd_bmp.c
8
+
9
+ Bitmap format support for libgd
10
+
11
+ * Written 2007, Scott MacVicar
12
+ ---------------------------------------------------------------------------
13
+
14
+ Todo:
15
+
16
+ RLE4, RLE8 and Bitfield encoding
17
+ Add full support for Windows v4 and Windows v5 header formats
18
+
19
+ ----------------------------------------------------------------------------
20
+ */
21
+
22
+ #ifndef BMP_H
23
+ #define BMP_H 1
24
+
25
+ #define BMP_PALETTE_3 1
26
+ #define BMP_PALETTE_4 2
27
+
28
+ #define BMP_WINDOWS_V3 40
29
+ #define BMP_OS2_V1 12
30
+ #define BMP_OS2_V2 64
31
+ #define BMP_WINDOWS_V4 108
32
+ #define BMP_WINDOWS_V5 124
33
+
34
+ #define BMP_BI_RGB 0
35
+ #define BMP_BI_RLE8 1
36
+ #define BMP_BI_RLE4 2
37
+ #define BMP_BI_BITFIELDS 3
38
+ #define BMP_BI_JPEG 4
39
+ #define BMP_BI_PNG 5
40
+
41
+ #define BMP_RLE_COMMAND 0
42
+ #define BMP_RLE_ENDOFLINE 0
43
+ #define BMP_RLE_ENDOFBITMAP 1
44
+ #define BMP_RLE_DELTA 2
45
+
46
+ #define BMP_RLE_TYPE_RAW 0
47
+ #define BMP_RLE_TYPE_RLE 1
48
+
49
+ /* BMP header. */
50
+ typedef struct
51
+ {
52
+ /* 16 bit - header identifying the type */
53
+ signed short int magic;
54
+
55
+ /* 32bit - size of the file */
56
+ int size;
57
+
58
+ /* 16bit - these two are in the spec but "reserved" */
59
+ signed short int reserved1;
60
+ signed short int reserved2;
61
+
62
+ /* 32 bit - offset of the bitmap header from data in bytes */
63
+ signed int off;
64
+
65
+ } bmp_hdr_t;
66
+
67
+ /* BMP info. */
68
+ typedef struct
69
+ {
70
+ /* 16bit - Type, ie Windows or OS/2 for the palette info */
71
+ signed short int type;
72
+ /* 32bit - The length of the bitmap information header in bytes. */
73
+ signed int len;
74
+
75
+ /* 32bit - The width of the bitmap in pixels. */
76
+ signed int width;
77
+
78
+ /* 32bit - The height of the bitmap in pixels. */
79
+ signed int height;
80
+
81
+ /* 8 bit - The bitmap data is specified in top-down order. */
82
+ signed char topdown;
83
+
84
+ /* 16 bit - The number of planes. This must be set to a value of one. */
85
+ signed short int numplanes;
86
+
87
+ /* 16 bit - The number of bits per pixel. */
88
+ signed short int depth;
89
+
90
+ /* 32bit - The type of compression used. */
91
+ signed int enctype;
92
+
93
+ /* 32bit - The size of the image in bytes. */
94
+ signed int size;
95
+
96
+ /* 32bit - The horizontal resolution in pixels/metre. */
97
+ signed int hres;
98
+
99
+ /* 32bit - The vertical resolution in pixels/metre. */
100
+ signed int vres;
101
+
102
+ /* 32bit - The number of color indices used by the bitmap. */
103
+ signed int numcolors;
104
+
105
+ /* 32bit - The number of color indices important for displaying the bitmap. */
106
+ signed int mincolors;
107
+
108
+ } bmp_info_t;
109
+
110
+ #endif
111
+
112
+ #ifdef __cplusplus
113
+ }
114
+ #endif
@@ -1,1130 +1,1130 @@
1
- /*
2
- gd_bmp.c
3
-
4
- Bitmap format support for libgd
5
-
6
- * Written 2007, Scott MacVicar
7
- ---------------------------------------------------------------------------
8
-
9
- Todo:
10
-
11
- Bitfield encoding
12
-
13
- ----------------------------------------------------------------------------
14
- */
15
- /* $Id$ */
16
- #ifdef HAVE_CONFIG_H
17
- #include "config.h"
18
- #endif
19
-
20
- #include <stdio.h>
21
- #include <math.h>
22
- #include <string.h>
23
- #include <stdlib.h>
24
- #include "gd.h"
25
- #include "gdhelpers.h"
26
- #include "bmp.h"
27
-
28
- static int compress_row(unsigned char *uncompressed_row, int length);
29
- static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
30
-
31
- static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
32
- static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
33
- static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
34
- static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
35
- static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
36
-
37
- static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
38
- static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
39
- static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
40
- static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
41
- static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
42
-
43
- #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
44
- /* Byte helper functions, since added to GD 2.1 */
45
- static int gdGetIntLSB(signed int *result, gdIOCtx * ctx);
46
- static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx);
47
- #endif
48
-
49
- #define BMP_DEBUG(s)
50
-
51
- static int gdBMPPutWord(gdIOCtx *out, int w)
52
- {
53
- /* Byte order is little-endian */
54
- gdPutC(w & 0xFF, out);
55
- gdPutC((w >> 8) & 0xFF, out);
56
- return 0;
57
- }
58
-
59
- static int gdBMPPutInt(gdIOCtx *out, int w)
60
- {
61
- /* Byte order is little-endian */
62
- gdPutC(w & 0xFF, out);
63
- gdPutC((w >> 8) & 0xFF, out);
64
- gdPutC((w >> 16) & 0xFF, out);
65
- gdPutC((w >> 24) & 0xFF, out);
66
- return 0;
67
- }
68
-
69
- BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
70
- {
71
- int bitmap_size = 0, info_size, total_size, padding;
72
- int i, row, xpos, pixel;
73
- int error = 0;
74
- unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
75
- FILE *tmpfile_for_compression = NULL;
76
- gdIOCtxPtr out_original = NULL;
77
-
78
- /* No compression if its true colour or we don't support seek */
79
- if (im->trueColor) {
80
- compression = 0;
81
- }
82
-
83
- if (compression == 1 && !out->seek) {
84
- /* Try to create a temp file where we can seek */
85
- if ((tmpfile_for_compression = tmpfile()) == NULL) {
86
- compression = 0;
87
- } else {
88
- out_original = out;
89
- if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
90
- out = out_original;
91
- out_original = NULL;
92
- compression = 0;
93
- }
94
- }
95
- }
96
-
97
- bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
98
-
99
- /* 40 byte Windows v3 header */
100
- info_size = BMP_WINDOWS_V3;
101
-
102
- /* data for the palette */
103
- if (!im->trueColor) {
104
- info_size += im->colorsTotal * 4;
105
- if (compression) {
106
- bitmap_size = 0;
107
- }
108
- }
109
-
110
- /* bitmap header + info header + data */
111
- total_size = 14 + info_size + bitmap_size;
112
-
113
- /* write bmp header info */
114
- gdPutBuf("BM", 2, out);
115
- gdBMPPutInt(out, total_size);
116
- gdBMPPutWord(out, 0);
117
- gdBMPPutWord(out, 0);
118
- gdBMPPutInt(out, 14 + info_size);
119
-
120
- /* write Windows v3 headers */
121
- gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
122
- gdBMPPutInt(out, im->sx); /* width */
123
- gdBMPPutInt(out, im->sy); /* height */
124
- gdBMPPutWord(out, 1); /* colour planes */
125
- gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
126
- gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
127
- gdBMPPutInt(out, bitmap_size); /* image size */
128
- gdBMPPutInt(out, 0); /* H resolution */
129
- gdBMPPutInt(out, 0); /* V ressolution */
130
- gdBMPPutInt(out, im->colorsTotal); /* colours used */
131
- gdBMPPutInt(out, 0); /* important colours */
132
-
133
- /* The line must be divisible by 4, else its padded with NULLs */
134
- padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
135
- if (padding) {
136
- padding = 4 - padding;
137
- }
138
-
139
- /* 8-bit colours */
140
- if (!im->trueColor) {
141
- for(i = 0; i< im->colorsTotal; ++i) {
142
- Putchar(gdImageBlue(im, i), out);
143
- Putchar(gdImageGreen(im, i), out);
144
- Putchar(gdImageRed(im, i), out);
145
- Putchar(0, out);
146
- }
147
-
148
- if (compression) {
149
- /* Can potentially change this to X + ((X / 128) * 3) */
150
- uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
151
- if (!uncompressed_row) {
152
- /* malloc failed */
153
- goto cleanup;
154
- }
155
- }
156
-
157
- for (row = (im->sy - 1); row >= 0; row--) {
158
- if (compression) {
159
- memset (uncompressed_row, 0, gdImageSX(im));
160
- }
161
-
162
- for (xpos = 0; xpos < im->sx; xpos++) {
163
- if (compression) {
164
- *uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
165
- } else {
166
- Putchar(gdImageGetPixel(im, xpos, row), out);
167
- }
168
- }
169
-
170
- if (!compression) {
171
- /* Add padding to make sure we have n mod 4 == 0 bytes per row */
172
- for (xpos = padding; xpos > 0; --xpos) {
173
- Putchar('\0', out);
174
- }
175
- } else {
176
- int compressed_size = 0;
177
- uncompressed_row = uncompressed_row_start;
178
- if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
179
- error = 1;
180
- break;
181
- }
182
- bitmap_size += compressed_size;
183
-
184
-
185
- gdPutBuf(uncompressed_row, compressed_size, out);
186
- Putchar(BMP_RLE_COMMAND, out);
187
- Putchar(BMP_RLE_ENDOFLINE, out);
188
- bitmap_size += 2;
189
- }
190
- }
191
-
192
- if (compression && uncompressed_row) {
193
- gdFree(uncompressed_row);
194
- if (error != 0) {
195
- goto cleanup;
196
- }
197
- /* Update filesize based on new values and set compression flag */
198
- Putchar(BMP_RLE_COMMAND, out);
199
- Putchar(BMP_RLE_ENDOFBITMAP, out);
200
- bitmap_size += 2;
201
-
202
- /* Write new total bitmap size */
203
- gdSeek(out, 2);
204
- gdBMPPutInt(out, total_size + bitmap_size);
205
-
206
- /* Total length of image data */
207
- gdSeek(out, 34);
208
- gdBMPPutInt(out, bitmap_size);
209
- }
210
-
211
- } else {
212
- for (row = (im->sy - 1); row >= 0; row--) {
213
- for (xpos = 0; xpos < im->sx; xpos++) {
214
- pixel = gdImageGetPixel(im, xpos, row);
215
-
216
- Putchar(gdTrueColorGetBlue(pixel), out);
217
- Putchar(gdTrueColorGetGreen(pixel), out);
218
- Putchar(gdTrueColorGetRed(pixel), out);
219
- }
220
-
221
- /* Add padding to make sure we have n mod 4 == 0 bytes per row */
222
- for (xpos = padding; xpos > 0; --xpos) {
223
- Putchar('\0', out);
224
- }
225
- }
226
- }
227
-
228
-
229
- /* If we needed a tmpfile for compression copy it over to out_original */
230
- if (tmpfile_for_compression) {
231
- unsigned char* copy_buffer = NULL;
232
- int buffer_size = 0;
233
-
234
- gdSeek(out, 0);
235
- copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
236
- if (copy_buffer == NULL) {
237
- goto cleanup;
238
- }
239
-
240
- while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
241
- if (buffer_size == 0) {
242
- break;
243
- }
244
- gdPutBuf(copy_buffer , buffer_size, out_original);
245
- }
246
- gdFree(copy_buffer);
247
-
248
- /* Replace the temp with the original which now has data */
249
- out->gd_free(out);
250
- out = out_original;
251
- out_original = NULL;
252
- }
253
-
254
- cleanup:
255
- if (tmpfile_for_compression) {
256
- #ifdef WIN32
257
- _rmtmp();
258
- #else
259
- fclose(tmpfile_for_compression);
260
- #endif
261
- tmpfile_for_compression = NULL;
262
- }
263
-
264
- if (out_original) {
265
- out_original->gd_free(out_original);
266
- }
267
- return;
268
- }
269
-
270
- BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
271
- {
272
- void *rv;
273
- gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
274
- gdImageBmpCtx(im, out, compression);
275
- rv = gdDPExtractData(out, size);
276
- out->gd_free(out);
277
- return rv;
278
- }
279
-
280
- BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
281
- {
282
- gdIOCtx *out = gdNewFileCtx(outFile);
283
- gdImageBmpCtx(im, out, compression);
284
- out->gd_free(out);
285
- }
286
-
287
- static int compress_row(unsigned char *row, int length)
288
- {
289
- int rle_type = 0;
290
- int compressed_length = 0;
291
- int pixel = 0, compressed_run = 0, rle_compression = 0;
292
- unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
293
-
294
- uncompressed_row = (unsigned char *) gdMalloc(length);
295
- if (!uncompressed_row) {
296
- return -1;
297
- }
298
-
299
- memcpy(uncompressed_row, row, length);
300
- uncompressed_start = uncompressed_rowp = uncompressed_row;
301
-
302
- for (pixel = 0; pixel < length; pixel++)
303
- {
304
- if (compressed_run == 0) {
305
- uncompressed_row = uncompressed_rowp;
306
- compressed_run++;
307
- uncompressed_rowp++;
308
- rle_type = BMP_RLE_TYPE_RAW;
309
- continue;
310
- }
311
-
312
- if (compressed_run == 1) {
313
- /* Compare next byte */
314
- if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
315
- rle_type = BMP_RLE_TYPE_RLE;
316
- }
317
- }
318
-
319
- if (rle_type == BMP_RLE_TYPE_RLE) {
320
- if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
321
- /* more than what we can store in a single run or run is over due to non match, force write */
322
- rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
323
- row += rle_compression;
324
- compressed_length += rle_compression;
325
- compressed_run = 0;
326
- pixel--;
327
- } else {
328
- compressed_run++;
329
- uncompressed_rowp++;
330
- }
331
- } else {
332
- if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
333
- /* more than what we can store in a single run or run is over due to match, force write */
334
- rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
335
- row += rle_compression;
336
- compressed_length += rle_compression;
337
- compressed_run = 0;
338
- pixel--;
339
- } else {
340
- /* add this pixel to the row */
341
- compressed_run++;
342
- uncompressed_rowp++;
343
- }
344
-
345
- }
346
- }
347
-
348
- if (compressed_run) {
349
- if (rle_type == BMP_RLE_TYPE_RLE) {
350
- compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
351
- } else {
352
- compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
353
- }
354
- }
355
-
356
- gdFree(uncompressed_start);
357
-
358
- return compressed_length;
359
- }
360
-
361
- static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
362
- {
363
- int compressed_size = 0;
364
- if (length < 1 || length > 128) {
365
- return 0;
366
- }
367
-
368
- /* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
369
- if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
370
- int i = 0;
371
- for (i = 0; i < length; i++) {
372
- compressed_size += 2;
373
- memset(row, 1, 1);
374
- row++;
375
-
376
- memcpy(row, data++, 1);
377
- row++;
378
- }
379
- } else if (packet_type == BMP_RLE_TYPE_RLE) {
380
- compressed_size = 2;
381
- memset(row, length, 1);
382
- row++;
383
-
384
- memcpy(row, data, 1);
385
- row++;
386
- } else {
387
- compressed_size = 2 + length;
388
- memset(row, BMP_RLE_COMMAND, 1);
389
- row++;
390
-
391
- memset(row, length, 1);
392
- row++;
393
-
394
- memcpy(row, data, length);
395
- row += length;
396
-
397
- /* Must be an even number for an uncompressed run */
398
- if (length % 2) {
399
- memset(row, 0, 1);
400
- row++;
401
- compressed_size++;
402
- }
403
- }
404
- return compressed_size;
405
- }
406
-
407
- BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
408
- {
409
- bmp_hdr_t *hdr;
410
- bmp_info_t *info;
411
- gdImagePtr im = NULL;
412
- int error = 0;
413
-
414
- if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
415
- return NULL;
416
- }
417
-
418
- if (bmp_read_header(infile, hdr)) {
419
- gdFree(hdr);
420
- return NULL;
421
- }
422
-
423
- if (hdr->magic != 0x4d42) {
424
- gdFree(hdr);
425
- return NULL;
426
- }
427
-
428
- if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
429
- gdFree(hdr);
430
- return NULL;
431
- }
432
-
433
- if (bmp_read_info(infile, info)) {
434
- gdFree(hdr);
435
- gdFree(info);
436
- return NULL;
437
- }
438
-
439
- BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
440
- BMP_DEBUG(printf("Width: %d\n", info->width));
441
- BMP_DEBUG(printf("Height: %d\n", info->height));
442
- BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
443
- BMP_DEBUG(printf("Depth: %d\n", info->depth));
444
- BMP_DEBUG(printf("Offset: %d\n", hdr->off));
445
-
446
- if (info->depth >= 16) {
447
- im = gdImageCreateTrueColor(info->width, info->height);
448
- } else {
449
- im = gdImageCreate(info->width, info->height);
450
- }
451
-
452
- if (!im) {
453
- gdFree(hdr);
454
- gdFree(info);
455
- return NULL;
456
- }
457
-
458
- switch (info->depth) {
459
- case 1:
460
- BMP_DEBUG(printf("1-bit image\n"));
461
- error = bmp_read_1bit(im, infile, info, hdr);
462
- break;
463
- case 4:
464
- BMP_DEBUG(printf("4-bit image\n"));
465
- error = bmp_read_4bit(im, infile, info, hdr);
466
- break;
467
- case 8:
468
- BMP_DEBUG(printf("8-bit image\n"));
469
- error = bmp_read_8bit(im, infile, info, hdr);
470
- break;
471
- case 16:
472
- case 24:
473
- case 32:
474
- BMP_DEBUG(printf("Direct BMP image\n"));
475
- error = bmp_read_direct(im, infile, info, hdr);
476
- break;
477
- default:
478
- BMP_DEBUG(printf("Unknown bit count\n"));
479
- error = 1;
480
- }
481
-
482
- gdFree(hdr);
483
- gdFree(info);
484
-
485
- if (error) {
486
- gdImageDestroy(im);
487
- return NULL;
488
- }
489
-
490
- return im;
491
- }
492
-
493
- BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
494
- {
495
- gdImagePtr im = 0;
496
- gdIOCtx *in = gdNewFileCtx(inFile);
497
- im = gdImageCreateFromBmpCtx(in);
498
- in->gd_free(in);
499
- return im;
500
- }
501
-
502
- BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
503
- {
504
- gdImagePtr im;
505
- gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
506
- im = gdImageCreateFromBmpCtx(in);
507
- in->gd_free(in);
508
- return im;
509
- }
510
-
511
- static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
512
- {
513
- if(
514
- !gdGetWordLSB(&hdr->magic, infile) ||
515
- !gdGetIntLSB(&hdr->size, infile) ||
516
- !gdGetWordLSB(&hdr->reserved1, infile) ||
517
- !gdGetWordLSB(&hdr->reserved2 , infile) ||
518
- !gdGetIntLSB(&hdr->off , infile)
519
- ) {
520
- return 1;
521
- }
522
- return 0;
523
- }
524
-
525
- static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
526
- {
527
- /* read BMP length so we can work out the version */
528
- if (!gdGetIntLSB(&info->len, infile)) {
529
- return 1;
530
- }
531
-
532
- switch (info->len) {
533
- /* For now treat Windows v4 + v5 as v3 */
534
- case BMP_WINDOWS_V3:
535
- case BMP_WINDOWS_V4:
536
- case BMP_WINDOWS_V5:
537
- BMP_DEBUG(printf("Reading Windows Header\n"));
538
- if (bmp_read_windows_v3_info(infile, info)) {
539
- return 1;
540
- }
541
- break;
542
- case BMP_OS2_V1:
543
- if (bmp_read_os2_v1_info(infile, info)) {
544
- return 1;
545
- }
546
- break;
547
- case BMP_OS2_V2:
548
- if (bmp_read_os2_v2_info(infile, info)) {
549
- return 1;
550
- }
551
- break;
552
- default:
553
- BMP_DEBUG(printf("Unhandled bitmap\n"));
554
- return 1;
555
- }
556
- return 0;
557
- }
558
-
559
- static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
560
- {
561
- if (
562
- !gdGetIntLSB(&info->width, infile) ||
563
- !gdGetIntLSB(&info->height, infile) ||
564
- !gdGetWordLSB(&info->numplanes, infile) ||
565
- !gdGetWordLSB(&info->depth, infile) ||
566
- !gdGetIntLSB(&info->enctype, infile) ||
567
- !gdGetIntLSB(&info->size, infile) ||
568
- !gdGetIntLSB(&info->hres, infile) ||
569
- !gdGetIntLSB(&info->vres, infile) ||
570
- !gdGetIntLSB(&info->numcolors, infile) ||
571
- !gdGetIntLSB(&info->mincolors, infile)
572
- ) {
573
- return 1;
574
- }
575
-
576
- if (info->height < 0) {
577
- info->topdown = 1;
578
- info->height = -info->height;
579
- } else {
580
- info->topdown = 0;
581
- }
582
-
583
- info->type = BMP_PALETTE_4;
584
-
585
- if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
586
- info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
587
- return 1;
588
- }
589
-
590
- return 0;
591
- }
592
-
593
- static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
594
- {
595
- if (
596
- !gdGetWordLSB((signed short int *)&info->width, infile) ||
597
- !gdGetWordLSB((signed short int *)&info->height, infile) ||
598
- !gdGetWordLSB(&info->numplanes, infile) ||
599
- !gdGetWordLSB(&info->depth, infile)
600
- ) {
601
- return 1;
602
- }
603
-
604
- /* OS2 v1 doesn't support topdown */
605
- info->topdown = 0;
606
-
607
- info->numcolors = 1 << info->depth;
608
- info->type = BMP_PALETTE_3;
609
-
610
- if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
611
- info->depth <= 0 || info->numcolors < 0) {
612
- return 1;
613
- }
614
-
615
- return 0;
616
- }
617
-
618
- static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
619
- {
620
- char useless_bytes[24];
621
- if (
622
- !gdGetIntLSB(&info->width, infile) ||
623
- !gdGetIntLSB(&info->height, infile) ||
624
- !gdGetWordLSB(&info->numplanes, infile) ||
625
- !gdGetWordLSB(&info->depth, infile) ||
626
- !gdGetIntLSB(&info->enctype, infile) ||
627
- !gdGetIntLSB(&info->size, infile) ||
628
- !gdGetIntLSB(&info->hres, infile) ||
629
- !gdGetIntLSB(&info->vres, infile) ||
630
- !gdGetIntLSB(&info->numcolors, infile) ||
631
- !gdGetIntLSB(&info->mincolors, infile)
632
- ) {
633
- return 1;
634
- }
635
-
636
- /* Lets seek the next 24 pointless bytes, we don't care too much about it */
637
- if (!gdGetBuf(useless_bytes, 24, infile)) {
638
- return 1;
639
- }
640
-
641
- if (info->height < 0) {
642
- info->topdown = 1;
643
- info->height = -info->height;
644
- } else {
645
- info->topdown = 0;
646
- }
647
-
648
- info->type = BMP_PALETTE_4;
649
-
650
- if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
651
- info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
652
- return 1;
653
- }
654
-
655
-
656
- return 0;
657
- }
658
-
659
- static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
660
- {
661
- int ypos = 0, xpos = 0, row = 0;
662
- int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
663
- signed short int data = 0;
664
-
665
- switch(info->enctype) {
666
- case BMP_BI_RGB:
667
- /* no-op */
668
- break;
669
-
670
- case BMP_BI_BITFIELDS:
671
- if (info->depth == 24) {
672
- BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
673
- return 1;
674
- }
675
- BMP_DEBUG(printf("Currently no bitfield support\n"));
676
- return 1;
677
- break;
678
-
679
- case BMP_BI_RLE8:
680
- if (info->depth != 8) {
681
- BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
682
- return 1;
683
- }
684
- case BMP_BI_RLE4:
685
- if (info->depth != 4) {
686
- BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
687
- return 1;
688
- }
689
- case BMP_BI_JPEG:
690
- case BMP_BI_PNG:
691
- default:
692
- BMP_DEBUG(printf("Unsupported BMP compression format\n"));
693
- return 1;
694
- }
695
-
696
- /* There is a chance the data isn't until later, would be wierd but it is possible */
697
- if (gdTell(infile) != header->off) {
698
- /* Should make sure we don't seek past the file size */
699
- gdSeek(infile, header->off);
700
- }
701
-
702
- /* The line must be divisible by 4, else its padded with NULLs */
703
- padding = ((int)(info->depth / 8) * info->width) % 4;
704
- if (padding) {
705
- padding = 4 - padding;
706
- }
707
-
708
-
709
- for (ypos = 0; ypos < info->height; ++ypos) {
710
- if (info->topdown) {
711
- row = ypos;
712
- } else {
713
- row = info->height - ypos - 1;
714
- }
715
-
716
- for (xpos = 0; xpos < info->width; xpos++) {
717
- if (info->depth == 16) {
718
- if (!gdGetWordLSB(&data, infile)) {
719
- return 1;
720
- }
721
- BMP_DEBUG(printf("Data: %X\n", data));
722
- red = ((data & 0x7C00) >> 10) << 3;
723
- green = ((data & 0x3E0) >> 5) << 3;
724
- blue = (data & 0x1F) << 3;
725
- BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
726
- } else if (info->depth == 24) {
727
- if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
728
- return 1;
729
- }
730
- } else {
731
- if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
732
- return 1;
733
- }
734
- }
735
- /*alpha = gdAlphaMax - (alpha >> 1);*/
736
- gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
737
- }
738
- for (xpos = padding; xpos > 0; --xpos) {
739
- if (!gdGetByte(&red, infile)) {
740
- return 1;
741
- }
742
- }
743
- }
744
-
745
- return 0;
746
- }
747
-
748
- static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
749
- {
750
- int i;
751
- int r, g, b, z;
752
-
753
- for (i = 0; i < count; i++) {
754
- if (
755
- !gdGetByte(&r, infile) ||
756
- !gdGetByte(&g, infile) ||
757
- !gdGetByte(&b, infile) ||
758
- (read_four && !gdGetByte(&z, infile))
759
- ) {
760
- return 1;
761
- }
762
- im->red[i] = r;
763
- im->green[i] = g;
764
- im->blue[i] = b;
765
- im->open[i] = 1;
766
- }
767
- return 0;
768
- }
769
-
770
- static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
771
- {
772
- int ypos = 0, xpos = 0, row = 0, index = 0;
773
- int padding = 0, current_byte = 0, bit = 0;
774
-
775
- if (info->enctype != BMP_BI_RGB) {
776
- return 1;
777
- }
778
-
779
- if (!info->numcolors) {
780
- info->numcolors = 2;
781
- } else if (info->numcolors < 0 || info->numcolors > 2) {
782
- return 1;
783
- }
784
-
785
- if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
786
- return 1;
787
- }
788
-
789
- im->colorsTotal = info->numcolors;
790
-
791
- /* There is a chance the data isn't until later, would be wierd but it is possible */
792
- if (gdTell(infile) != header->off) {
793
- /* Should make sure we don't seek past the file size */
794
- gdSeek(infile, header->off);
795
- }
796
-
797
- /* The line must be divisible by 4, else its padded with NULLs */
798
- padding = ((int)ceill(0.1 * info->width)) % 4;
799
- if (padding) {
800
- padding = 4 - padding;
801
- }
802
-
803
- for (ypos = 0; ypos < info->height; ++ypos) {
804
- if (info->topdown) {
805
- row = ypos;
806
- } else {
807
- row = info->height - ypos - 1;
808
- }
809
-
810
- for (xpos = 0; xpos < info->width; xpos += 8) {
811
- /* Bitmaps are always aligned in bytes so we'll never overflow */
812
- if (!gdGetByte(&current_byte, infile)) {
813
- return 1;
814
- }
815
-
816
- for (bit = 0; bit < 8; bit++) {
817
- index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
818
- if (im->open[index]) {
819
- im->open[index] = 0;
820
- }
821
- gdImageSetPixel(im, xpos + bit, row, index);
822
- /* No need to read anything extra */
823
- if ((xpos + bit) >= info->width) {
824
- break;
825
- }
826
- }
827
- }
828
-
829
- for (xpos = padding; xpos > 0; --xpos) {
830
- if (!gdGetByte(&index, infile)) {
831
- return 1;
832
- }
833
- }
834
- }
835
- return 0;
836
- }
837
-
838
- static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
839
- {
840
- int ypos = 0, xpos = 0, row = 0, index = 0;
841
- int padding = 0, current_byte = 0;
842
-
843
- if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
844
- return 1;
845
- }
846
-
847
- if (!info->numcolors) {
848
- info->numcolors = 16;
849
- } else if (info->numcolors < 0 || info->numcolors > 16) {
850
- return 1;
851
- }
852
-
853
- if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
854
- return 1;
855
- }
856
-
857
- im->colorsTotal = info->numcolors;
858
-
859
- /* There is a chance the data isn't until later, would be wierd but it is possible */
860
- if (gdTell(infile) != header->off) {
861
- /* Should make sure we don't seek past the file size */
862
- gdSeek(infile, header->off);
863
- }
864
-
865
- /* The line must be divisible by 4, else its padded with NULLs */
866
- padding = ((int)ceil(0.5 * info->width)) % 4;
867
- if (padding) {
868
- padding = 4 - padding;
869
- }
870
-
871
- switch (info->enctype) {
872
- case BMP_BI_RGB:
873
- for (ypos = 0; ypos < info->height; ++ypos) {
874
- if (info->topdown) {
875
- row = ypos;
876
- } else {
877
- row = info->height - ypos - 1;
878
- }
879
-
880
- for (xpos = 0; xpos < info->width; xpos += 2) {
881
- if (!gdGetByte(&current_byte, infile)) {
882
- return 1;
883
- }
884
-
885
- index = (current_byte >> 4) & 0x0f;
886
- if (im->open[index]) {
887
- im->open[index] = 0;
888
- }
889
- gdImageSetPixel(im, xpos, row, index);
890
-
891
- /* This condition may get called often, potential optimsations */
892
- if (xpos >= info->width) {
893
- break;
894
- }
895
-
896
- index = current_byte & 0x0f;
897
- if (im->open[index]) {
898
- im->open[index] = 0;
899
- }
900
- gdImageSetPixel(im, xpos + 1, row, index);
901
- }
902
-
903
- for (xpos = padding; xpos > 0; --xpos) {
904
- if (!gdGetByte(&index, infile)) {
905
- return 1;
906
- }
907
- }
908
- }
909
- break;
910
-
911
- case BMP_BI_RLE4:
912
- if (bmp_read_rle(im, infile, info)) {
913
- return 1;
914
- }
915
- break;
916
-
917
- default:
918
- return 1;
919
- }
920
- return 0;
921
- }
922
-
923
- static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
924
- {
925
- int ypos = 0, xpos = 0, row = 0, index = 0;
926
- int padding = 0;
927
-
928
- if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
929
- return 1;
930
- }
931
-
932
- if (!info->numcolors) {
933
- info->numcolors = 256;
934
- } else if (info->numcolors < 0 || info->numcolors > 256) {
935
- return 1;
936
- }
937
-
938
- if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
939
- return 1;
940
- }
941
-
942
- im->colorsTotal = info->numcolors;
943
-
944
- /* There is a chance the data isn't until later, would be wierd but it is possible */
945
- if (gdTell(infile) != header->off) {
946
- /* Should make sure we don't seek past the file size */
947
- gdSeek(infile, header->off);
948
- }
949
-
950
- /* The line must be divisible by 4, else its padded with NULLs */
951
- padding = (1 * info->width) % 4;
952
- if (padding) {
953
- padding = 4 - padding;
954
- }
955
-
956
- switch (info->enctype) {
957
- case BMP_BI_RGB:
958
- for (ypos = 0; ypos < info->height; ++ypos) {
959
- if (info->topdown) {
960
- row = ypos;
961
- } else {
962
- row = info->height - ypos - 1;
963
- }
964
-
965
- for (xpos = 0; xpos < info->width; ++xpos) {
966
- if (!gdGetByte(&index, infile)) {
967
- return 1;
968
- }
969
-
970
- if (im->open[index]) {
971
- im->open[index] = 0;
972
- }
973
- gdImageSetPixel(im, xpos, row, index);
974
- }
975
- /* Could create a new variable, but it isn't really worth it */
976
- for (xpos = padding; xpos > 0; --xpos) {
977
- if (!gdGetByte(&index, infile)) {
978
- return 1;
979
- }
980
- }
981
- }
982
- break;
983
-
984
- case BMP_BI_RLE8:
985
- if (bmp_read_rle(im, infile, info)) {
986
- return 1;
987
- }
988
- break;
989
-
990
- default:
991
- return 1;
992
- }
993
- return 0;
994
- }
995
-
996
- static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
997
- {
998
- int ypos = 0, xpos = 0, row = 0, index = 0;
999
- int rle_length = 0, rle_data = 0;
1000
- int padding = 0;
1001
- int i = 0, j = 0;
1002
- int pixels_per_byte = 8 / info->depth;
1003
-
1004
- for (ypos = 0; ypos < info->height && xpos <= info->width;) {
1005
- if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1006
- return 1;
1007
- }
1008
- row = info->height - ypos - 1;
1009
-
1010
- if (rle_length != BMP_RLE_COMMAND) {
1011
- if (im->open[rle_data]) {
1012
- im->open[rle_data] = 0;
1013
- }
1014
-
1015
- for (i = 0; (i < rle_length) && (xpos < info->width);) {
1016
- for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
1017
- index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
1018
- if (im->open[index]) {
1019
- im->open[index] = 0;
1020
- }
1021
- gdImageSetPixel(im, xpos, row, index);
1022
- }
1023
- }
1024
- } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
1025
- /* Uncompressed RLE needs to be even */
1026
- padding = 0;
1027
- for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
1028
- int max_pixels = pixels_per_byte;
1029
-
1030
- if (!gdGetByte(&index, infile)) {
1031
- return 1;
1032
- }
1033
- padding++;
1034
-
1035
- if (rle_data - i < max_pixels) {
1036
- max_pixels = rle_data - i;
1037
- }
1038
-
1039
- for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
1040
- int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
1041
- if (im->open[temp]) {
1042
- im->open[temp] = 0;
1043
- }
1044
- gdImageSetPixel(im, xpos, row, temp);
1045
- }
1046
- }
1047
-
1048
- /* Make sure the bytes read are even */
1049
- if (padding % 2 && !gdGetByte(&index, infile)) {
1050
- return 1;
1051
- }
1052
- } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
1053
- /* Next Line */
1054
- xpos = 0;
1055
- ypos++;
1056
- } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
1057
- /* Delta Record, used for bmp files that contain other data*/
1058
- if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1059
- return 1;
1060
- }
1061
- xpos += rle_length;
1062
- ypos += rle_data;
1063
- } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
1064
- /* End of bitmap */
1065
- break;
1066
- }
1067
- }
1068
- return 0;
1069
- }
1070
-
1071
- #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
1072
- static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx)
1073
- {
1074
- unsigned int high = 0, low = 0;
1075
- low = (ctx->getC) (ctx);
1076
- if (low == EOF) {
1077
- return 0;
1078
- }
1079
-
1080
- high = (ctx->getC) (ctx);
1081
- if (high == EOF) {
1082
- return 0;
1083
- }
1084
-
1085
- if (result) {
1086
- *result = (high << 8) | low;
1087
- }
1088
-
1089
- return 1;
1090
- }
1091
-
1092
- static int gdGetIntLSB(signed int *result, gdIOCtx * ctx)
1093
- {
1094
- int c = 0;
1095
- unsigned int r = 0;
1096
-
1097
- c = (ctx->getC) (ctx);
1098
- if (c == EOF) {
1099
- return 0;
1100
- }
1101
- r |= (c << 24);
1102
- r >>= 8;
1103
-
1104
- c = (ctx->getC) (ctx);
1105
- if (c == EOF) {
1106
- return 0;
1107
- }
1108
- r |= (c << 24);
1109
- r >>= 8;
1110
-
1111
- c = (ctx->getC) (ctx);
1112
- if (c == EOF) {
1113
- return 0;
1114
- }
1115
- r |= (c << 24);
1116
- r >>= 8;
1117
-
1118
- c = (ctx->getC) (ctx);
1119
- if (c == EOF) {
1120
- return 0;
1121
- }
1122
- r |= (c << 24);
1123
-
1124
- if (result) {
1125
- *result = (signed int)r;
1126
- }
1127
-
1128
- return 1;
1129
- }
1130
- #endif
1
+ /*
2
+ gd_bmp.c
3
+
4
+ Bitmap format support for libgd
5
+
6
+ * Written 2007, Scott MacVicar
7
+ ---------------------------------------------------------------------------
8
+
9
+ Todo:
10
+
11
+ Bitfield encoding
12
+
13
+ ----------------------------------------------------------------------------
14
+ */
15
+ /* $Id$ */
16
+ #ifdef HAVE_CONFIG_H
17
+ #include "config.h"
18
+ #endif
19
+
20
+ #include <stdio.h>
21
+ #include <math.h>
22
+ #include <string.h>
23
+ #include <stdlib.h>
24
+ #include "gd.h"
25
+ #include "gdhelpers.h"
26
+ #include "bmp.h"
27
+
28
+ static int compress_row(unsigned char *uncompressed_row, int length);
29
+ static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
30
+
31
+ static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
32
+ static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
33
+ static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
34
+ static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
35
+ static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
36
+
37
+ static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
38
+ static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
39
+ static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
40
+ static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
41
+ static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
42
+
43
+ #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
44
+ /* Byte helper functions, since added to GD 2.1 */
45
+ static int gdGetIntLSB(signed int *result, gdIOCtx * ctx);
46
+ static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx);
47
+ #endif
48
+
49
+ #define BMP_DEBUG(s)
50
+
51
+ static int gdBMPPutWord(gdIOCtx *out, int w)
52
+ {
53
+ /* Byte order is little-endian */
54
+ gdPutC(w & 0xFF, out);
55
+ gdPutC((w >> 8) & 0xFF, out);
56
+ return 0;
57
+ }
58
+
59
+ static int gdBMPPutInt(gdIOCtx *out, int w)
60
+ {
61
+ /* Byte order is little-endian */
62
+ gdPutC(w & 0xFF, out);
63
+ gdPutC((w >> 8) & 0xFF, out);
64
+ gdPutC((w >> 16) & 0xFF, out);
65
+ gdPutC((w >> 24) & 0xFF, out);
66
+ return 0;
67
+ }
68
+
69
+ BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
70
+ {
71
+ int bitmap_size = 0, info_size, total_size, padding;
72
+ int i, row, xpos, pixel;
73
+ int error = 0;
74
+ unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
75
+ FILE *tmpfile_for_compression = NULL;
76
+ gdIOCtxPtr out_original = NULL;
77
+
78
+ /* No compression if its true colour or we don't support seek */
79
+ if (im->trueColor) {
80
+ compression = 0;
81
+ }
82
+
83
+ if (compression == 1 && !out->seek) {
84
+ /* Try to create a temp file where we can seek */
85
+ if ((tmpfile_for_compression = tmpfile()) == NULL) {
86
+ compression = 0;
87
+ } else {
88
+ out_original = out;
89
+ if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
90
+ out = out_original;
91
+ out_original = NULL;
92
+ compression = 0;
93
+ }
94
+ }
95
+ }
96
+
97
+ bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
98
+
99
+ /* 40 byte Windows v3 header */
100
+ info_size = BMP_WINDOWS_V3;
101
+
102
+ /* data for the palette */
103
+ if (!im->trueColor) {
104
+ info_size += im->colorsTotal * 4;
105
+ if (compression) {
106
+ bitmap_size = 0;
107
+ }
108
+ }
109
+
110
+ /* bitmap header + info header + data */
111
+ total_size = 14 + info_size + bitmap_size;
112
+
113
+ /* write bmp header info */
114
+ gdPutBuf("BM", 2, out);
115
+ gdBMPPutInt(out, total_size);
116
+ gdBMPPutWord(out, 0);
117
+ gdBMPPutWord(out, 0);
118
+ gdBMPPutInt(out, 14 + info_size);
119
+
120
+ /* write Windows v3 headers */
121
+ gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
122
+ gdBMPPutInt(out, im->sx); /* width */
123
+ gdBMPPutInt(out, im->sy); /* height */
124
+ gdBMPPutWord(out, 1); /* colour planes */
125
+ gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
126
+ gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
127
+ gdBMPPutInt(out, bitmap_size); /* image size */
128
+ gdBMPPutInt(out, 0); /* H resolution */
129
+ gdBMPPutInt(out, 0); /* V ressolution */
130
+ gdBMPPutInt(out, im->colorsTotal); /* colours used */
131
+ gdBMPPutInt(out, 0); /* important colours */
132
+
133
+ /* The line must be divisible by 4, else its padded with NULLs */
134
+ padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
135
+ if (padding) {
136
+ padding = 4 - padding;
137
+ }
138
+
139
+ /* 8-bit colours */
140
+ if (!im->trueColor) {
141
+ for(i = 0; i< im->colorsTotal; ++i) {
142
+ Putchar(gdImageBlue(im, i), out);
143
+ Putchar(gdImageGreen(im, i), out);
144
+ Putchar(gdImageRed(im, i), out);
145
+ Putchar(0, out);
146
+ }
147
+
148
+ if (compression) {
149
+ /* Can potentially change this to X + ((X / 128) * 3) */
150
+ uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
151
+ if (!uncompressed_row) {
152
+ /* malloc failed */
153
+ goto cleanup;
154
+ }
155
+ }
156
+
157
+ for (row = (im->sy - 1); row >= 0; row--) {
158
+ if (compression) {
159
+ memset (uncompressed_row, 0, gdImageSX(im));
160
+ }
161
+
162
+ for (xpos = 0; xpos < im->sx; xpos++) {
163
+ if (compression) {
164
+ *uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
165
+ } else {
166
+ Putchar(gdImageGetPixel(im, xpos, row), out);
167
+ }
168
+ }
169
+
170
+ if (!compression) {
171
+ /* Add padding to make sure we have n mod 4 == 0 bytes per row */
172
+ for (xpos = padding; xpos > 0; --xpos) {
173
+ Putchar('\0', out);
174
+ }
175
+ } else {
176
+ int compressed_size = 0;
177
+ uncompressed_row = uncompressed_row_start;
178
+ if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
179
+ error = 1;
180
+ break;
181
+ }
182
+ bitmap_size += compressed_size;
183
+
184
+
185
+ gdPutBuf(uncompressed_row, compressed_size, out);
186
+ Putchar(BMP_RLE_COMMAND, out);
187
+ Putchar(BMP_RLE_ENDOFLINE, out);
188
+ bitmap_size += 2;
189
+ }
190
+ }
191
+
192
+ if (compression && uncompressed_row) {
193
+ gdFree(uncompressed_row);
194
+ if (error != 0) {
195
+ goto cleanup;
196
+ }
197
+ /* Update filesize based on new values and set compression flag */
198
+ Putchar(BMP_RLE_COMMAND, out);
199
+ Putchar(BMP_RLE_ENDOFBITMAP, out);
200
+ bitmap_size += 2;
201
+
202
+ /* Write new total bitmap size */
203
+ gdSeek(out, 2);
204
+ gdBMPPutInt(out, total_size + bitmap_size);
205
+
206
+ /* Total length of image data */
207
+ gdSeek(out, 34);
208
+ gdBMPPutInt(out, bitmap_size);
209
+ }
210
+
211
+ } else {
212
+ for (row = (im->sy - 1); row >= 0; row--) {
213
+ for (xpos = 0; xpos < im->sx; xpos++) {
214
+ pixel = gdImageGetPixel(im, xpos, row);
215
+
216
+ Putchar(gdTrueColorGetBlue(pixel), out);
217
+ Putchar(gdTrueColorGetGreen(pixel), out);
218
+ Putchar(gdTrueColorGetRed(pixel), out);
219
+ }
220
+
221
+ /* Add padding to make sure we have n mod 4 == 0 bytes per row */
222
+ for (xpos = padding; xpos > 0; --xpos) {
223
+ Putchar('\0', out);
224
+ }
225
+ }
226
+ }
227
+
228
+
229
+ /* If we needed a tmpfile for compression copy it over to out_original */
230
+ if (tmpfile_for_compression) {
231
+ unsigned char* copy_buffer = NULL;
232
+ int buffer_size = 0;
233
+
234
+ gdSeek(out, 0);
235
+ copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
236
+ if (copy_buffer == NULL) {
237
+ goto cleanup;
238
+ }
239
+
240
+ while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
241
+ if (buffer_size == 0) {
242
+ break;
243
+ }
244
+ gdPutBuf(copy_buffer , buffer_size, out_original);
245
+ }
246
+ gdFree(copy_buffer);
247
+
248
+ /* Replace the temp with the original which now has data */
249
+ out->gd_free(out);
250
+ out = out_original;
251
+ out_original = NULL;
252
+ }
253
+
254
+ cleanup:
255
+ if (tmpfile_for_compression) {
256
+ #ifdef WIN32
257
+ _rmtmp();
258
+ #else
259
+ fclose(tmpfile_for_compression);
260
+ #endif
261
+ tmpfile_for_compression = NULL;
262
+ }
263
+
264
+ if (out_original) {
265
+ out_original->gd_free(out_original);
266
+ }
267
+ return;
268
+ }
269
+
270
+ BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
271
+ {
272
+ void *rv;
273
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
274
+ gdImageBmpCtx(im, out, compression);
275
+ rv = gdDPExtractData(out, size);
276
+ out->gd_free(out);
277
+ return rv;
278
+ }
279
+
280
+ BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
281
+ {
282
+ gdIOCtx *out = gdNewFileCtx(outFile);
283
+ gdImageBmpCtx(im, out, compression);
284
+ out->gd_free(out);
285
+ }
286
+
287
+ static int compress_row(unsigned char *row, int length)
288
+ {
289
+ int rle_type = 0;
290
+ int compressed_length = 0;
291
+ int pixel = 0, compressed_run = 0, rle_compression = 0;
292
+ unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
293
+
294
+ uncompressed_row = (unsigned char *) gdMalloc(length);
295
+ if (!uncompressed_row) {
296
+ return -1;
297
+ }
298
+
299
+ memcpy(uncompressed_row, row, length);
300
+ uncompressed_start = uncompressed_rowp = uncompressed_row;
301
+
302
+ for (pixel = 0; pixel < length; pixel++)
303
+ {
304
+ if (compressed_run == 0) {
305
+ uncompressed_row = uncompressed_rowp;
306
+ compressed_run++;
307
+ uncompressed_rowp++;
308
+ rle_type = BMP_RLE_TYPE_RAW;
309
+ continue;
310
+ }
311
+
312
+ if (compressed_run == 1) {
313
+ /* Compare next byte */
314
+ if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
315
+ rle_type = BMP_RLE_TYPE_RLE;
316
+ }
317
+ }
318
+
319
+ if (rle_type == BMP_RLE_TYPE_RLE) {
320
+ if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
321
+ /* more than what we can store in a single run or run is over due to non match, force write */
322
+ rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
323
+ row += rle_compression;
324
+ compressed_length += rle_compression;
325
+ compressed_run = 0;
326
+ pixel--;
327
+ } else {
328
+ compressed_run++;
329
+ uncompressed_rowp++;
330
+ }
331
+ } else {
332
+ if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
333
+ /* more than what we can store in a single run or run is over due to match, force write */
334
+ rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
335
+ row += rle_compression;
336
+ compressed_length += rle_compression;
337
+ compressed_run = 0;
338
+ pixel--;
339
+ } else {
340
+ /* add this pixel to the row */
341
+ compressed_run++;
342
+ uncompressed_rowp++;
343
+ }
344
+
345
+ }
346
+ }
347
+
348
+ if (compressed_run) {
349
+ if (rle_type == BMP_RLE_TYPE_RLE) {
350
+ compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
351
+ } else {
352
+ compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
353
+ }
354
+ }
355
+
356
+ gdFree(uncompressed_start);
357
+
358
+ return compressed_length;
359
+ }
360
+
361
+ static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
362
+ {
363
+ int compressed_size = 0;
364
+ if (length < 1 || length > 128) {
365
+ return 0;
366
+ }
367
+
368
+ /* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
369
+ if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
370
+ int i = 0;
371
+ for (i = 0; i < length; i++) {
372
+ compressed_size += 2;
373
+ memset(row, 1, 1);
374
+ row++;
375
+
376
+ memcpy(row, data++, 1);
377
+ row++;
378
+ }
379
+ } else if (packet_type == BMP_RLE_TYPE_RLE) {
380
+ compressed_size = 2;
381
+ memset(row, length, 1);
382
+ row++;
383
+
384
+ memcpy(row, data, 1);
385
+ row++;
386
+ } else {
387
+ compressed_size = 2 + length;
388
+ memset(row, BMP_RLE_COMMAND, 1);
389
+ row++;
390
+
391
+ memset(row, length, 1);
392
+ row++;
393
+
394
+ memcpy(row, data, length);
395
+ row += length;
396
+
397
+ /* Must be an even number for an uncompressed run */
398
+ if (length % 2) {
399
+ memset(row, 0, 1);
400
+ row++;
401
+ compressed_size++;
402
+ }
403
+ }
404
+ return compressed_size;
405
+ }
406
+
407
+ BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
408
+ {
409
+ bmp_hdr_t *hdr;
410
+ bmp_info_t *info;
411
+ gdImagePtr im = NULL;
412
+ int error = 0;
413
+
414
+ if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
415
+ return NULL;
416
+ }
417
+
418
+ if (bmp_read_header(infile, hdr)) {
419
+ gdFree(hdr);
420
+ return NULL;
421
+ }
422
+
423
+ if (hdr->magic != 0x4d42) {
424
+ gdFree(hdr);
425
+ return NULL;
426
+ }
427
+
428
+ if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
429
+ gdFree(hdr);
430
+ return NULL;
431
+ }
432
+
433
+ if (bmp_read_info(infile, info)) {
434
+ gdFree(hdr);
435
+ gdFree(info);
436
+ return NULL;
437
+ }
438
+
439
+ BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
440
+ BMP_DEBUG(printf("Width: %d\n", info->width));
441
+ BMP_DEBUG(printf("Height: %d\n", info->height));
442
+ BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
443
+ BMP_DEBUG(printf("Depth: %d\n", info->depth));
444
+ BMP_DEBUG(printf("Offset: %d\n", hdr->off));
445
+
446
+ if (info->depth >= 16) {
447
+ im = gdImageCreateTrueColor(info->width, info->height);
448
+ } else {
449
+ im = gdImageCreate(info->width, info->height);
450
+ }
451
+
452
+ if (!im) {
453
+ gdFree(hdr);
454
+ gdFree(info);
455
+ return NULL;
456
+ }
457
+
458
+ switch (info->depth) {
459
+ case 1:
460
+ BMP_DEBUG(printf("1-bit image\n"));
461
+ error = bmp_read_1bit(im, infile, info, hdr);
462
+ break;
463
+ case 4:
464
+ BMP_DEBUG(printf("4-bit image\n"));
465
+ error = bmp_read_4bit(im, infile, info, hdr);
466
+ break;
467
+ case 8:
468
+ BMP_DEBUG(printf("8-bit image\n"));
469
+ error = bmp_read_8bit(im, infile, info, hdr);
470
+ break;
471
+ case 16:
472
+ case 24:
473
+ case 32:
474
+ BMP_DEBUG(printf("Direct BMP image\n"));
475
+ error = bmp_read_direct(im, infile, info, hdr);
476
+ break;
477
+ default:
478
+ BMP_DEBUG(printf("Unknown bit count\n"));
479
+ error = 1;
480
+ }
481
+
482
+ gdFree(hdr);
483
+ gdFree(info);
484
+
485
+ if (error) {
486
+ gdImageDestroy(im);
487
+ return NULL;
488
+ }
489
+
490
+ return im;
491
+ }
492
+
493
+ BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
494
+ {
495
+ gdImagePtr im = 0;
496
+ gdIOCtx *in = gdNewFileCtx(inFile);
497
+ im = gdImageCreateFromBmpCtx(in);
498
+ in->gd_free(in);
499
+ return im;
500
+ }
501
+
502
+ BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
503
+ {
504
+ gdImagePtr im;
505
+ gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
506
+ im = gdImageCreateFromBmpCtx(in);
507
+ in->gd_free(in);
508
+ return im;
509
+ }
510
+
511
+ static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
512
+ {
513
+ if(
514
+ !gdGetWordLSB(&hdr->magic, infile) ||
515
+ !gdGetIntLSB(&hdr->size, infile) ||
516
+ !gdGetWordLSB(&hdr->reserved1, infile) ||
517
+ !gdGetWordLSB(&hdr->reserved2 , infile) ||
518
+ !gdGetIntLSB(&hdr->off , infile)
519
+ ) {
520
+ return 1;
521
+ }
522
+ return 0;
523
+ }
524
+
525
+ static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
526
+ {
527
+ /* read BMP length so we can work out the version */
528
+ if (!gdGetIntLSB(&info->len, infile)) {
529
+ return 1;
530
+ }
531
+
532
+ switch (info->len) {
533
+ /* For now treat Windows v4 + v5 as v3 */
534
+ case BMP_WINDOWS_V3:
535
+ case BMP_WINDOWS_V4:
536
+ case BMP_WINDOWS_V5:
537
+ BMP_DEBUG(printf("Reading Windows Header\n"));
538
+ if (bmp_read_windows_v3_info(infile, info)) {
539
+ return 1;
540
+ }
541
+ break;
542
+ case BMP_OS2_V1:
543
+ if (bmp_read_os2_v1_info(infile, info)) {
544
+ return 1;
545
+ }
546
+ break;
547
+ case BMP_OS2_V2:
548
+ if (bmp_read_os2_v2_info(infile, info)) {
549
+ return 1;
550
+ }
551
+ break;
552
+ default:
553
+ BMP_DEBUG(printf("Unhandled bitmap\n"));
554
+ return 1;
555
+ }
556
+ return 0;
557
+ }
558
+
559
+ static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
560
+ {
561
+ if (
562
+ !gdGetIntLSB(&info->width, infile) ||
563
+ !gdGetIntLSB(&info->height, infile) ||
564
+ !gdGetWordLSB(&info->numplanes, infile) ||
565
+ !gdGetWordLSB(&info->depth, infile) ||
566
+ !gdGetIntLSB(&info->enctype, infile) ||
567
+ !gdGetIntLSB(&info->size, infile) ||
568
+ !gdGetIntLSB(&info->hres, infile) ||
569
+ !gdGetIntLSB(&info->vres, infile) ||
570
+ !gdGetIntLSB(&info->numcolors, infile) ||
571
+ !gdGetIntLSB(&info->mincolors, infile)
572
+ ) {
573
+ return 1;
574
+ }
575
+
576
+ if (info->height < 0) {
577
+ info->topdown = 1;
578
+ info->height = -info->height;
579
+ } else {
580
+ info->topdown = 0;
581
+ }
582
+
583
+ info->type = BMP_PALETTE_4;
584
+
585
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
586
+ info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
587
+ return 1;
588
+ }
589
+
590
+ return 0;
591
+ }
592
+
593
+ static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
594
+ {
595
+ if (
596
+ !gdGetWordLSB((signed short int *)&info->width, infile) ||
597
+ !gdGetWordLSB((signed short int *)&info->height, infile) ||
598
+ !gdGetWordLSB(&info->numplanes, infile) ||
599
+ !gdGetWordLSB(&info->depth, infile)
600
+ ) {
601
+ return 1;
602
+ }
603
+
604
+ /* OS2 v1 doesn't support topdown */
605
+ info->topdown = 0;
606
+
607
+ info->numcolors = 1 << info->depth;
608
+ info->type = BMP_PALETTE_3;
609
+
610
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
611
+ info->depth <= 0 || info->numcolors < 0) {
612
+ return 1;
613
+ }
614
+
615
+ return 0;
616
+ }
617
+
618
+ static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
619
+ {
620
+ char useless_bytes[24];
621
+ if (
622
+ !gdGetIntLSB(&info->width, infile) ||
623
+ !gdGetIntLSB(&info->height, infile) ||
624
+ !gdGetWordLSB(&info->numplanes, infile) ||
625
+ !gdGetWordLSB(&info->depth, infile) ||
626
+ !gdGetIntLSB(&info->enctype, infile) ||
627
+ !gdGetIntLSB(&info->size, infile) ||
628
+ !gdGetIntLSB(&info->hres, infile) ||
629
+ !gdGetIntLSB(&info->vres, infile) ||
630
+ !gdGetIntLSB(&info->numcolors, infile) ||
631
+ !gdGetIntLSB(&info->mincolors, infile)
632
+ ) {
633
+ return 1;
634
+ }
635
+
636
+ /* Lets seek the next 24 pointless bytes, we don't care too much about it */
637
+ if (!gdGetBuf(useless_bytes, 24, infile)) {
638
+ return 1;
639
+ }
640
+
641
+ if (info->height < 0) {
642
+ info->topdown = 1;
643
+ info->height = -info->height;
644
+ } else {
645
+ info->topdown = 0;
646
+ }
647
+
648
+ info->type = BMP_PALETTE_4;
649
+
650
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
651
+ info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
652
+ return 1;
653
+ }
654
+
655
+
656
+ return 0;
657
+ }
658
+
659
+ static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
660
+ {
661
+ int ypos = 0, xpos = 0, row = 0;
662
+ int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
663
+ signed short int data = 0;
664
+
665
+ switch(info->enctype) {
666
+ case BMP_BI_RGB:
667
+ /* no-op */
668
+ break;
669
+
670
+ case BMP_BI_BITFIELDS:
671
+ if (info->depth == 24) {
672
+ BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
673
+ return 1;
674
+ }
675
+ BMP_DEBUG(printf("Currently no bitfield support\n"));
676
+ return 1;
677
+ break;
678
+
679
+ case BMP_BI_RLE8:
680
+ if (info->depth != 8) {
681
+ BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
682
+ return 1;
683
+ }
684
+ case BMP_BI_RLE4:
685
+ if (info->depth != 4) {
686
+ BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
687
+ return 1;
688
+ }
689
+ case BMP_BI_JPEG:
690
+ case BMP_BI_PNG:
691
+ default:
692
+ BMP_DEBUG(printf("Unsupported BMP compression format\n"));
693
+ return 1;
694
+ }
695
+
696
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
697
+ if (gdTell(infile) != header->off) {
698
+ /* Should make sure we don't seek past the file size */
699
+ gdSeek(infile, header->off);
700
+ }
701
+
702
+ /* The line must be divisible by 4, else its padded with NULLs */
703
+ padding = ((int)(info->depth / 8) * info->width) % 4;
704
+ if (padding) {
705
+ padding = 4 - padding;
706
+ }
707
+
708
+
709
+ for (ypos = 0; ypos < info->height; ++ypos) {
710
+ if (info->topdown) {
711
+ row = ypos;
712
+ } else {
713
+ row = info->height - ypos - 1;
714
+ }
715
+
716
+ for (xpos = 0; xpos < info->width; xpos++) {
717
+ if (info->depth == 16) {
718
+ if (!gdGetWordLSB(&data, infile)) {
719
+ return 1;
720
+ }
721
+ BMP_DEBUG(printf("Data: %X\n", data));
722
+ red = ((data & 0x7C00) >> 10) << 3;
723
+ green = ((data & 0x3E0) >> 5) << 3;
724
+ blue = (data & 0x1F) << 3;
725
+ BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
726
+ } else if (info->depth == 24) {
727
+ if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
728
+ return 1;
729
+ }
730
+ } else {
731
+ if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
732
+ return 1;
733
+ }
734
+ }
735
+ /*alpha = gdAlphaMax - (alpha >> 1);*/
736
+ gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
737
+ }
738
+ for (xpos = padding; xpos > 0; --xpos) {
739
+ if (!gdGetByte(&red, infile)) {
740
+ return 1;
741
+ }
742
+ }
743
+ }
744
+
745
+ return 0;
746
+ }
747
+
748
+ static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
749
+ {
750
+ int i;
751
+ int r, g, b, z;
752
+
753
+ for (i = 0; i < count; i++) {
754
+ if (
755
+ !gdGetByte(&r, infile) ||
756
+ !gdGetByte(&g, infile) ||
757
+ !gdGetByte(&b, infile) ||
758
+ (read_four && !gdGetByte(&z, infile))
759
+ ) {
760
+ return 1;
761
+ }
762
+ im->red[i] = r;
763
+ im->green[i] = g;
764
+ im->blue[i] = b;
765
+ im->open[i] = 1;
766
+ }
767
+ return 0;
768
+ }
769
+
770
+ static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
771
+ {
772
+ int ypos = 0, xpos = 0, row = 0, index = 0;
773
+ int padding = 0, current_byte = 0, bit = 0;
774
+
775
+ if (info->enctype != BMP_BI_RGB) {
776
+ return 1;
777
+ }
778
+
779
+ if (!info->numcolors) {
780
+ info->numcolors = 2;
781
+ } else if (info->numcolors < 0 || info->numcolors > 2) {
782
+ return 1;
783
+ }
784
+
785
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
786
+ return 1;
787
+ }
788
+
789
+ im->colorsTotal = info->numcolors;
790
+
791
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
792
+ if (gdTell(infile) != header->off) {
793
+ /* Should make sure we don't seek past the file size */
794
+ gdSeek(infile, header->off);
795
+ }
796
+
797
+ /* The line must be divisible by 4, else its padded with NULLs */
798
+ padding = ((int)ceill(0.1 * info->width)) % 4;
799
+ if (padding) {
800
+ padding = 4 - padding;
801
+ }
802
+
803
+ for (ypos = 0; ypos < info->height; ++ypos) {
804
+ if (info->topdown) {
805
+ row = ypos;
806
+ } else {
807
+ row = info->height - ypos - 1;
808
+ }
809
+
810
+ for (xpos = 0; xpos < info->width; xpos += 8) {
811
+ /* Bitmaps are always aligned in bytes so we'll never overflow */
812
+ if (!gdGetByte(&current_byte, infile)) {
813
+ return 1;
814
+ }
815
+
816
+ for (bit = 0; bit < 8; bit++) {
817
+ index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
818
+ if (im->open[index]) {
819
+ im->open[index] = 0;
820
+ }
821
+ gdImageSetPixel(im, xpos + bit, row, index);
822
+ /* No need to read anything extra */
823
+ if ((xpos + bit) >= info->width) {
824
+ break;
825
+ }
826
+ }
827
+ }
828
+
829
+ for (xpos = padding; xpos > 0; --xpos) {
830
+ if (!gdGetByte(&index, infile)) {
831
+ return 1;
832
+ }
833
+ }
834
+ }
835
+ return 0;
836
+ }
837
+
838
+ static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
839
+ {
840
+ int ypos = 0, xpos = 0, row = 0, index = 0;
841
+ int padding = 0, current_byte = 0;
842
+
843
+ if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
844
+ return 1;
845
+ }
846
+
847
+ if (!info->numcolors) {
848
+ info->numcolors = 16;
849
+ } else if (info->numcolors < 0 || info->numcolors > 16) {
850
+ return 1;
851
+ }
852
+
853
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
854
+ return 1;
855
+ }
856
+
857
+ im->colorsTotal = info->numcolors;
858
+
859
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
860
+ if (gdTell(infile) != header->off) {
861
+ /* Should make sure we don't seek past the file size */
862
+ gdSeek(infile, header->off);
863
+ }
864
+
865
+ /* The line must be divisible by 4, else its padded with NULLs */
866
+ padding = ((int)ceil(0.5 * info->width)) % 4;
867
+ if (padding) {
868
+ padding = 4 - padding;
869
+ }
870
+
871
+ switch (info->enctype) {
872
+ case BMP_BI_RGB:
873
+ for (ypos = 0; ypos < info->height; ++ypos) {
874
+ if (info->topdown) {
875
+ row = ypos;
876
+ } else {
877
+ row = info->height - ypos - 1;
878
+ }
879
+
880
+ for (xpos = 0; xpos < info->width; xpos += 2) {
881
+ if (!gdGetByte(&current_byte, infile)) {
882
+ return 1;
883
+ }
884
+
885
+ index = (current_byte >> 4) & 0x0f;
886
+ if (im->open[index]) {
887
+ im->open[index] = 0;
888
+ }
889
+ gdImageSetPixel(im, xpos, row, index);
890
+
891
+ /* This condition may get called often, potential optimsations */
892
+ if (xpos >= info->width) {
893
+ break;
894
+ }
895
+
896
+ index = current_byte & 0x0f;
897
+ if (im->open[index]) {
898
+ im->open[index] = 0;
899
+ }
900
+ gdImageSetPixel(im, xpos + 1, row, index);
901
+ }
902
+
903
+ for (xpos = padding; xpos > 0; --xpos) {
904
+ if (!gdGetByte(&index, infile)) {
905
+ return 1;
906
+ }
907
+ }
908
+ }
909
+ break;
910
+
911
+ case BMP_BI_RLE4:
912
+ if (bmp_read_rle(im, infile, info)) {
913
+ return 1;
914
+ }
915
+ break;
916
+
917
+ default:
918
+ return 1;
919
+ }
920
+ return 0;
921
+ }
922
+
923
+ static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
924
+ {
925
+ int ypos = 0, xpos = 0, row = 0, index = 0;
926
+ int padding = 0;
927
+
928
+ if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
929
+ return 1;
930
+ }
931
+
932
+ if (!info->numcolors) {
933
+ info->numcolors = 256;
934
+ } else if (info->numcolors < 0 || info->numcolors > 256) {
935
+ return 1;
936
+ }
937
+
938
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
939
+ return 1;
940
+ }
941
+
942
+ im->colorsTotal = info->numcolors;
943
+
944
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
945
+ if (gdTell(infile) != header->off) {
946
+ /* Should make sure we don't seek past the file size */
947
+ gdSeek(infile, header->off);
948
+ }
949
+
950
+ /* The line must be divisible by 4, else its padded with NULLs */
951
+ padding = (1 * info->width) % 4;
952
+ if (padding) {
953
+ padding = 4 - padding;
954
+ }
955
+
956
+ switch (info->enctype) {
957
+ case BMP_BI_RGB:
958
+ for (ypos = 0; ypos < info->height; ++ypos) {
959
+ if (info->topdown) {
960
+ row = ypos;
961
+ } else {
962
+ row = info->height - ypos - 1;
963
+ }
964
+
965
+ for (xpos = 0; xpos < info->width; ++xpos) {
966
+ if (!gdGetByte(&index, infile)) {
967
+ return 1;
968
+ }
969
+
970
+ if (im->open[index]) {
971
+ im->open[index] = 0;
972
+ }
973
+ gdImageSetPixel(im, xpos, row, index);
974
+ }
975
+ /* Could create a new variable, but it isn't really worth it */
976
+ for (xpos = padding; xpos > 0; --xpos) {
977
+ if (!gdGetByte(&index, infile)) {
978
+ return 1;
979
+ }
980
+ }
981
+ }
982
+ break;
983
+
984
+ case BMP_BI_RLE8:
985
+ if (bmp_read_rle(im, infile, info)) {
986
+ return 1;
987
+ }
988
+ break;
989
+
990
+ default:
991
+ return 1;
992
+ }
993
+ return 0;
994
+ }
995
+
996
+ static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
997
+ {
998
+ int ypos = 0, xpos = 0, row = 0, index = 0;
999
+ int rle_length = 0, rle_data = 0;
1000
+ int padding = 0;
1001
+ int i = 0, j = 0;
1002
+ int pixels_per_byte = 8 / info->depth;
1003
+
1004
+ for (ypos = 0; ypos < info->height && xpos <= info->width;) {
1005
+ if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1006
+ return 1;
1007
+ }
1008
+ row = info->height - ypos - 1;
1009
+
1010
+ if (rle_length != BMP_RLE_COMMAND) {
1011
+ if (im->open[rle_data]) {
1012
+ im->open[rle_data] = 0;
1013
+ }
1014
+
1015
+ for (i = 0; (i < rle_length) && (xpos < info->width);) {
1016
+ for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
1017
+ index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
1018
+ if (im->open[index]) {
1019
+ im->open[index] = 0;
1020
+ }
1021
+ gdImageSetPixel(im, xpos, row, index);
1022
+ }
1023
+ }
1024
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
1025
+ /* Uncompressed RLE needs to be even */
1026
+ padding = 0;
1027
+ for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
1028
+ int max_pixels = pixels_per_byte;
1029
+
1030
+ if (!gdGetByte(&index, infile)) {
1031
+ return 1;
1032
+ }
1033
+ padding++;
1034
+
1035
+ if (rle_data - i < max_pixels) {
1036
+ max_pixels = rle_data - i;
1037
+ }
1038
+
1039
+ for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
1040
+ int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
1041
+ if (im->open[temp]) {
1042
+ im->open[temp] = 0;
1043
+ }
1044
+ gdImageSetPixel(im, xpos, row, temp);
1045
+ }
1046
+ }
1047
+
1048
+ /* Make sure the bytes read are even */
1049
+ if (padding % 2 && !gdGetByte(&index, infile)) {
1050
+ return 1;
1051
+ }
1052
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
1053
+ /* Next Line */
1054
+ xpos = 0;
1055
+ ypos++;
1056
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
1057
+ /* Delta Record, used for bmp files that contain other data*/
1058
+ if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
1059
+ return 1;
1060
+ }
1061
+ xpos += rle_length;
1062
+ ypos += rle_data;
1063
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
1064
+ /* End of bitmap */
1065
+ break;
1066
+ }
1067
+ }
1068
+ return 0;
1069
+ }
1070
+
1071
+ #if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
1072
+ static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx)
1073
+ {
1074
+ unsigned int high = 0, low = 0;
1075
+ low = (ctx->getC) (ctx);
1076
+ if (low == EOF) {
1077
+ return 0;
1078
+ }
1079
+
1080
+ high = (ctx->getC) (ctx);
1081
+ if (high == EOF) {
1082
+ return 0;
1083
+ }
1084
+
1085
+ if (result) {
1086
+ *result = (high << 8) | low;
1087
+ }
1088
+
1089
+ return 1;
1090
+ }
1091
+
1092
+ static int gdGetIntLSB(signed int *result, gdIOCtx * ctx)
1093
+ {
1094
+ int c = 0;
1095
+ unsigned int r = 0;
1096
+
1097
+ c = (ctx->getC) (ctx);
1098
+ if (c == EOF) {
1099
+ return 0;
1100
+ }
1101
+ r |= (c << 24);
1102
+ r >>= 8;
1103
+
1104
+ c = (ctx->getC) (ctx);
1105
+ if (c == EOF) {
1106
+ return 0;
1107
+ }
1108
+ r |= (c << 24);
1109
+ r >>= 8;
1110
+
1111
+ c = (ctx->getC) (ctx);
1112
+ if (c == EOF) {
1113
+ return 0;
1114
+ }
1115
+ r |= (c << 24);
1116
+ r >>= 8;
1117
+
1118
+ c = (ctx->getC) (ctx);
1119
+ if (c == EOF) {
1120
+ return 0;
1121
+ }
1122
+ r |= (c << 24);
1123
+
1124
+ if (result) {
1125
+ *result = (signed int)r;
1126
+ }
1127
+
1128
+ return 1;
1129
+ }
1130
+ #endif