4

I have a Rails app where I am trying to display a PNG file but I am getting this error:

ActionView::Template::Error (Your template was not saved as valid UTF-8. Please either specify UTF-8 as the encoding for your template in your text editor, or mark the template with its encoding by inserting the following as the first line of the template:

# encoding: <name of correct encoding>.

The source of your template was:

�PNG

IHDR#ͱ�)    pHYs�]s� IDATx���g@SW�E��7�ZuV묣�Z�:j�mպm�Z��U[W�:�պZ�*�j���@�3� I���p��}
��?�
���b�X�/���Z�I�N111,ӧO��x�T�?x۶mU����vtt

I've added:

Mime::Type.register "image/png", :png

to the config/initializers/mime_types.rb

I'm referencing and rendering the png file in its controller with:

render :inline => @object.body.string, :content_type => @object.content_type || "img/png", :layout => false

EDIT :

This is the method in the controller

 def read_data
  resource = Aws::S3::Resource.new(client: @new_client)
  if @files.size == 0 && @links.size == 0 && resource.bucket(@bucket.name).objects.first != nil && !request.original_url.end_with?('/')
  if request.original_url.split('/')[-1] != @bucket.name && resource.bucket(@bucket.name).object(@prefix).exists?
     @object = @new_client.get_object(bucket: @bucket.name, key: @prefix)
     if @prefix.present? && @object.last_modified && (@object.content_type.match(/text/) || @object.content_type.match("application/json") || @prefix.end_with?('.json') || @prefix.end_with?('.html') || @prefix.end_with?('.txt') || @prefix.end_with?('.xml') || (@object.content_length > 0 && @object.content_type == ""))
      render :inline => @object.body.string, :content_type => @object.content_type || "text/plain", :layout => false
     elsif @prefix.end_with?('.png')
         send_data(@object.body, 
                   :type         => @object.content_type || "image/png",
                   :disposition  => 'inline')
     else
      redirect_to resource.bucket(@bucket.name).object(@prefix).presigned_url(:get, expires_in: 8) #presigned url expires after 8 ms
    end
  end
end

end

Vincent Le
  • 136
  • 2
  • 11
  • 2
    You need to learn how HTML works. Binary objects, like images are NOT embedded inside the HTML, they're referenced using "uniform resource locator" ([URL](https://en.wikipedia.org/wiki/Uniform_resource_locator)s), which the browser then rerequests from the server referenced in the host section of the URL. At no time does the HTML contain binary data, it only contains text. If you want the browser to download something you can send the data as a separate stream, but that's a different process. – the Tin Man Sep 14 '15 at 16:21

2 Answers2

12

Use the send_data method to send binary files:

send_data(
  @object.body.string, 
  type: @object.content_type || 'image/png', 
  disposition: 'inline'
)
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • I tried adding it, but it gave me the same error when opening – Vincent Le Sep 14 '15 at 16:25
  • Did you remove the `render` line and added `send_data` instead? Are you sure you need `@object.body.string` and not just `@object.body`? – spickermann Sep 14 '15 at 16:29
  • Yeah, I replaced the render line with the send_data method and I've tried both `@object.body.string` and `@object.body` – Vincent Le Sep 14 '15 at 16:40
  • And you get the exact same error? Please post you view and controller code. – spickermann Sep 14 '15 at 16:42
  • On Safari you should use for mime-type: 'image/png' (not img), otherwise it downloads the file. Opposed to the inline disposition. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types – Roger Jun 15 '17 at 23:39
0

Use this code on your controller action:

respond_with @resource do |format|
    # format.html { send_data @resource.body } # => Download the image file.
    format.html { send_data @resource.body,
                  type: @resource.content_type || 'image/png',
                  disposition: 'inline' } # => Show in browser page.
end
leompeters
  • 886
  • 1
  • 13
  • 24