Tự động watermark ảnh với ImageMagick
Bài đăng này đã không được cập nhật trong 3 năm
Khách hàng trong dự án gần đây của tôi yêu cầu mỗi hình ảnh upload lên đều phải được watermark. Điều này khá quan trọng vì hiện nay, việc sử dụng hình ảnh vi phạm bản quyền là rất phổ biến. Để làm việc này, chúng ta có thể chèn một ảnh mờ hoặc một đoạn text chứa thông tin liên hệ lên trên ảnh gốc mà không che đi thông tin chính của ảnh gốc, điều này vừa để đánh dấu bản quyền vừa giúp khách hàng đỡ mất công tìm kiếm cách liên hệ.
Để chỉnh sửa hình ảnh, chúng ta cần một công cụ riêng biệt. Mặc định Carrierwave có hỗ trợ các gem RMagick
và MiniMagick
, sử dụng để thao tác lên hình ảnh với sự giúp đỡ của ImageMagick. ImageMagick
là một giải pháp mã nguồn mở được hỗ trợ trên tất cả các nền tảng lớn, cho phép chỉnh sửa các hình ảnh hiện có và tạo ra những hình ảnh mới, do đó, trước khi tiến hành bạn cần phải tải về và cài đặt nó. Tiếp theo, bạn có thể chọn một trong hai gem. Tôi chọn MiniMagick
vì nó dễ cài đặt và có hỗ trợ tốt hơn.
Đầu tiên, thêm gem "mini_magick"
vào Gemfile. Chạy bundle install
để cài đặt.
Trong file image_uploader.rb
, thêm include CarrierWave::MiniMagick
và xử lý process :watermark
.
File sau khi thêm sẽ có dạng sau:
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
process :watermark
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url(*args)
# For Rails 3.1+ asset pipeline compatibility:
# ActionController::Base.helpers.asset_path("fallback/default.png")
"/preview_no_image.jpg"
end
# Process files as they are uploaded:
# process scale: [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
version :blog_thumb, if: :is_blog_img? do
process resize_to_fit: [290, 230]
end
version :product_thumb, if: :is_product_img? do
process resize_to_fit: [210, 210]
end
def extension_whitelist
%w(jpg jpeg png)
end
def watermark
end
end
Vậy là xong phần khung, giờ chúng ta đi vào chi tiết là định nghĩa hàm watermark
. Như đã nói ở trên, có hai dạng watermark, giờ chúng ta vào dạng đầu tiên.
Watermark với hình ảnh
Đoạn xử lý dưới đây sẽ lấy url của một ảnh trong model hoặc một ảnh mặc định làm ảnh watermark, với mỗi ảnh được upload (img) sẽ dùng hàm composite
của ImageMagick
với tham số là ảnh mở bằng MiniMagick với url được lấy bên trên, bạn có thể dùng một trong ba hàm composite
, watermark
hoặc dissolve
để mogrify ảnh.
watermark_url = Company.first.watermark.url || "public/watermark.png"
watermark = MiniMagick::Image.open(watermark_url)
manipulate! do |img|
img = img.composite(MiniMagick::Image.open(watermark), "png") do |c|
c.gravity "South"
end
end
Chúng ta có thể đặt watermark ở bất cứ vị trí nào bằng cách điều chỉnh gravity
và geometry
. Có các lựa chọn cho gravity như NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast. Nếu muốn xoay ảnh, có thể dùng hàm rotate watermark = watermark.rotate(-45)
. Ngoài ra, có thể dùng combine_options
, một dạng command-line của ImageMagick:
manipulate! do |img|
img.combine_options do |cmd|
cmd.draw 'image Over 0,0 0,0 "public/watermark.png"'
end
img
end
Ví dụ với ảnh watermark này Sẽ cho ra kết quả:
Watermark với văn bản
Tương tự như với hình ảnh, chỉ khác một chút là trước khi mogrify, bạn cần chỉnh các thông số cho text hiển thị đúng ý muốn.
img = MiniMagick::Image.read("/home/aditya/Pictures/old_england_pic.jpg").first
mark = MiniMagick::Image.new(img.rows, img.columns) {self.background_color = "none"}
draw = MiniMagick::Draw.new
draw.annotate(mark, 0, 0, 0, 0, "creative commons") do
draw.gravity = MiniMagick::CenterGravity
draw.pointsize = 100
draw.font_family = "Times" # set font
draw.fill = "black" # set text color
draw.stroke = "none" # remove stroke
end
mark = mark.rotate(-45)
img = img.composite(mark, MiniMagick::CenterGravity, Magick::SoftLightCompositeOp)
hoặc
manipulate! do |img|
img.combine_options do |cmd|
draw_text = Company.first.mark
cmd.gravity 'south'
cmd.draw "text 10,10 '#{draw_text}'"
cmd.font '-*-helvetica-*-r-*-*-25-*-*-*-*-*-*-2'
cmd.fill 'black'
end
img
end
Kết quả
Nếu không muốn sử dụng minimagick
bạn có thể dùng rmagick
sử dụng convert
. convert
là một công cụ được cung cấp bởi ImageMagick và được xử lý trên cùng một hình ảnh. Nó tiêu tốn nhiều bộ nhớ so với ImageMagick mogrify
. convert
thích hợp cho nhiều thao tác trên cùng một tập tin trong khi mogrify
phù hợp hơn cho việc xử lý hàng loạt.
Tham khảo https://github.com/minimagick/minimagick https://github.com/rmagick-temp/rmagick https://snippets.aktagon.com/snippets/196-how-to-add-a-watermark-to-pictures-with-minimagick-and-ruby
All rights reserved