apple_png 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/apple_png/apple_png.c +41 -3
- metadata +1 -1
data/ext/apple_png/apple_png.c
CHANGED
@@ -6,18 +6,54 @@
|
|
6
6
|
#define PNG_HEADER "\x89PNG\r\n\x1a\n"
|
7
7
|
#define PNG_BYTES2UINT(char_ptr) (ntohl(*(uint32_t *)(char_ptr)))
|
8
8
|
|
9
|
+
#define DIV_CEIL(a,b) (((a) + (b) - 1) / (b))
|
10
|
+
|
9
11
|
#define APPLE_PNG_OK 0
|
10
12
|
#define APPLE_PNG_STREAM_ERROR Z_STREAM_ERROR
|
11
13
|
#define APPLE_PNG_DATA_ERROR Z_DATA_ERROR
|
12
14
|
#define APPLE_PNG_ZLIB_VERSION_ERROR Z_VERSION_ERROR
|
13
15
|
#define APPLE_PNG_NO_MEM_ERROR Z_MEM_ERROR
|
14
16
|
|
17
|
+
/* calculate how many scanlines an adam7 interlaced png will result in */
|
18
|
+
static uint32_t interlaced_count_scanlines(uint32_t width, uint32_t height) {
|
19
|
+
uint32_t pass[7];
|
20
|
+
|
21
|
+
if (width == 0 || height == 0) return 0;
|
22
|
+
|
23
|
+
/* For each pass, calculate how many resulting scanlines there will be.
|
24
|
+
* I'm sure there is a more elegant solution to accomplish this.
|
25
|
+
* This makes use of the adam7 raster:
|
26
|
+
* 1 6 4 6 2 6 4 6
|
27
|
+
* 7 7 7 7 7 7 7 7
|
28
|
+
* 5 6 5 6 5 6 5 6
|
29
|
+
* 7 7 7 7 7 7 7 7
|
30
|
+
* 3 6 4 6 3 6 4 6
|
31
|
+
* 7 7 7 7 7 7 7 7
|
32
|
+
* 5 6 5 6 5 6 5 6
|
33
|
+
* 7 7 7 7 7 7 7 7
|
34
|
+
*/
|
35
|
+
pass[0] = DIV_CEIL(height, 8u);
|
36
|
+
pass[1] = (width > 4) ? DIV_CEIL(height, 8u) : 0;
|
37
|
+
pass[2] = DIV_CEIL(height-4, 8u);
|
38
|
+
pass[3] = (width > 2) ? DIV_CEIL(height, 4u) : 0;
|
39
|
+
pass[4] = DIV_CEIL(height-2, 4u);
|
40
|
+
pass[5] = (width > 1) ? DIV_CEIL(height, 2u) : 0;
|
41
|
+
pass[6] = DIV_CEIL(height-1, 2u);
|
42
|
+
|
43
|
+
return pass[0] + pass[1] + pass[2] + pass[3] + pass[4] + pass[5] + pass[6];
|
44
|
+
}
|
45
|
+
|
15
46
|
/* inflate from apple png file, don't expect headers */
|
16
|
-
static int png_inflate(unsigned char *data, uint32_t length, uint32_t width, uint32_t height, unsigned char **out_buff, uint32_t *out_uncompressed_size) {
|
47
|
+
static int png_inflate(unsigned char *data, uint32_t length, uint32_t width, uint32_t height, int interlaced, unsigned char **out_buff, uint32_t *out_uncompressed_size) {
|
17
48
|
int error;
|
18
49
|
z_stream inflate_strm = {0};
|
19
50
|
|
20
|
-
|
51
|
+
if (interlaced) {
|
52
|
+
*out_uncompressed_size = interlaced_count_scanlines(width, height) + width * height * 4;
|
53
|
+
} else {
|
54
|
+
*out_uncompressed_size = height + width * height * 4;
|
55
|
+
}
|
56
|
+
|
21
57
|
*out_buff = malloc(sizeof(char) * (*out_uncompressed_size));
|
22
58
|
if (*out_buff == 0) {
|
23
59
|
return APPLE_PNG_NO_MEM_ERROR;
|
@@ -114,6 +150,7 @@ static uint32_t png_crc32(const char *chunkType, const char *chunkData, uint32_t
|
|
114
150
|
/* extract chunks from PNG data */
|
115
151
|
static int readPngChunks(VALUE self, const char *oldPNG, size_t oldPngLength, dyn_arr *newPNG) {
|
116
152
|
uint32_t width = 0, height = 0;
|
153
|
+
int interlaced = 0;
|
117
154
|
size_t cursor = 8;
|
118
155
|
dyn_arr *applePngCompressedPixelData = dyn_arr_create(oldPngLength);
|
119
156
|
if (applePngCompressedPixelData == 0) {
|
@@ -133,6 +170,7 @@ static int readPngChunks(VALUE self, const char *oldPNG, size_t oldPngLength, dy
|
|
133
170
|
/* extract dimensions from header */
|
134
171
|
width = PNG_BYTES2UINT(&chunkData[0]);
|
135
172
|
height = PNG_BYTES2UINT(&chunkData[4]);
|
173
|
+
interlaced = chunkData[12] == 1;
|
136
174
|
rb_funcall(self, rb_intern("width="), 1, INT2NUM(width));
|
137
175
|
rb_funcall(self, rb_intern("height="), 1, INT2NUM(height));
|
138
176
|
} else if (strncmp(chunkType, "IDAT", 4) == 0) {
|
@@ -151,7 +189,7 @@ static int readPngChunks(VALUE self, const char *oldPNG, size_t oldPngLength, dy
|
|
151
189
|
int error;
|
152
190
|
|
153
191
|
/* decompress, flip color bytes, then compress again */
|
154
|
-
error = png_inflate((unsigned char *)applePngCompressedPixelData->arr, (uint32_t)applePngCompressedPixelData->used, width, height, &decompressedPixelData, &uncompressed_size);
|
192
|
+
error = png_inflate((unsigned char *)applePngCompressedPixelData->arr, (uint32_t)applePngCompressedPixelData->used, width, height, interlaced, &decompressedPixelData, &uncompressed_size);
|
155
193
|
if (error != APPLE_PNG_OK) {
|
156
194
|
dyn_arr_free(applePngCompressedPixelData);
|
157
195
|
return error;
|