
Preview and Resize Pictures on the Fly
I redid the site to the customer on Netcat and was surprised to find that someone else was using the loading of individual pictures for the originals and for the previews and, as a result, the individual columns in the database table. Where it was still not going to create thumbnails on the server side after loading the original.
The idea is simple and not new. I first came across this approach in UMI-CMS, but used it in RubyOnRails. The point is that previews are created only when they are needed and of any size, and only the name of the original is stored in the database.
If you need to display a preview of the image, you call a function like:
The view_thumbs method checks in the folder (for example, "/ images / cache") the presence of the file originals_name_file_100xauto.jpg. If it finds it, it returns the string "originals_name_file_100xauto.jpg", if it does not find it, it creates a file of the right size on the fly and returns the same.
The advantages of the approach are obvious:
Practice shows that specifying only one size in a method with automatic fitting of another is not enough. If you limit only by the width, then the picture will be caught too high and the whole layout can move out. Same thing with height. And in the above code, when specifying both the height and the width, the resize will be without preserving the scale. Below is a piece of php code that implements resize with restrictions both in height and width while maintaining the mass.
The idea is simple and not new. I first came across this approach in UMI-CMS, but used it in RubyOnRails. The point is that previews are created only when they are needed and of any size, and only the name of the original is stored in the database.
If you need to display a preview of the image, you call a function like:
- @thumbs = Photo.view_thumbs('originals_name_file.jpg', '100', 'auto')
where the second and third parameters are the desired size in pixels (auto means automatic fit to scale). The view_thumbs method checks in the folder (for example, "/ images / cache") the presence of the file originals_name_file_100xauto.jpg. If it finds it, it returns the string "originals_name_file_100xauto.jpg", if it does not find it, it creates a file of the right size on the fly and returns the same.
The advantages of the approach are obvious:
- No garbage is created in the form of a large number of thumbnails on the disk. All previews are stored in one cache folder and can be deleted periodically to free up space.
- Unlimited thumbnails of various sizes. It is enough to set the necessary parameters in the method.
- require 'RMagick'
- class Photo < ActiveRecord::Base
-
- def self.view_thumbs(image, width = 'auto', height = 'auto')
- img_arr = image.split(".")
- img, img_type = img_arr[0], img_arr[1]
-
- img_thumbs = "#{img}_#{width}x#{height}"
- img_main_dir = "#{RAILS_ROOT}/public/images/"
- img_thumbs_dir = "#{RAILS_ROOT}/public/images/cache/"
- begin
- img_thumbs = Magick::Image.read("#{img_thumbs_dir}/#{img_thumbs}.#{img_type}")
- rescue Magick::ImageMagickError # Вся соль тут. Если нет нужного тхумбса, то после чтения вываливается ошибка, которую мы спасаем. Если всё нормально, то код далее не выполняется
- img_orig = Magick::Image.read("#{img_main_dir}/#{image}").first
- img_size = {:main =>{:cols => img_orig.columns,:rows => img_orig.rows},
- :thumb =>{:cols =>0.0, :rows =>0.0}
- }
- if 'auto' == width and 'auto' == height
- img_size[:thumb][:rows] = img_size[:main][:rows]
- img_size[:thumb][:cols] = img_size[:main][:cols]
- end
- if 'auto' != width and 'auto' == height
- img_size[:thumb][:rows] = ((width.to_f/img_size[:main][:cols])*img_size[:main][:rows]).to_i
- img_size[:thumb][:cols] = width.to_i
- end
- if 'auto' == width and 'auto' != height
- img_size[:thumb][:rows] = height.to_i
- img_size[:thumb][:cols] = ((height.to_f/img_size[:main][:rows])*img_size[:main][:cols]).to_i
- end
- if 'auto' != width and 'auto' != height
- img_size[:thumb][:rows] = height.to_i
- img_size[:thumb][:cols] = width.to_i
- end
- img_new = img_orig.resize!(img_size[:thumb][:cols].to_i, img_size[:thumb][:rows].to_i)
- img_new.write "#{img_thumbs_dir}/#{img_thumbs}.#{img_type}"
- end
- img_thumbs = x
- return "#{img_thumbs}.#{img_type}"
- end
- end
Practice shows that specifying only one size in a method with automatic fitting of another is not enough. If you limit only by the width, then the picture will be caught too high and the whole layout can move out. Same thing with height. And in the above code, when specifying both the height and the width, the resize will be without preserving the scale. Below is a piece of php code that implements resize with restrictions both in height and width while maintaining the mass.
- $img_size = array(
- 'main'=>array('width'=>imagesx($img_src), 'height'=>imagesy($img_src)),
- 'thumb'=>array('width'=>0, 'height'=>0)
- );
-
- if ('auto' == $width && 'auto' == $height) {
- $img_size['thumb']['height'] =(int) $img_size['main']['height'];
- $img_size['thumb']['width'] =(int) $img_size['main']['width'];
- }
- else if ('auto' != $width && 'auto' == $height) {
- $img_size['thumb']['width'] = (($img_size['main']['width'] <= $width) ? $img_size['main']['width'] : $width);
- $img_size['thumb']['height'] = (int) round(($img_size['thumb']['width']/$img_size['main']['width'])*$img_size['main']['height']);
- }
- else if ('auto' == $width && 'auto' != $height) {
- $img_size['thumb']['height'] = (($img_size['main']['height'] <= $height) ? $img_size['main']['height'] : $height);
- $img_size['thumb']['width'] = (int) round(($height/$img_size['main']['height'])*$img_size['main']['width']);
- }
- else if ('auto' != $width && 'auto' != $height) {
- $img_size['thumb']['height'] = (($img_size['main']['height'] <= $height) ? $img_size['main']['height'] : $height);
- $img_size['thumb']['width'] = (($img_size['main']['width'] <= $width) ? $img_size['main']['width'] : $width);
- $Kt = $img_size['thumb']['height']/$img_size['thumb']['width'];//5/1
- $Km = $img_size['main']['height']/$img_size['main']['width'];//5/1
- if ($Kt > $Km){
- $img_size['thumb']['height'] = $img_size['thumb']['width']*$Km;
- }
- else if ($Kt < $Km) {
- $img_size['thumb']['width'] = $img_size['thumb']['height']/$Km;
- }
- }
______________________