stb-image 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e73e6f2f11e07296a4a09386b46fb9bef372ecc8
4
+ data.tar.gz: 0d84e354e6971e9e101af7cf35c41e5fa6ec7d3e
5
+ SHA512:
6
+ metadata.gz: 38253ce9a581f1afadf8ffb3247c25a7fe54b83e0b2684e6ba39d27dbc084881ac80ee9974b329af0b4577b2d8d51bb921028cc59d33e699be8ce255ee94151f
7
+ data.tar.gz: 08ae2c60e53410e2faa892b9709aab3b91453af266b463465908d38916c07ee78c12c4932075597adf94b346f4c3445b82548cd30d4e8d5ea7090900a30c9011
data/COPYING ADDED
@@ -0,0 +1,10 @@
1
+ These bindings for stb_image ("the software") are public domain, as with
2
+ stb_image itself.
3
+
4
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10
+ THE SOFTWARE.
@@ -0,0 +1,58 @@
1
+ stb-image gem
2
+ =============
3
+
4
+ $ gem install stb-image
5
+
6
+ -------------------------------------------------------------------------------
7
+
8
+ This stb-image gem is a simple wrapper around [Sean Barrett's][sean-barrett]
9
+ stb_image.c file (including contributions by others), which provides a simple,
10
+ easy to use image loading API fo folks who really don't want anything other
11
+ than to load an image, cram it into a GL texture object, and discard it.
12
+
13
+ [sean-barrett]: http://nothings.org
14
+
15
+ Using it is fairly simple, and best illustrated by the following example:
16
+
17
+ require 'stb-image'
18
+
19
+ info = open('image.png') { |io|
20
+ STBI.load_image(io)
21
+ }
22
+ raise "Unable to load image" unless info
23
+ image_data, width, height, num_components = info
24
+
25
+ So, let's walk through this line by line.
26
+
27
+ 1. Require the stb-image gem. You probably know why this is necessary.
28
+ 2. Open 'image.png' with a block with the intent to store the result of the
29
+ block in the info variable.
30
+ 3. In the block, call STBI.load_image and pass the open IO object to it so it
31
+ can read data. The result, an array containing the image data string, the
32
+ width and height of the image, and the number of components per texel in the
33
+ image.
34
+ 4. If info is nil, raise an exception.
35
+ 5. Grab the data, width, height, and components from the returned info.
36
+ Commence doing whatever you want with this data.
37
+
38
+ It's pretty simple. Arguably, at least two or three steps here are optional.
39
+
40
+ In addition, if you'd like to load an HDR image or any image as floats instead
41
+ of bytes, you can use STBI.load_float_image, whose returned data is an array
42
+ of floats rather than bytes. You can inspect the results of either by using
43
+ info[0].unpack('f*') for HDR images and `'C*'` for LDR images.
44
+
45
+
46
+ License (or Lack Thereof)
47
+ -------
48
+
49
+ These bindings for stb_image ("the software") are public domain, as with
50
+ stb_image itself.
51
+
52
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
54
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
55
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
56
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
58
+ THE SOFTWARE.
@@ -0,0 +1,387 @@
1
+ /*
2
+ This source is part of the Ruby bindings for stb_image.
3
+ It is released into the public domain, as with stb_image itself.
4
+
5
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11
+ THE SOFTWARE.
12
+ */
13
+
14
+ #define STBI_NO_STDIO
15
+ #define STBI_HEADER_FILE_ONLY
16
+
17
+ #include "stb_image.c"
18
+ #include "ruby.h"
19
+
20
+ static VALUE s_stbi_module;
21
+ static ID s_read_funcid;
22
+ static ID s_skip_funcid;
23
+ static ID s_eof_funcid;
24
+ static ID s_eof_qm_funcid;
25
+
26
+ /******************************************************************************
27
+ Callbacks used by STBI to load data using either Ruby IO objects or 'special'
28
+ IO objects that implement both read and eof/eof? (and optionally skip).
29
+
30
+ Specifically, any class that has the following
31
+
32
+ class STBI_IO
33
+ def read(num_bytes)
34
+ end
35
+
36
+ def skip(num_bytes)
37
+ # optional
38
+ end
39
+
40
+ def eof?
41
+ end
42
+ end
43
+ ******************************************************************************/
44
+
45
+ static int sr_read_callback(void *user, char *data, int size)
46
+ {
47
+ VALUE callback_obj = *(VALUE *)user;
48
+ VALUE sr_size = INT2NUM(size);
49
+ VALUE sr_data = rb_check_funcall(callback_obj, s_read_funcid, 1, &sr_size);
50
+
51
+ if (sr_data != Qundef && RTEST(sr_data)) {
52
+ const char *string_data = StringValuePtr(sr_data);
53
+ int string_length = RSTRING_LENINT(sr_data);
54
+ memcpy(data, string_data, string_length);
55
+ return string_length;
56
+ }
57
+
58
+ rb_warn("IO object did not respond to read, returning 0 bytes read");
59
+
60
+ /*
61
+ stb_image should fail on its own if it doesn't get the data it wants here,
62
+ so just return 0
63
+ */
64
+ return 0;
65
+ }
66
+
67
+ static void sr_skip_callback(void *user, unsigned size)
68
+ {
69
+ VALUE callback_obj = *(VALUE *)user;
70
+ VALUE sr_size = UINT2NUM(size);
71
+
72
+ /* If skip doesn't exist, call read and discard the result */
73
+ if (rb_check_funcall(callback_obj, s_skip_funcid, 1, &sr_size) != Qundef ||
74
+ rb_check_funcall(callback_obj, s_read_funcid, 1, &sr_size) != Qundef) {
75
+ return;
76
+ }
77
+
78
+ rb_warn("IO object did not respond to either skip or read");
79
+ }
80
+
81
+ static int sr_eof_callback(void *user)
82
+ {
83
+ VALUE callback_obj = *(VALUE *)user;
84
+ VALUE result = rb_check_funcall(callback_obj, s_eof_qm_funcid, 0, NULL);
85
+ if (result == Qundef && (result = rb_check_funcall(callback_obj, s_eof_qm_funcid, 0, NULL)) == Qundef) {
86
+ rb_warn("IO object did not respond to eof or eof?, assuming not at EOF");
87
+ result = Qfalse;
88
+ }
89
+ return RTEST(result);
90
+ }
91
+
92
+ /* Callback structure -- passed to STBI */
93
+ static stbi_io_callbacks s_st_callbacks = {
94
+ sr_read_callback,
95
+ sr_skip_callback,
96
+ sr_eof_callback
97
+ };
98
+
99
+ /******************************************************************************
100
+ Bindings implementations
101
+ ******************************************************************************/
102
+
103
+ /*
104
+ call-seq:
105
+ load_image(io, required_components = COMPONENTS_DEFAULT) => [data, width, height, components]
106
+ load_image(io, required_components = COMPONENTS_DEFAULT) { |info| ... } => obj
107
+
108
+ Loads an image using stb_image and returns the resulting data and its width,
109
+ height, and the number of components per pixel in the data. The returned data
110
+ is a packed string of unsigned 8-bit integers (8 bits per component). The
111
+ length of the string will always be width * height * components.
112
+
113
+ In the second form, the info array is yielded to the block if the image is
114
+ successfully loaded. Otherwise, the method returns nil. This is possibly more
115
+ convenient than doing an <tt>if info ... end</tt> block to check if the
116
+ image was successfully loaded.
117
+
118
+ === IO Objects
119
+
120
+ IO objects accepted for loading data with must implement at least
121
+ IO#read(length) and either IO#eof or IO#eof?. In addition, they may also
122
+ implement a skip(length) method that skips length bytes and does not return
123
+ any value. If the IO object does not respond to #skip, #read will be called
124
+ instead and its result will be discarded. If you want to avoid unnecessary
125
+ allocations, it may be wise to implement a skip method.
126
+
127
+ === Components
128
+
129
+ If required_components is provided and not the default value, the image data
130
+ returned will have as many components as are requested. In turn, the number of
131
+ components returned via the array will be the same as required_components.
132
+
133
+ Valid options for required_components are:
134
+
135
+ [::COMPONENTS_DEFAULT] The default value, loads as many components as are
136
+ provided by the image.
137
+ [::COMPONENTS_GREY] Loads only one component.
138
+ [::COMPONENTS_GREY_ALPHA] Loads two components.
139
+ [::COMPONENTS_RGB] Loads three components (red, green, and blue).
140
+ [::COMPONENTS_RGB_ALPHA] Loads four components (red, green, blue, and alpha).
141
+
142
+ === Example
143
+
144
+ open('image.png') { |io|
145
+ STBI.load_image(io) { |data, width, height, components|
146
+ format = case components
147
+ when STBI::COMPONENTS_GREY then Gl::GL_RED
148
+ when STBI::COMPONENTS_GREY_ALPHA then Gl::GL_RG
149
+ when STBI_COMPONENTS_RGB then Gl::RGB
150
+ when STBI_COMPONENTS_RGB_ALPHA then Gl::RGBA
151
+ end
152
+
153
+ Gl::glTexImage2D(Gl::GL_TEXTURE_2D, 0, format, width, height, 0,
154
+ format, Gl::GL_UNSIGNED_BYTE, data)
155
+ }
156
+ }
157
+ */
158
+ static VALUE sr_load_image(int argc, VALUE *argv, VALUE sr_self)
159
+ {
160
+ VALUE sr_callbacks;
161
+ VALUE sr_req_comp;
162
+ VALUE sr_image_data = Qnil;
163
+ int x = 0;
164
+ int y = 0;
165
+ int components[2] = {
166
+ STBI_default,
167
+ 0
168
+ };
169
+
170
+ rb_scan_args(argc, argv, "11", &sr_callbacks, &sr_req_comp);
171
+
172
+ if (NIL_P(sr_callbacks)) {
173
+ rb_raise(rb_eArgError, "IO object cannot be nil");
174
+ return Qnil;
175
+ } if (RTEST(sr_req_comp)) {
176
+ components[0] = FIX2INT(sr_req_comp);
177
+ }
178
+
179
+ if (!rb_obj_respond_to(sr_callbacks, s_read_funcid, 0) ||
180
+ !(rb_obj_respond_to(sr_callbacks, s_eof_funcid, 0) ||
181
+ rb_obj_respond_to(sr_callbacks, s_eof_qm_funcid, 0))) {
182
+ rb_raise(rb_eTypeError, "IO object does not respond to either read or eof/eof?");
183
+ }
184
+
185
+ stbi_uc *data = stbi_load_from_callbacks(&s_st_callbacks, &sr_callbacks,
186
+ &x, &y, &components[1], components[0]);
187
+
188
+ if (data) {
189
+ const long length = x * y * components[!components[0]];
190
+ sr_image_data = rb_ary_new3(4,
191
+ rb_external_str_new((const char *)data, length),
192
+ INT2FIX(x), INT2FIX(y),
193
+ INT2FIX(components[!components[0]]));
194
+ stbi_image_free(data);
195
+ }
196
+
197
+ if (!NIL_P(sr_image_data) && rb_block_given_p()) {
198
+ return rb_yield_splat(sr_image_data);
199
+ } else {
200
+ return sr_image_data;
201
+ }
202
+ }
203
+
204
+ /*
205
+ call-seq:
206
+ load_float_image(io, required_components = COMPONENTS_DEFAULT) => [data, width, height, components]
207
+ load_float_image(io, required_components = COMPONENTS_DEFAULT) { |info| ... } => obj
208
+
209
+ Similar to ::load_image, except the returned image data is a packaed string
210
+ for an array of 32-bit floats (e.g., String#unpack('f*') will extract an array
211
+ of floating point values representing the components of the image's pixels).
212
+
213
+ In the second form, the info array is yielded to the block if the image is
214
+ successfully loaded. Otherwise, the method returns nil. This is possibly more
215
+ convenient than doing an <tt>if info ... end</tt> block to check if the
216
+ image was successfully loaded.
217
+
218
+ For further information on the IO object, the required_components argument,
219
+ and so on, see the documentation for load_image.
220
+
221
+ === Example
222
+
223
+ open('image.png') { |io|
224
+ STBI.load_float_image(io) { |data, width, height, components|
225
+ format = case components
226
+ when STBI::COMPONENTS_GREY then Gl::GL_RED
227
+ when STBI::COMPONENTS_GREY_ALPHA then Gl::GL_RG
228
+ when STBI_COMPONENTS_RGB then Gl::RGB
229
+ when STBI_COMPONENTS_RGB_ALPHA then Gl::RGBA
230
+ end
231
+
232
+ Gl::glTexImage2D(Gl::GL_TEXTURE_2D, 0, format, width, height, 0,
233
+ format, Gl::GL_FLOAT, data)
234
+ }
235
+ }
236
+ */
237
+ static VALUE sr_load_float_image(int argc, VALUE *argv, VALUE sr_self)
238
+ {
239
+ VALUE sr_callbacks;
240
+ VALUE sr_req_comp;
241
+ VALUE sr_image_data = Qnil;
242
+ int x = 0;
243
+ int y = 0;
244
+ int components[2] = {
245
+ STBI_default,
246
+ 0
247
+ };
248
+
249
+ rb_scan_args(argc, argv, "11", &sr_callbacks, &sr_req_comp);
250
+
251
+ if (NIL_P(sr_callbacks)) {
252
+ rb_raise(rb_eArgError, "IO object cannot be nil");
253
+ return Qnil;
254
+ } if (RTEST(sr_req_comp)) {
255
+ components[0] = FIX2INT(sr_req_comp);
256
+ }
257
+
258
+ float *data = stbi_loadf_from_callbacks(&s_st_callbacks, &sr_callbacks,
259
+ &x, &y, &components[1], components[0]);
260
+
261
+ if (data) {
262
+ const long length = x * y * components[!components[0]] * sizeof(float);
263
+ sr_image_data = rb_ary_new3(4,
264
+ rb_external_str_new((const char *)data, length),
265
+ INT2FIX(x), INT2FIX(y),
266
+ INT2FIX(components[!components[0]]));
267
+ stbi_image_free(data);
268
+ }
269
+
270
+ if (!NIL_P(sr_image_data) && rb_block_given_p()) {
271
+ return rb_yield_splat(sr_image_data);
272
+ } else {
273
+ return sr_image_data;
274
+ }
275
+ }
276
+
277
+ /*
278
+ call-seq:
279
+ set_hdr_to_ldr_gamma(value) => value
280
+
281
+ Sets the HDR to LDR gamma used when loading HDR images with load_image.
282
+ */
283
+ static VALUE sr_set_hdr_to_ldr_gamma(VALUE self, VALUE gamma)
284
+ {
285
+ stbi_hdr_to_ldr_gamma((float)NUM2DBL(gamma));
286
+ return gamma;
287
+ }
288
+
289
+ /*
290
+ call-seq:
291
+ set_hdr_to_ldr_scale(value) => value
292
+
293
+ Sets the HDR to LDR scale used when loading HDR images with load_image.
294
+ */
295
+ static VALUE sr_set_hdr_to_ldr_scale(VALUE self, VALUE scale)
296
+ {
297
+ stbi_hdr_to_ldr_scale((float)NUM2DBL(scale));
298
+ return scale;
299
+ }
300
+
301
+ /*
302
+ call-seq:
303
+ set_ldr_to_hdr_gamma(value) => value
304
+
305
+ Sets the LDR to HDR gamma used when loading LDR images with load_float_image.
306
+ */
307
+ static VALUE sr_set_ldr_to_hdr_gamma(VALUE self, VALUE gamma)
308
+ {
309
+ stbi_ldr_to_hdr_gamma((float)NUM2DBL(gamma));
310
+ return gamma;
311
+ }
312
+
313
+ /*
314
+ call-seq:
315
+ set_ldr_to_hdr_scale(value) => value
316
+
317
+ Sets the LDR to HDR scale used when loading LDR images with load_float_image.
318
+ */
319
+ static VALUE sr_set_ldr_to_hdr_scale(VALUE self, VALUE scale)
320
+ {
321
+ stbi_ldr_to_hdr_scale((float)NUM2DBL(scale));
322
+ return scale;
323
+ }
324
+
325
+ void Init_stb_image_bindings(void)
326
+ {
327
+ s_read_funcid = rb_intern("read");
328
+ s_skip_funcid = rb_intern("skip");
329
+ s_eof_funcid = rb_intern("eof");
330
+ s_eof_qm_funcid = rb_intern("eof?");
331
+
332
+ /*
333
+ Container module for stb-image bindings. Of main interest are load_image
334
+ and load_float_image, which allow you to load data from a variety of image
335
+ formats, including
336
+
337
+ - PNG
338
+ - JPEG
339
+ - TGA
340
+ - BMP
341
+ - PSD
342
+ - GIF
343
+ - HDR
344
+ - PIC
345
+
346
+ These formats come with some limitations, which you can read in the original
347
+ stb_image.c header.
348
+ */
349
+ s_stbi_module = rb_define_module("STBI");
350
+
351
+ /* The version constant provided by stb_image.c */
352
+ rb_define_const(s_stbi_module, "STBI_VERSION", INT2FIX(STBI_VERSION));
353
+ /*
354
+ Only valid for required_components arguments to load_image
355
+ and load_float_image. See load_image for usage.
356
+ */
357
+ rb_define_const(s_stbi_module, "COMPONENTS_DEFAULT", INT2FIX(STBI_default));
358
+ /*
359
+ Specifies that pixels in image data must have or has 1 component.
360
+ See load_image for usage.
361
+ */
362
+ rb_define_const(s_stbi_module, "COMPONENTS_GREY", INT2FIX(STBI_grey));
363
+ /*
364
+ Specifies that pixels in image data must have or has 2 components.
365
+ See load_image for usage.
366
+ */
367
+ rb_define_const(s_stbi_module, "COMPONENTS_GREY_ALPHA", INT2FIX(STBI_grey_alpha));
368
+ /*
369
+ Specifies that pixels in image data must have or has 3 components.
370
+ See load_image for usage.
371
+ */
372
+ rb_define_const(s_stbi_module, "COMPONENTS_RGB", INT2FIX(STBI_rgb));
373
+ /*
374
+ Specifies that pixels in image data must have or has 4 components.
375
+ See load_image for usage.
376
+ */
377
+ rb_define_const(s_stbi_module, "COMPONENTS_RGB_ALPHA", INT2FIX(STBI_rgb_alpha));
378
+
379
+ rb_define_singleton_method(s_stbi_module, "load_image", sr_load_image, -1);
380
+ rb_define_singleton_method(s_stbi_module, "load_float_image", sr_load_float_image, -1);
381
+
382
+ rb_define_singleton_method(s_stbi_module, "hdr_to_ldr_gamma=", sr_set_hdr_to_ldr_gamma, 1);
383
+ rb_define_singleton_method(s_stbi_module, "hdr_to_ldr_scale=", sr_set_hdr_to_ldr_scale, 1);
384
+ rb_define_singleton_method(s_stbi_module, "ldr_to_hdr_gamma=", sr_set_ldr_to_hdr_gamma, 1);
385
+ rb_define_singleton_method(s_stbi_module, "ldr_to_hdr_scale=", sr_set_ldr_to_hdr_scale, 1);
386
+ }
387
+