I do this:
begin
image = MiniMagick::Image.open(params[:avatar_file].path)
unless image.valid?
raise nil
end
rescue
return head :not_acceptable
end
image.format 'jpeg'
image.resize '128x128'
image.write dir.to_s + current_user.id.to_s + '_128x128.jpg'
And after the resizing, if an image wasn't a square, one of the sides has 128 pixels and the second is smaller than the first.
I would like to make them the same size by cropping the center of the image.
As far as I know, "convert" utility of ImageMagick has "gravity center", but I'm not sure that this is what I need and how to use it with MiniMagick.
The answer is in the image.combine_options block:
begin
image = MiniMagick::Image.open(params[:avatar_file].path)
unless image.valid?
raise nil
end
rescue
return head :not_acceptable
end
image.format 'jpeg'
image.combine_options do |c|
c.resize '128x128^'
c.gravity 'center'
c.extent '128x128'
end
image.write dir.to_s + current_user.id.to_s + '_128x128.jpg'
ImageMagick variant:
convert stock.jpg -resize 128x128^ -gravity center -extent 128x128 result.jpg
Related
I'm using Vips to resize images via Shrine, hoping it's possible to use the Vips library to merge a layer of text on top of the image.
ImageProcessing::Vips.source(image).resize_to_fill!(width, height)
This code works great, how can I add a layer of text after resize_to_fill?
The goal is to write 'Hello world' in white text, with a CSS text-shadow in the center of the image.
I've tried writing something like this, but I'm only getting errors so far:
Vips\Image::text('Hello world!', ['font' => 'sans 120', 'width' => $image->width - 100]);
Your example looks like PHP -- in Ruby you'd write something like:
text = Vips::Image.text 'Hello world!', font: 'sans 120', width: image.width - 100
I made a demo for you:
#!/usr/bin/ruby
require "vips"
image = Vips::Image.new_from_file ARGV[0], access: :sequential
text_colour = [255, 128, 128]
shadow_colour = [128, 255, 128]
h_shadow = 2
v_shadow = 5
blur_radius = 10
# position to render the top-left of the text
text_left = 100
text_top = 200
# render some text ... this will make a one-band uchar image, with 0
# for black, 255 for white and intermediate values for anti-aliasing
text_mask = Vips::Image.text "Hello world!", dpi: 300
# we need to enlarge the text mask before we blur so that the soft edges
# don't get clipped
shadow_mask = text_mask.embed(blur_radius, blur_radius,
text_mask.width + 2 * blur_radius,
text_mask.height + 2 * blur_radius)
# gaussblur() takes sigma as a parameter -- approximate as radius / 2
shadow_mask = shadow_mask.gaussblur(blur_radius / 2) if blur_radius > 0.1
# make an RGB image the size of the text mask with each pixel set to the
# constant, then attach the text mask as the alpha
rgb = text_mask.new_from_image(text_colour).copy(interpretation: "srgb")
text = rgb.bandjoin(text_mask)
rgb = shadow_mask.new_from_image(shadow_colour).copy(interpretation: "srgb")
shadow = rgb.bandjoin(shadow_mask)
# composite the three layers together
image = image.composite([shadow, text], "over",
x: [text_left + h_shadow, text_left],
y: [text_top + v_shadow, text_top])
image.write_to_file ARGV[1]
Run like this:
$ ./try319.rb ~/pics/PNG_transparency_demonstration_1.png x.png
To make:
I'm having issues to execute command in my processor. The same command works in console. Basically, I need to use two commands in one - convert and composite with tile so that watermark is repeated all over the image.
The command I ran in console is this:
run_string = "convert utah.jpg -resize 1200x1200 miff:- | composite -tile Watermark-Photo.png - utah2.jpg"=> "convert utah.jpg -resize 1200x1200 miff:- | composite -tile Watermark-Photo.png - utah2.jpg"
Paperclip.run run_string
And the result was perfect. However, when I put it into my processor:
module Paperclip
class Watermark < Processor
def initialize(file, options = {}, attachment = nil)
super
geometry = options[:geometry]
#file = file
#crop = geometry[-1,1] == '#'
#target_geometry = Geometry.parse geometry
#current_geometry = Geometry.from_file #file
#convert_options = options[:convert_options]
#whiny = options[:whiny].nil? ? true : options[:whiny]
#format = options[:format]
#watermark_path = options[:watermark_path]
#position = options[:position].nil? ? "SouthEast" : options[:position]
#watermark_offset = options[:watermark_offset]
#overlay = options[:overlay].nil? ? true : false
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
Rails.logger.info "watermark initialized"
end
# Returns true if the +target_geometry+ is meant to crop.
def crop?
#crop
end
# Returns true if the image is meant to make use of additional convert options.
def convert_options?
not #convert_options.blank?
end
# Performs the conversion of the +file+ into a watermark. Returns the Tempfile
# that contains the new image.
def make
Rails.logger.info "watermark make method"
src = #file
dst = Tempfile.new([#basename].compact.join("."))
dst.binmode
if #watermark_path.present?
# params = ["convert"]
# params += %W[#{fromfile}]
# params += transformation_command
# params += %W[| composite -tile #{#watermark_path} -]
# params << "#{tofile(dst)}"
run_string = "convert '#{fromfile}' #{transformation_command.join(' ')} | composite -tile '#{#watermark_path}' - '#{tofile(dst)}'"
else
# params = ["convert"]
# params += ["'#{fromfile}'"]
# params += transformation_command
# params << "'#{tofile(dst)}'"
run_string = "convert '#{fromfile}' #{transformation_command.join(' ')} '#{tofile(dst)}'"
end
Rails.logger.info 'params:' + run_string
begin
# Paperclip.run(params.join(' '))
Paperclip.run(run_string)
rescue ArgumentError, Cocaine::CommandLineError
raise Paperclip::Error.new("There was an error processing the watermark for #{#basename}") if #whiny
end
dst
end
def transformation_command
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = %W[-resize #{scale}]
trans += %W[-crop #{crop} +repage] if crop
trans += %W[miff:- ]
trans << #convert_options if #convert_options.present?
trans
end
def fromfile
File.expand_path(#file.path)
end
def tofile(destination)
File.expand_path(destination.path)
end
end
end
I can see from log that it executes the command:
Command :: convert '/tmp/7179f28e8260099624b8c2e7e8fe8fb420170902-1-1ud7pah.jpg' -resize 600x600> miff:- | composite -tile '/storycraftstock/app/assets/images/Watermark-Photo.png' - '/tmp/7179f28e8260099624b8c2e7e8fe8fb420170902-1-1ud7pah20170902-1-1kbmamu'
Gives this unspecific error:
exception while processing Spree::Image ID 11:
There was an error processing the watermark for 32a2a05e7393f7ddc78f0134bcf32e4a20170902-1-19oyq1j
As you can see I've commented a lot of things in the code just to make it run, but still no luck. Any ideal what am I doing wrong?
I am using Paperclip to create a thumbnail and apply a watermark to an uploaded image. The problem is that the thumbnail is created from a watermarked image instead of the original.
How can I make a thumbnail from the original file?
Model
has_attached_file :image,processors:[:thumbnail, :watermark], styles:{thumb:"240x240#", original: {watermark_path: "#Rails.root}/public/images/watermark.png"}}
Watermark Processor
module Paperclip
class Watermark < Processor
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :watermark_path, :overlay, :position
def initialize file, options = {}, attachment = nil
super
geometry = options[:geometry]
#file = file
if geometry.present?
#crop = geometry[-1, 1] == '#'
end
#target_geometry = Geometry.parse geometry
#current_geometry = Geometry.from_file #file
#convert_options = options[:convert_options]
#whiny = options[:whiny].nil? ? true : options[:whiny]
#format = options[:format]
#watermark_path = options[:watermark_path]
#position = options[:position].nil? ? "SouthEast" : options[:position]
#overlay = options[:overlay].nil? ? true : false
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
# Returns true if the +target_geometry+ is meant to crop.
def crop?
#crop
end
# Returns true if the image is meant to make use of additional convert options.
def convert_options?
not #convert_options.blank?
end
# Performs the conversion of the +file+ into a watermark. Returns the Tempfile
# that contains the new image.
def make
return #file unless watermark_path
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
command = "convert"
params = [fromfile]
params += transformation_command
params << tofile(dst)
begin
success = Paperclip.run(command, params.flatten.compact.collect { |e| "'#{e}'" }.join(" "))
rescue Paperclip::Errors::CommandNotFoundError
raise Paperclip::Errors::CommandNotFoundError, "There was an error resizing and cropping #{#basename}" if #whiny
end
if watermark_path
command = "composite"
params = %W[-gravity #{#position} #{watermark_path} #{tofile(dst)}]
params << tofile(dst)
begin
success = Paperclip.run(command, params.flatten.compact.collect { |e| "'#{e}'" }.join(" "))
rescue Paperclip::Errors::CommandNotFoundError
raise Paperclip::Errors::CommandNotFoundError, "There was an error processing the watermark for #{#basename}" if #whiny
end
end
dst
end
def fromfile
File.expand_path(#file.path)
end
def tofile(destination)
File.expand_path(destination.path)
end
def transformation_command
if #target_geometry.present?
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = %W[-resize #{scale}]
trans += %W[-crop #{crop} +repage] if crop
trans << convert_options if convert_options?
trans
else
scale, crop = #current_geometry.transformation_to(#current_geometry, crop?)
trans = %W[-resize #{scale}]
trans += %W[-crop #{crop} +repage] if crop
trans << convert_options if convert_options?
trans
end
end
end
end
How can I use a script such as Textcleaner within a Ruby-On-Rails application? Currently I'm using a custom paperclip processor where I use parameters similar to the script. Here is the has_attached_file line in my ActiveRecord:
has_attached_file :file, :style=> { :processors => [:text_cleaner] } }
Here is the Paperclip Processor:
module Paperclip
# Handles grayscale conversion of images that are uploaded.
class TextCleaner< Processor
def initialize file, options = {}, attachment = nil
super
#format = File.extname(#file.path)
#basename = File.basename(#file.path, #format)
end
def make
src = #file
dst = Tempfile.new([#basename, #format])
dst.binmode
begin
parameters = []
parameters << ":source"
parameters << "-auto-orient"
parameters << "-colorspace Gray"
#parameters << "-sharpen 0x1"
#parameters << "-type grayscale"
#parameters << "-contrast-stretch 0"
#parameters << "-clone 0"
#parameters << "-deskew 40%"
parameters << ":dest"
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}[0]", :dest => File.expand_path(dst.path))
rescue PaperclipCommandLineError => e
raise PaperclipError, "There was an error during the grayscale conversion for #{#basename}" if #whiny
end
dst
end
end
end
Using paperclip I was able to add a Text Cleaner processor. I added it as a style in model via:
has_attached_file :file, :styles => { :clean => { :processors => [:text_cleaner] } }
And in /lib/paperclip_processors/text_cleaner.rb I have:
module Paperclip
# Handles grayscale conversion of images that are uploaded.
class TextCleaner < Processor
def initialize file, options = {}, attachment = nil
super
#format = File.extname(#file.path)
#basename = File.basename(#file.path, #format)
end
def make
src = #file
dst = Tempfile.new([#basename,#format])
dst.binmode
begin
parameters = '-respect-parenthesis \( :source -colorspace gray -type grayscale -contrast-stretch 0 \) \( -clone 0 -colorspace gray -negate -lat 15x15+5% -contrast-stretch 0 \) -compose copy_opacity -composite -fill "white" -opaque none +matte -deskew 40% -auto-orient -sharpen 0x1 :dest'
success = Paperclip.run('convert', parameters, :source => File.expand_path(#file.path), :dest => File.expand_path(dst.path))
rescue PaperclipCommandLineError => e
raise PaperclipError, "There was an error during the textclean conversion for #{#basename}" if #whiny
end
dst
end
end
end
I have read:
Undefined Method crop! Using Carrierwave with MiniMagick on rails 3.1.3
Carrierwave Cropping
http://pastebin.com/ue4mVbC8
And so I tried:
# encoding: utf-8
class ProjectPictureUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process :cropper
# process :crop
process resize_to_fit: [200, 200]
end
def cropper
manipulate! do |img|
# if model.crop_x.present?
image = MiniMagick::Image.open(current_path)
crop_w = (image[:width] * 0.8).to_i
crop_y = (image[:height] * 0.8).to_i
crop_x = (image[:width] * 0.1).to_i
crop_y = (image[:height] * 0.1).to_i
# end
img = img.crop "#{crop_x}x#{crop_y}+#{crop_w}+#{crop_h}"
img
end
end
def crop
if model.crop_x.present?
resize_to_limit(700, 700)
manipulate! do |img|
x = model.crop_x
y = model.crop_y
w = model.crop_w
h = model.crop_h
w << 'x' << h << '+' << x << '+' << y
img.crop(w)
img
end
end
end
end
Then I used cropper: undefined local variable or method `crop_h' for /uploads/tmp/20121006-2227-4220-9621/thumb_Koala.jpg:#
Then crop: undefined method `crop_x' for #
Model:
class Project < ActiveRecord::Base
...
mount_uploader :picture, ProjectPictureUploader
end
Rails 3.2, Win7,
convert -version
Version: ImageMagick 6.7.9-4 2012-09-08 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP
I have understood.
version :thumb do
process resize_to_fit: [300, nil]
process crop: '300x150+0+0'
#process resize_and_crop: 200
end
private
# Simplest way
def crop(geometry)
manipulate! do |img|
img.crop(geometry)
img
end
end
# Resize and crop square from Center
def resize_and_crop(size)
manipulate! do |image|
if image[:width] < image[:height]
remove = ((image[:height] - image[:width])/2).round
image.shave("0x#{remove}")
elsif image[:width] > image[:height]
remove = ((image[:width] - image[:height])/2).round
image.shave("#{remove}x0")
end
image.resize("#{size}x#{size}")
image
end
end
resize_and_crop from here:
http://blog.aclarke.eu/crop-and-resize-an-image-using-minimagick/
In #cropper your crop_h is not initialized(you double initialize crop_y instead).
In #crop error is exactly what error message said - you don't have defined crop_x for Project class.