rszr 0.5.2 → 0.5.3
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 +4 -4
- data/README.md +53 -7
- data/ext/rszr/image.c +141 -5
- data/lib/rszr/image.rb +76 -20
- data/lib/rszr/image_processing.rb +82 -0
- data/lib/rszr/version.rb +1 -1
- metadata +59 -15
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d7322db19722cd5afc93e887fabe4031fa3a3064949956dc3bac562299918f10
         | 
| 4 | 
            +
              data.tar.gz: 8c03c8922f29d3f7989f427018e7baeb6f09c4c9f561fef1b6a92a80f4042ec8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 82b7c3ea10061666bacd712c39319ef36f19b2aecce3fa89556c591c0ef6f2cedf10b0fb1ed4ee6ac8613cfb40904b7e42306cd08d247d2653ca3135450244ba
         | 
| 7 | 
            +
              data.tar.gz: 52cac4fe43b0feb24e6fb837fdbed69bb4c91e53807ef5d5821c5ab1793d41a698632e1b342e8b14fed0219db080d05179d37eeb6fcef91e8052b66205c2ab07
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,7 +1,8 @@ | |
| 1 1 | 
             
            [](http://badge.fury.io/rb/rszr) [](https://travis-ci.org/mtgrosser/rszr)
         | 
| 2 2 | 
             
            # Rszr - fast image resizer for Ruby
         | 
| 3 3 |  | 
| 4 | 
            -
            Rszr is an image resizer for Ruby based on the Imlib2 library. | 
| 4 | 
            +
            Rszr is an image resizer for Ruby based on the Imlib2 library.
         | 
| 5 | 
            +
            It is faster and consumes less memory than MiniMagick, GD2 and VIPS, and comes with an optional drop-in interface for Rails ActiveStorage image processing.
         | 
| 5 6 |  | 
| 6 7 | 
             
            ## Installation
         | 
| 7 8 |  | 
| @@ -47,7 +48,15 @@ image.save('resized.jpg') | |
| 47 48 |  | 
| 48 49 | 
             
            # save it as PNG
         | 
| 49 50 | 
             
            image.save('resized.png')
         | 
| 51 | 
            +
            ```
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            ### Transformations
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            For each transformation, there is a bang! and non-bang method.
         | 
| 56 | 
            +
            The bang method changes the image in place, while the non-bang method
         | 
| 57 | 
            +
            creates a copy of the image in memory.
         | 
| 50 58 |  | 
| 59 | 
            +
            ```ruby
         | 
| 51 60 | 
             
            # auto height
         | 
| 52 61 | 
             
            image.resize(400, :auto)
         | 
| 53 62 |  | 
| @@ -66,30 +75,67 @@ image.turn!(3) | |
| 66 75 | 
             
            # rotate one time 90 deg counterclockwise
         | 
| 67 76 | 
             
            image.turn!(-1)
         | 
| 68 77 |  | 
| 78 | 
            +
            # rotate by arbitrary angle
         | 
| 79 | 
            +
            image.rotate(45)
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            # sharpen image by pixel radius
         | 
| 82 | 
            +
            image.sharpen!(1)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            # blur image by pixel radius
         | 
| 85 | 
            +
            image.blur!(1)
         | 
| 86 | 
            +
             | 
| 69 87 | 
             
            # initialize copy
         | 
| 70 88 | 
             
            image.dup
         | 
| 71 89 |  | 
| 72 90 | 
             
            # save memory, do not duplicate instance
         | 
| 73 91 | 
             
            image.resize!(400, :auto)
         | 
| 92 | 
            +
            ```
         | 
| 74 93 |  | 
| 75 | 
            -
             | 
| 94 | 
            +
            ### Image info
         | 
| 95 | 
            +
            ```ruby
         | 
| 76 96 | 
             
            image.width => 400
         | 
| 77 97 | 
             
            image.height => 300
         | 
| 78 98 | 
             
            image.dimensions => [400, 300]
         | 
| 79 99 | 
             
            image.format => "jpeg"
         | 
| 80 100 | 
             
            ```
         | 
| 81 101 |  | 
| 102 | 
            +
            ## Rails / ActiveStorage interface
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            Rszr provides a drop-in interface to the `image_resizing` gem.
         | 
| 105 | 
            +
            It is faster than both `mini_magick` and `vips` and way easier to install than the latter.
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            ```ruby
         | 
| 108 | 
            +
            # Gemfile
         | 
| 109 | 
            +
            gem 'image_resizing'
         | 
| 110 | 
            +
            gem 'rszr'
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            # config/initializers/rszr.rb
         | 
| 113 | 
            +
            require 'rszr/image_processing'
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            # config/application.rb
         | 
| 116 | 
            +
            config.active_storage.variant_processor = :rszr
         | 
| 117 | 
            +
            ```
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            When creating image variants, you can use all of Rszr's transformation methods:
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            ```erb
         | 
| 122 | 
            +
            <%= image_tag user.avatar.variant(resize_to_fit: [300, 200]) %>
         | 
| 123 | 
            +
            ```
         | 
| 124 | 
            +
             | 
| 82 125 | 
             
            ## Thread safety
         | 
| 83 126 |  | 
| 84 | 
            -
            As of version 0. | 
| 127 | 
            +
            As of version 0.5.0, Rszr is thread safe through Ruby's global VM lock.
         | 
| 85 128 | 
             
            Use of any previous versions in a threaded environment is discouraged.
         | 
| 86 129 |  | 
| 87 130 | 
             
            ## Speed
         | 
| 88 131 |  | 
| 89 | 
            -
            Resizing  | 
| 132 | 
            +
            Resizing a 1500x997 JPEG image to 800x532, 500 times:
         | 
| 133 | 
            +
            
         | 
| 134 | 
            +
             | 
| 90 135 |  | 
| 91 136 | 
             
            Library         | Time
         | 
| 92 137 | 
             
            ----------------|-----------
         | 
| 93 | 
            -
            MiniMagick      |  | 
| 94 | 
            -
            GD2             |  | 
| 95 | 
            -
             | 
| 138 | 
            +
            MiniMagick      | 27.0 s
         | 
| 139 | 
            +
            GD2             | 28.2 s
         | 
| 140 | 
            +
            VIPS            | 13.6 s
         | 
| 141 | 
            +
            Rszr            |  7.9 s
         | 
    
        data/ext/rszr/image.c
    CHANGED
    
    | @@ -75,7 +75,7 @@ static VALUE rszr_image_s__load(VALUE klass, VALUE rb_path) | |
| 75 75 | 
             
            }
         | 
| 76 76 |  | 
| 77 77 |  | 
| 78 | 
            -
            static VALUE  | 
| 78 | 
            +
            static VALUE rszr_image_format_get(VALUE self)
         | 
| 79 79 | 
             
            {
         | 
| 80 80 | 
             
              rszr_image_handle * handle;
         | 
| 81 81 | 
             
              char * format;
         | 
| @@ -93,6 +93,20 @@ static VALUE rszr_image_format(VALUE self) | |
| 93 93 | 
             
            }
         | 
| 94 94 |  | 
| 95 95 |  | 
| 96 | 
            +
            static VALUE rszr_image__format_set(VALUE self, VALUE rb_format)
         | 
| 97 | 
            +
            {
         | 
| 98 | 
            +
              rszr_image_handle * handle;
         | 
| 99 | 
            +
              char * format = StringValueCStr(rb_format);
         | 
| 100 | 
            +
              
         | 
| 101 | 
            +
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 102 | 
            +
              
         | 
| 103 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 104 | 
            +
              imlib_image_set_format(format);
         | 
| 105 | 
            +
              
         | 
| 106 | 
            +
              return self;
         | 
| 107 | 
            +
            }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
             | 
| 96 110 | 
             
            static VALUE rszr_image_width(VALUE self)
         | 
| 97 111 | 
             
            {
         | 
| 98 112 | 
             
              rszr_image_handle * handle;
         | 
| @@ -120,6 +134,44 @@ static VALUE rszr_image_height(VALUE self) | |
| 120 134 | 
             
              return INT2NUM(height);
         | 
| 121 135 | 
             
            }
         | 
| 122 136 |  | 
| 137 | 
            +
            /*
         | 
| 138 | 
            +
            static VALUE rszr_image_get_quality(VALUE self)
         | 
| 139 | 
            +
            {
         | 
| 140 | 
            +
              rszr_image_handle * handle;
         | 
| 141 | 
            +
              int quality;
         | 
| 142 | 
            +
              
         | 
| 143 | 
            +
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 144 | 
            +
              
         | 
| 145 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 146 | 
            +
              quality = imlib_image_get_attached_value("quality");
         | 
| 147 | 
            +
              
         | 
| 148 | 
            +
              if (quality) {
         | 
| 149 | 
            +
                return INT2NUM(quality);
         | 
| 150 | 
            +
              } else {
         | 
| 151 | 
            +
                return Qnil;
         | 
| 152 | 
            +
              }
         | 
| 153 | 
            +
            }
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            static VALUE rszr_image_set_quality(VALUE self, VALUE rb_quality)
         | 
| 156 | 
            +
            {
         | 
| 157 | 
            +
              rszr_image_handle * handle;
         | 
| 158 | 
            +
              int quality;
         | 
| 159 | 
            +
              
         | 
| 160 | 
            +
              Check_Type(rb_quality, T_FIXNUM);
         | 
| 161 | 
            +
              quality = FIX2INT(rb_quality);
         | 
| 162 | 
            +
              if (quality <= 0) {
         | 
| 163 | 
            +
                rb_raise(rb_eArgError, "quality must be >= 0");
         | 
| 164 | 
            +
                return Qnil;
         | 
| 165 | 
            +
              }
         | 
| 166 | 
            +
              
         | 
| 167 | 
            +
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 168 | 
            +
              
         | 
| 169 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 170 | 
            +
              imlib_image_attach_data_value("quality", NULL, quality, NULL);
         | 
| 171 | 
            +
              
         | 
| 172 | 
            +
              return INT2NUM(quality);
         | 
| 173 | 
            +
            }
         | 
| 174 | 
            +
            */
         | 
| 123 175 |  | 
| 124 176 | 
             
            static VALUE rszr_image_dup(VALUE self)
         | 
| 125 177 | 
             
            {
         | 
| @@ -159,6 +211,77 @@ static VALUE rszr_image__turn_bang(VALUE self, VALUE orientation) | |
| 159 211 | 
             
            }
         | 
| 160 212 |  | 
| 161 213 |  | 
| 214 | 
            +
            static VALUE rszr_image__rotate(VALUE self, VALUE bang, VALUE rb_angle)
         | 
| 215 | 
            +
            {
         | 
| 216 | 
            +
              rszr_image_handle * handle;
         | 
| 217 | 
            +
              rszr_image_handle * rotated_handle;
         | 
| 218 | 
            +
              Imlib_Image rotated_image;
         | 
| 219 | 
            +
              VALUE oRotatedImage;
         | 
| 220 | 
            +
              double angle;
         | 
| 221 | 
            +
              
         | 
| 222 | 
            +
              angle = NUM2DBL(rb_angle);
         | 
| 223 | 
            +
              
         | 
| 224 | 
            +
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 225 | 
            +
              
         | 
| 226 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 227 | 
            +
              rotated_image = imlib_create_rotated_image(angle);
         | 
| 228 | 
            +
              
         | 
| 229 | 
            +
              if (!rotated_image) {
         | 
| 230 | 
            +
                rb_raise(eRszrTransformationError, "error rotating image");
         | 
| 231 | 
            +
                return Qnil;
         | 
| 232 | 
            +
              }
         | 
| 233 | 
            +
              
         | 
| 234 | 
            +
              if (RTEST(bang)) {
         | 
| 235 | 
            +
                rszr_free_image(handle->image);
         | 
| 236 | 
            +
                handle->image = rotated_image;
         | 
| 237 | 
            +
                
         | 
| 238 | 
            +
                return self;
         | 
| 239 | 
            +
              }
         | 
| 240 | 
            +
              else {
         | 
| 241 | 
            +
                oRotatedImage = rszr_image_s_allocate(cImage);
         | 
| 242 | 
            +
                Data_Get_Struct(oRotatedImage, rszr_image_handle, rotated_handle);
         | 
| 243 | 
            +
                rotated_handle->image = rotated_image;
         | 
| 244 | 
            +
              
         | 
| 245 | 
            +
                return oRotatedImage;
         | 
| 246 | 
            +
              }
         | 
| 247 | 
            +
            }
         | 
| 248 | 
            +
             | 
| 249 | 
            +
            /*
         | 
| 250 | 
            +
            static VALUE rszr_image__brighten_bang(VALUE self, VALUE rb_brightness)
         | 
| 251 | 
            +
            {
         | 
| 252 | 
            +
              rszr_image_handle * handle;
         | 
| 253 | 
            +
              double brightness;
         | 
| 254 | 
            +
              
         | 
| 255 | 
            +
              brightness = NUM2DBL(rb_brightness);
         | 
| 256 | 
            +
              
         | 
| 257 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 258 | 
            +
              imlib_modify_color_modifier_brightness(brightness);
         | 
| 259 | 
            +
              
         | 
| 260 | 
            +
              return self;
         | 
| 261 | 
            +
            }
         | 
| 262 | 
            +
            */
         | 
| 263 | 
            +
             | 
| 264 | 
            +
            static VALUE rszr_image__sharpen_bang(VALUE self, VALUE rb_radius)
         | 
| 265 | 
            +
            {
         | 
| 266 | 
            +
              rszr_image_handle * handle;
         | 
| 267 | 
            +
              int radius;
         | 
| 268 | 
            +
              
         | 
| 269 | 
            +
              radius = NUM2INT(rb_radius);
         | 
| 270 | 
            +
              
         | 
| 271 | 
            +
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 272 | 
            +
              
         | 
| 273 | 
            +
              imlib_context_set_image(handle->image);
         | 
| 274 | 
            +
              
         | 
| 275 | 
            +
              if (radius >= 0) {
         | 
| 276 | 
            +
                imlib_image_sharpen(radius);
         | 
| 277 | 
            +
              } else {
         | 
| 278 | 
            +
                imlib_image_blur(radius);
         | 
| 279 | 
            +
              }
         | 
| 280 | 
            +
              
         | 
| 281 | 
            +
              return self;
         | 
| 282 | 
            +
            }
         | 
| 283 | 
            +
             | 
| 284 | 
            +
             | 
| 162 285 | 
             
            static Imlib_Image rszr_create_cropped_scaled_image(const Imlib_Image image, VALUE rb_src_x, VALUE rb_src_y, VALUE rb_src_w, VALUE rb_src_h, VALUE rb_dst_w, VALUE rb_dst_h)
         | 
| 163 286 | 
             
            {
         | 
| 164 287 | 
             
              Imlib_Image resized_image;
         | 
| @@ -262,20 +385,24 @@ static VALUE rszr_image__crop(VALUE self, VALUE bang, VALUE rb_x, VALUE rb_y, VA | |
| 262 385 | 
             
            }
         | 
| 263 386 |  | 
| 264 387 |  | 
| 265 | 
            -
            static VALUE rszr_image__save(VALUE self, VALUE rb_path, VALUE rb_format)
         | 
| 388 | 
            +
            static VALUE rszr_image__save(VALUE self, VALUE rb_path, VALUE rb_format, VALUE rb_quality)
         | 
| 266 389 | 
             
            {
         | 
| 267 390 | 
             
              rszr_image_handle * handle;
         | 
| 268 391 | 
             
              char * path;
         | 
| 269 392 | 
             
              char * format;
         | 
| 393 | 
            +
              int quality;
         | 
| 270 394 | 
             
              Imlib_Load_Error save_error;
         | 
| 271 395 |  | 
| 272 396 | 
             
              path = StringValueCStr(rb_path);
         | 
| 273 397 | 
             
              format = StringValueCStr(rb_format);
         | 
| 274 | 
            -
              
         | 
| 398 | 
            +
              quality = (NIL_P(rb_quality)) ? 0 : FIX2INT(rb_quality);
         | 
| 399 | 
            +
             | 
| 275 400 | 
             
              Data_Get_Struct(self, rszr_image_handle, handle);
         | 
| 276 401 |  | 
| 277 402 | 
             
              imlib_context_set_image(handle->image);
         | 
| 278 403 | 
             
              imlib_image_set_format(format);
         | 
| 404 | 
            +
              if (quality)
         | 
| 405 | 
            +
                imlib_image_attach_data_value("quality", NULL, quality, NULL);
         | 
| 279 406 | 
             
              imlib_save_image_with_error_return(path, &save_error);
         | 
| 280 407 |  | 
| 281 408 | 
             
              if (save_error) {
         | 
| @@ -298,12 +425,21 @@ void Init_rszr_image() | |
| 298 425 | 
             
              rb_define_method(cImage, "initialize",  rszr_image_initialize, 2);
         | 
| 299 426 | 
             
              rb_define_method(cImage, "width",       rszr_image_width, 0);
         | 
| 300 427 | 
             
              rb_define_method(cImage, "height",      rszr_image_height, 0);
         | 
| 301 | 
            -
              rb_define_method(cImage, "format",       | 
| 428 | 
            +
              rb_define_method(cImage, "format",      rszr_image_format_get, 0);
         | 
| 302 429 | 
             
              rb_define_method(cImage, "dup",         rszr_image_dup, 0);
         | 
| 430 | 
            +
              // rb_define_method(cImage, "quality",     rszr_image_get_quality, 0);
         | 
| 431 | 
            +
              // rb_define_method(cImage, "quality=",    rszr_image_set_quality, 1);
         | 
| 432 | 
            +
              
         | 
| 433 | 
            +
              rb_define_protected_method(cImage, "_format=", rszr_image__format_set, 1);
         | 
| 434 | 
            +
              
         | 
| 303 435 | 
             
              rb_define_private_method(cImage, "_resize",  rszr_image__resize, 7);
         | 
| 304 436 | 
             
              rb_define_private_method(cImage, "_crop",    rszr_image__crop, 5);
         | 
| 305 437 | 
             
              rb_define_private_method(cImage, "_turn!",   rszr_image__turn_bang, 1);
         | 
| 306 | 
            -
              rb_define_private_method(cImage, " | 
| 438 | 
            +
              rb_define_private_method(cImage, "_rotate",  rszr_image__rotate, 2);
         | 
| 439 | 
            +
              rb_define_private_method(cImage, "_sharpen!",   rszr_image__sharpen_bang, 1);
         | 
| 440 | 
            +
              /* rb_define_private_method(cImage, "_brighten!",  rszr_image__brighten_bang, 1); */
         | 
| 441 | 
            +
              
         | 
| 442 | 
            +
              rb_define_private_method(cImage, "_save",       rszr_image__save, 3);
         | 
| 307 443 | 
             
            }
         | 
| 308 444 |  | 
| 309 445 | 
             
            #endif
         | 
    
        data/lib/rszr/image.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ module Rszr | |
| 3 3 |  | 
| 4 4 | 
             
                class << self
         | 
| 5 5 |  | 
| 6 | 
            -
                  def load(path,  | 
| 6 | 
            +
                  def load(path, **opts)
         | 
| 7 7 | 
             
                    path = path.to_s
         | 
| 8 8 | 
             
                    raise FileNotFound unless File.exist?(path)
         | 
| 9 9 | 
             
                    _load(path)
         | 
| @@ -15,6 +15,11 @@ module Rszr | |
| 15 15 | 
             
                def dimensions
         | 
| 16 16 | 
             
                  [width, height]
         | 
| 17 17 | 
             
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                def format=(fmt)
         | 
| 20 | 
            +
                  fmt = fmt.to_s if fmt.is_a?(Symbol)
         | 
| 21 | 
            +
                  self._format = fmt
         | 
| 22 | 
            +
                end
         | 
| 18 23 |  | 
| 19 24 | 
             
                def inspect
         | 
| 20 25 | 
             
                  fmt = format
         | 
| @@ -22,30 +27,72 @@ module Rszr | |
| 22 27 | 
             
                  "#<#{self.class.name}:0x#{object_id.to_s(16)} #{width}x#{height}#{fmt}>"
         | 
| 23 28 | 
             
                end
         | 
| 24 29 |  | 
| 25 | 
            -
                 | 
| 26 | 
            -
                   | 
| 27 | 
            -
             | 
| 30 | 
            +
                module Transformations
         | 
| 31 | 
            +
                  def resize(*args)
         | 
| 32 | 
            +
                    _resize(false, *calculate_size(*args))
         | 
| 33 | 
            +
                  end
         | 
| 28 34 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 35 | 
            +
                  def resize!(*args)
         | 
| 36 | 
            +
                    _resize(true, *calculate_size(*args))
         | 
| 37 | 
            +
                  end
         | 
| 32 38 |  | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 39 | 
            +
                  def crop(x, y, width, height)
         | 
| 40 | 
            +
                    _crop(false, x, y, width, height)
         | 
| 41 | 
            +
                  end
         | 
| 36 42 |  | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 43 | 
            +
                  def crop!(x, y, width, height)
         | 
| 44 | 
            +
                    _crop(true, x, y, width, height)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                  def turn(orientation)
         | 
| 48 | 
            +
                    dup.turn!(orientation)
         | 
| 49 | 
            +
                  end
         | 
| 40 50 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 51 | 
            +
                  def turn!(orientation)
         | 
| 52 | 
            +
                    orientation = orientation.abs + 2 if orientation.negative?
         | 
| 53 | 
            +
                    _turn!(orientation % 4)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                  def rotate(deg)
         | 
| 57 | 
            +
                    _rotate(false, deg.to_f * Math::PI / 180.0)
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                
         | 
| 60 | 
            +
                  def rotate!(deg)
         | 
| 61 | 
            +
                    _rotate(true, deg.to_f * Math::PI / 180.0)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                  def sharpen(radius)
         | 
| 65 | 
            +
                    dup.sharpen!(radius)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                  def sharpen!(radius)
         | 
| 69 | 
            +
                    raise ArgumentError, 'illegal radius' if radius < 0
         | 
| 70 | 
            +
                    _sharpen!(radius)
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                  def blur(radius)
         | 
| 74 | 
            +
                    dup.blur!(radius)
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
                
         | 
| 77 | 
            +
                  def blur!(radius)
         | 
| 78 | 
            +
                    raise ArgumentError, 'illegal radius' if radius < 0
         | 
| 79 | 
            +
                    _sharpen!(-radius)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  
         | 
| 82 | 
            +
                  # TODO
         | 
| 83 | 
            +
                  #def brighten!(brightness)
         | 
| 84 | 
            +
                  #  raise ArgumentError, 'illegal brightness' if brightness > 1 || brightness < -1
         | 
| 85 | 
            +
                  #  _brighten!(brightness)
         | 
| 86 | 
            +
                  #end
         | 
| 44 87 | 
             
                end
         | 
| 88 | 
            +
                
         | 
| 89 | 
            +
                include Transformations
         | 
| 45 90 |  | 
| 46 | 
            -
                def save(path, format  | 
| 47 | 
            -
                  format ||= format_from_filename(path) || 'jpg'
         | 
| 48 | 
            -
                   | 
| 91 | 
            +
                def save(path, format: nil, quality: nil)
         | 
| 92 | 
            +
                  format ||= format_from_filename(path) || self.format || 'jpg'
         | 
| 93 | 
            +
                  raise ArgumentError, "invalid quality #{quality.inspect}" if quality && !(0..100).cover?(quality)
         | 
| 94 | 
            +
                  ensure_path_is_writable(path)
         | 
| 95 | 
            +
                  _save(path.to_s, format.to_s, quality)
         | 
| 49 96 | 
             
                end
         | 
| 50 97 |  | 
| 51 98 | 
             
                private
         | 
| @@ -56,7 +103,7 @@ module Rszr | |
| 56 103 | 
             
                # :auto, 300        auto width, fit height
         | 
| 57 104 | 
             
                # 400, 300, crop: :center_middle
         | 
| 58 105 | 
             
                # 400, 300, background: rgba
         | 
| 59 | 
            -
                # 400, 300,  | 
| 106 | 
            +
                # 400, 300, skew: true
         | 
| 60 107 |  | 
| 61 108 | 
             
                def calculate_size(*args)
         | 
| 62 109 | 
             
                  options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| @@ -104,6 +151,15 @@ module Rszr | |
| 104 151 | 
             
                def format_from_filename(path)
         | 
| 105 152 | 
             
                  File.extname(path)[1..-1]
         | 
| 106 153 | 
             
                end
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                def ensure_path_is_writable(path)
         | 
| 156 | 
            +
                  path = Pathname.new(path)
         | 
| 157 | 
            +
                  path.dirname.realpath.writable?
         | 
| 158 | 
            +
                rescue Errno::ENOENT => e
         | 
| 159 | 
            +
                  raise SaveError, 'Non-existant path component'
         | 
| 160 | 
            +
                rescue SystemCallError => e
         | 
| 161 | 
            +
                  raise SaveError, e.message
         | 
| 162 | 
            +
                end
         | 
| 107 163 |  | 
| 108 164 | 
             
                def assert_valid_keys(hsh, *valid_keys)
         | 
| 109 165 | 
             
                  if unknown_key = (hsh.keys - valid_keys).first
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            require 'rszr'
         | 
| 2 | 
            +
            require 'image_processing'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module ImageProcessing
         | 
| 5 | 
            +
              module Rszr
         | 
| 6 | 
            +
                extend Chainable
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class << self
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  # Returns whether the given image file is processable.
         | 
| 11 | 
            +
                  def valid_image?(file)
         | 
| 12 | 
            +
                    ::Rszr::Image.load(file).width
         | 
| 13 | 
            +
                    true
         | 
| 14 | 
            +
                  rescue ::Rszr::Error
         | 
| 15 | 
            +
                    false
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                class Processor < ImageProcessing::Processor
         | 
| 21 | 
            +
                  accumulator :image, ::Rszr::Image
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  class << self
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    # Loads the image on disk into a Rszr::Image object
         | 
| 26 | 
            +
                    def load_image(path_or_image, **options)
         | 
| 27 | 
            +
                      if path_or_image.is_a?(::Rszr::Image)
         | 
| 28 | 
            +
                        path_or_image
         | 
| 29 | 
            +
                      else
         | 
| 30 | 
            +
                        ::Rszr::Image.load(path_or_image)
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                      # TODO: image = image.autorot if autorot && !options.key?(:autorotate)
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    # Writes the image object to disk. 
         | 
| 36 | 
            +
                    # Accepts additional options (quality, format).
         | 
| 37 | 
            +
                    def save_image(image, destination_path, **options)
         | 
| 38 | 
            +
                      image.save(destination_path, **options)
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    # Calls the operation to perform the processing. If the operation is
         | 
| 42 | 
            +
                    # defined on the processor (macro), calls it. Otherwise calls the
         | 
| 43 | 
            +
                    # bang variant of the method directly on the Rszr image object.
         | 
| 44 | 
            +
                    def apply_operation(accumulator, (name, args, block))
         | 
| 45 | 
            +
                      return super if method_defined?(name)
         | 
| 46 | 
            +
                      accumulator.send("#{name}!", *args, &block)
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  # Resizes the image to not be larger than the specified dimensions.
         | 
| 52 | 
            +
                  def resize_to_limit(width, height, **options)
         | 
| 53 | 
            +
                    width, height = default_dimensions(width, height)
         | 
| 54 | 
            +
                    thumbnail(width, height, **options)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  # Resizes the image to fit within the specified dimensions.
         | 
| 58 | 
            +
                  def resize_to_fit(width, height, **options)
         | 
| 59 | 
            +
                    width, height = default_dimensions(width, height)
         | 
| 60 | 
            +
                    thumbnail(width, height, **options)
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  # Resizes the image to fill the specified dimensions, applying any
         | 
| 64 | 
            +
                  # necessary cropping.
         | 
| 65 | 
            +
                  def resize_to_fill(width, height, **options)
         | 
| 66 | 
            +
                    thumbnail(width, height, crop: :center, **options)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  private
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def thumbnail(width, height, **options)
         | 
| 72 | 
            +
                    image.resize!(width, height, **options)
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def default_dimensions(width, height)
         | 
| 76 | 
            +
                    raise Error, 'either width or height must be specified' unless width || height
         | 
| 77 | 
            +
                    [width || :auto, height || :auto]
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
    
        data/lib/rszr/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,43 +1,43 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rszr
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.5. | 
| 4 | 
            +
              version: 0.5.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Matthias Grosser
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2021-03-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - - " | 
| 17 | 
            +
                - - ">="
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: ' | 
| 19 | 
            +
                    version: '0'
         | 
| 20 20 | 
             
              type: :development
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - - " | 
| 24 | 
            +
                - - ">="
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: ' | 
| 26 | 
            +
                    version: '0'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: rake
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 | 
            -
                - - " | 
| 31 | 
            +
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version:  | 
| 33 | 
            +
                    version: 12.3.3
         | 
| 34 34 | 
             
              type: :development
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 | 
            -
                - - " | 
| 38 | 
            +
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version:  | 
| 40 | 
            +
                    version: 12.3.3
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: rake-compiler
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -80,6 +80,20 @@ dependencies: | |
| 80 80 | 
             
                - - ">="
         | 
| 81 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 82 | 
             
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: minitest
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - ">="
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - ">="
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 83 97 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 84 98 | 
             
              name: simplecov
         | 
| 85 99 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -94,6 +108,20 @@ dependencies: | |
| 94 108 | 
             
                - - ">="
         | 
| 95 109 | 
             
                  - !ruby/object:Gem::Version
         | 
| 96 110 | 
             
                    version: '0'
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: image_processing
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - ">="
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: '0'
         | 
| 118 | 
            +
              type: :development
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - ">="
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: '0'
         | 
| 97 125 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 98 126 | 
             
              name: gd2-ffij
         | 
| 99 127 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -122,6 +150,20 @@ dependencies: | |
| 122 150 | 
             
                - - ">="
         | 
| 123 151 | 
             
                  - !ruby/object:Gem::Version
         | 
| 124 152 | 
             
                    version: '0'
         | 
| 153 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 154 | 
            +
              name: ruby-vips
         | 
| 155 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
                requirements:
         | 
| 157 | 
            +
                - - ">="
         | 
| 158 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                    version: '0'
         | 
| 160 | 
            +
              type: :development
         | 
| 161 | 
            +
              prerelease: false
         | 
| 162 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 163 | 
            +
                requirements:
         | 
| 164 | 
            +
                - - ">="
         | 
| 165 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 166 | 
            +
                    version: '0'
         | 
| 125 167 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 126 168 | 
             
              name: memory_profiler
         | 
| 127 169 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -156,12 +198,13 @@ files: | |
| 156 198 | 
             
            - ext/rszr/rszr.h
         | 
| 157 199 | 
             
            - lib/rszr.rb
         | 
| 158 200 | 
             
            - lib/rszr/image.rb
         | 
| 201 | 
            +
            - lib/rszr/image_processing.rb
         | 
| 159 202 | 
             
            - lib/rszr/version.rb
         | 
| 160 203 | 
             
            homepage: https://github.com/mtgrosser/rszr
         | 
| 161 204 | 
             
            licenses:
         | 
| 162 205 | 
             
            - MIT
         | 
| 163 206 | 
             
            metadata: {}
         | 
| 164 | 
            -
            post_install_message: | 
| 207 | 
            +
            post_install_message:
         | 
| 165 208 | 
             
            rdoc_options: []
         | 
| 166 209 | 
             
            require_paths:
         | 
| 167 210 | 
             
            - lib
         | 
| @@ -176,9 +219,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 176 219 | 
             
              - - ">="
         | 
| 177 220 | 
             
                - !ruby/object:Gem::Version
         | 
| 178 221 | 
             
                  version: '0'
         | 
| 179 | 
            -
            requirements: | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 222 | 
            +
            requirements:
         | 
| 223 | 
            +
            - Imlib2
         | 
| 224 | 
            +
            rubygems_version: 3.1.4
         | 
| 225 | 
            +
            signing_key:
         | 
| 182 226 | 
             
            specification_version: 4
         | 
| 183 227 | 
             
            summary: Fast image resizer
         | 
| 184 228 | 
             
            test_files: []
         |