The following Rails/Ruby code gives me this error: "Zero-length blob not permitted". @magick_image = Magick::Image.from_blob(@file.read).first Where @file is a StringIO object or a File object, depending on the size of the uploaded file. @file.read.size returns the expected file size (in bytes). Any ideas? Thanks, Joe
Joe Van Dyk wrote:>The following Rails/Ruby code gives me this error: "Zero-length blob >not permitted". > >@magick_image = Magick::Image.from_blob(@file.read).first > >Where @file is a StringIO object or a File object, depending on the >size of the uploaded file. > >I can''t really explain your behaviour, but that''s how I read in uploaded images and it works for me... if file.is_a?(StringIO) img = Magick::Image::from_blob(file.string).first else img = Magick::Image::read(file.local_path).first end Cheers Sebastian
On 8/3/05, Sebastian Kanthak <sebastian.kanthak-ZS8b95Whz3sUSW6y5lq3GQ@public.gmane.org> wrote:> Joe Van Dyk wrote: > > >The following Rails/Ruby code gives me this error: "Zero-length blob > >not permitted". > > > >@magick_image = Magick::Image.from_blob(@file.read).first > > > >Where @file is a StringIO object or a File object, depending on the > >size of the uploaded file. > > > > > I can''t really explain your behaviour, but that''s how I read in uploaded > images and it works for me... > > if file.is_a?(StringIO) > img = Magick::Image::from_blob(file.string).first > else > img = Magick::Image::read(file.local_path).first > endYeah, I''m not sure why it''s failing either. Also, File objects support #read, so why do you have that distinction in there?
Joe Van Dyk wrote:>On 8/3/05, Sebastian Kanthak <sebastian.kanthak-ZS8b95Whz3sUSW6y5lq3GQ@public.gmane.org> wrote: > > >> if file.is_a?(StringIO) >> img = Magick::Image::from_blob(file.string).first >> else >> img = Magick::Image::read(file.local_path).first >> end >> >> > >Also, File objects support #read, so why do you have that distinction in there? > >mainly, because I''m not so sure if it is a good idea to read a (possibly pretty big) image into main memory. I''m not sure what RMagick does, but it could be optimized to only read the header information and process the image in a "streaming" mode. For a StringIO object it doesn''t really matter, as these are only created if the upload is reasonably small, so I can use from_blob safely, here. Sebastian
On 8/3/05, Sebastian Kanthak <sebastian.kanthak-ZS8b95Whz3sUSW6y5lq3GQ@public.gmane.org> wrote:> Joe Van Dyk wrote: > > >On 8/3/05, Sebastian Kanthak <sebastian.kanthak-ZS8b95Whz3sUSW6y5lq3GQ@public.gmane.org> wrote: > > > > > >> if file.is_a?(StringIO) > >> img = Magick::Image::from_blob(file.string).first > >> else > >> img = Magick::Image::read(file.local_path).first > >> end > >> > >> > > > >Also, File objects support #read, so why do you have that distinction in there? > > > > > mainly, because I''m not so sure if it is a good idea to read a (possibly > pretty big) image into main memory. I''m not sure what RMagick does, but > it could be optimized to only read the header information and process > the image in a "streaming" mode. > > For a StringIO object it doesn''t really matter, as these are only > created if the upload is reasonably small, so I can use from_blob > safely, here.Ah, good idea. I still have no idea why it''s giving me "Zero-length blob not permitted" for this line: @magick_image = Magick::Image.from_blob(@file.read).first What''s weird is that if I leave out the .first method call, I don''t get that error. But if I print out the size of @file.read.size, and then call the Image.from_blob line, then I get the Zero-length blob error. It''s driving me crazy. :(
On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 8/3/05, Tim Hunter <cyclists-P1JKnMZDrucAvxtiuMwx3w@public.gmane.org> wrote: > > Joe Van Dyk wrote: > > > > > The following Rails/Ruby code gives me this error: "Zero-length blob > > > not permitted". > > > > > > @magick_image = Magick::Image.from_blob(@file.read).first > > > > > > Where @file is a StringIO object or a File object, depending on the > > > size of the uploaded file. > > > > > > @file.read.size returns the expected file size (in bytes). > > > > > > Any ideas? > > > > Well, it works for me. Here''s my attempt to reproduce the problem. > > > > require ''RMagick'' > > require ''stringio'' > > > > file = File.open(''Flower_Hat.jpg'') > > img = Magick::Image.from_blob(file.read).first > > p img > > > > blob = IO.read(''Flower_Hat.jpg'') > > sio = StringIO.new(blob) > > img = Magick::Image.from_blob(sio.read).first > > p img > > > > > > The output is: > > tim: ~> ruby test.rb > > JPEG 200x250 DirectClass 8-bit 9kb > > JPEG 200x250 DirectClass 8-bit 9kb > > Yeah, I tried to do that test last night and it worked fine. > > So I have no idea why the code is failing inside my Image model.Here''s my image model. Perhaps that will give someone some insight. Say, I''m doing the Magick::Image.from_blob call in #after_save. Perhaps something weird is happening with @file''s lifetime or something? class Image < ActiveRecord::Base belongs_to :house belongs_to :community belongs_to :contractor FileLocation = "#{RAILS_ROOT}/public/media/" DisplayLocation = "/media" def file=(file) if file.size > 0 self.content_type = file.content_type.strip @file = file end end # Runs after Image is saved, saves the image to the file system. def after_save if @file @magick_image = Magick::Image.from_blob(@file.read).first save_full_image save_thumbnail_image save_rounded_thumbnail_image save_medium_image save_large_image end end # If image is already a jpeg, then just write it to a file. # If it''s not, convert it to a jpeg and then write. def save_full_image @magick_image.write(full_file) end # Write a thumbnail to the filesystem def save_thumbnail_image thumbnailed_magick_image = resize_image_to_exact_size(180,135) thumbnailed_magick_image.write(thumbnail_file) end def save_rounded_thumbnail_image thumbnail_image = resize_image_to_exact_size(180, 135) color = "#000033" corner_width = 15 corners = Magick::Draw.new corners.stroke(color) corners.fill_opacity(0) corners.stroke_width(15) corners.roundrectangle(0, 0, thumbnail_image.columns, thumbnail_image.rows, corner_width, corner_width) corners.draw(thumbnail_image) thumbnail_image.write(rounded_thumbnail_file) end # Resizes a Magick image to an exact size, keeping the same aspect ratio def resize_image_to_exact_size(width, height) new_aspect_ratio = width.to_f / height.to_f old_aspect_ratio = @magick_image.columns.to_f / @magick_image.rows.to_f if old_aspect_ratio < new_aspect_ratio # Image too tall, geometry string should restrict height geometry_string = "#{width}" else # Image too wide or just right, geometry string should # restrict width geometry_string = "x#{height}" end # Get the resized image resized_image = resize_image(geometry_string) # Return the resized, crop image resized_image.crop(Magick::CenterGravity, width, height) end def resize_image(geometry_string) logger.debug "resizing image to #{geometry_string}" @magick_image.change_geometry(geometry_string) do |w, h, img| img.resize(w, h) end end def save_medium_image medium_image = resize_image("275") medium_image.write(medium_file) end def save_large_image large_image = resize_image("500") large_image.write(large_file) end # Delete images from filesystem def after_destroy File.delete(full_file) if File.exist? "#{full_file}" File.delete(thumbnail_file) if File.exist? "#{thumbnail_file}" File.delete(rounded_thumbnail_file) if File.exist? "#{rounded_thumbnail_file}" File.delete(medium_file) if File.exist? "#{medium_file}" File.delete(large_file) if File.exist? "#{large_file}" end # Returns the filesystem location of the image file def full_file "#{FileLocation}/full/#{id}.jpg" end def thumbnail_file "#{FileLocation}/thumbnail/#{id}.jpg" end def rounded_thumbnail_file "#{FileLocation}/rounded_thumbnail/#{id}.jpg" end def medium_file "#{FileLocation}/medium/#{id}.jpg" end def large_file "#{FileLocation}/large/#{id}.jpg" end # Returns the location of the image to the browser def full "#{DisplayLocation}/full/#{id}.jpg" end def thumbnail "#{DisplayLocation}/thumbnail/#{id}.jpg" end def medium "#{DisplayLocation}/medium/#{id}.jpg" end def large "#{DisplayLocation}/large/#{id}.jpg" end def rounded_thumbnail "#{DisplayLocation}/rounded_thumbnail/#{id}.jpg" end def resize if File.exist? full_file @file = File.open full_file save end end end
On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > On 8/3/05, Tim Hunter <cyclists-P1JKnMZDrucAvxtiuMwx3w@public.gmane.org> wrote: > > > Joe Van Dyk wrote: > > > > > > > The following Rails/Ruby code gives me this error: "Zero-length blob > > > > not permitted". > > > > > > > > @magick_image = Magick::Image.from_blob(@file.read).first > > > > > > > > Where @file is a StringIO object or a File object, depending on the > > > > size of the uploaded file. > > > > > > > > @file.read.size returns the expected file size (in bytes). > > > > > > > > Any ideas? > > > > > > Well, it works for me. Here''s my attempt to reproduce the problem. > > > > > > require ''RMagick'' > > > require ''stringio'' > > > > > > file = File.open(''Flower_Hat.jpg'') > > > img = Magick::Image.from_blob(file.read).first > > > p img > > > > > > blob = IO.read(''Flower_Hat.jpg'') > > > sio = StringIO.new(blob) > > > img = Magick::Image.from_blob(sio.read).first > > > p img > > > > > > > > > The output is: > > > tim: ~> ruby test.rb > > > JPEG 200x250 DirectClass 8-bit 9kb > > > JPEG 200x250 DirectClass 8-bit 9kb > > > > Yeah, I tried to do that test last night and it worked fine. > > > > So I have no idea why the code is failing inside my Image model. > > Here''s my image model. Perhaps that will give someone some insight. > > Say, I''m doing the Magick::Image.from_blob call in #after_save. > Perhaps something weird is happening with @file''s lifetime or > something? > > class Image < ActiveRecord::Base > belongs_to :house > belongs_to :community > belongs_to :contractor > > FileLocation = "#{RAILS_ROOT}/public/media/" > DisplayLocation = "/media" > > def file=(file) > if file.size > 0 > self.content_type = file.content_type.strip > @file = file > end > end > > # Runs after Image is saved, saves the image to the file system. > def after_save > if @file > @magick_image = Magick::Image.from_blob(@file.read).first > save_full_image > save_thumbnail_image > save_rounded_thumbnail_image > save_medium_image > save_large_image > end > end > > # If image is already a jpeg, then just write it to a file. > # If it''s not, convert it to a jpeg and then write. > def save_full_image > @magick_image.write(full_file) > end > > # Write a thumbnail to the filesystem > def save_thumbnail_image > thumbnailed_magick_image = resize_image_to_exact_size(180,135) > thumbnailed_magick_image.write(thumbnail_file) > end > > def save_rounded_thumbnail_image > thumbnail_image = resize_image_to_exact_size(180, 135) > color = "#000033" > corner_width = 15 > corners = Magick::Draw.new > corners.stroke(color) > corners.fill_opacity(0) > corners.stroke_width(15) > corners.roundrectangle(0, 0, > thumbnail_image.columns, thumbnail_image.rows, > corner_width, corner_width) > corners.draw(thumbnail_image) > thumbnail_image.write(rounded_thumbnail_file) > end > > # Resizes a Magick image to an exact size, keeping the same aspect ratio > def resize_image_to_exact_size(width, height) > new_aspect_ratio = width.to_f / height.to_f > old_aspect_ratio = @magick_image.columns.to_f / @magick_image.rows.to_f > > if old_aspect_ratio < new_aspect_ratio > # Image too tall, geometry string should restrict height > geometry_string = "#{width}" > else > # Image too wide or just right, geometry string should > # restrict width > geometry_string = "x#{height}" > end > > # Get the resized image > resized_image = resize_image(geometry_string) > > # Return the resized, crop image > resized_image.crop(Magick::CenterGravity, width, height) > end > > def resize_image(geometry_string) > logger.debug "resizing image to #{geometry_string}" > @magick_image.change_geometry(geometry_string) do |w, h, img| > img.resize(w, h) > end > end > > def save_medium_image > medium_image = resize_image("275") > medium_image.write(medium_file) > end > > def save_large_image > large_image = resize_image("500") > large_image.write(large_file) > end > > > > # Delete images from filesystem > def after_destroy > File.delete(full_file) if File.exist? "#{full_file}" > File.delete(thumbnail_file) if File.exist? "#{thumbnail_file}" > File.delete(rounded_thumbnail_file) if File.exist? > "#{rounded_thumbnail_file}" > File.delete(medium_file) if File.exist? "#{medium_file}" > File.delete(large_file) if File.exist? "#{large_file}" > end > > # Returns the filesystem location of the image file > def full_file > "#{FileLocation}/full/#{id}.jpg" > end > def thumbnail_file > "#{FileLocation}/thumbnail/#{id}.jpg" > end > def rounded_thumbnail_file > "#{FileLocation}/rounded_thumbnail/#{id}.jpg" > end > def medium_file > "#{FileLocation}/medium/#{id}.jpg" > end > def large_file > "#{FileLocation}/large/#{id}.jpg" > end > > > # Returns the location of the image to the browser > def full > "#{DisplayLocation}/full/#{id}.jpg" > end > def thumbnail > "#{DisplayLocation}/thumbnail/#{id}.jpg" > end > def medium > "#{DisplayLocation}/medium/#{id}.jpg" > end > def large > "#{DisplayLocation}/large/#{id}.jpg" > end > def rounded_thumbnail > "#{DisplayLocation}/rounded_thumbnail/#{id}.jpg" > end def resize > if File.exist? full_file > @file = File.open full_file > save > end > end > end >I''ll be damned. Moving @magick_image = Magick::Image.from_blob(@file.read).first from Image#after_save to Image#file= fixed the problem. So, apparently, something weird happens to @file before Image#after_save is called. Any ideas?
I''ve had this problem too, changing my setter to image_file= solved all my problems, I suspect AR/CGI/something is using @file during the after_save phase. SIMEN BREKKEN / born to synthesize. Joe Van Dyk wrote:> On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > >>On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> >>>On 8/3/05, Tim Hunter <cyclists-P1JKnMZDrucAvxtiuMwx3w@public.gmane.org> wrote: >>> >>>>Joe Van Dyk wrote: >>>> >>>> >>>>>The following Rails/Ruby code gives me this error: "Zero-length blob >>>>>not permitted". >>>>> >>>>>@magick_image = Magick::Image.from_blob(@file.read).first >>>>> >>>>>Where @file is a StringIO object or a File object, depending on the >>>>>size of the uploaded file. >>>>> >>>>>@file.read.size returns the expected file size (in bytes). >>>>> >>>>>Any ideas? >>>> >>>>Well, it works for me. Here''s my attempt to reproduce the problem. >>>> >>>>require ''RMagick'' >>>>require ''stringio'' >>>> >>>>file = File.open(''Flower_Hat.jpg'') >>>>img = Magick::Image.from_blob(file.read).first >>>>p img >>>> >>>>blob = IO.read(''Flower_Hat.jpg'') >>>>sio = StringIO.new(blob) >>>>img = Magick::Image.from_blob(sio.read).first >>>>p img >>>> >>>> >>>>The output is: >>>>tim: ~> ruby test.rb >>>> JPEG 200x250 DirectClass 8-bit 9kb >>>> JPEG 200x250 DirectClass 8-bit 9kb >>> >>>Yeah, I tried to do that test last night and it worked fine. >>> >>>So I have no idea why the code is failing inside my Image model. >> >>Here''s my image model. Perhaps that will give someone some insight. >> >>Say, I''m doing the Magick::Image.from_blob call in #after_save. >>Perhaps something weird is happening with @file''s lifetime or >>something? >> >>class Image < ActiveRecord::Base >> belongs_to :house >> belongs_to :community >> belongs_to :contractor >> >> FileLocation = "#{RAILS_ROOT}/public/media/" >> DisplayLocation = "/media" >> >>def file=(file) >> if file.size > 0 >> self.content_type = file.content_type.strip >> @file = file >> end >> end >> >> # Runs after Image is saved, saves the image to the file system. >> def after_save >> if @file >> @magick_image = Magick::Image.from_blob(@file.read).first >> save_full_image >> save_thumbnail_image >> save_rounded_thumbnail_image >> save_medium_image >> save_large_image >> end >> end >> >> # If image is already a jpeg, then just write it to a file. >> # If it''s not, convert it to a jpeg and then write. >> def save_full_image >> @magick_image.write(full_file) >> end >> >> # Write a thumbnail to the filesystem >> def save_thumbnail_image >> thumbnailed_magick_image = resize_image_to_exact_size(180,135) >> thumbnailed_magick_image.write(thumbnail_file) >> end >> >> def save_rounded_thumbnail_image >> thumbnail_image = resize_image_to_exact_size(180, 135) >> color = "#000033" >> corner_width = 15 >> corners = Magick::Draw.new >> corners.stroke(color) >> corners.fill_opacity(0) >> corners.stroke_width(15) >> corners.roundrectangle(0, 0, >> thumbnail_image.columns, thumbnail_image.rows, >> corner_width, corner_width) >> corners.draw(thumbnail_image) >> thumbnail_image.write(rounded_thumbnail_file) >> end >> >> # Resizes a Magick image to an exact size, keeping the same aspect ratio >> def resize_image_to_exact_size(width, height) >> new_aspect_ratio = width.to_f / height.to_f >> old_aspect_ratio = @magick_image.columns.to_f / @magick_image.rows.to_f >> >> if old_aspect_ratio < new_aspect_ratio >> # Image too tall, geometry string should restrict height >> geometry_string = "#{width}" >> else >> # Image too wide or just right, geometry string should >> # restrict width >> geometry_string = "x#{height}" >> end >> >> # Get the resized image >> resized_image = resize_image(geometry_string) >> >> # Return the resized, crop image >> resized_image.crop(Magick::CenterGravity, width, height) >> end >> >> def resize_image(geometry_string) >> logger.debug "resizing image to #{geometry_string}" >> @magick_image.change_geometry(geometry_string) do |w, h, img| >> img.resize(w, h) >> end >> end >> >> def save_medium_image >> medium_image = resize_image("275") >> medium_image.write(medium_file) >> end >> >> def save_large_image >> large_image = resize_image("500") >> large_image.write(large_file) >> end >> >> >> >> # Delete images from filesystem >> def after_destroy >> File.delete(full_file) if File.exist? "#{full_file}" >> File.delete(thumbnail_file) if File.exist? "#{thumbnail_file}" >> File.delete(rounded_thumbnail_file) if File.exist? >>"#{rounded_thumbnail_file}" >> File.delete(medium_file) if File.exist? "#{medium_file}" >> File.delete(large_file) if File.exist? "#{large_file}" >> end >> >> # Returns the filesystem location of the image file >> def full_file >> "#{FileLocation}/full/#{id}.jpg" >> end >> def thumbnail_file >> "#{FileLocation}/thumbnail/#{id}.jpg" >> end >> def rounded_thumbnail_file >> "#{FileLocation}/rounded_thumbnail/#{id}.jpg" >> end >> def medium_file >> "#{FileLocation}/medium/#{id}.jpg" >> end >> def large_file >> "#{FileLocation}/large/#{id}.jpg" >> end >> >> >> # Returns the location of the image to the browser >> def full >> "#{DisplayLocation}/full/#{id}.jpg" >> end >> def thumbnail >> "#{DisplayLocation}/thumbnail/#{id}.jpg" >> end >> def medium >> "#{DisplayLocation}/medium/#{id}.jpg" >> end >> def large >> "#{DisplayLocation}/large/#{id}.jpg" >> end >> def rounded_thumbnail >> "#{DisplayLocation}/rounded_thumbnail/#{id}.jpg" >> end def resize >> if File.exist? full_file >> @file = File.open full_file >> save >> end >> end >>end >> > > > > I''ll be damned. Moving > @magick_image = Magick::Image.from_blob(@file.read).first > from Image#after_save to Image#file= fixed the problem. > > So, apparently, something weird happens to @file before > Image#after_save is called. Any ideas?
rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
2005-Aug-04 12:53 UTC
Re: Fwd: RMagick problem
Hi ! Joe Van Dyk said the following on 2005-08-03 22:30:> On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > # Resizes a Magick image to an exact size, keeping the same aspect ratio > def resize_image_to_exact_size(width, height) > new_aspect_ratio = width.to_f / height.to_f > old_aspect_ratio = @magick_image.columns.to_f / @magick_image.rows.to_f > > if old_aspect_ratio < new_aspect_ratio > # Image too tall, geometry string should restrict height > geometry_string = "#{width}" > else > # Image too wide or just right, geometry string should > # restrict width > geometry_string = "x#{height}" > endThere''s no need to do that. RMagick''s documentation says about geometry strings: "By default, the width and height are maximum values. That is, the image is expanded or contracted to fit the width and height value while maintaining the aspect ratio of the image." http://studio.imagemagick.org/RMagick/doc/imusage.html#geometry Hope that helps ! François
On 8/4/05, rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> wrote:> Hi ! > > Joe Van Dyk said the following on 2005-08-03 22:30: > > On 8/3/05, Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > # Resizes a Magick image to an exact size, keeping the same aspect ratio > > def resize_image_to_exact_size(width, height) > > new_aspect_ratio = width.to_f / height.to_f > > old_aspect_ratio = @magick_image.columns.to_f / @magick_image.rows.to_f > > > > if old_aspect_ratio < new_aspect_ratio > > # Image too tall, geometry string should restrict height > > geometry_string = "#{width}" > > else > > # Image too wide or just right, geometry string should > > # restrict width > > geometry_string = "x#{height}" > > end > > There''s no need to do that. RMagick''s documentation says about geometry > strings: > > "By default, the width and height are maximum values. That is, the image > is expanded or contracted to fit the width and height value while > maintaining the aspect ratio of the image." > > http://studio.imagemagick.org/RMagick/doc/imusage.html#geometry > > Hope that helps ! > FrançoisIf you look again, you''ll notice I have two resize methods. One resize method that just resizes an image, keeping the same aspect ratio. And then the resize_to_exact_size method that resizes an image to an exact size. See http://jerrymahan.com/contents/show/front . You''ll notice that those thumbnails on the right are all the exact same size (same height and width). But the original images all had differently aspect ratios. To make sure that all the thumbnails are the exact same size, I had to do some additional calculations. (or so it appeared to me)
Joe Van Dyk said the following on 2005-08-04 11:36:> On 8/4/05, rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> wrote: > > If you look again, you''ll notice I have two resize methods. One > resize method that just resizes an image, keeping the same aspect > ratio. And then the resize_to_exact_size method that resizes an image > to an exact size.Ha, I didn''t notice that. Then, in the geometry page, simply append an exclamation mark to your geometry string, as mentionned on http://studio.imagemagick.org/RMagick/doc/struct.html#Geometry If your original is 640x328 and you do: img.change_geometry("320x240") the cols and rows will be: 320x164, while if you do: img.change_geometry("320x240!") cols and rows will be 320 and 240, respectively. Hope that helps ! François