libpng-ruby 0.5.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.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.md +74 -0
- data/Rakefile +9 -0
- data/bin/pnginfo +7 -0
- data/ext/png/extconf.rb +7 -0
- data/ext/png/png.c +1497 -0
- data/lib/png.rb +32 -0
- data/lib/png/version.rb +3 -0
- data/libpng-ruby.gemspec +39 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 01ba3c06d3239eb5638f1a4b316988f36b64e571aa8d571b3e61e46dd6f296f2
|
4
|
+
data.tar.gz: 5d6cc04e434eb327aa111a388e4838e2bbc841a9f18b5703589d9c610ac79e9b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48977b718f74f3df9124a6e8cceba2bacd2d7cf2fbfdce2098585b9cf56ca59f0248ed1477ebe488d854b988408d86a134629c7b3466e4f5fa5f72fed7919ff7
|
7
|
+
data.tar.gz: 297bcc6fb934b6a42f7638c421ffe772246a9952670afd795b2e5f4ba4658256826c21650e3df22e177bf9ab82b9fc726c3ff9c7a5c3f22a665313c01ccb591b
|
data/.gitignore
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2019 Hiroshi Kuwagata
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# libpng-ruby
|
2
|
+
libpng interface for ruby.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
gem 'libpng-ruby'
|
8
|
+
```
|
9
|
+
|
10
|
+
And then execute:
|
11
|
+
|
12
|
+
$ bundle
|
13
|
+
|
14
|
+
Or install it yourself as:
|
15
|
+
|
16
|
+
$ gem install libpng-ruby
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### decode sample
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'png'
|
24
|
+
|
25
|
+
dec = PNG::Decoder.new(:color_type => :BGR)
|
26
|
+
|
27
|
+
p dec.read_header(IO.binread("test.png"))
|
28
|
+
|
29
|
+
raw = dec << IO.binread("test.png")
|
30
|
+
p raw.meta
|
31
|
+
|
32
|
+
IO.binwrite("test.bgr", raw)
|
33
|
+
```
|
34
|
+
|
35
|
+
#### decode options
|
36
|
+
| option | value type | description |
|
37
|
+
|---|---|---|
|
38
|
+
| :api_type | "simplified" or "classic" | |
|
39
|
+
| :pixel_format | String or Symbol | output format<br>(ignored when to use classic API) |
|
40
|
+
| :without_meta | Boolean | T.B.D |
|
41
|
+
| :display_gamma | Numeric | T.B.D<br>(ignored when to use simplified API) |
|
42
|
+
|
43
|
+
#### supported output color type
|
44
|
+
GRAY GRAYSCALE GA AG RGB BGR RGBA ARGB BGRA ABGR
|
45
|
+
|
46
|
+
### encode sample
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require 'png'
|
50
|
+
|
51
|
+
enc = PNG::Encoder.new(640, 480, :color_type => :YCbCr)
|
52
|
+
|
53
|
+
IO.binwrite("test.png", enc << IO.binread("test.raw"))
|
54
|
+
```
|
55
|
+
#### encode options
|
56
|
+
| option | value type | description |
|
57
|
+
|---|---|---|
|
58
|
+
| :pixel_fromat | String or Symbol | input pixel format |
|
59
|
+
| :interlace | Boolean | use interlace mode |
|
60
|
+
| :compression | Integer or String or Symbol | compression level |
|
61
|
+
| :text | Hash | text information |
|
62
|
+
| :time | Boolean | with tIME chunk |
|
63
|
+
| :gamma | Numeric | file gamma value |
|
64
|
+
|
65
|
+
#### supported input color type
|
66
|
+
GRAY GRASCALE GA RGB RGBA
|
67
|
+
|
68
|
+
#### available compression level
|
69
|
+
##### Integer
|
70
|
+
0 to 9(0:no compression, 9:best compression).
|
71
|
+
|
72
|
+
#### String
|
73
|
+
NO_COMPRESSION BEST_SPEED BEST_COMPRESSION DEFAULT
|
74
|
+
|
data/Rakefile
ADDED
data/bin/pnginfo
ADDED
data/ext/png/extconf.rb
ADDED
data/ext/png/png.c
ADDED
@@ -0,0 +1,1497 @@
|
|
1
|
+
/*
|
2
|
+
* PNG encode/decode library for Ruby
|
3
|
+
*
|
4
|
+
* Copyright (C) 2016 Hiroshi Kuwagata <kgt9221@gmail.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
/*
|
8
|
+
* $Id: png.c 67 2016-06-07 06:10:47Z pi $
|
9
|
+
*/
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdint.h>
|
13
|
+
#include <string.h>
|
14
|
+
#include <setjmp.h>
|
15
|
+
#include <time.h>
|
16
|
+
#include <math.h>
|
17
|
+
|
18
|
+
#include <png.h>
|
19
|
+
#include <zlib.h>
|
20
|
+
|
21
|
+
#include "ruby.h"
|
22
|
+
|
23
|
+
#define N(x) (sizeof(x)/sizeof(*x))
|
24
|
+
|
25
|
+
#define RUNTIME_ERROR(msg) rb_raise(rb_eRuntimeError, (msg))
|
26
|
+
#define ARGUMENT_ERROR(msg) rb_raise(rb_eArgError, (msg))
|
27
|
+
#define TYPE_ERROR(msg) rb_raise(rb_eTypeError, (msg))
|
28
|
+
#define NOMEMORY_ERROR(msg) rb_raise(rb_eNoMemError, (msg))
|
29
|
+
|
30
|
+
#define API_SIMPLIFIED 1
|
31
|
+
#define API_CLASSIC 2
|
32
|
+
|
33
|
+
#define EQ_STR(val,str) (rb_to_id(val) == rb_intern(str))
|
34
|
+
#define EQ_INT(val,n) (FIX2INT(val) == n)
|
35
|
+
|
36
|
+
static VALUE module;
|
37
|
+
static VALUE encoder_klass;
|
38
|
+
static VALUE decoder_klass;
|
39
|
+
static VALUE meta_klass;
|
40
|
+
|
41
|
+
static ID id_meta;
|
42
|
+
static ID id_stride;
|
43
|
+
static ID id_format;
|
44
|
+
static ID id_pixfmt;
|
45
|
+
static ID id_ncompo;
|
46
|
+
|
47
|
+
typedef struct {
|
48
|
+
uint8_t* ptr;
|
49
|
+
size_t size;
|
50
|
+
int pos;
|
51
|
+
} mem_io_t;
|
52
|
+
|
53
|
+
typedef struct {
|
54
|
+
/*
|
55
|
+
* for raw level chunk access
|
56
|
+
*/
|
57
|
+
png_structp ctx; // as 'context'
|
58
|
+
png_infop info;
|
59
|
+
|
60
|
+
png_uint_32 width;
|
61
|
+
png_uint_32 height;
|
62
|
+
|
63
|
+
png_byte** rows;
|
64
|
+
|
65
|
+
int stride;
|
66
|
+
int num_comp;
|
67
|
+
int pixels;
|
68
|
+
int with_time;
|
69
|
+
|
70
|
+
int c_type; // as 'color type'
|
71
|
+
int i_meth; // as 'interlace method'
|
72
|
+
int c_level; // as 'compression level'
|
73
|
+
int f_type; // as 'filter type'
|
74
|
+
|
75
|
+
png_text* text;
|
76
|
+
int num_text;
|
77
|
+
|
78
|
+
double gamma;
|
79
|
+
} png_encoder_t;
|
80
|
+
|
81
|
+
typedef union {
|
82
|
+
struct {
|
83
|
+
int api_type;
|
84
|
+
int format;
|
85
|
+
int need_meta;
|
86
|
+
double display_gamma;
|
87
|
+
} common;
|
88
|
+
|
89
|
+
struct {
|
90
|
+
/*
|
91
|
+
* common field
|
92
|
+
*/
|
93
|
+
int api_type;
|
94
|
+
int format;
|
95
|
+
int need_meta;
|
96
|
+
double display_gamma;
|
97
|
+
|
98
|
+
/*
|
99
|
+
* classic api context
|
100
|
+
*/
|
101
|
+
png_structp ctx; // as 'context'
|
102
|
+
png_infop fsi; // as 'front side infomation'
|
103
|
+
png_infop bsi; // as 'back side infomation'
|
104
|
+
|
105
|
+
png_uint_32 width;
|
106
|
+
png_uint_32 height;
|
107
|
+
|
108
|
+
png_byte** rows;
|
109
|
+
|
110
|
+
int depth;
|
111
|
+
int c_type; // as 'color type'
|
112
|
+
int i_meth; // as 'interlace method'
|
113
|
+
int c_meth; // as 'compression method'
|
114
|
+
int f_meth; // as 'filter method'
|
115
|
+
|
116
|
+
mem_io_t io;
|
117
|
+
|
118
|
+
png_text* text;
|
119
|
+
int num_text;
|
120
|
+
png_time* time;
|
121
|
+
double file_gamma;
|
122
|
+
} classic;
|
123
|
+
|
124
|
+
struct {
|
125
|
+
/*
|
126
|
+
* common field
|
127
|
+
*/
|
128
|
+
int api_type;
|
129
|
+
int format;
|
130
|
+
int need_meta;
|
131
|
+
double display_gamma;
|
132
|
+
|
133
|
+
/*
|
134
|
+
* simplified api context
|
135
|
+
*/
|
136
|
+
png_image* ctx;
|
137
|
+
} simplified;
|
138
|
+
} png_decoder_t;
|
139
|
+
|
140
|
+
static const char* decoder_opt_keys[] ={
|
141
|
+
"pixel_format", // alias of "color_type"
|
142
|
+
"without_meta", // bool (default: false)
|
143
|
+
"api_type", // string ("simplified" or "classic")
|
144
|
+
"display_gamma", // float
|
145
|
+
};
|
146
|
+
|
147
|
+
static ID decoder_opt_ids[N(decoder_opt_keys)];
|
148
|
+
|
149
|
+
static const char* encoder_opt_keys[] ={
|
150
|
+
"pixel_format", // alias of "color_type"
|
151
|
+
"interlace", // bool (default: false)
|
152
|
+
"compression", // int 0~9
|
153
|
+
"text", // hash<String,String>
|
154
|
+
"time", // bool (default: true)
|
155
|
+
"gamma", // float
|
156
|
+
};
|
157
|
+
|
158
|
+
static ID encoder_opt_ids[N(encoder_opt_keys)];
|
159
|
+
|
160
|
+
|
161
|
+
static void
|
162
|
+
rb_encoder_free(void* _ptr)
|
163
|
+
{
|
164
|
+
png_encoder_t* ptr;
|
165
|
+
int i;
|
166
|
+
|
167
|
+
ptr = (png_encoder_t*)_ptr;
|
168
|
+
|
169
|
+
if (ptr->ctx != NULL) {
|
170
|
+
if (ptr->rows != NULL) {
|
171
|
+
png_free(ptr->ctx, ptr->rows);
|
172
|
+
}
|
173
|
+
|
174
|
+
png_destroy_write_struct(&ptr->ctx, &ptr->info);
|
175
|
+
}
|
176
|
+
|
177
|
+
if (ptr->text != NULL) {
|
178
|
+
for (i = 0; i < ptr->num_text; i++) {
|
179
|
+
if (ptr->text[i].key != NULL) {
|
180
|
+
xfree(ptr->text[i].key);
|
181
|
+
}
|
182
|
+
|
183
|
+
if (ptr->text[i].text != NULL) {
|
184
|
+
xfree(ptr->text[i].text);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
free(ptr);
|
190
|
+
}
|
191
|
+
|
192
|
+
static void
|
193
|
+
mem_io_write_data(png_structp ctx, png_bytep src, png_size_t size)
|
194
|
+
{
|
195
|
+
VALUE buf;
|
196
|
+
|
197
|
+
buf = (VALUE)png_get_io_ptr(ctx);
|
198
|
+
rb_str_buf_cat(buf, (const char *)src, size);
|
199
|
+
}
|
200
|
+
|
201
|
+
static void
|
202
|
+
mem_io_flush(png_structp ctx)
|
203
|
+
{
|
204
|
+
// ignore
|
205
|
+
}
|
206
|
+
|
207
|
+
static VALUE
|
208
|
+
rb_encoder_alloc(VALUE self)
|
209
|
+
{
|
210
|
+
png_encoder_t* ptr;
|
211
|
+
|
212
|
+
ptr = ALLOC(png_encoder_t);
|
213
|
+
memset(ptr, 0, sizeof(*ptr));
|
214
|
+
|
215
|
+
ptr->c_type = PNG_COLOR_TYPE_RGB;
|
216
|
+
ptr->i_meth = PNG_INTERLACE_NONE;
|
217
|
+
ptr->c_level = Z_DEFAULT_COMPRESSION;
|
218
|
+
ptr->f_type = PNG_FILTER_TYPE_BASE;
|
219
|
+
ptr->num_comp = 3;
|
220
|
+
ptr->with_time = !0;
|
221
|
+
ptr->gamma = NAN;
|
222
|
+
|
223
|
+
return Data_Wrap_Struct(encoder_klass, 0, rb_encoder_free, ptr);
|
224
|
+
}
|
225
|
+
|
226
|
+
static void
|
227
|
+
eval_encoder_opt_color_type(png_encoder_t* ptr, VALUE opt)
|
228
|
+
{
|
229
|
+
if (opt != Qundef) {
|
230
|
+
if (EQ_STR(opt, "GRAY") || EQ_STR(opt, "GRAYSCALE")) {
|
231
|
+
ptr->c_type = PNG_COLOR_TYPE_GRAY;
|
232
|
+
ptr->num_comp = 1;
|
233
|
+
|
234
|
+
} else if (EQ_STR(opt, "GA")) {
|
235
|
+
ptr->c_type = PNG_COLOR_TYPE_GA;
|
236
|
+
ptr->num_comp = 2;
|
237
|
+
|
238
|
+
} else if (EQ_STR(opt, "RGB")) {
|
239
|
+
ptr->c_type = PNG_COLOR_TYPE_RGB;
|
240
|
+
ptr->num_comp = 3;
|
241
|
+
|
242
|
+
} else if (EQ_STR(opt, "RGBA")) {
|
243
|
+
ptr->c_type = PNG_COLOR_TYPE_RGBA;
|
244
|
+
ptr->num_comp = 4;
|
245
|
+
|
246
|
+
} else {
|
247
|
+
ARGUMENT_ERROR(":color_type is invalid value");
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
static void
|
253
|
+
eval_encoder_opt_interlace(png_encoder_t* ptr, VALUE opt)
|
254
|
+
{
|
255
|
+
if (opt != Qundef) {
|
256
|
+
ptr->i_meth = (RTEST(opt))? PNG_INTERLACE_ADAM7: PNG_INTERLACE_NONE;
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
static void
|
261
|
+
eval_encoder_opt_compression(png_encoder_t* ptr, VALUE opt)
|
262
|
+
{
|
263
|
+
int val;
|
264
|
+
|
265
|
+
if (opt != Qundef) {
|
266
|
+
switch (TYPE(opt)) {
|
267
|
+
case T_FIXNUM:
|
268
|
+
val = FIX2INT(opt);
|
269
|
+
if (val < 0 || val > 9) {
|
270
|
+
ARGUMENT_ERROR(":compress is out of range");
|
271
|
+
}
|
272
|
+
break;
|
273
|
+
|
274
|
+
case T_STRING:
|
275
|
+
case T_SYMBOL:
|
276
|
+
if (EQ_STR(opt, "NO_COMPRESSION")) {
|
277
|
+
val = Z_NO_COMPRESSION;
|
278
|
+
|
279
|
+
} else if (EQ_STR(opt, "BEST_SPEED")) {
|
280
|
+
val = Z_BEST_SPEED;
|
281
|
+
|
282
|
+
} else if (EQ_STR(opt, "BEST_COMPRESSION")) {
|
283
|
+
val = Z_BEST_COMPRESSION;
|
284
|
+
|
285
|
+
} else if (EQ_STR(opt, "DEFAULT")) {
|
286
|
+
val = Z_DEFAULT_COMPRESSION;
|
287
|
+
|
288
|
+
} else {
|
289
|
+
ARGUMENT_ERROR(":interlace is invalid value");
|
290
|
+
}
|
291
|
+
break;
|
292
|
+
|
293
|
+
default:
|
294
|
+
TYPE_ERROR(":interlace is not Symbol and String");
|
295
|
+
}
|
296
|
+
|
297
|
+
ptr->c_level = val;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
static VALUE
|
302
|
+
capitalize(VALUE str)
|
303
|
+
{
|
304
|
+
VALUE tmp;
|
305
|
+
int i;
|
306
|
+
|
307
|
+
tmp = rb_str_split(rb_funcall(str, rb_intern("to_s"), 0), "_");
|
308
|
+
|
309
|
+
for (i = 0; i < RARRAY_LEN(tmp); i++) {
|
310
|
+
rb_funcall(RARRAY_AREF(tmp, i), rb_intern("capitalize!"), 0);
|
311
|
+
}
|
312
|
+
|
313
|
+
return rb_ary_join(tmp, rb_str_new_cstr(" "));
|
314
|
+
}
|
315
|
+
|
316
|
+
static char*
|
317
|
+
clone_cstr(VALUE s)
|
318
|
+
{
|
319
|
+
char* ret;
|
320
|
+
size_t sz;
|
321
|
+
|
322
|
+
sz = RSTRING_LEN(s);
|
323
|
+
ret = (char*)malloc(sz + 1);
|
324
|
+
|
325
|
+
memcpy(ret, RSTRING_PTR(s), sz);
|
326
|
+
ret[sz] = '\0';
|
327
|
+
|
328
|
+
return ret;
|
329
|
+
}
|
330
|
+
|
331
|
+
|
332
|
+
static void
|
333
|
+
eval_encoder_opt_text(png_encoder_t* ptr, VALUE opt)
|
334
|
+
{
|
335
|
+
VALUE keys;
|
336
|
+
VALUE key;
|
337
|
+
VALUE val;
|
338
|
+
int i;
|
339
|
+
png_text* text;
|
340
|
+
|
341
|
+
text = NULL;
|
342
|
+
|
343
|
+
if (opt != Qundef) {
|
344
|
+
if (TYPE(opt) == T_HASH && RHASH_SIZE(opt) > 0) {
|
345
|
+
keys = rb_funcall(opt, rb_intern("keys"), 0);
|
346
|
+
text = (png_text*)xmalloc(sizeof(png_text) * RHASH_SIZE(opt));
|
347
|
+
|
348
|
+
/*
|
349
|
+
* 途中で例外が発生する可能性があるので rb_encoder_free()で
|
350
|
+
* 資源回収できる様に 0クリアとコンテキスト登録を最初に済ま
|
351
|
+
* せておく。
|
352
|
+
*
|
353
|
+
* なお、この処理はinitialize()の過程で呼び出される。このた
|
354
|
+
* め例外が発生しコンテキストの状態が中途半端な状態でユーザ
|
355
|
+
* から参照されることはない。
|
356
|
+
*/
|
357
|
+
memset(text, 0, sizeof(*text));
|
358
|
+
ptr->text = text;
|
359
|
+
ptr->num_text = RARRAY_LEN(keys);
|
360
|
+
|
361
|
+
for (i = 0; i < RARRAY_LEN(keys); i++) {
|
362
|
+
key = RARRAY_AREF(keys, i);
|
363
|
+
val = rb_hash_aref(opt, key);
|
364
|
+
|
365
|
+
if (TYPE(key) != T_STRING && TYPE(key) != T_SYMBOL) {
|
366
|
+
ARGUMENT_ERROR(":type is invalid structure");
|
367
|
+
}
|
368
|
+
|
369
|
+
if (TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL) {
|
370
|
+
ARGUMENT_ERROR(":type is invalid structure");
|
371
|
+
}
|
372
|
+
|
373
|
+
key = capitalize(key);
|
374
|
+
if (RSTRING_LEN(key) >= 0 && RSTRING_LEN(key) <= 79) {
|
375
|
+
text[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
376
|
+
text[i].key = clone_cstr(key);
|
377
|
+
text[i].text = clone_cstr(val);
|
378
|
+
text[i].text_length = RSTRING_LEN(val);
|
379
|
+
|
380
|
+
} else {
|
381
|
+
ARGUMENT_ERROR("keyword in :text is too long");
|
382
|
+
}
|
383
|
+
}
|
384
|
+
} else {
|
385
|
+
ARGUMENT_ERROR(":text is invalid value");
|
386
|
+
}
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
static void
|
391
|
+
eval_encoder_opt_time(png_encoder_t* ptr, VALUE opt)
|
392
|
+
{
|
393
|
+
if (opt != Qundef) {
|
394
|
+
ptr->with_time = RTEST(opt);
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
static void
|
399
|
+
eval_encoder_opt_gamma(png_encoder_t* ptr, VALUE opt)
|
400
|
+
{
|
401
|
+
if (opt != Qundef) {
|
402
|
+
ptr->gamma = NUM2DBL(opt);
|
403
|
+
}
|
404
|
+
}
|
405
|
+
|
406
|
+
static void
|
407
|
+
set_encoder_context(png_encoder_t* ptr, int wd, int ht, VALUE opt)
|
408
|
+
{
|
409
|
+
png_structp ctx;
|
410
|
+
png_infop info;
|
411
|
+
VALUE opts[N(encoder_opt_ids)];
|
412
|
+
|
413
|
+
const char* err;
|
414
|
+
png_byte** rows;
|
415
|
+
|
416
|
+
/*
|
417
|
+
* parse options
|
418
|
+
*/
|
419
|
+
rb_get_kwargs(opt, encoder_opt_ids, 0, N(encoder_opt_ids), opts);
|
420
|
+
|
421
|
+
/*
|
422
|
+
* set context
|
423
|
+
*/
|
424
|
+
eval_encoder_opt_color_type(ptr, opts[0]);
|
425
|
+
eval_encoder_opt_interlace(ptr, opts[1]);
|
426
|
+
eval_encoder_opt_compression(ptr, opts[2]);
|
427
|
+
eval_encoder_opt_text(ptr, opts[3]);
|
428
|
+
eval_encoder_opt_time(ptr, opts[4]);
|
429
|
+
eval_encoder_opt_gamma(ptr, opts[5]);
|
430
|
+
|
431
|
+
/*
|
432
|
+
* create PNG context
|
433
|
+
*/
|
434
|
+
do {
|
435
|
+
err = NULL;
|
436
|
+
rows = NULL;
|
437
|
+
info = NULL;
|
438
|
+
|
439
|
+
ctx = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
440
|
+
if (ctx == NULL) {
|
441
|
+
err = "png_create_read_struct() failed.";
|
442
|
+
break;
|
443
|
+
}
|
444
|
+
|
445
|
+
info = png_create_info_struct(ctx);
|
446
|
+
if (info == NULL) {
|
447
|
+
err = "png_create_info_structt() failed.";
|
448
|
+
break;
|
449
|
+
}
|
450
|
+
|
451
|
+
rows = png_malloc(ctx, ht * sizeof(png_byte*));
|
452
|
+
if (rows == NULL) {
|
453
|
+
err = "png_malloc() failed.";
|
454
|
+
break;
|
455
|
+
}
|
456
|
+
|
457
|
+
memset(rows, 0, ht * sizeof(png_byte*));
|
458
|
+
|
459
|
+
ptr->ctx = ctx;
|
460
|
+
ptr->info = info;
|
461
|
+
ptr->width = wd;
|
462
|
+
ptr->height = ht;
|
463
|
+
ptr->stride = ptr->width * ptr->num_comp;
|
464
|
+
ptr->pixels = ptr->stride * ptr->height;
|
465
|
+
ptr->rows = rows;
|
466
|
+
|
467
|
+
} while(0);
|
468
|
+
|
469
|
+
/*
|
470
|
+
* post process
|
471
|
+
*/
|
472
|
+
if (err != NULL) {
|
473
|
+
if (ctx != NULL) {
|
474
|
+
png_destroy_write_struct(&ctx, &info);
|
475
|
+
}
|
476
|
+
|
477
|
+
if (rows != NULL) {
|
478
|
+
png_free(ctx, rows);
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
|
483
|
+
static VALUE
|
484
|
+
rb_encoder_initialize(int argc, VALUE* argv, VALUE self)
|
485
|
+
{
|
486
|
+
png_encoder_t* ptr;
|
487
|
+
VALUE wd;
|
488
|
+
VALUE ht;
|
489
|
+
VALUE opts;
|
490
|
+
|
491
|
+
/*
|
492
|
+
* strip object
|
493
|
+
*/
|
494
|
+
Data_Get_Struct(self, png_encoder_t, ptr);
|
495
|
+
|
496
|
+
/*
|
497
|
+
* parse argument
|
498
|
+
*/
|
499
|
+
rb_scan_args(argc, argv, "21", &wd, &ht, &opts);
|
500
|
+
|
501
|
+
Check_Type(wd, T_FIXNUM);
|
502
|
+
Check_Type(ht, T_FIXNUM);
|
503
|
+
if (opts != Qnil) Check_Type(opts, T_HASH);
|
504
|
+
|
505
|
+
|
506
|
+
/*
|
507
|
+
* set context
|
508
|
+
*/
|
509
|
+
set_encoder_context(ptr, FIX2INT(wd), FIX2INT(ht), opts);
|
510
|
+
|
511
|
+
return self;
|
512
|
+
}
|
513
|
+
|
514
|
+
static VALUE
|
515
|
+
rb_encoder_encode(VALUE self, VALUE data)
|
516
|
+
{
|
517
|
+
VALUE ret;
|
518
|
+
png_encoder_t* ptr;
|
519
|
+
png_uint_32 i;
|
520
|
+
uint8_t* p;
|
521
|
+
|
522
|
+
/*
|
523
|
+
* initialize
|
524
|
+
*/
|
525
|
+
ret = rb_str_buf_new(0);
|
526
|
+
|
527
|
+
/*
|
528
|
+
* strip object
|
529
|
+
*/
|
530
|
+
Data_Get_Struct(self, png_encoder_t, ptr);
|
531
|
+
|
532
|
+
/*
|
533
|
+
* argument check
|
534
|
+
*/
|
535
|
+
Check_Type(data, T_STRING);
|
536
|
+
if (RSTRING_LEN(data) != ptr->pixels) {
|
537
|
+
ARGUMENT_ERROR("invalid data size");
|
538
|
+
}
|
539
|
+
|
540
|
+
/*
|
541
|
+
* call libpng
|
542
|
+
*/
|
543
|
+
png_set_IHDR(ptr->ctx,
|
544
|
+
ptr->info,
|
545
|
+
ptr->width,
|
546
|
+
ptr->height,
|
547
|
+
8,
|
548
|
+
ptr->c_type,
|
549
|
+
ptr->i_meth,
|
550
|
+
PNG_COMPRESSION_TYPE_BASE,
|
551
|
+
PNG_FILTER_TYPE_BASE);
|
552
|
+
|
553
|
+
if (ptr->text) {
|
554
|
+
png_set_text(ptr->ctx, ptr->info, ptr->text, ptr->num_text);
|
555
|
+
}
|
556
|
+
|
557
|
+
if (ptr->with_time) {
|
558
|
+
time_t tm;
|
559
|
+
png_time png_time;
|
560
|
+
|
561
|
+
time(&tm);
|
562
|
+
png_convert_from_time_t(&png_time, tm);
|
563
|
+
png_set_tIME(ptr->ctx, ptr->info, &png_time);
|
564
|
+
}
|
565
|
+
|
566
|
+
if (!isnan(ptr->gamma)) {
|
567
|
+
png_set_gAMA(ptr->ctx, ptr->info, ptr->gamma);
|
568
|
+
}
|
569
|
+
|
570
|
+
png_set_compression_level(ptr->ctx, ptr->c_level);
|
571
|
+
|
572
|
+
png_set_write_fn(ptr->ctx,
|
573
|
+
(png_voidp)ret,
|
574
|
+
(png_rw_ptr)mem_io_write_data,
|
575
|
+
(png_flush_ptr)mem_io_flush);
|
576
|
+
|
577
|
+
p = (png_byte*)RSTRING_PTR(data);
|
578
|
+
for (i = 0; i < ptr->height; i++) {
|
579
|
+
ptr->rows[i] = p;
|
580
|
+
p += ptr->stride;
|
581
|
+
}
|
582
|
+
|
583
|
+
png_set_rows(ptr->ctx, ptr->info, ptr->rows);
|
584
|
+
|
585
|
+
if (setjmp(png_jmpbuf(ptr->ctx))) {
|
586
|
+
RUNTIME_ERROR("encode error");
|
587
|
+
|
588
|
+
} else {
|
589
|
+
png_write_png(ptr->ctx, ptr->info, PNG_TRANSFORM_IDENTITY, NULL);
|
590
|
+
}
|
591
|
+
|
592
|
+
return ret;
|
593
|
+
}
|
594
|
+
|
595
|
+
static void
|
596
|
+
mem_io_read_data(png_structp ctx, png_bytep dst, png_size_t rq_size)
|
597
|
+
{
|
598
|
+
mem_io_t* io;
|
599
|
+
|
600
|
+
io = (mem_io_t*)png_get_io_ptr(ctx);
|
601
|
+
|
602
|
+
if (io->pos + rq_size <= io->size) {
|
603
|
+
memcpy(dst, io->ptr + io->pos, rq_size);
|
604
|
+
io->pos += rq_size;
|
605
|
+
|
606
|
+
} else {
|
607
|
+
png_error(ctx, "data not enough.");
|
608
|
+
}
|
609
|
+
}
|
610
|
+
|
611
|
+
|
612
|
+
static void
|
613
|
+
rb_decoder_free(void* _ptr)
|
614
|
+
{
|
615
|
+
png_decoder_t* ptr;
|
616
|
+
|
617
|
+
ptr = (png_decoder_t*)_ptr;
|
618
|
+
|
619
|
+
if (ptr->common.api_type == API_SIMPLIFIED) {
|
620
|
+
if (ptr->simplified.ctx) {
|
621
|
+
png_image_free(ptr->simplified.ctx);
|
622
|
+
xfree(ptr->simplified.ctx);
|
623
|
+
}
|
624
|
+
|
625
|
+
} else {
|
626
|
+
if (ptr->classic.ctx != NULL) {
|
627
|
+
if (ptr->classic.rows != NULL) {
|
628
|
+
png_free(ptr->classic.ctx, ptr->classic.rows);
|
629
|
+
}
|
630
|
+
|
631
|
+
png_destroy_read_struct(&ptr->classic.ctx,
|
632
|
+
&ptr->classic.fsi,
|
633
|
+
&ptr->classic.bsi);
|
634
|
+
}
|
635
|
+
}
|
636
|
+
|
637
|
+
free(ptr);
|
638
|
+
}
|
639
|
+
|
640
|
+
static VALUE
|
641
|
+
rb_decoder_alloc(VALUE self)
|
642
|
+
{
|
643
|
+
png_decoder_t* ptr;
|
644
|
+
|
645
|
+
ptr = ALLOC(png_decoder_t);
|
646
|
+
memset(ptr, 0, sizeof(*ptr));
|
647
|
+
|
648
|
+
ptr->common.api_type = API_SIMPLIFIED;
|
649
|
+
ptr->common.format = PNG_FORMAT_RGB;
|
650
|
+
ptr->common.need_meta = !0;
|
651
|
+
ptr->common.display_gamma = NAN;
|
652
|
+
|
653
|
+
return Data_Wrap_Struct(decoder_klass, 0, rb_decoder_free, ptr);
|
654
|
+
}
|
655
|
+
|
656
|
+
static void
|
657
|
+
eval_decoder_opt_api_type(png_decoder_t* ptr, VALUE opt)
|
658
|
+
{
|
659
|
+
int api_type;
|
660
|
+
|
661
|
+
if (opt != Qundef) {
|
662
|
+
if (EQ_STR(opt, "simplified")) {
|
663
|
+
api_type = API_SIMPLIFIED;
|
664
|
+
|
665
|
+
} else if (EQ_STR(opt, "classic")) {
|
666
|
+
api_type = API_CLASSIC;
|
667
|
+
|
668
|
+
} else {
|
669
|
+
ARGUMENT_ERROR(":api_type is invalid value");
|
670
|
+
}
|
671
|
+
|
672
|
+
ptr->common.api_type = api_type;
|
673
|
+
}
|
674
|
+
}
|
675
|
+
|
676
|
+
static void
|
677
|
+
eval_decoder_opt_pixel_format(png_decoder_t* ptr, VALUE opt)
|
678
|
+
{
|
679
|
+
int format;
|
680
|
+
|
681
|
+
if (opt != Qundef) {
|
682
|
+
if (EQ_STR(opt, "GRAY") || EQ_STR(opt, "GRAYSCALE")) {
|
683
|
+
format = PNG_FORMAT_GRAY;
|
684
|
+
|
685
|
+
} else if (EQ_STR(opt, "GA")) {
|
686
|
+
format = PNG_FORMAT_GA;
|
687
|
+
|
688
|
+
} else if (EQ_STR(opt, "AG")) {
|
689
|
+
format = PNG_FORMAT_AG;
|
690
|
+
|
691
|
+
} else if (EQ_STR(opt, "RGB")) {
|
692
|
+
format = PNG_FORMAT_RGB;
|
693
|
+
|
694
|
+
} else if (EQ_STR(opt, "BGR")) {
|
695
|
+
format = PNG_FORMAT_BGR;
|
696
|
+
|
697
|
+
} else if (EQ_STR(opt, "RGBA")) {
|
698
|
+
format = PNG_FORMAT_RGBA;
|
699
|
+
|
700
|
+
} else if (EQ_STR(opt, "ARGB")) {
|
701
|
+
format = PNG_FORMAT_ARGB;
|
702
|
+
|
703
|
+
} else if (EQ_STR(opt, "BGRA")) {
|
704
|
+
format = PNG_FORMAT_BGRA;
|
705
|
+
|
706
|
+
} else if (EQ_STR(opt, "ABGR")) {
|
707
|
+
format = PNG_FORMAT_ABGR;
|
708
|
+
|
709
|
+
} else {
|
710
|
+
ARGUMENT_ERROR(":color_type is invalid value");
|
711
|
+
}
|
712
|
+
|
713
|
+
ptr->common.format = format;
|
714
|
+
}
|
715
|
+
}
|
716
|
+
|
717
|
+
static void
|
718
|
+
eval_decoder_opt_without_meta(png_decoder_t* ptr, VALUE opt)
|
719
|
+
{
|
720
|
+
if (opt != Qundef) {
|
721
|
+
ptr->common.need_meta = !RTEST(opt);
|
722
|
+
}
|
723
|
+
}
|
724
|
+
|
725
|
+
static void
|
726
|
+
eval_decoder_opt_display_gamma(png_decoder_t* ptr, VALUE opt)
|
727
|
+
{
|
728
|
+
if (opt != Qundef) {
|
729
|
+
ptr->common.display_gamma = NUM2DBL(opt);
|
730
|
+
}
|
731
|
+
}
|
732
|
+
|
733
|
+
static void
|
734
|
+
set_decoder_context(png_decoder_t* ptr, VALUE opt)
|
735
|
+
{
|
736
|
+
VALUE opts[N(decoder_opt_ids)];
|
737
|
+
|
738
|
+
/*
|
739
|
+
* parse options
|
740
|
+
*/
|
741
|
+
rb_get_kwargs(opt, decoder_opt_ids, 0, N(decoder_opt_ids), opts);
|
742
|
+
|
743
|
+
/*
|
744
|
+
* set context
|
745
|
+
*/
|
746
|
+
eval_decoder_opt_api_type(ptr, opts[2]);
|
747
|
+
eval_decoder_opt_pixel_format(ptr, opts[0]);
|
748
|
+
eval_decoder_opt_without_meta(ptr, opts[1]);
|
749
|
+
eval_decoder_opt_display_gamma(ptr, opts[3]);
|
750
|
+
}
|
751
|
+
|
752
|
+
static VALUE
|
753
|
+
rb_decoder_initialize(int argc, VALUE* argv, VALUE self)
|
754
|
+
{
|
755
|
+
png_decoder_t* ptr;
|
756
|
+
VALUE opt;
|
757
|
+
|
758
|
+
/*
|
759
|
+
* strip object
|
760
|
+
*/
|
761
|
+
Data_Get_Struct(self, png_decoder_t, ptr);
|
762
|
+
|
763
|
+
/*
|
764
|
+
* parse argument
|
765
|
+
*/
|
766
|
+
rb_scan_args(argc, argv, "01", &opt);
|
767
|
+
if (opt != Qnil) Check_Type(opt, T_HASH);
|
768
|
+
|
769
|
+
/*
|
770
|
+
* set context
|
771
|
+
*/
|
772
|
+
set_decoder_context(ptr, opt);
|
773
|
+
|
774
|
+
return Qtrue;
|
775
|
+
}
|
776
|
+
|
777
|
+
static void
|
778
|
+
set_read_context(png_decoder_t* ptr, VALUE data)
|
779
|
+
{
|
780
|
+
png_structp ctx;
|
781
|
+
png_infop fsi;
|
782
|
+
png_infop bsi;
|
783
|
+
|
784
|
+
const char* err;
|
785
|
+
|
786
|
+
do {
|
787
|
+
err = NULL;
|
788
|
+
fsi = NULL;
|
789
|
+
bsi = NULL;
|
790
|
+
|
791
|
+
ctx = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
792
|
+
if (ctx == NULL) {
|
793
|
+
err = "png_create_read_struct() failed.";
|
794
|
+
break;
|
795
|
+
}
|
796
|
+
|
797
|
+
fsi = png_create_info_struct(ctx);
|
798
|
+
bsi = png_create_info_struct(ctx);
|
799
|
+
if (fsi == NULL || bsi == NULL) {
|
800
|
+
err = "png_create_info_struct() failed.";
|
801
|
+
break;
|
802
|
+
}
|
803
|
+
|
804
|
+
ptr->classic.ctx = ctx;
|
805
|
+
ptr->classic.fsi = fsi;
|
806
|
+
ptr->classic.bsi = bsi;
|
807
|
+
|
808
|
+
ptr->classic.io.ptr = (uint8_t*)RSTRING_PTR(data);
|
809
|
+
ptr->classic.io.size = RSTRING_LEN(data);
|
810
|
+
ptr->classic.io.pos = 0;
|
811
|
+
|
812
|
+
if (setjmp(png_jmpbuf(ptr->classic.ctx))) {
|
813
|
+
RUNTIME_ERROR("decode error");
|
814
|
+
|
815
|
+
} else {
|
816
|
+
png_set_read_fn(ptr->classic.ctx,
|
817
|
+
(png_voidp)&ptr->classic.io,
|
818
|
+
(png_rw_ptr)mem_io_read_data);
|
819
|
+
}
|
820
|
+
} while(0);
|
821
|
+
|
822
|
+
if (err != NULL) {
|
823
|
+
if (ctx != NULL) {
|
824
|
+
png_destroy_read_struct(&ctx, &fsi, &bsi);
|
825
|
+
}
|
826
|
+
|
827
|
+
RUNTIME_ERROR(err);
|
828
|
+
}
|
829
|
+
}
|
830
|
+
|
831
|
+
static void
|
832
|
+
get_header_info(png_decoder_t* ptr)
|
833
|
+
{
|
834
|
+
png_get_IHDR(ptr->classic.ctx,
|
835
|
+
ptr->classic.fsi,
|
836
|
+
&ptr->classic.width,
|
837
|
+
&ptr->classic.height,
|
838
|
+
&ptr->classic.depth,
|
839
|
+
&ptr->classic.c_type,
|
840
|
+
&ptr->classic.i_meth,
|
841
|
+
&ptr->classic.c_meth,
|
842
|
+
&ptr->classic.f_meth);
|
843
|
+
|
844
|
+
png_get_tIME(ptr->classic.ctx, ptr->classic.fsi, &ptr->classic.time);
|
845
|
+
|
846
|
+
png_get_text(ptr->classic.ctx,
|
847
|
+
ptr->classic.fsi,
|
848
|
+
&ptr->classic.text,
|
849
|
+
&ptr->classic.num_text);
|
850
|
+
|
851
|
+
if (!png_get_gAMA(ptr->classic.ctx,
|
852
|
+
ptr->classic.fsi, &ptr->classic.file_gamma)) {
|
853
|
+
ptr->classic.file_gamma = NAN;
|
854
|
+
}
|
855
|
+
}
|
856
|
+
|
857
|
+
static VALUE
|
858
|
+
get_color_type_str(png_decoder_t* ptr)
|
859
|
+
{
|
860
|
+
const char* cstr;
|
861
|
+
char tmp[32];
|
862
|
+
|
863
|
+
switch (ptr->classic.c_type) {
|
864
|
+
case PNG_COLOR_TYPE_GRAY:
|
865
|
+
cstr = "GRAY";
|
866
|
+
break;
|
867
|
+
|
868
|
+
case PNG_COLOR_TYPE_PALETTE:
|
869
|
+
cstr = "PALETTE";
|
870
|
+
break;
|
871
|
+
|
872
|
+
case PNG_COLOR_TYPE_RGB:
|
873
|
+
cstr = "RGB";
|
874
|
+
break;
|
875
|
+
|
876
|
+
case PNG_COLOR_TYPE_RGBA:
|
877
|
+
cstr = "RGBA";
|
878
|
+
break;
|
879
|
+
|
880
|
+
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
881
|
+
cstr = "GA";
|
882
|
+
break;
|
883
|
+
|
884
|
+
default:
|
885
|
+
sprintf(tmp, "UNKNOWN(%d)", ptr->classic.c_type);
|
886
|
+
cstr = tmp;
|
887
|
+
break;
|
888
|
+
}
|
889
|
+
|
890
|
+
return rb_str_new_cstr(cstr);
|
891
|
+
}
|
892
|
+
|
893
|
+
static VALUE
|
894
|
+
get_interlace_method_str(png_decoder_t* ptr)
|
895
|
+
{
|
896
|
+
const char* cstr;
|
897
|
+
char tmp[32];
|
898
|
+
|
899
|
+
switch (ptr->classic.i_meth) {
|
900
|
+
case PNG_INTERLACE_NONE:
|
901
|
+
cstr = "NONE";
|
902
|
+
break;
|
903
|
+
|
904
|
+
case PNG_INTERLACE_ADAM7:
|
905
|
+
cstr = "ADAM7";
|
906
|
+
break;
|
907
|
+
|
908
|
+
default:
|
909
|
+
sprintf(tmp, "UNKNOWN(%d)", ptr->classic.i_meth);
|
910
|
+
cstr = tmp;
|
911
|
+
break;
|
912
|
+
}
|
913
|
+
|
914
|
+
return rb_str_new_cstr(cstr);
|
915
|
+
}
|
916
|
+
|
917
|
+
static VALUE
|
918
|
+
get_compression_method_str(png_decoder_t* ptr)
|
919
|
+
{
|
920
|
+
const char* cstr;
|
921
|
+
char tmp[32];
|
922
|
+
|
923
|
+
switch (ptr->classic.c_meth) {
|
924
|
+
case PNG_COMPRESSION_TYPE_BASE:
|
925
|
+
cstr = "BASE";
|
926
|
+
break;
|
927
|
+
|
928
|
+
default:
|
929
|
+
sprintf(tmp, "UNKNOWN(%d)", ptr->classic.c_meth);
|
930
|
+
cstr = tmp;
|
931
|
+
break;
|
932
|
+
}
|
933
|
+
|
934
|
+
return rb_str_new_cstr(cstr);
|
935
|
+
}
|
936
|
+
|
937
|
+
static VALUE
|
938
|
+
get_filter_method_str(png_decoder_t* ptr)
|
939
|
+
{
|
940
|
+
const char* cstr;
|
941
|
+
char tmp[32];
|
942
|
+
|
943
|
+
switch (ptr->classic.f_meth) {
|
944
|
+
case PNG_FILTER_TYPE_BASE:
|
945
|
+
cstr = "BASE";
|
946
|
+
break;
|
947
|
+
|
948
|
+
case PNG_INTRAPIXEL_DIFFERENCING:
|
949
|
+
cstr = "INTRAPIXEL_DIFFERENCING";
|
950
|
+
break;
|
951
|
+
|
952
|
+
default:
|
953
|
+
sprintf(tmp, "UNKNOWN(%d)", ptr->classic.f_meth);
|
954
|
+
cstr = tmp;
|
955
|
+
break;
|
956
|
+
}
|
957
|
+
|
958
|
+
return rb_str_new_cstr(cstr);
|
959
|
+
}
|
960
|
+
|
961
|
+
static VALUE
|
962
|
+
create_text_meta(png_decoder_t* ptr)
|
963
|
+
{
|
964
|
+
VALUE ret;
|
965
|
+
VALUE key;
|
966
|
+
VALUE val;
|
967
|
+
|
968
|
+
int i;
|
969
|
+
|
970
|
+
ret = rb_hash_new();
|
971
|
+
|
972
|
+
for (i = 0; i < ptr->classic.num_text; i++) {
|
973
|
+
key = rb_str_new2(ptr->classic.text[i].key);
|
974
|
+
val = rb_str_new(ptr->classic.text[i].text,
|
975
|
+
ptr->classic.text[i].text_length);
|
976
|
+
|
977
|
+
rb_funcall(key, rb_intern("downcase!"), 0);
|
978
|
+
rb_funcall(key, rb_intern("gsub!"), 2, rb_str_new2(" "), rb_str_new2("_"));
|
979
|
+
|
980
|
+
rb_hash_aset(ret, rb_to_symbol(key), val);
|
981
|
+
}
|
982
|
+
|
983
|
+
return ret;
|
984
|
+
}
|
985
|
+
|
986
|
+
static VALUE
|
987
|
+
create_time_meta(png_decoder_t* ptr)
|
988
|
+
{
|
989
|
+
VALUE ret;
|
990
|
+
|
991
|
+
ret = rb_funcall(rb_cTime,
|
992
|
+
rb_intern("utc"),
|
993
|
+
6,
|
994
|
+
INT2FIX(ptr->classic.time->year),
|
995
|
+
INT2FIX(ptr->classic.time->month),
|
996
|
+
INT2FIX(ptr->classic.time->day),
|
997
|
+
INT2FIX(ptr->classic.time->hour),
|
998
|
+
INT2FIX(ptr->classic.time->minute),
|
999
|
+
INT2FIX(ptr->classic.time->second));
|
1000
|
+
|
1001
|
+
rb_funcall(ret, rb_intern("localtime"), 0);
|
1002
|
+
|
1003
|
+
return ret;
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
static VALUE
|
1007
|
+
create_meta(png_decoder_t* ptr)
|
1008
|
+
{
|
1009
|
+
VALUE ret;
|
1010
|
+
|
1011
|
+
ret = rb_obj_alloc(meta_klass);
|
1012
|
+
|
1013
|
+
rb_ivar_set(ret, rb_intern("@width"), INT2FIX(ptr->classic.width));
|
1014
|
+
rb_ivar_set(ret, rb_intern("@height"), INT2FIX(ptr->classic.height));
|
1015
|
+
rb_ivar_set(ret, rb_intern("@bit_depth"), INT2FIX(ptr->classic.depth));
|
1016
|
+
rb_ivar_set(ret, rb_intern("@color_type"), get_color_type_str(ptr));
|
1017
|
+
|
1018
|
+
rb_ivar_set(ret, rb_intern("@interlace_method"),
|
1019
|
+
get_interlace_method_str(ptr));
|
1020
|
+
|
1021
|
+
rb_ivar_set(ret, rb_intern("@compression_method"),
|
1022
|
+
get_compression_method_str(ptr));
|
1023
|
+
|
1024
|
+
rb_ivar_set(ret, rb_intern("@filter_method"), get_filter_method_str(ptr));
|
1025
|
+
|
1026
|
+
if (ptr->classic.text) {
|
1027
|
+
rb_ivar_set(ret, rb_intern("@text"), create_text_meta(ptr));
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
if (ptr->classic.time) {
|
1031
|
+
rb_ivar_set(ret, rb_intern("@time"), create_time_meta(ptr));
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
if (!isnan(ptr->classic.file_gamma)) {
|
1035
|
+
rb_ivar_set(ret,
|
1036
|
+
rb_intern("@file_gamma"),
|
1037
|
+
DBL2NUM(ptr->classic.file_gamma));
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
return ret;
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
static VALUE
|
1044
|
+
create_tiny_meta(png_decoder_t* ptr)
|
1045
|
+
{
|
1046
|
+
VALUE ret;
|
1047
|
+
const char* fmt;
|
1048
|
+
int nc;
|
1049
|
+
|
1050
|
+
ret = rb_obj_alloc(meta_klass);
|
1051
|
+
|
1052
|
+
rb_ivar_set(ret, rb_intern("@width"),
|
1053
|
+
INT2FIX(ptr->simplified.ctx->width));
|
1054
|
+
|
1055
|
+
rb_ivar_set(ret, id_stride,
|
1056
|
+
INT2FIX(PNG_IMAGE_ROW_STRIDE(*ptr->simplified.ctx)));
|
1057
|
+
|
1058
|
+
rb_ivar_set(ret, rb_intern("@height"),
|
1059
|
+
INT2FIX(ptr->simplified.ctx->height));
|
1060
|
+
|
1061
|
+
switch (ptr->common.format) {
|
1062
|
+
case PNG_FORMAT_GRAY:
|
1063
|
+
fmt = "GRAY";
|
1064
|
+
nc = 1;
|
1065
|
+
break;
|
1066
|
+
|
1067
|
+
case PNG_FORMAT_GA:
|
1068
|
+
fmt = "GA";
|
1069
|
+
nc = 2;
|
1070
|
+
break;
|
1071
|
+
|
1072
|
+
case PNG_FORMAT_AG:
|
1073
|
+
fmt = "AG";
|
1074
|
+
nc = 2;
|
1075
|
+
break;
|
1076
|
+
|
1077
|
+
case PNG_FORMAT_RGB:
|
1078
|
+
fmt = "RGB";
|
1079
|
+
nc = 3;
|
1080
|
+
break;
|
1081
|
+
|
1082
|
+
case PNG_FORMAT_BGR:
|
1083
|
+
fmt = "BGR";
|
1084
|
+
nc = 3;
|
1085
|
+
break;
|
1086
|
+
|
1087
|
+
case PNG_FORMAT_RGBA:
|
1088
|
+
fmt = "RGBA";
|
1089
|
+
nc = 4;
|
1090
|
+
break;
|
1091
|
+
|
1092
|
+
case PNG_FORMAT_ARGB:
|
1093
|
+
fmt = "ARGB";
|
1094
|
+
nc = 4;
|
1095
|
+
break;
|
1096
|
+
|
1097
|
+
case PNG_FORMAT_BGRA:
|
1098
|
+
fmt = "BGRA";
|
1099
|
+
nc = 4;
|
1100
|
+
break;
|
1101
|
+
|
1102
|
+
case PNG_FORMAT_ABGR:
|
1103
|
+
fmt = "ABGR";
|
1104
|
+
nc = 4;
|
1105
|
+
break;
|
1106
|
+
|
1107
|
+
default:
|
1108
|
+
fmt = "unknown";
|
1109
|
+
nc = 0;
|
1110
|
+
break;
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
rb_ivar_set(ret, id_pixfmt, rb_str_new_cstr(fmt));
|
1114
|
+
rb_ivar_set(ret, id_ncompo, INT2FIX(nc));
|
1115
|
+
|
1116
|
+
return ret;
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
static void
|
1120
|
+
clear_read_context(png_decoder_t* ptr)
|
1121
|
+
{
|
1122
|
+
if (ptr->classic.ctx != NULL) {
|
1123
|
+
png_destroy_read_struct(&ptr->classic.ctx,
|
1124
|
+
&ptr->classic.fsi,
|
1125
|
+
&ptr->classic.bsi);
|
1126
|
+
|
1127
|
+
ptr->classic.ctx = NULL;
|
1128
|
+
ptr->classic.fsi = NULL;
|
1129
|
+
ptr->classic.bsi = NULL;
|
1130
|
+
|
1131
|
+
ptr->classic.text = NULL;
|
1132
|
+
ptr->classic.time = NULL;
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
ptr->classic.io.ptr = NULL;
|
1136
|
+
ptr->classic.io.size = 0;
|
1137
|
+
ptr->classic.io.pos = 0;
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
typedef struct {
|
1141
|
+
png_decoder_t* ptr;
|
1142
|
+
VALUE data;
|
1143
|
+
} read_header_arg_t ;
|
1144
|
+
|
1145
|
+
static VALUE
|
1146
|
+
read_header_body(VALUE _arg)
|
1147
|
+
{
|
1148
|
+
read_header_arg_t* arg;
|
1149
|
+
png_decoder_t* ptr;
|
1150
|
+
VALUE data;
|
1151
|
+
|
1152
|
+
/*
|
1153
|
+
* initialize
|
1154
|
+
*/
|
1155
|
+
arg = (read_header_arg_t*)_arg;
|
1156
|
+
ptr = arg->ptr;
|
1157
|
+
data = arg->data;
|
1158
|
+
|
1159
|
+
/*
|
1160
|
+
* set context
|
1161
|
+
*/
|
1162
|
+
set_read_context(ptr, data);
|
1163
|
+
|
1164
|
+
/*
|
1165
|
+
* read header
|
1166
|
+
*/
|
1167
|
+
png_read_info(ptr->classic.ctx, ptr->classic.fsi);
|
1168
|
+
get_header_info(ptr);
|
1169
|
+
|
1170
|
+
return create_meta(ptr);
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
static VALUE
|
1174
|
+
read_header_ensure(VALUE _arg)
|
1175
|
+
{
|
1176
|
+
clear_read_context((png_decoder_t*)_arg);
|
1177
|
+
|
1178
|
+
return Qundef;
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
static VALUE
|
1182
|
+
rb_decoder_read_header(VALUE self, VALUE data)
|
1183
|
+
{
|
1184
|
+
VALUE ret;
|
1185
|
+
png_decoder_t* ptr;
|
1186
|
+
read_header_arg_t arg;
|
1187
|
+
|
1188
|
+
/*
|
1189
|
+
* argument check
|
1190
|
+
*/
|
1191
|
+
Check_Type(data, T_STRING);
|
1192
|
+
|
1193
|
+
if (RSTRING_LEN(data) < 8) {
|
1194
|
+
RUNTIME_ERROR("data too short.");
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
if (png_sig_cmp((png_const_bytep)RSTRING_PTR(data), 0, 8)) {
|
1198
|
+
RUNTIME_ERROR("Invalid PNG signature.");
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
/*
|
1202
|
+
* strip object
|
1203
|
+
*/
|
1204
|
+
Data_Get_Struct(self, png_decoder_t, ptr);
|
1205
|
+
|
1206
|
+
/*
|
1207
|
+
* call read header funciton
|
1208
|
+
*/
|
1209
|
+
arg.ptr = ptr;
|
1210
|
+
arg.data = data;
|
1211
|
+
|
1212
|
+
ret = rb_ensure(read_header_body, (VALUE)&arg,
|
1213
|
+
read_header_ensure, (VALUE)ptr);
|
1214
|
+
|
1215
|
+
return ret;
|
1216
|
+
}
|
1217
|
+
|
1218
|
+
static VALUE
|
1219
|
+
rb_decode_result_meta(VALUE self)
|
1220
|
+
{
|
1221
|
+
return rb_ivar_get(self, id_meta);
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
typedef struct {
|
1225
|
+
png_decoder_t* ptr;
|
1226
|
+
VALUE data;
|
1227
|
+
} decode_arg_t;
|
1228
|
+
|
1229
|
+
static VALUE
|
1230
|
+
decode_simplified_api_body(VALUE _arg)
|
1231
|
+
{
|
1232
|
+
VALUE ret;
|
1233
|
+
|
1234
|
+
decode_arg_t* arg;
|
1235
|
+
png_decoder_t* ptr;
|
1236
|
+
VALUE data;
|
1237
|
+
|
1238
|
+
size_t stride;
|
1239
|
+
size_t size;
|
1240
|
+
|
1241
|
+
/*
|
1242
|
+
* initialize
|
1243
|
+
*/
|
1244
|
+
arg = (decode_arg_t*)_arg;
|
1245
|
+
ptr = arg->ptr;
|
1246
|
+
data = arg->data;
|
1247
|
+
|
1248
|
+
/*
|
1249
|
+
* call simplified API
|
1250
|
+
*/
|
1251
|
+
do {
|
1252
|
+
ptr->simplified.ctx = (png_imagep)xmalloc(sizeof(png_image));
|
1253
|
+
memset(ptr->simplified.ctx, 0, sizeof(png_image));
|
1254
|
+
|
1255
|
+
ptr->simplified.ctx->version = PNG_IMAGE_VERSION;
|
1256
|
+
|
1257
|
+
png_image_begin_read_from_memory(ptr->simplified.ctx,
|
1258
|
+
RSTRING_PTR(data), RSTRING_LEN(data));
|
1259
|
+
if (PNG_IMAGE_FAILED(*ptr->simplified.ctx)) {
|
1260
|
+
RUNTIME_ERROR("png_image_begin_read_from_memory() failed");
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
ptr->simplified.ctx->format = ptr->common.format;
|
1264
|
+
|
1265
|
+
stride = PNG_IMAGE_ROW_STRIDE(*ptr->simplified.ctx);
|
1266
|
+
size = PNG_IMAGE_BUFFER_SIZE(*ptr->simplified.ctx, stride);
|
1267
|
+
ret = rb_str_buf_new(size);
|
1268
|
+
rb_str_set_len(ret, size);
|
1269
|
+
|
1270
|
+
png_image_finish_read(ptr->simplified.ctx,
|
1271
|
+
NULL, RSTRING_PTR(ret), stride, NULL);
|
1272
|
+
if (PNG_IMAGE_FAILED(*ptr->simplified.ctx)) {
|
1273
|
+
RUNTIME_ERROR("png_image_finish_read() failed");
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
if (ptr->common.need_meta) {
|
1277
|
+
rb_ivar_set(ret, id_meta, create_tiny_meta(ptr));
|
1278
|
+
rb_define_singleton_method(ret, "meta", rb_decode_result_meta, 0);
|
1279
|
+
}
|
1280
|
+
} while(0);
|
1281
|
+
|
1282
|
+
return ret;
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
static VALUE
|
1286
|
+
decode_simplified_api_ensure(VALUE _arg)
|
1287
|
+
{
|
1288
|
+
png_decoder_t* ptr;
|
1289
|
+
|
1290
|
+
ptr = (png_decoder_t*)_arg;
|
1291
|
+
|
1292
|
+
if (ptr->simplified.ctx) {
|
1293
|
+
png_image_free(ptr->simplified.ctx);
|
1294
|
+
xfree(ptr->simplified.ctx);
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
ptr->simplified.ctx = NULL;
|
1298
|
+
|
1299
|
+
return Qundef;
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
static VALUE
|
1303
|
+
decode_classic_api_body(VALUE _arg)
|
1304
|
+
{
|
1305
|
+
VALUE ret;
|
1306
|
+
|
1307
|
+
decode_arg_t* arg;
|
1308
|
+
png_decoder_t* ptr;
|
1309
|
+
VALUE data;
|
1310
|
+
|
1311
|
+
size_t stride;
|
1312
|
+
|
1313
|
+
png_uint_32 i;
|
1314
|
+
png_byte* p;
|
1315
|
+
|
1316
|
+
double file_gamma;
|
1317
|
+
|
1318
|
+
/*
|
1319
|
+
* initialize
|
1320
|
+
*/
|
1321
|
+
arg = (decode_arg_t*)_arg;
|
1322
|
+
ptr = arg->ptr;
|
1323
|
+
data = arg->data;
|
1324
|
+
|
1325
|
+
/*
|
1326
|
+
* set context
|
1327
|
+
*/
|
1328
|
+
set_read_context(ptr, data);
|
1329
|
+
|
1330
|
+
/*
|
1331
|
+
* read basic info
|
1332
|
+
*/
|
1333
|
+
png_read_info(ptr->classic.ctx, ptr->classic.fsi);
|
1334
|
+
|
1335
|
+
/*
|
1336
|
+
* gamma correction
|
1337
|
+
*/
|
1338
|
+
if (!isnan(ptr->common.display_gamma)) {
|
1339
|
+
if (!png_get_gAMA(ptr->classic.ctx, ptr->classic.fsi, &file_gamma)) {
|
1340
|
+
file_gamma = 0.45;
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
png_set_gamma(ptr->classic.ctx, ptr->common.display_gamma, file_gamma);
|
1344
|
+
}
|
1345
|
+
|
1346
|
+
png_read_update_info(ptr->classic.ctx, ptr->classic.fsi);
|
1347
|
+
|
1348
|
+
/*
|
1349
|
+
* get image size
|
1350
|
+
*/
|
1351
|
+
|
1352
|
+
ptr->classic.width = \
|
1353
|
+
png_get_image_width(ptr->classic.ctx, ptr->classic.fsi);
|
1354
|
+
|
1355
|
+
ptr->classic.height = \
|
1356
|
+
png_get_image_height(ptr->classic.ctx, ptr->classic.fsi);
|
1357
|
+
|
1358
|
+
stride = png_get_rowbytes(ptr->classic.ctx, ptr->classic.fsi);
|
1359
|
+
|
1360
|
+
/*
|
1361
|
+
* alloc return memory
|
1362
|
+
*/
|
1363
|
+
ret = rb_str_buf_new(stride * ptr->classic.height);
|
1364
|
+
rb_str_set_len(ret, stride * ptr->classic.height);
|
1365
|
+
|
1366
|
+
/*
|
1367
|
+
* alloc rows
|
1368
|
+
*/
|
1369
|
+
ptr->classic.rows = png_malloc(ptr->classic.ctx,
|
1370
|
+
ptr->classic.height * sizeof(png_byte*));
|
1371
|
+
if (ptr->classic.rows == NULL) {
|
1372
|
+
NOMEMORY_ERROR("no memory");
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
p = (png_byte*)RSTRING_PTR(ret);
|
1376
|
+
for (i = 0; i < ptr->classic.height; i++) {
|
1377
|
+
ptr->classic.rows[i] = p;
|
1378
|
+
p += stride;
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
png_read_image(ptr->classic.ctx, ptr->classic.rows);
|
1382
|
+
png_read_end(ptr->classic.ctx, ptr->classic.fsi);
|
1383
|
+
|
1384
|
+
if (ptr->classic.need_meta) {
|
1385
|
+
get_header_info(ptr);
|
1386
|
+
rb_ivar_set(ret, id_meta, create_meta(ptr));
|
1387
|
+
rb_define_singleton_method(ret, "meta", rb_decode_result_meta, 0);
|
1388
|
+
}
|
1389
|
+
|
1390
|
+
return ret;
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
static VALUE
|
1394
|
+
decode_classic_api_ensure(VALUE _arg)
|
1395
|
+
{
|
1396
|
+
png_decoder_t* ptr;
|
1397
|
+
|
1398
|
+
ptr = (png_decoder_t*)_arg;
|
1399
|
+
|
1400
|
+
if (ptr->classic.rows) {
|
1401
|
+
png_free(ptr->classic.ctx, ptr->classic.rows);
|
1402
|
+
ptr->classic.rows = NULL;
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
clear_read_context(ptr);
|
1406
|
+
|
1407
|
+
return Qundef;
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
static VALUE
|
1411
|
+
rb_decoder_decode(VALUE self, VALUE data)
|
1412
|
+
{
|
1413
|
+
VALUE ret;
|
1414
|
+
png_decoder_t* ptr;
|
1415
|
+
decode_arg_t arg;
|
1416
|
+
|
1417
|
+
/*
|
1418
|
+
* argument check
|
1419
|
+
*/
|
1420
|
+
Check_Type(data, T_STRING);
|
1421
|
+
|
1422
|
+
/*
|
1423
|
+
* strip object
|
1424
|
+
*/
|
1425
|
+
Data_Get_Struct(self, png_decoder_t, ptr);
|
1426
|
+
|
1427
|
+
/*
|
1428
|
+
* call decode funcs
|
1429
|
+
*/
|
1430
|
+
arg.ptr = ptr;
|
1431
|
+
arg.data = data;
|
1432
|
+
|
1433
|
+
if (ptr->common.api_type == API_SIMPLIFIED) {
|
1434
|
+
ret = rb_ensure(decode_simplified_api_body, (VALUE)&arg,
|
1435
|
+
decode_simplified_api_ensure, (VALUE)ptr);
|
1436
|
+
|
1437
|
+
} else {
|
1438
|
+
ret = rb_ensure(decode_classic_api_body, (VALUE)&arg,
|
1439
|
+
decode_classic_api_ensure, (VALUE)ptr);
|
1440
|
+
}
|
1441
|
+
|
1442
|
+
return ret;
|
1443
|
+
}
|
1444
|
+
|
1445
|
+
#define DEFINE_SYMBOL(name, str)
|
1446
|
+
|
1447
|
+
void
|
1448
|
+
Init_png()
|
1449
|
+
{
|
1450
|
+
int i;
|
1451
|
+
|
1452
|
+
module = rb_define_module("PNG");
|
1453
|
+
|
1454
|
+
encoder_klass = rb_define_class_under(module, "Encoder", rb_cObject);
|
1455
|
+
rb_define_alloc_func(encoder_klass, rb_encoder_alloc);
|
1456
|
+
rb_define_method(encoder_klass, "initialize", rb_encoder_initialize, -1);
|
1457
|
+
rb_define_method(encoder_klass, "encode", rb_encoder_encode, 1);
|
1458
|
+
rb_define_alias(encoder_klass, "compress", "encode");
|
1459
|
+
rb_define_alias(encoder_klass, "<<", "encode");
|
1460
|
+
|
1461
|
+
decoder_klass = rb_define_class_under(module, "Decoder", rb_cObject);
|
1462
|
+
rb_define_alloc_func(decoder_klass, rb_decoder_alloc);
|
1463
|
+
rb_define_method(decoder_klass, "initialize", rb_decoder_initialize, -1);
|
1464
|
+
rb_define_method(decoder_klass, "read_header", rb_decoder_read_header, 1);
|
1465
|
+
rb_define_method(decoder_klass, "decode", rb_decoder_decode, 1);
|
1466
|
+
rb_define_alias(decoder_klass, "decompress", "decode");
|
1467
|
+
rb_define_alias(decoder_klass, "<<", "decode");
|
1468
|
+
|
1469
|
+
meta_klass = rb_define_class_under(module, "Meta", rb_cObject);
|
1470
|
+
rb_define_attr(meta_klass, "width", 1, 0);
|
1471
|
+
rb_define_attr(meta_klass, "height", 1, 0);
|
1472
|
+
rb_define_attr(meta_klass, "stride", 1, 0);
|
1473
|
+
rb_define_attr(meta_klass, "bit_depth", 1, 0);
|
1474
|
+
rb_define_attr(meta_klass, "color_type", 1, 0);
|
1475
|
+
rb_define_attr(meta_klass, "interlace_method", 1, 0);
|
1476
|
+
rb_define_attr(meta_klass, "compression_method", 1, 0);
|
1477
|
+
rb_define_attr(meta_klass, "filter_method", 1, 0);
|
1478
|
+
rb_define_attr(meta_klass, "pixel_format", 1, 0);
|
1479
|
+
rb_define_attr(meta_klass, "num_components", 1, 0);
|
1480
|
+
rb_define_attr(meta_klass, "text", 1, 0);
|
1481
|
+
rb_define_attr(meta_klass, "time", 1, 0);
|
1482
|
+
rb_define_attr(meta_klass, "file_gamma", 1, 0);
|
1483
|
+
|
1484
|
+
for (i = 0; i < (int)N(encoder_opt_keys); i++) {
|
1485
|
+
encoder_opt_ids[i] = rb_intern_const(encoder_opt_keys[i]);
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
for (i = 0; i < (int)N(decoder_opt_keys); i++) {
|
1489
|
+
decoder_opt_ids[i] = rb_intern_const(decoder_opt_keys[i]);
|
1490
|
+
}
|
1491
|
+
|
1492
|
+
id_meta = rb_intern_const("@meta");
|
1493
|
+
id_stride = rb_intern_const("@stride");
|
1494
|
+
id_format = rb_intern_const("@format");
|
1495
|
+
id_pixfmt = rb_intern_const("@pixel_format");
|
1496
|
+
id_ncompo = rb_intern_const("@num_components");
|
1497
|
+
}
|