diff --git a/Gemfile b/Gemfile index 1d6c1bc..b75cd2b 100644 --- a/Gemfile +++ b/Gemfile @@ -60,6 +60,8 @@ gem "aws-sdk-s3", "~> 1.177" gem "sidekiq", "~> 7.3" gem "sidekiq-scheduler", "~> 5.0" +gem "image_processing", "~> 1.13" + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" diff --git a/Gemfile.lock b/Gemfile.lock index 30d3377..9ff2d31 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -164,6 +164,7 @@ GEM multipart-post (~> 2.0) faraday-net_http (3.4.0) net-http (>= 0.5.0) + ffi (1.17.1-arm64-darwin) formtastic (5.0.0) actionpack (>= 6.0.0) formtastic_i18n (0.7.0) @@ -183,6 +184,9 @@ GEM multi_xml (>= 0.5.2) i18n (1.14.6) 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) actionpack (>= 6.0) has_scope (>= 0.6) @@ -240,6 +244,7 @@ GEM matrix (0.4.2) meta-tags (2.22.1) actionpack (>= 6.0.0, < 8.1) + mini_magick (4.13.2) mini_mime (1.1.5) minitest (5.25.4) msgpack (1.7.5) @@ -386,6 +391,9 @@ GEM faraday (>= 1) faraday-multipart (>= 1) ruby-progressbar (1.13.0) + ruby-vips (2.2.2) + ffi (~> 1.12) + logger ruby2_keywords (0.0.5) rubyzip (2.4.1) rufus-scheduler (3.9.2) @@ -502,6 +510,7 @@ DEPENDENCIES down (~> 5.4) friendly_id (~> 5.5) httparty (~> 0.22.0) + image_processing (~> 1.13) jbuilder jsbundling-rails kamal diff --git a/app/assets/images/today_ai_weather_copyright_watermark1.png b/app/assets/images/today_ai_weather_copyright_watermark1.png new file mode 100644 index 0000000..47c2ce9 Binary files /dev/null and b/app/assets/images/today_ai_weather_copyright_watermark1.png differ diff --git a/app/models/weather_art.rb b/app/models/weather_art.rb index e45c2b5..078a58e 100644 --- a/app/models/weather_art.rb +++ b/app/models/weather_art.rb @@ -4,6 +4,7 @@ class WeatherArt < ApplicationRecord belongs_to :city has_one_attached :image + has_one_attached :image_with_watermark has_many :visits, class_name: "Ahoy::Visit", foreign_key: :weather_art_id has_many :events, class_name: "Ahoy::Event", foreign_key: :weather_art_id diff --git a/app/workers/add_watermark_to_weatherart_worker.rb b/app/workers/add_watermark_to_weatherart_worker.rb new file mode 100644 index 0000000..6f27610 --- /dev/null +++ b/app/workers/add_watermark_to_weatherart_worker.rb @@ -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