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 /app/services/pdf_processor_service.rb | |
parent | e2c2aaedece3a971e45072b11ca5e514b12715f6 (diff) |
Big refactoring of the PDF snapshotting - into service file
Diffstat (limited to 'app/services/pdf_processor_service.rb')
-rw-r--r-- | app/services/pdf_processor_service.rb | 132 |
1 files changed, 132 insertions, 0 deletions
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 |