diff options
author | Matthew Lemon <y@yulqen.org> | 2024-11-14 09:50:29 +0000 |
---|---|---|
committer | Matthew Lemon <y@yulqen.org> | 2024-11-14 09:50:29 +0000 |
commit | ed4a5a07b70f1d3e23dd74bc217477694200e9cb (patch) | |
tree | 90784f7f01c476ba5a8ccfdf648ddf8a9634dbf9 | |
parent | e2c2aaedece3a971e45072b11ca5e514b12715f6 (diff) |
Big refactoring of the PDF snapshotting - into service file
-rw-r--r-- | app/controllers/pdfresources_controller.rb | 52 | ||||
-rw-r--r-- | app/services/pdf_processor_service.rb | 132 |
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 |