I'm writing a nodeJS 5.3.0 application using gm (http://aheckmann.github.io/gm/)
I know that it uses the GraphicsMagicK library.
the problem is that I'm having is that after I resize an image, it loses it's exif format. the code samples actually shows that the exif format is lost.
for example:
var fs = require('fs')
, gm = require('gm').subClass({imageMagick: true});
// resize and remove EXIF profile data
gm('/path/to/my/img.jpg')
.resize(240, 240)
in this example they say that exif profile data is removed.
I know that I can get the orientation of an image before resizing using:
gm('path/tp/my/img.jpg').orientation(function(err,value){
var orientation = value;
});
the question is..
can I preserve exif data when resizing ? and If not.. can I set exif orientation data after resizing ?
thanks
More specifically in the following code, only noProfile() function remove EXIF, so if you remove it you can preserve EXIF data
// resize and remove EXIF profile data
gm('/path/to/my/img.jpg')
.resize(240, 240)
.noProfile()
.write('/path/to/resize.png', function (err) {
if (!err) console.log('done');
});
Otherwise you can check the gm doc here
Related
I am using Jimp (https://www.npmjs.com/package/jimp) library to crop the image.
Crop is working fine but I only have an issue with image orientation.
Sometimes, user uploaded rotated images and its result rotated cropped images.
I went through with https://www.npmjs.com/package/jimp documentation but couldn't find anything related to this.
Here are couple of links I went through but didn't helped:
https://justmarkup.com/articles/2019-10-21-image-orientation/
Accessing JPEG EXIF rotation data in JavaScript on the client side
Please help
So, long story short: jimp correctly reads images rotated via exif orientation property and rearranges the pixels as if the exif/orientation property didn't exist, but then also stores the old exif property instead of resetting it to 1 as it should for it to be displayed properly on every device.
The simplest solution I was able to implement was using exif-auto-rotate to rotate the image pixels and reset the exif property on the frontend before uploading the (base64 encoded) image to the backend:
import Rotator from 'exif-auto-rotate';
// ...
const [file] = e.target.files;
const image = await Rotator.createRotatedImageAsync(file, "base64")
.catch(err => {
if (err === "Image is NOT have a exif code" || err === "Image is NOT JPEG") {
// just return base64 encoded image if image is not jpeg or contains no exif orientation property
return toBase64(file)
}
// reject if other error
return Promise.reject(err)
});
If you need to do this on the backend then you are probably better off using jpeg-autorotate with buffers as suggested here:
const fileIn = fs.readFileSync('input.jpg')
const jo = require('jpeg-autorotate')
const {buffer} = await jo.rotate(fileIn, {quality: 30})
const image = await Jimp.read(buffer)
More info on browser-based exif orientation issues:
EXIF Orientation Handling Is a Ghetto
just change the jimp version to
"jimp": "0.8.5",
I'm trying to extract EXIF data from images using ImageMagick inside AWS Lambda but I can't find the way to do it.
I have a piece of code to resize the image, it's working fine but I want to add the part to extract EXIF data.
Here is what I have right now to resize images:
var im = require("gm").subClass({imageMagick: true});
var operation = im(image.buffer).autoOrient().resize(width, height, '^');
operation.toBuffer(image.imageType, function(err, buffer) {
if (err) {
//do something with the error
} else {
//do something with the image
}
});
Any idea how to extract the metadata from the image ?
Thanks.
C.C.
I'm writing an API endpoint to accept images and send them to my S3 server. Before that, however, it has to orient the images correctly so that not display wrong when in image tags. Since JPEGs use exif data to determine image rotation and the img tag does not refer to the exif data for orientation information, my images appear sideways on my website, but right side up on other platforms. Here is my code for rotating the image:
if (file.mimetype == 'image/jpeg'){
var exifData = Parser.create(uploadedFile).parse();
if (exifData.tags.Orientation == 6 || exifData.tags.Orientation == 8){
var degrees = exifData.tags.Orientation == 6 ? 90 : 270;
gm(file.path).rotate('black', degrees).write(file.path, function(err){
if (err)
return cb1(err);
finish();
});
}else
finish();
}else
finish();
finish() is the function that sends the file off to S3. Why is it that my image is not rotating? I have it set to overwrite the existing file on rotate. There are no errors being returned, as the entire call would fail.
I am using the knox package to connect my S3 account and pull an image, like this:
var picturestring;
knoxclient.get(key).on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
res.setEncoding('base64');
res.on('data', function(chunk){
picturestring += chunk;
});
res.on('end', function () {
console.log(picturestring);
resizeimage(picturestring, done); // use the resize library in this function
});
}).end();
After that, I want to use a library that can take in that string (picturestring), resize the image, and return a new base64 string that represents the resized image. At this point, I plan on uploaded the resized image to S3.
I wrote a similar script in Golang that let me resize images like this, but every JS resizing library I've reviewed only give examples on resizing images from the local file system.
Is there any way that I can avoid reading the image from S3 into the file system, and focus on dealing with the returned string exclusively??
***************UPDATE***********************
function pullFromS3 (key, done) {
console.log("This is the key being pulled from Amazon: ", key);
var originalstream = new MemoryStream(null, {readable: false});
var picturefile;
client.get(key).on('response', function(res){
console.log("This is the res status code: ", res.statusCode);
res.setEncoding('base64');
res.pipe(originalstream);
res.on('end', function () {
resizeImage(originalstream, key, done);
});
}).end();
};
function resizeImage (originalstream, key, done) {
console.log("This is the original stream: ", originalstream.toString());
var resizedstream = new MemoryStream(null, {readable: false});
var resize = im().resize('160x160').quality(90);
// getting stuck here ******
originalstream.pipe(resize).pipe(resizedstream);
done();
};
I can't seem to get a grip on how the piping from originalstream --> to the resize ImageMagick function ---> to the resizestream works. Ideally, the resizestream should hold the base64 string for the resized image, which I can then upload to S3.
1) How do I wait for the piping to finish, and THEN use the data in resizedstream?
2) Am I doing the piping correctly? I can't debug it because I am unsure how to wait for the piping to finish!
I'm not using S3 but a local cloud provider in China to store images and their thumbnails. In my case I was using imagemagick library with imagemagick-stream and memorystream modules.
imagemagick-stream provides a way to process image with imagemagick through Stream so that I don't need to save the image in local disk.
memorystream provides a way to store the source image and thumbnail image binaries in memory, and with the ability to read/write to Stream.
So the logic I have is
1, Retrieve the image binaries from the client POST request.
2, Save the image into memory using memorystream
3, Upload it to, in your case, S3
4, Define the image process action in imagemagick-stream, for example resize to 180x180
5, Create a read stream from the original image binaries in step 1 using memorystream, pipe into imagemagick-stream created in step 4, and then pipe into a new memory writable created by memorystream where stores the thumbnail.
6, Upload the thumbnail I got in step 5 to S3.
The only problem in my solution is that, your virtual machine might run out of memory if many huge images came. But I know this should not be happened in my case so that's OK. But you'd better evaluate by yourself.
Hope this helps a bit.
I have a web service that takes a base 64 encoded string representing an image, creates a thumbnail of that image using the imagemagick library, then stores both of them in mongodb. I am doing this with the following code (approximately):
var buf = new Buffer(req.body.data, "base64"); //original image
im.resize({ srcData: buf, width: 256 }, function(err, stdout, stderr) {
this.thumbnail = new Buffer(stdout, "binary");
//store buf and stdout in mongo
});
You will notice that I am creating a Buffer object using the "binary" encoding, which the docs say not to do:
'binary' - A way of encoding raw binary data into strings by using
only the first 8 bits of each character. This encoding method is
deprecated and should be avoided in favor of Buffer objects where
possible. This encoding will be removed in future versions of Node.
First off I'm not sure what they are saying there. I'm trying to create a Buffer object and they seem to imply I should already have one.
Secondly, the source of the problem appears to be that the imagemagick resize method returns a string containing binary data. Doing typedef(stdout) return "string" and printing it out to the screen certainly appears to show a bunch of non-character data.
So what do I do here? I can't change how imagemagick works. Is there another way of doing what I'm trying to do?
Thats how I am doing the same with success, storing images in mongodb.
//original ---> base64
var thumbnail = new Buffer(req.body.data).toString('base64');
//you can store this string value in a mongoose model property, and save to mongodb
//base64 ---> image
var buffer = new Buffer(thumbnail, "base64");
I am not sure if storing images as base64 is the best way to do it
Please try this as your base64 might not be pre-handled:
var imgRawData =
req.body.images[0].replace(/^data:image\/png;base64,|^data:image\/jpeg;base64,|^data:image\/jpg;base64,|^data:image\/bmp;base64,/, "");
var yourBuffer = new Buffer(imgRawData, "base64");
Then, save the yourBuffer into MongoDB buffer.