Skip to content

Commit

Permalink
Initial work for generating images with transparent background
Browse files Browse the repository at this point in the history
  • Loading branch information
andersonkrs committed Jul 28, 2024
1 parent 2faebce commit 354fddd
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 13 deletions.
3 changes: 2 additions & 1 deletion app/controllers/calendars_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class CalendarsController < ApplicationController
include UserScoped

def show
@user = User.find_by!(username: params[:user_username])
@calendar = @user.calendars.fetch(params[:year])

fresh_when [@user, @calendar]
Expand Down
13 changes: 13 additions & 0 deletions app/controllers/concerns/user_scoped.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module UserScoped
extend ActiveSupport::Concern

included do
before_action :set_user
end

private

def set_user
@user = User.find_by!(username: params[:user_username])
end
end
17 changes: 17 additions & 0 deletions app/controllers/images/calendars_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Images::CalendarsController < ApplicationController
include UserScoped

def show
if small?
redirect_to @user.calendar_image.variant(:small)
else
redirect_to @user.calendar_image.variant(:large)
end
end

private

def small?
params[:variant] == "small"
end
end
10 changes: 2 additions & 8 deletions app/controllers/signatures_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
class SignaturesController < ApplicationController
before_action :set_user
include UserScoped

def show
redirect_to url_for(@user.signature)
end

private

def set_user
@user = User.with_attached_signature.find_by!(username: params[:user_username])
redirect_to @user.signature
end
end
3 changes: 2 additions & 1 deletion app/controllers/timelines_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class TimelinesController < ApplicationController
include UserScoped

def show
@user = User.find_by!(username: params[:user_username])
@calendar = @user.calendars.fetch(params[:year])

fresh_when [@user, @calendar]
Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class User < ApplicationRecord
include MALSyncable
include Mergeable
include Calendars
include CalendarImageable
include Signaturable
include Deactivatable
include Geolocatable
Expand Down
23 changes: 23 additions & 0 deletions app/models/user/calendar_imageable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module User::CalendarImageable
extend ActiveSupport::Concern

included do
has_one_attached :calendar_image do |attachable|
attachable.variant :large, resize_to_limit: [1200, 180], preprocessed: true
attachable.variant :small, resize_to_limit: [600, 150], preprocessed: true
end

after_create_commit :enqueue_calendar_images_generation
after_update_commit :enqueue_calendar_images_generation, if: -> { calendar_images.obsolete? }
end

def calendar_images
User::CalendarImages.new(self)
end

private

def enqueue_calendar_images_generation
calendar_images.generate_later
end
end
73 changes: 73 additions & 0 deletions app/models/user/calendar_images.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require "image_processing/vips"

class User::CalendarImages
def initialize(user)
super()
@user = user
end

def generate
Instrumentation.instrument(title: "#{self.class.name}#generate") do
user.with_time_zone { generate_from_activities }
end
end

def generate_later
User::CalendarImages::GenerateJob.perform_later(user)
end

def obsolete?
return true unless user.calendar_image.attached?
return true if user.saved_change_to_checksum?

user.calendar_image.blob.created_at.in_time_zone.to_date != Time.zone.today
end

class GenerateJob < ApplicationJob
retry_on(*BrowserSession::RETRYABLE_ERRORS, attempts: 10, wait: :polynomially_longer)

limits_concurrency to: 1, key: :screenshots, duration: 2.hours

queue_as :screenshots

def perform(user)
user.calendar_images.generate
end
end

private

attr_reader :user

def generate_from_activities
calendar_html = render_calendar_html

capture_html_screenshot(calendar_html)
end

def render_calendar_html
activities_amount_per_day = user.calendars.current_year.activities_amount_sum_per_day

ApplicationController.render("users/signature", locals: { activities_amount_per_day: }, layout: nil)
end

def capture_html_screenshot(html_page)
BrowserSession.fetch_page do |page|
page.go_to("data:text/html;base64,#{Base64.strict_encode64(html_page)}")

image = page
.screenshot(
encoding: :binary,
selector: ".signature",
format: :png,
background_color: Ferrum::RGBA.new(0, 0, 0, 0.0)
)

user.calendar_image.attach(
io: StringIO.new(image),
filename: "#{user.username}_calendar.png",
content_type: "application/png"
)
end
end
end
12 changes: 9 additions & 3 deletions app/views/users/signature.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
<style type="text/css">
<%= Rails.application.assets.resolver.read("application.css").html_safe.force_encoding("UTF-8") %>

html {
background-color: transparent !important;
}
body {
background-color: transparent !important;
}
.signature {
padding: 0.75em;
display: inline-grid;
background-color: transparent;
padding: 0.75em;
display: inline-grid;
background-color: transparent !important;
}
</style>
</head>
Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
resource :signature, only: :show, on: :member
resources :calendars, only: :show, on: :member, param: "year"
resources :timelines, only: :show, on: :member, param: "year"

namespace :images do
resource :calendar, on: :member, only: :show
end
end

get "/about", to: "application#about", as: "about"
Expand Down

0 comments on commit 354fddd

Please sign in to comment.