am trying yo do this using tornado and pil and mongodb.
avat = self.request.files['avatar'][0]["body"]
nomfich = self.request.files['avatar'][0]["filename"]
try:
image = Image.open(StringIO.StringIO(buf=avat))
size = image.size
type = image.format
avatar = r"/profile-images/{0}/{1}".format(pseudo, nomfich)
except IOError:
self.redirect("/erreur-im")
and the database code:
user={
"pseudo": pseudo,
"password":password,
"email":email,
"tel":tel,
"commune":commune,
"statut":statut,
"nom":nom,
"prenom":prenom,
"daten":daten,
"sexe":sexe,
"avatar":avatar
}
self.db.essog.insert(user)
and it worked ok, the "avatar" is saved, but there in no image, it saves only a name!
my problem is:
to understand how database deals with pictures, must i make image.save(path, format), but the path, is it a path of a normal system path (windows, or linux)?
the profile is simple, and i've limited the picture upload to 500ko, and the document in mongodb is 16mb, so the document will handle the entire profile, but must i use gridFS even for small document when it contains picture?
the key problem is in path of the picture saving, am stuck, and it's the first time i deal with database, so am sorry for that question.
You don't necessarily need GridFS for storing files in MongoDB, but it surely makes it a nicer experience, because it handles the splitting and saving of the binary data, while making the metadata also available. You can then store an ID in your User document to the avatar picture.
That aside, you could also store binary data directly in your documents, though in your code you are not saving the data. You simply are opening it with PIL.Image, but then doing nothing with it.
Assuming you are using pymongo for your driver, I think what you can do is just wrap the binary data in a Binary container, and then store it. This is untested by me, but I assume it should work:
from pymongo.binary import Binary
binary_avatar = Binary(avat)
user={
...
"avatar":avatar,
"avatar_file": binary_avatar
...
}
Now that being said... just make it easier on yourself and use GridFS. That is what it is meant for.
If you were to use GridFS, it might look like this:
from gridfs import GridFS
avat_ctype = self.request.files['avatar'][0]["content_type"]
fs = GridFS(db)
avatar_id = fs.put(avat, content_type=avat_ctype, filename=nomfich)
user={
...
"avatar_name":avatar,
"avatar_id": avatar_id
...
}
This is the code to insert and retrieve image in mongodb without using gridfs.
def insert_image(request):
with open(request.GET["image_name"], "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
print encoded_string
abc=db.database_name.insert({"image":encoded_string})
return HttpResponse("inserted")
def retrieve_image(request):
data = db.database_name.find()
data1 = json.loads(dumps(data))
img = data1[0]
img1 = img['image']
decode=img1.decode()
img_tag = '<img alt="sample" src="data:image/png;base64,{0}">'.format(decode)
return HttpResponse(img_tag)
there is an error in :
from pymongo.binary import Binary
the correct syntax is:
from bson.binary import Binary
thk you all for your endless support
Luca
You need to save binary data using the Binary() datatype of pymongo.
http://api.mongodb.org/python/2.0/api/bson/binary.html#module-bson.binary
Related
I want to store an image in my MongoDB using a form, but I want to store the whole image into my database and not upload it to the server, and then store the image path in the database.
Is there any way I can encode it to a blob, Base64 or even Binary?
And no, the way described here (http://www.yiiframework.com/wiki/622/upload-files-in-yii2-with-mongodb-and-gridfs/) is not the way I'm looking to do it.
Any help would greatly be appreciated.
For images up to 16MB you can use the type MongoBinData.
Something like:
// get temporary filename from form model
$tmpname = UploadedFile::getInstance($model,'file')->tempName;
// create new Active Record
$imageModel = new UploadedImage;
// set attribute using a new MongoBinData object
// the object is created using $tmpname contents
$imageModel->contents = new MongoBinData(
file_get_contents($tmpname),
MongoBinData::GENERIC);
You may also want to check some php.ini parameters for any restrictions to upload size and maximum PHP memory size.
One way to serve the file back is:
public function actionDownloadImage($id) {
$model = UploadedImage::findOne($id);
$stream = fopen("data://image/jpeg;base64," .
base64_encode($model->contents->bin) );
return \Yii::$app->response->sendStreamAsFile($stream)->send();
}
I'm building a flask application where I will be serving small images. These images are stored in MongoDB as BinaryData. In a helper function, I can store the data with these lines of python:
a = {"file_name": f, "payload": Binary(article.read())}
ARTICLES.insert(a)
I'm trying to build a class that contains the image. However, I cannot find the correct field declaration
class BinaryFile(mongo.Document):
created_at = mongo.DateTimeField(default=datetime.datetime.now, required=True)
file_name = mongo.StringField(max_length=255, required=True)
payload = mongo.Binary()
producing this error:
AttributeError: 'MongoEngine' object has no attribute 'Binary'
Can anyone suggest the correct way to declare this value or am I completely off base? This page does not provide a way to declare a field as Binary: http://api.mongodb.org/python/current/api/bson/index.html
Thanks!
Gabe helped get me on the right path.
First, I had to decide whether to use standard Binary format or move to GridFS, I chose to stick with regular Binary.
What I didn't understand was that the DateTimeField and StringField were being provided by MongoEngine. Gabe's comment got me going that way and I found the MongoEngine fields docs: http://docs.mongoengine.org/apireference.html#fields
I called that and got the error here: mongoengine.fields.ImproperlyConfigured: PIL library was not found which was fixed by doing
pip install Pillow
So now I have
import datetime
from app import mongo
from flask import url_for
from bson.binary import Binary
class BinaryFile(mongo.Document):
created_at = mongo.DateTimeField(default=datetime.datetime.now, required=True)
file_name = mongo.StringField(max_length=255, required=True)
payload = mongo.ImageField(required=False)
and I'm on to the next error! See you soon!
I'm trying to backup a Lunr Index to Mongo (daily), and because it's running around 13MB, I'm triggering MongoError: document is larger than capped size errors. I'd like to use GridFS to get around the problem, but I'm having a heck of a time getting it to click.
In the simplest terms: Within Meteor, I'd like to save a 13MB JSON object to MongoDB using GridFS, and then be able to retrieve it when necessary -- all only on the server.
I've gone through the File-Collection and CollectionFS docs, and they seem far too complicated for what I'm trying to accomplish, and don't seem to address simply storing the contents of a variable. (Or, more likely, they do, and I'm just missing it.)
Here's what I'd like to do, in pseudo-code:
Backup = new GridFSCollection('backup');
var backupdata = (serialized search index data object);
Backup.insert({name:'searchindex', data:backupdata, date:new Date().getTime()});
var retrieved = Backup.findOne({name:'searchindex'});
Any suggestions?
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = MongoInternals.NpmModule.GridStore;
var largedata = new GridStore(db,'name','w'); //to write
largedata.open(function(error,gs){
if (error) return;
gs.write('somebigdata',function(error,done){
if (error) return;
largedata.close();
})
});
var largedata = new GridStore(db,'name','r'); //to read data
largedata.open(function(error,gs){
if (error) return;
gs.read(function(error,result){
if (error) return;
//then do something with the result
largedata.close();
})
});
explanation
First you need the db object, which can be exposed via the MongoInternals https://github.com/meteor/meteor/tree/devel/packages/mongo
Second, you need the GridStore object, you get it from the MongoInternals as well
Then you can create a write or read object and follow the API http://mongodb.github.io/node-mongodb-native/1.4/markdown-docs/gridfs.html
The mongo used by Meteor is 1.3.x whereas the latest node mongodb native driver is 2.x.x http://mongodb.github.io/node-mongodb-native/2.0/api-docs/
So the API may change in the future. Currently, you need to do open and close and the callback are all async, you may want to wrap them with Meteor.wrapAsync (may not work on largedata.open), Future or Fiber
Using WinJS, while looping through a directory, how to retrieve only images in that particular directory and ignoring any other file extension, including the DoubleDots .. and the SingleDot . etc?
Something like:
var dir = Windows.Storage.KnownFolders.picturesLibrary;
dir.getFilesAsync().done(function (filesFound) {
for(var i=0; i < filesFound.length; i++){}
if(filesFound[i] IS_REALLY_AN_IMAGE_(jpeg,jpg,png,gif Only)){
//Retrieve it now!
}else{
//Escape it.
}
}})
Instead of trying to process pathnames, it will work much better to use a file query, which lets the file system do the search/filtering for you. A query also allows you to listen for the query's contentschanged event if you want to dynamically track the folder contents rather than explicitly enumerating again.
A query is created via StorageFolder.createFileQuery, createFolderQuery, or other variants. In your particular case, where you want to filter by file types, you can use createFileQueryWithOptions. This function takes a QueryOptions object which you can initialize with an array of file types. For example:
var picturesLibrary = Windows.Storage.KnownFolders.picturesLibrary;
var options = new Windows.Storage.Search.QueryOptions(
Windows.Storage.Search.CommonFileQuery.orderByName, [".jpg", ".jpeg", ".png", ".gif"]);
//Could also use orderByDate instead of orderByName
if (picturesLibrary.areQueryOptionsSupported(options)) {
var query = picturesLibrary.createFileQueryWithOptions(options);
showResults(query.getFilesAsync());
}
where showResults is some function that takes the promise from query.getFilesAsync and iterates as needed.
I go into this subject at length in Chapter 11 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, in the section "Folders and Folder Queries". Also refer to the Programmatic file search sample, as I do in the book.
When you want to display the image files, be sure to use thumbnails instead of loading the whole image (images are typically much larger than a display). That is, for each StorageFile, call its getThumbnailAsync or getScaledImageAsThumbnailAsync method. Pass the resulting thumbnail (blob) to URL.createObjectURL which returns a URL you can assign to an img.src attribute. Or you can use a WinJS.UI.ListView control, but that's another topic altogether (see Chapter 7 of my book).
Currently I am writing a Sinatra app that gets some pictures from user and returns a new picture.
There's part of haml form:
%input{type:'file', name:'user_image'}
And there's a code from handler: (montage is another picture)
source_userpic = params[:user_image][:tempfile]
blob = File.open(source_userpic).read
userpic = ImageList.new
userpic.from_blob(blob)
resized_img = userpic.scale(montage.columns,
montage.rows)
resized_img.opacity = MaxRGB/3
Then two images are "layered" with composite and stored (don't need)
final_picture = ImageList.new
final_picture << montage.composite(resized_img, 0, 0, OverCompositeOp)
final_picture.write("./public/uploads/#{DateTime.now}.jpg" # dirty (for example)
Next, I need to show a final_picture with ajax. There are two obvious problems: first, I don't need to save a final_picture - it's just preview, second, I must write code to avoid filenames conflicts...
How to send a final_picture to view? to_blob method? But what's next?
I solved that by using the data URI scheme.
require 'base64'
final_picture.format = "jpeg" # whatever
# Using a to_blob method to create a direct-to-memory version of the image.
# Then encode it to base64 string
data_uri = Base64.encode64(final_picture.to_blob).gsub(/\n/, "")
#image_tag = '<img alt="preview" src="data:image/jpeg;base64,%s">' % data_uri
haml:'pages/preview'
Then display a picture by
= #image_tag
Not sure if it's best solution
Take a look at Tempfile, that should take care of file name conflicts for you.
Then you could use the technique from the answers to this question, using send_file to send the tempfile.
You have to remember that the tempfile won't persist, so you have to be careful to manage that persistence if you are using different requests and responses to serve the file.