rgd 0.4.1a → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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