feat: add watermarking functionality to weather art
Some checks failed
Docker / docker (push) Has been cancelled

- Include the image_processing gem to handle image manipulation
- Create a background worker for adding watermarks to weather art images
- Update WeatherArt model to attach watermark images
- Add a new watermark image asset

This commit enhances the WeatherArt feature by allowing images to
have watermarks added asynchronously, improving the visual
presentation of the art. It ensures sufficient image dimensions
before processing and includes error handling for the worker.
This commit is contained in:
songtianlun 2025-01-29 01:53:50 +08:00
parent 62bfe8888e
commit bbf8dfc2e6
5 changed files with 65 additions and 0 deletions

View File

@ -60,6 +60,8 @@ gem "aws-sdk-s3", "~> 1.177"
gem "sidekiq", "~> 7.3" gem "sidekiq", "~> 7.3"
gem "sidekiq-scheduler", "~> 5.0" gem "sidekiq-scheduler", "~> 5.0"
gem "image_processing", "~> 1.13"
group :development, :test do group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

View File

@ -164,6 +164,7 @@ GEM
multipart-post (~> 2.0) multipart-post (~> 2.0)
faraday-net_http (3.4.0) faraday-net_http (3.4.0)
net-http (>= 0.5.0) net-http (>= 0.5.0)
ffi (1.17.1-arm64-darwin)
formtastic (5.0.0) formtastic (5.0.0)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
formtastic_i18n (0.7.0) formtastic_i18n (0.7.0)
@ -183,6 +184,9 @@ GEM
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (1.14.6) i18n (1.14.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
image_processing (1.13.0)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
inherited_resources (1.14.0) inherited_resources (1.14.0)
actionpack (>= 6.0) actionpack (>= 6.0)
has_scope (>= 0.6) has_scope (>= 0.6)
@ -240,6 +244,7 @@ GEM
matrix (0.4.2) matrix (0.4.2)
meta-tags (2.22.1) meta-tags (2.22.1)
actionpack (>= 6.0.0, < 8.1) actionpack (>= 6.0.0, < 8.1)
mini_magick (4.13.2)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.25.4) minitest (5.25.4)
msgpack (1.7.5) msgpack (1.7.5)
@ -386,6 +391,9 @@ GEM
faraday (>= 1) faraday (>= 1)
faraday-multipart (>= 1) faraday-multipart (>= 1)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-vips (2.2.2)
ffi (~> 1.12)
logger
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (2.4.1) rubyzip (2.4.1)
rufus-scheduler (3.9.2) rufus-scheduler (3.9.2)
@ -502,6 +510,7 @@ DEPENDENCIES
down (~> 5.4) down (~> 5.4)
friendly_id (~> 5.5) friendly_id (~> 5.5)
httparty (~> 0.22.0) httparty (~> 0.22.0)
image_processing (~> 1.13)
jbuilder jbuilder
jsbundling-rails jsbundling-rails
kamal kamal

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -4,6 +4,7 @@ class WeatherArt < ApplicationRecord
belongs_to :city belongs_to :city
has_one_attached :image has_one_attached :image
has_one_attached :image_with_watermark
has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id
has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id

View File

@ -0,0 +1,53 @@
class AddWatermarkToWeatherArtWorker
include Sidekiq::Worker
def perform(weather_art_id)
@weather_art = WeatherArt.find_by(id: weather_art_id)
return unless @weather_art
add_watermark
rescue StandardError => e
Rails.logger.error "Error adding watermark to WeatherArt #{weather_art_id}: #{e.message}"
Rails.logger.error e.backtrace.join("\n")
end
private
attr_reader :weather_art
def add_watermark
return if weather_art.image_with_watermark.attached?
watermark_path = Rails.root.join("app/assets/images/today_ai_weather_copyright_watermark1.png")
return unless File.exist?(watermark_path)
image_tempfile = nil
watermark_tempfile = nil
begin
image_tempfile = weather_art.image.download
return unless image_dimensions_are_sufficient?(image_tempfile.path)
image = ImageProcessing::Vips.source(image_tempfile.path)
watermark = ImageProcessing::Vips.source(watermark_path)
watermarked_image = image.composite(watermark, "overlay")
watermark_tempfile = Tempfile.new([ "watermarked_image", ".png" ])
watermarked_image.write_to_file(watermark_tempfile.path)
weather_art.image_with_watermark.attach(
io: File.open(watermark_tempfile.path),
filename: "#{generate_filename("watermarked")}",
content_type: "image/png"
)
ensure
watermark_tempfile.unlink if watermark_tempfile
end
end
def image_dimensions_are_sufficient?(image_path)
dimensions = ImageProcessing::Vips.source(image_path).sizes
dimensions.width >= 200 && dimensions.height >= 200
end
def generate_filename(prefix)
"#{prefix}_#{weather_art.image.filename.base}"
end
end