diff --git a/app/models/city.rb b/app/models/city.rb index 8f5e73f..4d7f95b 100644 --- a/app/models/city.rb +++ b/app/models/city.rb @@ -42,14 +42,14 @@ class City < ApplicationRecord # 根据数据库类型构建不同的查询 base_query = if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite" joins(<<-SQL.squish) - LEFT JOIN ahoy_events ON + LEFT JOIN ahoy_events ON#{' '} json_extract(ahoy_events.properties, '$.city_id') = cities.id AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view' AND ahoy_events.time > '#{start_time}' SQL else joins(<<-SQL.squish) - LEFT JOIN ahoy_events ON + LEFT JOIN ahoy_events ON#{' '} (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id AND ahoy_events.properties::jsonb->>'event_type' = 'city_view' AND ahoy_events.time > '#{start_time}' diff --git a/app/models/weather_art.rb b/app/models/weather_art.rb index 1eea6e5..344fe8b 100644 --- a/app/models/weather_art.rb +++ b/app/models/weather_art.rb @@ -4,7 +4,6 @@ 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 @@ -59,4 +58,145 @@ class WeatherArt < ApplicationRecord def image_url image.attached? ? image.blob : nil end + + def webp_image + return nil unless image.attached? + + image.variant( + format: "webp", + saver: { + quality: 100, + strip: true, # 移除元数据以减小文件大小 + interlace: "plane" # 渐进式加载 + } + ) + end + + # 添加图片变体处理 + PREVIEW_DIMENSIONS = { + big: [ 1792, 1024 ], + medium: [ 896, 512 ], + small: [ 448, 256 ] + }.freeze + def preview_image(size = :medium) + return nil unless image.attached? + + width, height = PREVIEW_DIMENSIONS[size] || PREVIEW_DIMENSIONS[:medium] + + image.variant( + resize_to_limit: [ width, height ], + format: "webp", + saver: { + quality: 75, + strip: true, # 移除元数据以减小文件大小 + interlace: "plane" # 渐进式加载 + } + ) + end + + def watermarked_image + return nil unless image.attached? + + overlay_text = create_overlay_text + + image.variant( + composite: [ { + input: overlay_text, + gravity: "southeast" + } ] + ) + end + + private + + def create_overlay_text + { + create: { + width: 400, + height: 100, + background: [ 0, 0, 0, 0.5 ] # 半透明黑色背景 + }, + "svg-overlay": %( + + ) + } + end + + def create_text_layer(font_size) + text = [ + weather_date.strftime("%Y-%m-%d"), + "#{temperature}°C, #{description}", + "#{city.name}, #{city.country.name}, #{city.country.region.name}", + "© todayaiweather.com" + ].join("\n") + + { + create: { + width: 600, + height: 200, + background: [ 0, 0, 0, 0 ] + }, + "svg-overlay": %( + + ) + } + end + + def watermark_command(font_size:, stroke_width:, spacing:) + date_str = weather_date.strftime("%Y-%m-%d") + weather_info = "#{temperature}°C, #{description}" + location_info = "#{city.name}, #{city.country.name}, #{city.country.region.name}" + copyright = "© todayaiweather.com" + + "gravity southeast " \ + "fill white " \ + "font Arial " \ + "pointsize #{font_size} " \ + "stroke black " \ + "strokewidth #{stroke_width} " \ + "text 30,#{spacing * 12} '#{copyright}' " \ + "text 30,#{spacing * 8} '#{location_info}' " \ + "text 30,#{spacing * 4} '#{weather_info}' " \ + "text 30,#{spacing} '#{date_str}'" + end + + def watermark_text + date_str = weather_date.strftime("%Y-%m-%d") + weather_info = "#{temperature}°C, #{description}" + location_info = "#{city.name}, #{city.country.name}, #{city.country.region.name}" + copyright = "© todayaiweather.com" + + [ + "text 30,120 '#{copyright}'", + "text 30,80 '#{location_info}'", + "text 30,40 '#{weather_info}'", + "text 30,0 '#{date_str}'" + ].join(" ") + end end diff --git a/app/views/arts/index.html.erb b/app/views/arts/index.html.erb index 7c677a9..42a55b1 100644 --- a/app/views/arts/index.html.erb +++ b/app/views/arts/index.html.erb @@ -6,7 +6,7 @@ <% if featured_art&.image&.attached? %>