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();
}
Related
I have implemented functionality in my application to allow user to draw clouds by drawing various adjacent semi circles using pdfbox library. I need information regarding the locations of these clouds, to detect whether the user's click location corresponds to a cloud.Since, the pdfbox library doesn't give me any information regarding location of these clouds, I store their location in pdf's meta data field using the following code(while the cloud is being drawn).
PDDocumentCatalog catalog = doc.getDocumentCatalog();
PDMetadata pdMetaData = catalog.getMetadata();
// Code to append new metadata to previous stored meta data.
java.io.InputStream newData = new java.io.ByteArrayInputStream(Encoding.UTF8.GetBytes(newMetaData));
PDMetadata newPDMetadata = new PDMetadata(doc, newData, false);
catalog.setMetadata(newPDMetadata);
I store the location data as xml in the metadata field.And, when new location data is to be stored, I extract the previous meta data and add a new xml tag corresponding to the new cloud location.And again store the xml in the pdf's meta data field.But, the problem with this approach is that pdf's meta data field will be overwritten, in case the user uses some other pdf editor, which might store some data in the meta data field.
Is there a way to store metadata in pdf as key value pair.So, that it can only be edited, by a person who knows the key corresponding the data, just like websites store cookies.
Here is the code which solved my problem:
int pageNum = 0;
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get(pageNum);
COSName markupMetadataElement = COSName.getPDFName(Key);
COSDictionary dictionary = page.getCOSDictionary();
COSString newCosString = new COSString(newMetaData);
dictionary.setItem(markupMetadataElement, newCosString);
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.
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
I developing an application in zend framework. I want to store certain secure images and pdf documents outside public folder like /project/data/uploads or /projects/application/data/uploads.
I am not able to access the images/pdf documents other than public folder.
Can someone suggest a way to do it.
thank you
You have to have a separate action that knows how to fetch and deliver all that stuff. Something like this:
public function viewpdfAction()
{
$id = (int) $this->_getParam('id', 0);
// You implement some function - either here in your controller
// or someplace else - to get the pdf name from the passed id.
// Alternatively, you can pass the name itself. Up to you, of course.
// The key is that the request somehow identifies the file requested.
$pdfName = $this->_mapPdfIdToName($id);
// The path to the real pdf
$pdfFile = '/project/data/uploads/pdf/' . $pdfName;
// Disable rendering
$this->_helper->viewRenderer->setNoRender(true);
// Send the right mime headers for the content type
$this->getResponse()
->setBody('')
->setHeader('Cache-control', 'public') // needed for IE, I have read
->setHeader('Content-type', 'application/pdf')
->setHeader('Content-Disposition', sprintf('attachment; filename="%s"', $pdfName));
// Send the content
readfile($pdfFile);
}
Of course, some of this can be pushed down into service classes to keep the controller as thin as possible. Everyone has different tastes in this regard.
I confess that this code not completely tested, mostly trying to give the basic idea. If I have made a total bonehead error in here, please let me know.
Hope it helps!