ImageScalr + Grails + AWS plugin - grails

Im trying to implement some pics upload to my webapp.
The problem im having is that im trying to use Imagescalr to create thumbs of the original photos, and Im using AWS Plugin to upload them to my bucket.
So, the code i've is the following: (deleted validations and things that dont influence the question/posible answer)
def uploadPic() {
def f = request.getFile('file')
.
.
.
def s3file = f.inputStream.s3upload(filename) { //this is for the normal photo
path "POI/ID/"
}
def imageIn = ImageIO.read(???); //Dont know if I can put the f file here as parameter... do I have to store it somewhere first, call the s3 file, or I can resize on - the - fly?
BufferedImage scaledImage = Scalr.resize(imageIn, 150);
//Here I should upload the thumb. How can I call something like what is done for the normal photo?
So the problems/questions are explained along the code, hope someone knows how to do this. Thanks in advance.

in Grails, request.getFile() doesn't return a java.io.File object. You could use the input stream to write out a file but I'd probably do something like this, although I'd use services and break things up a little more. But this should get you started in the right direction. Consider this more of a pseudo code workflow suggestion.
def uploadPic() {
def f = request.getFile('file')
def tempFile = new File('/some/local/dir/myImage.png')
f.transferTo(tempFile)
// upload the original image to S3
whateverApi.s3Upload(tempFile)
def bufferedImage = ImageIO.read(tempFile)
def scaledBufferedImage = Scalr.resize(bufferedImage, 150)
// write the scaledImg to disk
def scaledImage = new File('/some/local/dir/myImage-150.png');
ImageIO.write(scaledBufferedImage, "png", scaledImage);
//upload scaled image to S3
whateverApi.s3Upload(scaledImage)
// clean up
tempFile.delete()
scaledImage.delete()
}

Related

Grails file upload to file system

I can't find a good explanation of how to upload files to the file system in Grails. The tutorial books I've gone through "keep it simple" by uploading directly to the database using a byte[] field, but that wouldn't be ideal for my particular situation. The Grails documentation explains file uploading here: http://grails.org/doc/latest/guide/theWebLayer.html#uploadingFiles. So I tried modifying this to fit my resource:
def save(Person personInstance) {
// ... a couple standard error checks
// Handle file upload
def f = request.getFile(params.thumbnail)
if (f.empty) {
flash.message = 'file cannot be empty'
return
}
def filename = "myfile.txt"
def webrootDir = servletContext.getRealPath("/") //app directory
f.transferTo(new File(webrootDir,"images/uploads/thumbnails/$filename"))
personInstance.save flush:true
// ... response
}
Could not find matching constructor for:
java.lang.String(org.springframework.web.multipart.commons.CommonsMultipartFile)
I also tried using the name of the field, def f = request.getFile('thumbnail'), but got the same error. I made sure to add the g:uploadForm tag and set the <input name="thumbnail" type="file"/> within the form.
I would like to be able to upload an image to the file system and then use a String field in the database to store the name of that image.

How to Save Multipart Form in Grails; Text and File Upload

I'm trying to submit a form entry with an uploaded file, but I can't seem to get the controller to save the data properly.
Essentially, I want to post a caption and the uploaded source in one form.
An example of my domain class:
class Image {
String caption
Date dateCreated
Date lastUpated
String source
}
I don't how to store the source file and save the entry.
Here is what I've done so far:
def upload () {
def f = request.getFile('source')
f.transferTo(new File("/path/to/file.tmp"))
return
}
def save () {
upload()
def img = new Image(params)
img.save(flush: true)
...runtime exception...
}
File creation works, but obviously the details on saving the Image entry is incorrect.
Consider this question answered. The problem was not Grails, but the tiny detail of me failing to install the plug-in necessary to insert data into the database.
See this source code Grails file upload example or this presentation Uploading files with Grails.
Hope this helps

Saving images with Carrierwave inside a ruby worker

I'm trying to write a method to store an image from a given url, inside a ruby worker. It comes along my Rails app in which I display the object image.
Here is what I've come up with :
def store(url)
#object = Object.find(1)
#object[:image] = CarrierWave::Uploader.store!(image_url)
end
It doesn't seem to work at all.
Any clues?
Is there another way around?
[EDIT]
Here is the current situation :
def store
#object = Object.find(1)
my_uploader = ImageUploader.new
image = open("http://twitpic.com/show/iphone/xxxx.jpg")
# or for a local file:
image = File.open(Rails.root.join('xxxx.png'))
#object[:image] = my_uploader.store!(image)
#object.save!
end
The filename in the [:image] attibute is still wrong. It gives "[:store_versions!]". How do I get the filename right?
[EDIT2]
Got the filename right by adding #artwork[:image] = my_uploader.filename before save.
But #object = Object.find(1) won't work. How do I access the Object class, which is inside my rails app, from the worker?
#object.image.store!(image) finally did the job!
You'll want to create a new uploader object and point it to your file
image = File.open(Rails.root.join('path', 'to', 'file.png'))
#object[:image] = YourUploader.new(image)

Carrierwave and mini_magick finding widths & height

After a bit of investigation I decided to use Carrierwave and mini_magick on my new rail3 app.
I've set it up and it works perfectly. However I have a one question. I'd like to be able to access the width and height, so I can form the html correctly. However, there is no default data from which to get this information. Because of the way it stores the data I'm I cannot think of any way that I can add it to the database.
Can anyone suggest any tips or ideas? Is it even possible?
class Attachment
mount_uploader :file, FileUploader
def image
#image ||= MiniMagick::Image.open(file.path)
end
end
And use it like this:
Attachment.first.image['width'] # => 400
Attachment.first.image['height'] # => 300
Just for record, I have used a similar solution, however using files with Mongo GridFS, here it goes:
def image
#image ||= MiniMagick::Image.read(Mongo::GridFileSystem.new(Mongoid.database).open(file.path, 'r'))
end
Disadvantage of calculating Image height / width using RMagick or MiniMagick in run time:
Its CPU intensive
It requires Internet to get image and calculate the dimensions.
Its a slow process
FYI You can also calculate the Image Height, Width after the
Image is fully loaded by using the load event associated with the
<img> tag with the help of jQuery.
For Example:
$(document).ready(function(){
var $image = $('.fixed-frame img');
$image.load(function(){
rePositionLogo($image);
});
if($image.prop('complete')){
rePositionLogo($image);
}
});
function rePositionLogo($image){
var height = $image.height();
var width = $image.width();
if (width > height) {
$image.parents('.header').addClass('landscape');
var marginTop = (105 - $image.height())/2;
$image.css('margin-top', marginTop + 'px')
}else{
$image.parents('.header').addClass('portrait');
}
}
Be careful, because load() will not trigger when an image is already loaded. This can happens easily when an image is in the user's browser cache.
You can check if an image is already loaded using $('#myImage').prop('complete'), which returns true when an image is loaded.
I think the best way is to store the image dimensions in the model (database).
In my case, the model name is attachment. Then I created a migration:
rails g migration add_dimensions_to_attachments image_width:integer image_height:integer
After that, run the migration:
rake db:migrate
In my Image Uploader file app/uploaders/image_uploader.rb, I have:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process :store_dimensions
private
def store_dimensions
if file && model
model.image_width, model.image_height = ::MiniMagick::Image.open(file.file)[:dimensions]
end
end
end
With this, the image dimensions is saved in the upload step.
To get the dimensions, I simply run attachment.image_width or attachment.image_height
See the reference here.

How do I get "happy" names using Amazon S3 plugin for Grails (via Jets3t)

References:
http://www.grails.org/plugin/amazon-s3
http://svn.codehaus.org/grails-plugins/grails-amazon-s3/trunk/grails-app/services/org/grails/s3/S3AssetService.groovy
http://svn.codehaus.org/grails-plugins/grails-amazon-s3/trunk/grails-app/domain/org/grails/s3/S3Asset.groovy
By "happy" names, I mean the real name of the file I'm uploading... for instance, if I'm putting a file called "foo.png" I'd expect the url to the file to be /foo.png. Currently, I'm just getting what appears to be a GUID (with no file extension) for the file name.
Any ideas?
You can set the key field on the S3Asset object to achieve what you need.
I'll update the doco page with more information on this.
With length, inputstream and fileName given from the uploaded file, you should achieve what you want with the following code :
S3Service s3Service = new RestS3Service(new AWSCredentials(accessKey, secretKey))
S3Object up = new S3Object(s3Service.getBucket("myBucketName"), fileName)
up.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
up.setContentLength length
up.setContentType "image/jpeg"
up.setDataInputStream inputstream
up = s3Service.putObject(bucket, up)
I hope it helps.
Actual solution (as provided by #leebutts):
import java.io.*;
import org.grails.s3.*;
def s3AssetService;
def file = new File("foo.png"); //assuming this file exists
def asset = new S3Asset(file);
asset.mimeType = extension;
asset.key = "foo.png"
s3AssetService.put(asset);

Resources