apple_png 0.1.1 → 0.1.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.
- 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;
|