Matthew Law
2006-May-19 12:01 UTC
[Rails] Resize uploaded image file without creating temp file?
Hi, I need to take a single uploaded image file and save three resized versions of it, a thumbnail, normal and large version. I was planning on doing this in my model by having an array of geometry strings and looping through them, each time saving a new image object resized to the correct geometry. I know that file column does similar stuff, but I would prefer to have a separate database row for each image size, rather than one row and multiple saved files, which is what file_column seems to want to do. If I store the images as blobs (I use postgresql, so they will be bytea columns...), is it possible to resize an uploaded image file before assigning it to the model attribute corresponding to the blob without writing it to a temp file first? On the other hand, is it better for performance and maintenance reasons to use files and just save the location of the image file? Finally, does anyone have any working code snippet which does these kind of things using either Magick or preferably, MiniMagick that they can share, as a starting point? Sorry for the braindump and flood of questions, but I was hoping people could save me from spending a lot of time writing something only to realise that I should have done it another way :-) Many thanks, Matt.
Al Evans
2006-May-19 12:44 UTC
[Rails] Re: Resize uploaded image file without creating temp file?
Matthew Law wrote:> ...is it possible to resize an uploaded image file before > assigning it to the model attribute corresponding to the blob without > writing it to a temp file first?It will already be a temp file when you get it, unless it''s pretty small.> On the other hand, is it better for > performance and maintenance reasons to use files and just save the > location of the image file?Opinions vary. I think it''s better to save images to the file system, rather than the database, but others disagree. On the other hand, it''s easy enough to read the file and store it as a blob, either with or without processing. For example, in RMagick: photo_data = uploaded_file.read img = Image.from_blob(photo_data).first img.strip!.change_geometry("1024x1024") { |cols, rows, img| img.resize!(cols, rows) } blob = img.to_blob> Finally, does anyone have any working code snippet which does these kind > of things using either Magick or preferably, MiniMagick that they can > share, as a starting point?Here''s one routine I use to process an incoming image. I''m converting it to an intermediate "work" copy, no larger than 1024x1024. I''ve already checked the incoming file to make sure I like it. def cache_image_for_processing(uploaded_file) img = nil path = uploaded_file.local_path if path.blank? photo_data = uploaded_file.read img = Image.from_blob(photo_data).first else img = Image.read(path).first end img.strip!.change_geometry("1024x1024") { |cols, rows, img| img.resize!(cols, rows) } img.write(cache_file_name) img = nil GC.start end Notice the special handling for the case where the incoming "file" isn''t a file, but an "IOString". This happens if it''s below a couple k in size. Also note the "img = nil; GC.start" at the end. This is important if you want to keep memory usage reasonable. --Al Evans -- Posted via http://www.ruby-forum.com/.
Matthew Law
2006-May-24 16:05 UTC
[Rails] Re: Resize uploaded image file without creating temp file?
> Here''s one routine I use to process an incoming image. I''m converting it > to an intermediate "work" copy, no larger than 1024x1024. I''ve already > checked the incoming file to make sure I like it. > > def cache_image_for_processing(uploaded_file) > img = nil > path = uploaded_file.local_path > if path.blank? > photo_data = uploaded_file.read > img = Image.from_blob(photo_data).first > else > img = Image.read(path).first > end > img.strip!.change_geometry("1024x1024") { |cols, rows, img| > img.resize!(cols, rows) > } > img.write(cache_file_name) > img = nil > GC.start > end > > Notice the special handling for the case where the incoming "file" isn''t > a file, but an "IOString". This happens if it''s below a couple k in > size. Also note the "img = nil; GC.start" at the end. This is important > if you want to keep memory usage reasonable. > > --Al EvansThanks, Al! That has given me a good start on what I want to do. Matt.
njmacinnes@gmail.com
2006-May-24 16:49 UTC
[Rails] Re: Resize uploaded image file without creating temp file?
I would normally agree with Al, saying it''s better to use a temporary file. But I''ve been looking at the Wikimedia project source (it bears similarities to my own project), and I like the way they do images. They store them as blobs, and if you want to get an image of a particular width, you put that as a parameter in the getImage URL, and it''s resized dynamically per request. (I think it''s cached as well to speed things up). Using that method, you can just put "/Image/32/800" (32 being the id and 800 being the width) in the src of your img tag. Hope this helps. -Nathan On 24/05/06, Matthew Law <matt@matthewlaw.plus.com> wrote:> > Here''s one routine I use to process an incoming image. I''m converting it > > to an intermediate "work" copy, no larger than 1024x1024. I''ve already > > checked the incoming file to make sure I like it. > > > > def cache_image_for_processing(uploaded_file) > > img = nil > > path = uploaded_file.local_path > > if path.blank? > > photo_data = uploaded_file.read > > img = Image.from_blob(photo_data).first > > else > > img = Image.read(path).first > > end > > img.strip!.change_geometry("1024x1024") { |cols, rows, img| > > img.resize!(cols, rows) > > } > > img.write(cache_file_name) > > img = nil > > GC.start > > end > > > > Notice the special handling for the case where the incoming "file" isn''t > > a file, but an "IOString". This happens if it''s below a couple k in > > size. Also note the "img = nil; GC.start" at the end. This is important > > if you want to keep memory usage reasonable. > > > > --Al Evans > > Thanks, Al! > > That has given me a good start on what I want to do. > > Matt. > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Al Evans
2006-May-24 22:04 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
unknown wrote:> ...But I''ve been looking at the Wikimedia project source (it bears > similarities to my own project), and I like the way they do images. > They store them as blobs, and if you want to get an image of a > particular width, you put that as a parameter in the getImage URL, and > it''s resized dynamically per request.Context is everything:-) If you''re on your own server, with plenty of memory and processing power, sure, why not. But re-sizing images per request is very expensive, computationally. Personally, I wouldn''t even think of doing it on the shared server I''m using. I guess you could have client-side Javascript get the screen dimensions and give them to your server, then rewrite all the image tags to fit the user''s screen. But it seems to me that you would have to have a Really Good Reason to do that:-) --Al Evans -- Posted via http://www.ruby-forum.com/.
Matthew Law
2006-May-30 13:20 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
Al Evans wrote:> unknown wrote: > >> ...But I''ve been looking at the Wikimedia project source (it bears >> similarities to my own project), and I like the way they do images. >> They store them as blobs, and if you want to get an image of a >> particular width, you put that as a parameter in the getImage URL, and >> it''s resized dynamically per request. >> > > Context is everything:-) > > If you''re on your own server, with plenty of memory and processing > power, sure, why not. > > But re-sizing images per request is very expensive, computationally. > Personally, I wouldn''t even think of doing it on the shared server I''m > using. > > I guess you could have client-side Javascript get the screen dimensions > and give them to your server, then rewrite all the image tags to fit the > user''s screen. But it seems to me that you would have to have a Really > Good Reason to do that:-) > > --Al EvanThat is a cool way of doing it, but I agree with Al on this. Although I am on a dedicated server, it isn''t flush with horsepower and most of my listing objects have a few image objects with 100x100, 320x320 and large (800x600) versions plus a PDF. They all have to be loaded everytime a listing is viewed because they are scrolled with javascript. Doing the dynamic resizing alone could easily kill my server if the site gets moderately busy. I have not made up my mind if I can get away with storing the images in the DB - I am not sure if the cache hit rate would be high enough to justify caching the image objects given that the box doesn''t have enough memory to give a lot over to the cache. Mmm...decisions, decisions. Matt.
Tom Davies
2006-May-30 13:31 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
I have a similar requirement for a site I am building. I am also on a shared server so creating separate thumbnails is too resource exhaustive for me for the time being. So, I ended up writing this clientside javascript to dynamically resize the images: function resize(which, max) { var elem = document.getElementById(which); if (elem == undefined || elem == null) return false; if (max == undefined) max = 100; if (elem.width > elem.height) { if (elem.width > max) elem.width = max; } else { if (elem.height > max) elem.height = max; } } This has been tested in IE 6 and Firefox 1.5. The interesting thing I found is that both of these browsers will maintain the aspect ratio for you if you just resize the largest dimension to fit your maximum allowed size. To make this work you need to resize the images after they''ve been loaded using the :onload option like so: <%= image_tag(image_url, {:id => "image_x", :onload => "resize(''image_x'')"}) %> Feel free to use this if it meets your needs. Tom On 5/30/06, Matthew Law <matt@matthewlaw.plus.com> wrote:> Al Evans wrote: > > unknown wrote: > > > >> ...But I''ve been looking at the Wikimedia project source (it bears > >> similarities to my own project), and I like the way they do images. > >> They store them as blobs, and if you want to get an image of a > >> particular width, you put that as a parameter in the getImage URL, and > >> it''s resized dynamically per request. > >> > > > > Context is everything:-) > > > > If you''re on your own server, with plenty of memory and processing > > power, sure, why not. > > > > But re-sizing images per request is very expensive, computationally. > > Personally, I wouldn''t even think of doing it on the shared server I''m > > using. > > > > I guess you could have client-side Javascript get the screen dimensions > > and give them to your server, then rewrite all the image tags to fit the > > user''s screen. But it seems to me that you would have to have a Really > > Good Reason to do that:-) > > > > --Al Evan > That is a cool way of doing it, but I agree with Al on this. Although I > am on a dedicated server, it isn''t flush with horsepower and most of my > listing objects have a few image objects with 100x100, 320x320 and large > (800x600) versions plus a PDF. They all have to be loaded everytime a > listing is viewed because they are scrolled with javascript. Doing the > dynamic resizing alone could easily kill my server if the site gets > moderately busy. > > I have not made up my mind if I can get away with storing the images in > the DB - I am not sure if the cache hit rate would be high enough to > justify caching the image objects given that the box doesn''t have enough > memory to give a lot over to the cache. Mmm...decisions, decisions. > > Matt. > > > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Tom Davies http://blog.atomgiant.com http://gifthat.com
Stephen Bartholomew
2006-May-30 13:39 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
Surely this would just resize the displayed image, not the actual file site. If your source images were quite large and you had a whole page of them, it would take ages to download. Steve Tom Davies wrote:> I have a similar requirement for a site I am building. I am also on a > shared server so creating separate thumbnails is too resource > exhaustive for me for the time being. So, I ended up writing this > clientside javascript to dynamically resize the images: > > function resize(which, max) { > var elem = document.getElementById(which); > if (elem == undefined || elem == null) return false; > if (max == undefined) max = 100; > if (elem.width > elem.height) { > if (elem.width > max) elem.width = max; > } else { > if (elem.height > max) elem.height = max; > } > } > > This has been tested in IE 6 and Firefox 1.5. The interesting thing I > found is that both of these browsers will maintain the aspect ratio > for you if you just resize the largest dimension to fit your maximum > allowed size. To make this work you need to resize the images after > they''ve been loaded using the :onload option like so: > > <%= image_tag(image_url, {:id => "image_x", :onload => > "resize(''image_x'')"}) %> > > Feel free to use this if it meets your needs. > > Tom > > > On 5/30/06, Matthew Law <matt@matthewlaw.plus.com> wrote: > >> Al Evans wrote: >> > unknown wrote: >> > >> >> ...But I''ve been looking at the Wikimedia project source (it bears >> >> similarities to my own project), and I like the way they do images. >> >> They store them as blobs, and if you want to get an image of a >> >> particular width, you put that as a parameter in the getImage URL, and >> >> it''s resized dynamically per request. >> >> >> > >> > Context is everything:-) >> > >> > If you''re on your own server, with plenty of memory and processing >> > power, sure, why not. >> > >> > But re-sizing images per request is very expensive, computationally. >> > Personally, I wouldn''t even think of doing it on the shared server I''m >> > using. >> > >> > I guess you could have client-side Javascript get the screen dimensions >> > and give them to your server, then rewrite all the image tags to fit >> the >> > user''s screen. But it seems to me that you would have to have a Really >> > Good Reason to do that:-) >> > >> > --Al Evan >> That is a cool way of doing it, but I agree with Al on this. Although I >> am on a dedicated server, it isn''t flush with horsepower and most of my >> listing objects have a few image objects with 100x100, 320x320 and large >> (800x600) versions plus a PDF. They all have to be loaded everytime a >> listing is viewed because they are scrolled with javascript. Doing the >> dynamic resizing alone could easily kill my server if the site gets >> moderately busy. >> >> I have not made up my mind if I can get away with storing the images in >> the DB - I am not sure if the cache hit rate would be high enough to >> justify caching the image objects given that the box doesn''t have enough >> memory to give a lot over to the cache. Mmm...decisions, decisions. >> >> Matt. >> >> >> >> >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> > >
Matthew Law
2006-May-30 13:44 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
That is my problem. I could have a paginated list of results, each with a thumbnail. Viewing any one of these would yield at least three images of up to 800x600 which would require resizing to 320x320 for display and also be ready to place in a pop-up at full size if the user wants to see the enlarged image. Anyways, thanks for the javascript, Tom. It might come in handy somewhere :-) M. Stephen Bartholomew wrote:> Surely this would just resize the displayed image, not the actual file > site. If your source images were quite large and you had a whole page > of them, it would take ages to download. > > Steve > > > Tom Davies wrote: >> I have a similar requirement for a site I am building. I am also on a >> shared server so creating separate thumbnails is too resource >> exhaustive for me for the time being. So, I ended up writing this >> clientside javascript to dynamically resize the images: >> >> function resize(which, max) { >> var elem = document.getElementById(which); >> if (elem == undefined || elem == null) return false; >> if (max == undefined) max = 100; >> if (elem.width > elem.height) { >> if (elem.width > max) elem.width = max; >> } else { >> if (elem.height > max) elem.height = max; >> } >> } >> >> This has been tested in IE 6 and Firefox 1.5. The interesting thing I >> found is that both of these browsers will maintain the aspect ratio >> for you if you just resize the largest dimension to fit your maximum >> allowed size. To make this work you need to resize the images after >> they''ve been loaded using the :onload option like so: >> >> <%= image_tag(image_url, {:id => "image_x", :onload => >> "resize(''image_x'')"}) %> >> >> Feel free to use this if it meets your needs. >> >> Tom
Tom Davies
2006-May-30 14:24 UTC
[Rails] Re: Re: Resize uploaded image file without creating temp fil
Yes, this just resizes the display of the image. For large images, this is definitely an inferior solution to resizing them on the server and storing them for future use. But for my current requirements, it is a reasonable work around until I get the resources to afford resizing on the server. Good Luck Matt. Tom On 5/30/06, Matthew Law <matt@matthewlaw.plus.com> wrote:> That is my problem. I could have a paginated list of results, each with > a thumbnail. Viewing any one of these would yield at least three images > of up to 800x600 which would require resizing to 320x320 for display and > also be ready to place in a pop-up at full size if the user wants to see > the enlarged image. > > Anyways, thanks for the javascript, Tom. It might come in handy > somewhere :-) > > M. > > Stephen Bartholomew wrote: > > Surely this would just resize the displayed image, not the actual file > > site. If your source images were quite large and you had a whole page > > of them, it would take ages to download. > > > > Steve > > > > > > Tom Davies wrote: > >> I have a similar requirement for a site I am building. I am also on a > >> shared server so creating separate thumbnails is too resource > >> exhaustive for me for the time being. So, I ended up writing this > >> clientside javascript to dynamically resize the images: > >> > >> function resize(which, max) { > >> var elem = document.getElementById(which); > >> if (elem == undefined || elem == null) return false; > >> if (max == undefined) max = 100; > >> if (elem.width > elem.height) { > >> if (elem.width > max) elem.width = max; > >> } else { > >> if (elem.height > max) elem.height = max; > >> } > >> } > >> > >> This has been tested in IE 6 and Firefox 1.5. The interesting thing I > >> found is that both of these browsers will maintain the aspect ratio > >> for you if you just resize the largest dimension to fit your maximum > >> allowed size. To make this work you need to resize the images after > >> they''ve been loaded using the :onload option like so: > >> > >> <%= image_tag(image_url, {:id => "image_x", :onload => > >> "resize(''image_x'')"}) %> > >> > >> Feel free to use this if it meets your needs. > >> > >> Tom > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Tom Davies http://blog.atomgiant.com http://gifthat.com