Skip to content

Commit

Permalink
Add PDF Generator.
Browse files Browse the repository at this point in the history
  • Loading branch information
tpendragon committed Aug 11, 2017
1 parent b65926f commit b1b9380
Show file tree
Hide file tree
Showing 22 changed files with 405 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Style/PredicateName:
Rails/OutputSafety:
Exclude:
- 'app/decorators/**/*'
Metrics/AbcSize:
Exclude:
- 'app/services/pdf_generator/cover_page_generator.rb'
Metrics/BlockLength:
Exclude:
- 'valhalla/app/models/concerns/valhalla/ability.rb'
Expand All @@ -36,13 +39,15 @@ Metrics/BlockLength:
- 'db/schema.rb'
- 'lib/tasks/dev.rake'
- 'app/models/plum_schema.rb'
- 'app/services/pdf_generator/cover_page_generator.rb'
Metrics/MethodLength:
Exclude:
- 'db/migrate/**/*'
- 'app/models/schema/dublin_core.rb'
- 'app/models/schema/marc_relators.rb'
- 'app/models/schema/plum/local.rb'
- 'spec/services/manifest_builder_spec.rb'
- 'app/services/pdf_generator/cover_page_generator.rb'
Metrics/ModuleLength:
Exclude:
- 'app/models/schema/dublin_core.rb'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :development, :test do
gem 'coveralls'
gem "dotenv-rails"
gem "factory_girl_rails"
gem 'pdf-reader', github: 'yob/pdf-reader'
gem "pry-byebug"
gem "pry-rails"
gem 'rails-controller-testing'
Expand Down Expand Up @@ -77,3 +78,4 @@ gem 'valhalla', path: 'valhalla'
source 'https://rails-assets.org' do
gem 'rails-assets-bootstrap-select', '1.12.2'
end
gem 'prawn'
22 changes: 22 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ GIT
activesupport (>= 4)
iiif-presentation (~> 0.2.0)

GIT
remote: git://github.com/yob/pdf-reader.git
revision: bb7747a3cb4279ecd963185f357dbd718f9d20f3
specs:
pdf-reader (2.0.0)
Ascii85 (~> 1.0.0)
afm (~> 0.2.1)
hashery (~> 2.0)
ruby-rc4
ttfunk

GIT
remote: https://github.com/cbeer/devise-guests.git
revision: 0999e0bf31841640ad52331e8db14c3f0e1c9765
Expand Down Expand Up @@ -66,6 +77,7 @@ GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
specs:
Ascii85 (1.0.2)
aasm (4.12.2)
concurrent-ruby (~> 1.0)
actioncable (5.1.1)
Expand Down Expand Up @@ -126,6 +138,7 @@ GEM
tzinfo (~> 1.1)
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
afm (0.2.2)
almond-rails (0.1.0)
rails (>= 4.2, < 6)
arel (8.0.0)
Expand Down Expand Up @@ -321,6 +334,7 @@ GEM
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashdiff (0.3.4)
hashery (2.1.2)
hashie (3.5.6)
honeybadger (3.1.2)
httmultiparty (0.3.16)
Expand Down Expand Up @@ -457,12 +471,16 @@ GEM
parallel (1.12.0)
parser (2.4.0.0)
ast (~> 2.2)
pdf-core (0.7.0)
pg (0.21.0)
poltergeist (1.15.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
powerpack (0.1.1)
prawn (2.2.2)
pdf-core (~> 0.7.0)
ttfunk (~> 1.5)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
Expand Down Expand Up @@ -582,6 +600,7 @@ GEM
multipart-post
oauth2
ruby-progressbar (1.8.1)
ruby-rc4 (0.1.5)
ruby_dep (1.5.0)
ruby_tika_app (1.5.0)
open4
Expand Down Expand Up @@ -660,6 +679,7 @@ GEM
title (0.0.7)
i18n
rails (>= 3.1)
ttfunk (1.5.0)
twitter-typeahead-rails (0.11.1.pre.corejavascript)
actionpack (>= 3.1)
jquery-rails
Expand Down Expand Up @@ -725,8 +745,10 @@ DEPENDENCIES
normalize-rails
omniauth-cas
openseadragon
pdf-reader!
pg
poltergeist
prawn
pry-byebug
pry-rails
pul_metadata_services!
Expand Down
1 change: 1 addition & 0 deletions app/change_sets/scanned_resource_change_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class ScannedResourceChangeSet < Valkyrie::ChangeSet
property :state, multiple: false, required: true, default: BookWorkflow.aasm.initial_state.to_s
property :read_groups, multiple: true, required: false
property :workflow_note, multiple: true, required: false, default: []
property :file_metadata, multiple: true, required: false, default: []
# Virtual Attributes
property :refresh_remote_metadata, virtual: true, multiple: false
property :files, virtual: true, multiple: true, required: false
Expand Down
12 changes: 12 additions & 0 deletions app/controllers/scanned_resources_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ def manifest
end
end

def pdf
change_set = change_set_class.new(find_resource(params[:id])).prepopulate!
authorize! :pdf, change_set.resource
pdf_file = PDFGenerator.new(resource: change_set.resource, storage_adapter: Valkyrie::StorageAdapter.find(:derivatives)).render
change_set_persister.buffer_into_index do |buffered_changeset_persister|
change_set.validate(file_metadata: [pdf_file])
change_set.sync
buffered_changeset_persister.save(change_set: change_set)
end
redirect_to valhalla.download_path(resource_id: change_set.id, id: pdf_file.id)
end

def selected_file_params
params[:selected_files].to_unsafe_h
end
Expand Down
1 change: 0 additions & 1 deletion app/models/file_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ class FileSet < Valhalla::Resource
include Valkyrie::Resource::AccessControls
attribute :id, Valkyrie::Types::ID.optional
attribute :title, Valkyrie::Types::Set
attribute :member_ids, Valkyrie::Types::Array
attribute :file_metadata, Valkyrie::Types::Set.member(FileMetadata.optional)
attribute :depositor

Expand Down
7 changes: 7 additions & 0 deletions app/models/scanned_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ScannedResource < Valhalla::Resource
attribute :logical_structure, Valkyrie::Types::Array.member(Structure.optional).optional
attribute :pending_uploads, Valkyrie::Types::Array.member(PendingUpload)
attribute :workflow_note, Valkyrie::Types::Array.member(WorkflowNote).optional
attribute :file_metadata, Valkyrie::Types::Set.member(FileMetadata.optional)

def to_s
"#{human_readable_type}: #{title.to_sentence}"
Expand All @@ -20,6 +21,12 @@ def primary_imported_metadata
Array.wrap(imported_metadata).first || ImportedMetadata.new
end

def pdf_file
file_metadata.find do |file|
file.mime_type == ["application/pdf"]
end
end

def title
primary_imported_metadata.title.present? ? primary_imported_metadata.title : @title
end
Expand Down
6 changes: 5 additions & 1 deletion app/services/file_appender.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def append_to(resource)
return updated_files unless updated_files.empty?

file_sets = build_file_sets || file_nodes
if resource.respond_to?(:file_metadata)
if file_set?(resource)
resource.file_metadata += file_sets
else
resource.member_ids += file_sets.map(&:id)
Expand All @@ -23,6 +23,10 @@ def append_to(resource)
file_sets
end

def file_set?(resource)
resource.respond_to?(:file_metadata) && !resource.respond_to?(:member_ids)
end

def update_files(resource, files)
files.select { |file| file.is_a?(Hash) }.map do |file|
node = resource.file_metadata.select { |x| x.id.to_s == file.keys.first }.first
Expand Down
7 changes: 4 additions & 3 deletions app/services/manifest_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def work_presenters

def file_set_presenters
@file_set_presenters ||= leaf_nodes.map do |node|
LeafNode.new(node)
LeafNode.new(node, self)
end
end

Expand Down Expand Up @@ -106,10 +106,11 @@ def id
end

class LeafNode
attr_reader :resource
attr_reader :resource, :parent_node
delegate :query_service, to: :metadata_adapter
def initialize(resource)
def initialize(resource, parent_node)
@resource = resource
@parent_node = parent_node
end

delegate :id, to: :resource
Expand Down
58 changes: 58 additions & 0 deletions app/services/pdf_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true
class PDFGenerator
attr_reader :resource, :storage_adapter
def initialize(resource:, storage_adapter:)
@resource = resource
@storage_adapter = storage_adapter
end

def render
CoverPageGenerator.new(self).apply(prawn_document)
canvas_downloaders.each_with_index do |downloader, _index|
prawn_document.start_new_page layout: downloader.layout
page_size = [Canvas::LETTER_WIDTH, Canvas::LETTER_HEIGHT]
page_size.reverse! unless downloader.portrait?
prawn_document.image downloader.download, width: downloader.width, height: downloader.height, fit: page_size
end
prawn_document.render_file(tmp_file.path)
build_node
end

def build_node
file = IngestableFile.new(file_path: tmp_file.path, mime_type: 'application/pdf', original_filename: 'derivative_pdf.pdf')
node = FileMetadata.for(file: file).new(id: SecureRandom.uuid)
stored_file = storage_adapter.upload(resource: node, file: file)
node.file_identifiers = stored_file.id
node
end

def prawn_document
@prawn_document ||= Prawn::Document.new(prawn_options)
end

def prawn_options
default_options = { margin: 0 }
default_options[:page_layout] = :portrait if canvas_downloaders.first
default_options
end

def canvas_images
@canvas_images ||= manifest['sequences'][0]['canvases'].map { |x| x['images'][0] }.map do |x|
Canvas.new(x)
end
end

def manifest
@manifest ||= ManifestBuilder.new(resource).build
end

def canvas_downloaders
@canvas_images ||= canvas_images.map do |image|
CanvasDownloader.new(image, quality: resource.pdf_type.first)
end
end

def tmp_file
@tmp_file ||= Tempfile.new("pdf")
end
end
25 changes: 25 additions & 0 deletions app/services/pdf_generator/canvas.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true
class PDFGenerator
class Canvas
# Letter width/height in points for a PDF.
LETTER_WIDTH = PDF::Core::PageGeometry::SIZES["LETTER"].first
LETTER_HEIGHT = PDF::Core::PageGeometry::SIZES["LETTER"].last
BITONAL_SIZE = 2000
attr_reader :canvas
def initialize(canvas)
@canvas = canvas
end

def width
canvas["resource"]["width"].to_i
end

def height
canvas["resource"]["height"].to_i
end

def url
canvas["resource"]["service"]["@id"]
end
end
end
63 changes: 63 additions & 0 deletions app/services/pdf_generator/canvas_downloader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true
class PDFGenerator
class CanvasDownloader
attr_reader :canvas
delegate :width, :height, to: :canvas
def initialize(canvas, quality: "grey")
@canvas = canvas
@quality = quality
end

def download
open(canvas_url, 'rb')
end

def layout
if portrait?
:portrait
else
:landscape
end
end

def quality
if @quality == 'gray'
'grey'
else
'default'
end
end

def portrait?
canvas.width <= canvas.height
end

private

def canvas_url
"#{canvas.url}/full/#{max_width},#{max_height}/0/#{quality}.#{format}"
end

def format
bitonal? ? 'png' : 'jpg'
end

def max_width
return Canvas::BITONAL_SIZE if bitonal?
[(Canvas::LETTER_WIDTH * scale_factor).round, canvas.width].min
end

def max_height
return Canvas::BITONAL_SIZE if bitonal?
[(Canvas::LETTER_HEIGHT * scale_factor).round, canvas.height].min
end

def scale_factor
1.5
end

def bitonal?
quality == 'bitonal'
end
end
end
Loading

0 comments on commit b1b9380

Please sign in to comment.