Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pdf thumbnail not being generated when file is encoded in base64 #97

Open
eghamra opened this issue Sep 23, 2022 · 0 comments
Open

Pdf thumbnail not being generated when file is encoded in base64 #97

eghamra opened this issue Sep 23, 2022 · 0 comments

Comments

@eghamra
Copy link

eghamra commented Sep 23, 2022

Describe the issue
Hello everyone, thanks for the amazing job you've been doing with kt-paperclip.

We are currently working on a project that would store different types of files (images, videos, documents, etc) through an API call. We have 2 different projects working at the same time. On the first one ('Project Base'), we already have in place the system working and it's working as expected. The second project ('Project Client') would make an API call to Project Base, sending the desired files converted to base64 through a json call.

Everything works as expected when storing from Project Client to Project Base, except for pdf files. For this specific type, the thumbnail is never being generated, although the original file is stored as expected. Note that the same functionality on Project Base works as expected (if we upload from there, then the thumbnail is generated and stored on our s3 bucket).

Our controller for the upload action on Project Base is this one:

  def create
    @attachment = base_attachments.build(attachment_params.merge(user_id: current_user.id))

    respond_to do |format|
      if @attachment.save
        format.json
      else
        format.json { render json: { error: @attachment.errors.full_messages.to_sentence }, status: :bad_request }
      end
    end
  end

We wanted to verify if this could be an issue originating on Project Client so we modified this to store the file after converting it to a Base64 string.

    def create
      attachment = attachment_params[:attachment]
      base64 = "data:application/pdf;base64,#{Base64.strict_encode64(File.open(attachment).read)}"
      base_64 = attachment_params[:attachment]
      @attachment = base_attachments.build(attachment_params.merge(attachment: base64, user_id: current_user.id))

      respond_to do |format|
        if @attachment.save
          format.json
        else
          format.json { render json: { error: @attachment.errors.full_messages.to_sentence }, status: :bad_request }
        end
      end
    end

With this, same behaviour occurs: the original file is stored but the thumbnail is never generated.

The model is defined as follows:

module AttachmentType
  class Download < Attachment
    include AttachmentThumbnailConcern

    has_attached_file(
      :attachment,
      bucket: APP_CONFIG[:aws][:bucket],
      default_url: '/images/:style/missing.png',
      path: "/#{Rails.env}/downloads/:attachable_type/:attachable_id/:style/:basename.:extension",
      s3_region: APP_CONFIG[:aws][:region],
      styles: ->(a) { a.instance.check_file_type },
      processors: ->(a) { a.is_video? ? [:transcoder] : [:thumbnail] }
    )

    # Before applying the Imagemagick post processing to this record
    # check to see if we indeed wish to process the file. In the case
    # of audio files, we don't want to apply post processing
    before_post_process :apply_post_processing?

    validates_attachment_content_type :attachment, content_type: %w[
      image/png
      image/jpg
      image/jpeg
      application/pdf
      application/msword
      application/vnd.openxmlformats-officedocument.wordprocessingml.document
      application/vnd.ms-powerpoint
      application/vnd.openxmlformats-officedocument.presentationml.presentation
      application/vnd.ms-excel
      application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    ]

    def microsoft_file?
      File.extname(attachment_file_name).match?(/xlsx?\Z|docx?\Z|pptx?\Z/)
    end

    def thumbnail_uri
      if microsoft_file?
        generic_icon_path
      else
        attachment.url(is_pdf? ? :pdf_thumbnail : :thumb)
      end
    end

    def generic_icon_path
      ext = File.extname(attachment_file_name).tr('.', '')
      ext = ext[0..-2] if ext.last == 'x'
      url = "/images/files/#{ext}.svg"

      if File.exists?("#{Rails.root}/public#{url}")
        url
      else
        "/images/files/default.svg"
      end
    end
  end
end

AttachmentThumbnailConcern is defined as follows:

require 'active_support/concern'
module AttachmentThumbnailConcern
  extend ActiveSupport::Concern

  included do
    # Helper method that uses the =~ regex method to see if
    # the current file_upload has a content_type
    # attribute that contains the string "image" / "video", or "audio"
    def is_image?
      attachment.content_type =~ %r(image)
    end

    def is_video?
      attachment.content_type =~ %r(video)
    end

    def is_audio?
      attachment.content_type =~ /\Aaudio\/.*\Z/
    end

    def is_plain_text?
      attachment_file_name =~ %r{\.(txt)$}i
    end

    def is_excel?
      attachment_file_name =~ %r{\.(xls|xlt|xla|xlsx|xlsm|xltx|xltm|xlsb|xlam|csv|tsv)$}i
    end

    def is_word_document?
      attachment_file_name =~ %r{\.(docx|doc|dotx|docm|dotm)$}i
    end

    def is_powerpoint?
      attachment_file_name =~ %r{\.(pptx|ppt|potx|pot|ppsx|pps|pptm|potm|ppsm|ppam)$}i
    end

    def is_pdf?
      attachment_file_name =~ %r{\.(pdf)$}i
    end

    def has_default_image?
      is_audio?
      is_plain_text?
      is_excel?
      is_word_document?
    end

    # If the uploaded content type is an audio file,
    # return false so that we'll skip audio post processing
    def apply_post_processing?
      if has_default_image?
        return false
      else
        return true
      end
    end

    # Method to be called in order to determine what styles we should
    # save of a file.
    def check_file_type
      if is_image?
        {
          thumb: "300x300>"
        }
      elsif is_pdf?
        {
          pdf_thumbnail: ["", :png]
        }

      elsif is_video?
        {
          thumb: {
            geometry: "432x243>",
            format: 'jpg',
            time: 2
          },
          # medium: {
          #   geometry: "500x500>",
          #   format: 'jpg',
          #   time: 0
          # }
        }
      elsif is_audio?
        {
          audio: {
            format: "mp3"
          }
        }
      else
        {}
      end
    end
  end
end

config/initializers/paperclip.rb is defined as follows:

Paperclip::UriAdapter.register
Paperclip::DataUriAdapter.register
Paperclip::HttpUrlProxyAdapter.register

Paperclip.interpolates :attachable_id do |attachment, style|
  attachment.instance.attachable_id
end

Paperclip.interpolates :attachable_type do |attachment, style|
  attachment.instance.attachable_type.pluralize.underscore
end

Currently using
kt-paperclip 7.0.1
Rails 6.1.6
Ruby 2.7.5

Expected behavior
We understand that handling base64 files should be handled the same as an UploadedFile object and that no other options should be passed to has_attached_file.

I've been through the code and the documentation and can't see anything related to any different option in the event of a base64 string file, so not sure if this could be an actual issue or maybe some parameter not being passed properly.

If you have any idea on this, I would really much appreciate your suggestions on this matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant