magro 0.5.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1383da33f22a42bc1dbf7ed16cd1f6d21d0e8444967fb027b29bb39dd189d836
4
- data.tar.gz: 710cb0248ab131d7a5cfc6671b0ec2e83f335287221dfe795887bf3784b0a682
3
+ metadata.gz: 461bbd071fe195f5edc86daf605b89b021aa97a8164a060e2239f9c7eef57b77
4
+ data.tar.gz: 0dc546f4643257704deb3e31dbdf1d2dd0dc42405d35386babcab59c3ab618aa
5
5
  SHA512:
6
- metadata.gz: c3bb0a6c16df89efa22b8e057b425fba66235c826f9d2fcaca74d8191825f8b6153d440fe1edda003b311cef313b2ec8b7a817d3a7e54b86f182474bad26899f
7
- data.tar.gz: 804a97560558d95d56a9867c4a1b36275a1aaca62a872a340ba2eb2a765a3b9e120e072ddc8a6d923b12b20b304f2b25e0e83d957fbe4b3dbf72a0bfe618c471
6
+ metadata.gz: 19756e1ccb2b703de929a8c589e249442ae8901c12d095a8a9976c8e8c49593a55a6ba1267a1696cacbcbb15dc6a4d210cee11362854f8c72181a54ecb10f24a
7
+ data.tar.gz: 89695893f37e8e69cc2470a7e09f0b064f447df4293773218104b91a95a59033395d72f2a0b12bf1b83858841e3cefa7e8958c67206d2969f063bda411837260
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 0.6.1
2
+
3
+ - Refactor codes and configs with RuboCop.
4
+
5
+ # 0.6.0
6
+ - Reorganize native exntesion codes.
7
+ - Remove dependent gem's type declaration file from installation files.
8
+ - Update documentations.
9
+ - Introduce conventional commits.
10
+
11
+ # 0.5.1
12
+ - Fix version specifier of runtime dependencies.
13
+
1
14
  # 0.5.0
2
15
  - Add type declaration files.
3
16
  - Refactor some codes.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2019-2021 Atsushi Tatsuma
1
+ Copyright (c) 2019-2022 Atsushi Tatsuma
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Coverage Status](https://coveralls.io/repos/github/yoshoku/magro/badge.svg?branch=main)](https://coveralls.io/github/yoshoku/magro?branch=main)
5
5
  [![Gem Version](https://badge.fury.io/rb/magro.svg)](https://badge.fury.io/rb/magro)
6
6
  [![BSD 3-Clause License](https://img.shields.io/badge/License-BSD%203--Clause-orange.svg)](https://github.com/yoshoku/numo-liblinear/blob/main/LICENSE.txt)
7
- [![Documentation](http://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/magro/doc/)
7
+ [![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/magro/doc/)
8
8
 
9
9
  Magro is a minimal image processing library in Ruby.
10
10
  Magro uses [Numo::NArray](https://github.com/ruby-numo/numo-narray) arrays as image objects and
@@ -59,8 +59,8 @@ Or install it yourself as:
59
59
  ## Contributing
60
60
 
61
61
  Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/magro.
62
- This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
62
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://contributor-covenant.org) code of conduct.
63
63
 
64
- ## Code of Conduct
64
+ ## License
65
65
 
66
- Everyone interacting in the Magro project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/yoshoku/magro/blob/main/CODE_OF_CONDUCT.md).
66
+ The gem is available as open source under the terms of the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
data/ext/magro/extconf.rb CHANGED
@@ -8,10 +8,7 @@ $LOAD_PATH.each do |lp|
8
8
  end
9
9
  end
10
10
 
11
- unless have_header('numo/narray.h')
12
- puts 'numo/narray.h not found.'
13
- exit(1)
14
- end
11
+ abort 'numo/narray.h not found.' unless have_header('numo/narray.h')
15
12
 
16
13
  if RUBY_PLATFORM =~ /mswin|cygwin|mingw/
17
14
  $LOAD_PATH.each do |lp|
@@ -20,35 +17,14 @@ if RUBY_PLATFORM =~ /mswin|cygwin|mingw/
20
17
  break
21
18
  end
22
19
  end
23
- unless have_library('narray', 'nary_new')
24
- puts 'libnarray.a not found.'
25
- exit(1)
26
- end
27
- end
28
-
29
- unless have_header('setjmp.h')
30
- puts 'setjmp.h not found.'
31
- exit(1)
32
- end
33
-
34
- unless have_header('png.h')
35
- puts 'png.h not found.'
36
- exit(1)
20
+ abort 'libnarray.a not found.' unless have_library('narray', 'nary_new')
37
21
  end
38
22
 
39
- unless have_header('jpeglib.h')
40
- puts 'jpeglib.h not found.'
41
- exit(1)
42
- end
23
+ abort 'setjmp.h not found.' unless have_header('setjmp.h')
24
+ abort 'png.h not found.' unless have_header('png.h')
25
+ abort 'libpng not found.' unless have_library('png')
43
26
 
44
- unless have_library('png')
45
- puts 'libpng not found.'
46
- exit(1)
47
- end
48
-
49
- unless have_library('jpeg')
50
- puts 'libjpeg not found.'
51
- exit(1)
52
- end
27
+ abort 'jpeglib.h not found.' unless have_header('jpeglib.h')
28
+ abort 'libjpeg not found.' unless have_library('jpeg')
53
29
 
54
30
  create_makefile('magro/magro')
data/ext/magro/magro.c CHANGED
@@ -1,9 +1,462 @@
1
+ /**
2
+ * Copyright (c) 2019-2022 Atsushi Tatsuma
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * * Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * * Neither the name of the copyright holder nor the names of its
16
+ * contributors may be used to endorse or promote products derived from
17
+ * this software without specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
1
31
  #include "magro.h"
2
32
 
3
33
  VALUE mMagro;
34
+ VALUE mMagroIO;
35
+
36
+ static VALUE magro_io_read_png(VALUE self, VALUE filename_) {
37
+ char* filename = StringValuePtr(filename_);
38
+ FILE* file_ptr = fopen(filename, "rb");
39
+ unsigned char header[8];
40
+ png_structp png_ptr;
41
+ png_infop info_ptr;
42
+ png_bytep* row_ptr_ptr;
43
+ png_bytep row_ptr;
44
+ png_uint_32 width, height;
45
+ int color_type;
46
+ int bit_depth;
47
+ png_uint_32 y;
48
+ int n_dims = 0;
49
+ int n_ch;
50
+ size_t shape[3] = {0};
51
+ VALUE nary;
52
+ uint8_t* nary_ptr;
53
+
54
+ if (file_ptr == NULL) {
55
+ rb_raise(rb_eIOError, "Failed to open file '%s'", filename);
56
+ return Qnil;
57
+ }
58
+
59
+ if (fread(header, 1, 8, file_ptr) < 8) {
60
+ fclose(file_ptr);
61
+ rb_raise(rb_eIOError, "Failed to read header info '%s'", filename);
62
+ return Qnil;
63
+ }
64
+
65
+ if (png_sig_cmp(header, 0, 8)) {
66
+ fclose(file_ptr);
67
+ rb_raise(rb_eIOError, "Failed to read header info '%s'", filename);
68
+ return Qnil;
69
+ }
70
+
71
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
72
+ if (png_ptr == NULL) {
73
+ fclose(file_ptr);
74
+ rb_raise(rb_eNoMemError, "Failed to allocate memory.");
75
+ return Qnil;
76
+ }
77
+ info_ptr = png_create_info_struct(png_ptr);
78
+ if (info_ptr == NULL) {
79
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
80
+ fclose(file_ptr);
81
+ rb_raise(rb_eNoMemError, "Failed to allocate memory.");
82
+ return Qnil;
83
+ }
84
+ if (setjmp(png_jmpbuf(png_ptr))) {
85
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
86
+ fclose(file_ptr);
87
+ rb_raise(rb_eIOError, "Error happened while reading file '%s'", filename);
88
+ return Qnil;
89
+ }
90
+
91
+ png_init_io(png_ptr, file_ptr);
92
+ png_set_sig_bytes(png_ptr, 8);
93
+
94
+ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL);
95
+ row_ptr_ptr = png_get_rows(png_ptr, info_ptr);
96
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
97
+
98
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
99
+ png_set_palette_to_rgb(png_ptr);
100
+ png_read_update_info(png_ptr, info_ptr);
101
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
102
+ }
103
+
104
+ switch (color_type) {
105
+ case PNG_COLOR_TYPE_GRAY:
106
+ n_ch = 1;
107
+ n_dims = 2;
108
+ shape[0] = height;
109
+ shape[1] = width;
110
+ break;
111
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
112
+ n_ch = 2;
113
+ n_dims = 3;
114
+ shape[0] = height;
115
+ shape[1] = width;
116
+ shape[2] = 2;
117
+ break;
118
+ case PNG_COLOR_TYPE_RGB:
119
+ n_ch = 3;
120
+ n_dims = 3;
121
+ shape[0] = height;
122
+ shape[1] = width;
123
+ shape[2] = 3;
124
+ break;
125
+ case PNG_COLOR_TYPE_RGB_ALPHA:
126
+ n_ch = 4;
127
+ n_dims = 3;
128
+ shape[0] = height;
129
+ shape[1] = width;
130
+ shape[2] = 4;
131
+ break;
132
+ default:
133
+ n_dims = 0;
134
+ break;
135
+ }
136
+
137
+ if (n_dims == 0) {
138
+ fclose(file_ptr);
139
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
140
+ rb_raise(rb_eIOError, "Unsupported color type of input file '%s'", filename);
141
+ return Qnil;
142
+ }
143
+
144
+ nary = rb_narray_new(numo_cUInt8, n_dims, shape);
145
+ nary_ptr = (uint8_t*)na_get_pointer_for_write(nary);
146
+
147
+ for (y = 0; y < height; y++) {
148
+ row_ptr = row_ptr_ptr[y];
149
+ memcpy(nary_ptr + y * width * n_ch, row_ptr, width * n_ch);
150
+ }
151
+
152
+ fclose(file_ptr);
153
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
154
+
155
+ RB_GC_GUARD(filename_);
156
+
157
+ return nary;
158
+ }
159
+
160
+ static VALUE magro_io_save_png(VALUE self, VALUE filename_, VALUE image) {
161
+ char* filename = StringValuePtr(filename_);
162
+ FILE* file_ptr = fopen(filename, "wb");
163
+ png_structp png_ptr;
164
+ png_infop info_ptr;
165
+ png_bytep* row_ptr_ptr;
166
+ png_uint_32 width, height;
167
+ int color_type;
168
+ int bit_depth = 8;
169
+ png_uint_32 y;
170
+ int n_ch;
171
+ int n_dims;
172
+ narray_t* image_nary;
173
+ uint8_t* image_ptr;
174
+
175
+ if (file_ptr == NULL) {
176
+ rb_raise(rb_eIOError, "Failed to open file '%s'", filename);
177
+ return Qfalse;
178
+ }
179
+
180
+ if (CLASS_OF(image) != numo_cUInt8) image = rb_funcall(numo_cUInt8, rb_intern("cast"), 1, image);
181
+ if (!RTEST(nary_check_contiguous(image))) image = nary_dup(image);
182
+
183
+ GetNArray(image, image_nary);
184
+ n_dims = NA_NDIM(image_nary);
185
+ height = (png_uint_32)NA_SHAPE(image_nary)[0];
186
+ width = (png_uint_32)NA_SHAPE(image_nary)[1];
187
+ image_ptr = (uint8_t*)na_get_pointer_for_read(image);
188
+ n_ch = n_dims == 3 ? (int)NA_SHAPE(image_nary)[2] : 1;
189
+
190
+ switch (n_ch) {
191
+ case 4:
192
+ color_type = PNG_COLOR_TYPE_RGBA;
193
+ break;
194
+ case 3:
195
+ color_type = PNG_COLOR_TYPE_RGB;
196
+ break;
197
+ case 2:
198
+ color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
199
+ break;
200
+ default:
201
+ color_type = PNG_COLOR_TYPE_GRAY;
202
+ break;
203
+ }
204
+
205
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
206
+ if (png_ptr == NULL) {
207
+ fclose(file_ptr);
208
+ rb_raise(rb_eNoMemError, "Failed to allocate memory.");
209
+ return Qfalse;
210
+ }
211
+ info_ptr = png_create_info_struct(png_ptr);
212
+ if (info_ptr == NULL) {
213
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
214
+ fclose(file_ptr);
215
+ rb_raise(rb_eNoMemError, "Failed to allocate memory.");
216
+ return Qfalse;
217
+ }
218
+ if (setjmp(png_jmpbuf(png_ptr))) {
219
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
220
+ fclose(file_ptr);
221
+ return Qfalse;
222
+ }
223
+
224
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
225
+ PNG_FILTER_TYPE_DEFAULT);
226
+
227
+ row_ptr_ptr = png_malloc(png_ptr, height * sizeof(png_bytep));
228
+ for (y = 0; y < height; y++) {
229
+ row_ptr_ptr[y] = png_malloc(png_ptr, width * n_ch * sizeof(png_byte));
230
+ memcpy(row_ptr_ptr[y], image_ptr + y * width * n_ch, width * n_ch);
231
+ }
232
+
233
+ png_init_io(png_ptr, file_ptr);
234
+ png_set_rows(png_ptr, info_ptr, row_ptr_ptr);
235
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
236
+
237
+ fclose(file_ptr);
238
+ for (y = 0; y < height; y++) png_free(png_ptr, row_ptr_ptr[y]);
239
+ png_free(png_ptr, row_ptr_ptr);
240
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
241
+
242
+ RB_GC_GUARD(image);
243
+ RB_GC_GUARD(filename_);
244
+
245
+ return Qtrue;
246
+ }
247
+
248
+ struct my_error_mgr {
249
+ struct jpeg_error_mgr pub;
250
+ jmp_buf setjmp_buffer;
251
+ };
252
+
253
+ static void my_error_exit(j_common_ptr cinfo) {
254
+ struct my_error_mgr* my_err = (struct my_error_mgr*)cinfo->err;
255
+ (*cinfo->err->output_message)(cinfo);
256
+ longjmp(my_err->setjmp_buffer, 1);
257
+ }
258
+
259
+ static VALUE magro_io_read_jpg(VALUE self, VALUE filename_) {
260
+ char* filename = StringValuePtr(filename_);
261
+ FILE* file_ptr = fopen(filename, "rb");
262
+ struct jpeg_decompress_struct jpeg;
263
+ struct my_error_mgr err;
264
+ unsigned int width, height;
265
+ int n_colors;
266
+ size_t shape[3] = {0};
267
+ int n_dims;
268
+ unsigned int y;
269
+ VALUE nary;
270
+ uint8_t* nary_ptr;
271
+ JSAMPLE* tmp;
272
+
273
+ if (file_ptr == NULL) {
274
+ rb_raise(rb_eIOError, "Failed to open file '%s'", filename);
275
+ return Qnil;
276
+ }
277
+
278
+ jpeg.err = jpeg_std_error(&err.pub);
279
+ err.pub.error_exit = my_error_exit;
280
+ if (setjmp(err.setjmp_buffer)) {
281
+ rb_raise(rb_eIOError, "Error happened while reading file '%s'", filename);
282
+ return Qnil;
283
+ }
284
+
285
+ jpeg_create_decompress(&jpeg);
286
+ jpeg_stdio_src(&jpeg, file_ptr);
287
+ jpeg_read_header(&jpeg, TRUE);
288
+ jpeg_start_decompress(&jpeg);
289
+
290
+ width = jpeg.output_width;
291
+ height = jpeg.output_height;
292
+ n_colors = jpeg.out_color_components;
293
+
294
+ n_dims = n_colors == 1 ? 2 : 3;
295
+ shape[0] = height;
296
+ shape[1] = width;
297
+ shape[2] = n_colors;
298
+ nary = rb_narray_new(numo_cUInt8, n_dims, shape);
299
+ nary_ptr = (uint8_t*)na_get_pointer_for_write(nary);
300
+
301
+ for (y = 0; y < height; y++) {
302
+ tmp = nary_ptr + y * width * n_colors;
303
+ jpeg_read_scanlines(&jpeg, &tmp, 1);
304
+ }
305
+
306
+ fclose(file_ptr);
307
+ jpeg_finish_decompress(&jpeg);
308
+ jpeg_destroy_decompress(&jpeg);
309
+
310
+ RB_GC_GUARD(filename_);
311
+
312
+ return nary;
313
+ }
314
+
315
+ static VALUE magro_io_save_jpg(int argc, VALUE* argv, VALUE self) {
316
+ VALUE filename_;
317
+ VALUE image;
318
+ VALUE quality_;
319
+ char* filename;
320
+ FILE* file_ptr;
321
+ struct jpeg_compress_struct jpeg;
322
+ struct my_error_mgr err;
323
+ narray_t* image_nary;
324
+ int quality;
325
+ int n_dims, n_ch;
326
+ unsigned int width, height, y;
327
+ uint8_t* image_ptr;
328
+ JSAMPLE* tmp;
329
+
330
+ rb_scan_args(argc, argv, "21", &filename_, &image, &quality_);
331
+
332
+ quality = NIL_P(quality_) ? 95 : NUM2INT(quality_);
333
+
334
+ filename = StringValuePtr(filename_);
335
+
336
+ if (CLASS_OF(image) != numo_cUInt8) image = rb_funcall(numo_cUInt8, rb_intern("cast"), 1, image);
337
+ if (!RTEST(nary_check_contiguous(image))) image = nary_dup(image);
338
+
339
+ jpeg.err = jpeg_std_error(&err.pub);
340
+ err.pub.error_exit = my_error_exit;
341
+ if (setjmp(err.setjmp_buffer)) return Qfalse;
342
+
343
+ jpeg_create_compress(&jpeg);
344
+
345
+ file_ptr = fopen(filename, "wb");
346
+ if (file_ptr == NULL) {
347
+ rb_raise(rb_eIOError, "Failed to open file '%s'", filename);
348
+ jpeg_destroy_compress(&jpeg);
349
+ return Qfalse;
350
+ }
351
+
352
+ GetNArray(image, image_nary);
353
+ n_dims = NA_NDIM(image_nary);
354
+ height = (unsigned int)NA_SHAPE(image_nary)[0];
355
+ width = (unsigned int)NA_SHAPE(image_nary)[1];
356
+ image_ptr = (uint8_t*)na_get_pointer_for_read(image);
357
+ n_ch = n_dims == 3 ? (int)NA_SHAPE(image_nary)[2] : 1;
358
+
359
+ jpeg_stdio_dest(&jpeg, file_ptr);
360
+
361
+ jpeg.image_height = height;
362
+ jpeg.image_width = width;
363
+ jpeg.input_components = n_ch;
364
+
365
+ switch (n_ch) {
366
+ case 3:
367
+ jpeg.in_color_space = JCS_RGB;
368
+ break;
369
+ case 1:
370
+ jpeg.in_color_space = JCS_GRAYSCALE;
371
+ break;
372
+ default:
373
+ jpeg.in_color_space = JCS_UNKNOWN;
374
+ break;
375
+ }
376
+
377
+ jpeg_set_defaults(&jpeg);
378
+
379
+ jpeg_set_quality(&jpeg, quality, TRUE);
380
+
381
+ jpeg_start_compress(&jpeg, TRUE);
382
+
383
+ for (y = 0; y < height; y++) {
384
+ tmp = image_ptr + y * width * n_ch;
385
+ jpeg_write_scanlines(&jpeg, &tmp, 1);
386
+ }
387
+
388
+ jpeg_finish_compress(&jpeg);
389
+ jpeg_destroy_compress(&jpeg);
390
+
391
+ fclose(file_ptr);
392
+
393
+ RB_GC_GUARD(image);
394
+ RB_GC_GUARD(filename_);
395
+
396
+ return Qtrue;
397
+ }
4
398
 
5
399
  void Init_magro() {
400
+ /**
401
+ * Document-module: Magro
402
+ * Magro is an image processing library in Ruby.
403
+ */
6
404
  mMagro = rb_define_module("Magro");
7
-
8
- init_io_module();
405
+ /**
406
+ * Document-module: Magro::IO
407
+ * IO module provides functions for input and output of image file.
408
+ */
409
+ mMagroIO = rb_define_module_under(mMagro, "IO");
410
+ /**
411
+ * @!visibility private
412
+ *
413
+ * Loads PNG image file.
414
+ *
415
+ * @overload read_png(filename) -> Numo::UInt8
416
+ * @param filename [String] File path of PNG image file.
417
+ *
418
+ * @raise [IOError] This error is raised when failed to read image file.
419
+ * @raise [NoMemoryError] If memory allocation of image data fails, this error is raised.
420
+ * @return [Numo::UInt8] (shape: [height, width, n_channels]) Loaded image.
421
+ */
422
+ rb_define_module_function(mMagroIO, "read_png", RUBY_METHOD_FUNC(magro_io_read_png), 1);
423
+ /**
424
+ * @!visibility private
425
+ *
426
+ * Saves PNG image file.
427
+ *
428
+ * @overload save_png(filename, image) -> Boolean
429
+ * @param filename [String] Path to image file to be saved.
430
+ * @param image [Numo::UInt8] (shape: [height, width, n_channels]) Image data to be saved.
431
+ *
432
+ * @raise [IOError] This error is raised when failed to write image file.
433
+ * @raise [NoMemoryError] If memory allocation of image data fails, this error is raised.
434
+ * @return [Boolean] true if file save is successful.
435
+ */
436
+ rb_define_module_function(mMagroIO, "save_png", RUBY_METHOD_FUNC(magro_io_save_png), 2);
437
+ /**
438
+ * @!visibility private
439
+ *
440
+ * Loads JPEG image file.
441
+ *
442
+ * @overload read_jpg(filename) -> Numo::UInt8
443
+ * @param filename [String] File path of JPEG image file.
444
+ *
445
+ * @raise [IOError] This error is raised when failed to read image file.
446
+ * @return [Numo::UInt8] (shape: [height, width, n_channels]) Loaded image.
447
+ */
448
+ rb_define_module_function(mMagroIO, "read_jpg", RUBY_METHOD_FUNC(magro_io_read_jpg), 1);
449
+ /**
450
+ * @!visibility private
451
+ *
452
+ * Saves JPEG image file.
453
+ *
454
+ * @overload save_jpg(filename, image, quality) -> Boolean
455
+ * @param filename [String] Path to image file to be saved.
456
+ * @param image [Numo::UInt8] (shape: [height, width, n_channels]) Image data to be saved.
457
+ * @param quality [Integer/Nil] Quality parameter of jpeg image that takes a value between 0 to 100.
458
+ *
459
+ * @return [Boolean] true if file save is successful.
460
+ */
461
+ rb_define_module_function(mMagroIO, "save_jpg", RUBY_METHOD_FUNC(magro_io_save_jpg), -1);
9
462
  }
data/ext/magro/magro.h CHANGED
@@ -1,8 +1,48 @@
1
+ /**
2
+ * Copyright (c) 2019-2022 Atsushi Tatsuma
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * * Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * * Neither the name of the copyright holder nor the names of its
16
+ * contributors may be used to endorse or promote products derived from
17
+ * this software without specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
1
31
  #ifndef MAGRO_H
2
32
  #define MAGRO_H 1
3
33
 
34
+ #include <stdio.h>
35
+ #include <stdlib.h>
36
+ #include <string.h>
37
+
38
+ #include <setjmp.h>
39
+
40
+ #include <jpeglib.h>
41
+ #include <png.h>
42
+
4
43
  #include <ruby.h>
5
44
 
6
- #include "imgrw.h"
45
+ #include <numo/narray.h>
46
+ #include <numo/template.h>
7
47
 
8
48
  #endif /* MAGRO_H */
data/lib/magro/filter.rb CHANGED
@@ -26,6 +26,7 @@ module Magro
26
26
  # @return [Numo::UInt8] (shape: [height, width, n_channels]) Filtered image.
27
27
  def filter2d(image, kernel, scale: nil, offset: 0)
28
28
  raise ArgumentError, 'Expect class of image to be Numo::NArray.' unless image.is_a?(Numo::NArray)
29
+
29
30
  filter_h, filter_w = kernel.shape
30
31
  padded = zero_padding(image, filter_h, filter_w)
31
32
  n_channels = image.shape[2]
@@ -46,11 +47,12 @@ module Magro
46
47
  # @param arr2 [Numo::NArray] (shape: [row2, col2]) Second input array.
47
48
  # @raise [ArgumentError] This error is raised when class of input array is not Numo::NArray.
48
49
  # @return [Numo::NArray] (shape: [row1 - row2 + 1, col1 - col2 + 1]) Convolution of arr1 with arr2.
49
- def convolve2d(arr1, arr2)
50
+ def convolve2d(arr1, arr2) # rubocop:disable Metrics/AbcSize
50
51
  raise ArgumentError, 'Expect class of first input array to be Numo::NArray.' unless arr1.is_a?(Numo::NArray)
51
52
  raise ArgumentError, 'Expect class of second input array to be Numo::NArray.' unless arr2.is_a?(Numo::NArray)
52
53
  raise ArgumentError, 'Expect first input array to be 2-dimensional array.' unless arr1.ndim == 2
53
54
  raise ArgumentError, 'Expect second input array to be 2-dimensional array.' unless arr2.ndim == 2
55
+
54
56
  row1, col1 = arr1.shape
55
57
  row2, col2 = arr2.shape
56
58
  # FIXME: lib/numo/narray/extra.rb:1098: warning: Using the last argument as keyword parameters is deprecated
@@ -61,7 +63,7 @@ module Magro
61
63
 
62
64
  # private
63
65
 
64
- def zero_padding(image, filter_h, filter_w)
66
+ def zero_padding(image, filter_h, filter_w) # rubocop:disable Metrics/AbcSize
65
67
  image_h, image_w, n_channels = image.shape
66
68
  pad_h = filter_h / 2
67
69
  pad_w = filter_w / 2