+1

Tự động watermark ảnh với ImageMagick

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 RMagickMiniMagick, 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 gravitygeometry. 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí