aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-11-14 09:50:29 +0000
committerMatthew Lemon <y@yulqen.org>2024-11-14 09:50:29 +0000
commited4a5a07b70f1d3e23dd74bc217477694200e9cb (patch)
tree90784f7f01c476ba5a8ccfdf648ddf8a9634dbf9
parente2c2aaedece3a971e45072b11ca5e514b12715f6 (diff)
Big refactoring of the PDF snapshotting - into service file
-rw-r--r--app/controllers/pdfresources_controller.rb52
-rw-r--r--app/services/pdf_processor_service.rb132
2 files changed, 133 insertions, 51 deletions
diff --git a/app/controllers/pdfresources_controller.rb b/app/controllers/pdfresources_controller.rb
index f1634a2..4cd2d74 100644
--- a/app/controllers/pdfresources_controller.rb
+++ b/app/controllers/pdfresources_controller.rb
@@ -26,7 +26,7 @@ class PdfresourcesController < ApplicationController
respond_to do |format|
if @pdfresource.save
- process_pdfs(@pdfresource.pdfs)
+ PdfProcessorService.new(@pdfresource).process_pdfs
format.html { redirect_to @pdfresource, notice: "Resource was successfully created." }
format.json { render :show, status: :created, location: @pdfresource }
else
@@ -36,56 +36,6 @@ class PdfresourcesController < ApplicationController
end
end
- def process_pdfs(pdfs)
- pdfs.each do |pdf|
- pdf_path = ActiveStorage::Blob.service.send(:path_for, pdf.key)
- convert_pdf_to_images(pdf_path, @pdfresource)
- end
- end
-
- def convert_pdf_to_images(pdf_path, resource)
- page_count_output = MiniMagick::Tool::Identify.new do |identify|
- identify.format '%n'
- identify << pdf_path
- end
-
- page_count = page_count_output.size
-
- page_count.times do |index|
- image_path = "page-#{index + 1}.jpg"
- reduced_image_path = "reduced-page-#{index + 1}.jpg"
- MiniMagick::Tool::Magick.new do |magick|
- magick << "#{pdf_path}[#{index}]" # Process each PDF page individually
- magick << image_path
- end
-
- image_reduced = MiniMagick::Tool::Magick.new do |magick|
- magick << image_path
- magick << "-quality"
- magick << "40"
- magick.strip
- magick << "-resize"
- magick << "50%"
- magick << reduced_image_path
- end
-
- if File.exist?(reduced_image_path)
- fn = resource.name.strip.downcase.gsub("\s", "_") << "_page-"
- image_blob = ActiveStorage::Blob.create_and_upload!(
- io: File.open(reduced_image_path),
- filename: "#{fn}#{index + 1}.jpg",
- content_type: 'image/jpg'
- )
- resource.pdf_snapshots.attach(image_blob)
-
- File.delete(image_path) if File.exist?(image_path)
- File.delete(reduced_image_path) if File.exist?(reduced_image_path)
- else
- raise "Reduced image file wasn't created successfully: #{image_reduced}"
- end
- end
- end
-
# PATCH/PUT /pdfresources/1 or /pdfresources/1.json
def update
respond_to do |format|
diff --git a/app/services/pdf_processor_service.rb b/app/services/pdf_processor_service.rb
new file mode 100644
index 0000000..3f97611
--- /dev/null
+++ b/app/services/pdf_processor_service.rb
@@ -0,0 +1,132 @@
+class PdfProcessorService
+ DEFAULT_OPTIONS = {
+ quality: 40,
+ resize_percentage: 50,
+ format: 'jpg'
+ }.freeze
+
+ def initialize(resource, options = {})
+ @resource = resource
+ @options = DEFAULT_OPTIONS.merge(options)
+ end
+
+ def process_pdfs
+ @resource.pdfs.each do |pdf|
+ pdf_path = get_blob_path(pdf)
+ process_single_pdf(pdf_path)
+ end
+ end
+
+ private
+
+ def get_blob_path(pdf)
+ ActiveStorage::Blob.service.send(:path_for, pdf.key)
+ end
+
+ def process_single_pdf(pdf_path)
+ page_count = get_page_count(pdf_path)
+
+ (0...page_count).each do |index|
+ Rails.logger.info "Processing page #{index + 1} of #{page_count} from #{pdf_path}"
+ process_page(pdf_path, index)
+ rescue StandardError => e
+ Rails.logger.error "Failed to process page #{index + 1}: #{e.message}"
+ raise
+ end
+ end
+
+ def get_page_count(pdf_path)
+ Rails.logger.debug "Checking PDF: #{pdf_path}"
+ Rails.logger.debug "File exists: #{File.exist?(pdf_path)}"
+ Rails.logger.debug "File size: #{File.size(pdf_path)}"
+ Rails.logger.debug "File type: #{`file -b #{pdf_path}`}"
+
+ # Try multiple methods to get page count
+ identify_output = `identify -format %n "#{pdf_path}" 2>&1`
+ gs_output = `gs -q -dNODISPLAY -c "#{pdf_path} (r) file runpdfbegin pdfpagecount = quit" 2>&1`
+
+ Rails.logger.debug "Identify output: #{identify_output}"
+ Rails.logger.debug "Ghostscript output: #{gs_output}"
+
+ count = identify_output.to_i
+ if count <= 0
+ count = gs_output.to_i
+ end
+
+ Rails.logger.debug "Final page count: #{count}"
+ raise "Invalid page count: #{count}" unless count.positive?
+ count
+ rescue StandardError => e
+ Rails.logger.error "Failed to get page count: #{e.message}"
+ raise
+ end
+
+ def process_page(pdf_path, page_index)
+ temp_files = create_page_images(pdf_path, page_index)
+ attach_processed_image(temp_files[:reduced], page_index)
+ ensure
+ cleanup_temp_files(temp_files)
+ end
+
+ def create_page_images(pdf_path, index)
+ original_path = "page-#{index + 1}.#{@options[:format]}"
+ reduced_path = "reduced-page-#{index + 1}.#{@options[:format]}"
+
+ create_original_image(pdf_path, index, original_path)
+ create_reduced_image(original_path, reduced_path)
+
+ { original: original_path, reduced: reduced_path }
+ end
+
+ def create_original_image(pdf_path, index, output_path)
+ MiniMagick::Tool::Convert.new do |convert|
+ convert << "#{pdf_path}[#{index}]"
+ convert << output_path
+ end
+ rescue StandardError => e
+ Rails.logger.error "Failed to create original image for page #{index + 1} from #{pdf_path}: #{e.message}"
+ raise
+ end
+
+ def create_reduced_image(input_path, output_path)
+ MiniMagick::Tool::Convert.new do |convert|
+ convert << input_path
+ convert << "-quality"
+ convert << @options[:quality].to_s
+ convert.strip
+ convert << "-resize"
+ convert << "#{@options[:resize_percentage]}%"
+ convert << output_path
+ end
+ rescue StandardError => e
+ Rails.logger.error "Failed to create reduced image from #{input_path}: #{e.message}"
+ raise
+ end
+
+ def attach_processed_image(image_path, index)
+ return unless File.exist?(image_path)
+
+ filename = generate_filename(index)
+ image_blob = create_blob(image_path, filename)
+ @resource.pdf_snapshots.attach(image_blob)
+ end
+
+ def generate_filename(index)
+ base_name = @resource.name.strip.downcase.gsub(/\s/, "_")
+ "#{base_name}_page-#{index + 1}.#{@options[:format]}"
+ end
+
+ def create_blob(path, filename)
+ ActiveStorage::Blob.create_and_upload!(
+ io: File.open(path),
+ filename: filename,
+ content_type: "image/#{@options[:format]}"
+ )
+ end
+
+ def cleanup_temp_files(temp_files)
+ temp_files.values.each do |path|
+ File.delete(path) if File.exist?(path)
+ end
+ end
+end \ No newline at end of file