stb-image 1.0.0

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.
@@ -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
+