Write EXIF data to image stream Node.js - javascript

I found a nice npm package that allows you to read and write Exif data to images, https://github.com/Sobesednik/node-exiftool.
The challenge that I have is that it requires you to provide the path to an image. So, the image has to be written to disk if you want to modify the EXIF using this package. Is there an easy way to check/read the EXIF, and if necessary, write EXIF data to an image stream?
var imageURL = 'https://nodejs.org/static/images/logos/nodejs-new-pantone-black.png'
var upstreamServer = 'http://someupstreamserver/uploads'
request
.get(imageURL)
.pipe(
// TODO read EXIF
// TODO write missing EXIF
request
.post(upstreamServer, function(err, httpResponse, body){
res.send(201)
})
)
EDIT: This question was also asked on node-exiftool

i had a similar task. I had to write physical dimensions and additional metadata to PNG files. I have found some solutions and combined it into one small library.
png-metadata
it could read PNG metadata from NodeJS Buffers, and create a new Buffers with new metadata.
Here is an example:
const buffer = fs.readFileSync('1000ppcm.png')
console.log(readMetadata(buffer));
withMetadata(buffer,{
clear: true, //remove old metadata
pHYs: { //300 dpi
x: 30000,
y: 30000,
units: RESOLUTION_UNITS.INCHES
},
tEXt: {
Title: "Short (one line) title or caption for image",
Author: "Name of image's creator",
Description: "Description of image (possibly long)",
Copyright: "Copyright notice",
Software: "Software used to create the image",
Disclaimer: "Legal disclaimer",
Warning: "Warning of nature of content",
Source: "Device used to create the image",
Comment: "Miscellaneous comment"
}
});
It could be modified to be used with streams, for example, you could implement WritableBufferStream class.
const { Writable } = require('stream');
/**
* Simple writable buffer stream
* #docs: https://nodejs.org/api/stream.html#stream_writable_streams
*/
class WritableBufferStream extends Writable {
constructor(options) {
super(options);
this._chunks = [];
}
_write(chunk, enc, callback) {
this._chunks.push(chunk);
return callback(null);
}
_destroy(err, callback) {
this._chunks = null;
return callback(null);
}
toBuffer() {
return Buffer.concat(this._chunks);
}
}

Related

WordPress media library with metadata limit

I want to create a media library window. attachment should filter with mime types and metadata.
the mime-type filter is done. How can I build a metadata filter just for this?
function upload_image_tinymce(e) {
e.preventDefault();
var $input_field = $('.mce-my_input_image');
var custom_uploader = wp.media.frames.file_frame = wp.media({
title: 'Add Video',
button: {
text: 'Add Video'
},
library: {
type: [
'video/MP4',
'video/quicktime',
'video/x-m4v',
],
},
multiple: false
});
custom_uploader.on('select', function() {
var attachment = custom_uploader.state().get('selection').first().toJSON();
$input_field.val(attachment.id);
});
custom_uploader.open();
}
I cant help you with the whole filter code (not enoth knowlage ...)
But you can use the hook wp_get_attachment_metadata('attachment id') to get an array with the whole metadata of the attachment.
$meta = wp_get_attachment_metadata(126);
Will produce an array with the metadata from the attachment 126.
$cam = $meta[camera]
$cam will then hold the camera string from the metadata ...
Not much but maybe it will lead you a little bit in the right direction.

How to upload contentBytes chunk by chunk on Graph url return by createUploadSession graph API?

As per microsoft graph API documentation the createUploadSession graph API only return the URL where attachment can upload but how to upload attachment chunk by chunk in javascript? does anyone knows? Thanks in advance.
I'm referring this reference
Here is the reference for attaching the Attachment to a post in JavaScript, Please refer this Document
const options = {
authProvider,
};
const client = Client.init(options);
const reply = {
post: {
body: {
contentType: 'text',
content: 'Which quarter does that file cover? See my attachment.'
},
attachments: [{
'#odata.type': '#microsoft.graph.fileAttachment',
name: 'Another file as attachment',
contentBytes: 'VGhpcyBpcyBhIGZpbGUgdG8gYmUgYXR0YWNoZWQu'
} ]
}
};
await client.api('/groups/1848753d-185d-4c08-a4e4-6ee40521d115/threads/AAQkADJUdfolA==/reply')
.post(reply);
Hope this helpful.

How to Create New Google Spreadsheet Using googleapis in Node.js

I want to create a new Google Spreadsheet using googleapis package.
Thanks to Daniel Apt's answer, I am able to create the blank file of it. But I want to give the file values.
I tried this way
const createOption = {
resource: {
properties: {
title: 'Ini judul spreadsetnya'
},
values: ['a']
}
}
But it said that Invalid JSON payload received. Unknown name "values" at 'spreadsheet': Cannot find field.. What field should I add to insert the values? And how do I create the spreadsheet in specific folder? Thank you.
What you are trying to accomplish:
You want to create a new spreadsheet with specific values.
You want this spreadsheet to be created on a specific folder on Google Drive.
Solution:
The first step to accomplish this is to understand why you can't use the values property in your request.
Looking into the documentation you can see that the request is supposed to be of an instance Spreadsheet, and this type does not contain values.
You can also see that there is no way to specify where the spreadsheet will be created, since the Spreadsheet resource does not contain any reference to it's parent folder.
If we break it down, you actually want to do three things:
Create a new spreadsheet
Move it to a specific folder
Fill it with values
Note: You can do step 1 and 2 with a single API call
Create a new spreadsheet:
Change your request body to be like the following:
const createOption = {
resource: {
properties: {
title: 'Ini judul spreadsetnya'
}
}
};
Move the spreadsheet to another folder
You will need to use the Drive API to move a file.
You do this by updating the file to have another parent. In this case, you will use the file.update call with the addParents option where you can add a comma-separated list of parentIds.
These parentIds are the Ids of the folder your file should belong to. (Yes, you can have it in multiple places).
You can extract these via API or thru the interface:
Here is how your request should look like:
const driveMoveOption = {
fileId: "", //You will insert this later
addParents: "<YOUR PARENT ID HERE>",
removeParents: "root" //To remove it from the "MyDrive" section
}
And here is a sample of how to use it:
sheets.spreadsheets.create(createOption, function (err, response) {
if (err) {
console.error(err);
return;
}
//response contains the `Spreadsheet` resource we want, with it's fileId
driveMoveOption.fileId = response.spreadsheetId; //Set the spreadsheet Id to
drive.files.update(driveMoveOption, function (err, response) {
if (err) {
console.error(err);
return;
}
//response contains the structure of a Files structure: https://developers.google.com/drive/api/v3/reference/files#resource
});
});
Creating a spreadsheet on a specific folder
If you use the Drive.files.create API instead you can use this request:
{
"mimeType": "application/vnd.google-apps.spreadsheet",
"name": "Test",
"parents": [
"<YOUR PARENT ID HERE>"
]
}
and call it with
const driveCreateAndMoveOption = {
"mimeType": "application/vnd.google-apps.spreadsheet",
"name": "Test",
"parents": [
"<YOUR PARENT ID HERE>"
]
};
drive.files.update(driveCreateAndMoveOption, function (err, response) {
if (err) {
console.error(err);
return;
}
//response contains the structure of a Files structure. Use this to get the file ID for the spreadsheet call.
});
Insert your custom values
The request to insert values on your spreadsheet should look something like this:
const appendOption = {
"spreadsheetId": "", //You will insert this later
"range": "A:A",
"valueInputOption": "USER_ENTERED",
"resource": {
"values": [
[
"a"
]
]
}
}
To use the correct SpreadsheetId you will need to run this code after you create it, and use that number.
This can be done like this:
sheets.spreadsheets.create(createOption, function (err, response) {
if (err) {
console.error(err);
return;
}
//response contains the `Spreadsheet` resource we want, with it's fileId
appendOption.spreadsheetId = response.spreadsheetId; //Set the spreadsheet Id to insert the values on.
sheets.spreadsheets.values.append(appendOption, function (err, response) {
if (err) {
console.error(err);
return;
}
//response contains the structure detailed on: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append#response-body
});
});
So as jonrsharpe's comment, finally I tried to create the blank spreadsheet and update it (there are two command call).

How get image from FormData to Rails API and saves in ActiveStorage

I am trying to send a FormData object from my React Native app to my Rails API.
I am using react-native-image-crop-picker to pick the image from gallery and store the image object in my state:
ImagePicker.openPicker({
multiple: true,
cropping: true,
includeBase64: true,
compressImageMaxHeight: 1080,
compressImageMaxWidth: 1080,
})
.then(selectedImages => {
selectedImages.map(image => {
let prefix;
let ext;
[prefix, ext] = image.filename.split(".");
ext = ext.toLowerCase() === "heic" ? "jpg" : ext;
const upload = {
uri: image.path,
type: image.mime,
name: `${prefix}.${ext}`,
};
this.setState(prevState => ({
event: {
...prevState.event,
images: [...prevState.event.images, upload],
},
}));
});
})
.catch(error => {
});
Then i create a FormData object to send yo my Rails API:
const data = new FormData();
data.append("name", event.name);
data.append("description", event.description);
data.append("date", event.date);
data.append("time", event.time);
data.append("images", event.images[0]);
My api successfully receives que request:
Parameters: {"event"=>{"_parts"=>[["event[name]", ""], ["event[description]", ""], ["event[date]", ""], ["event[time]", ""], ["event[images]", {"uri"=>"/private/var/mobile/Containers/Data/Application/6226B812-CDEC-4994-A864-0A91EE8C44B3/tmp/react-native-image-crop-picker/BFC043EC-D33F-4E07-BBEA-634CE5DE8A3F.jpg", "type"=>"image/jpeg", "name"=>"IMG_7142.jpg"}]]}}
Now, how can i recover this image and saves directly in my Rails ActiveStorage?
I am trying to directly attach the image object: {"uri"=>"/private/var/mobile/Containers/Data/Application/6226B812-CDEC-4994-A864-0A91EE8C44B3/tmp/react-native-image-crop-picker/BFC043EC-D33F-4E07-BBEA-634CE5DE8A3F.jpg", "type"=>"image/jpeg", "name"=>"IMG_7142.jpg"} to my model, but i am getting the current exception: ActiveRecord::RecordNotSaved (Failed to save the new associated avatar_attachment.):
I see that you have multiple images to attach.
If you've already gone through the documentation, I believe you must have already setup active storage by now.
In your model do you have has_many_attached :images? note that images could've been something else or just about any name.
I was able to retrieve the image name by doing the following (but I doubt if it will work for your purpose):
hash = {"uri"=>"/private/var/mobile/Containers/Data/Application/6226B812-CDEC-4994-A864-0A91EE8C44B3/tmp/react-native-image-crop-picker/BFC043EC-D33F-4E07-BBEA-634CE5DE8A3F.jpg", "type"=>"image/jpeg", "name"=>"IMG_7142.jpg"}
hash['uri'].split('/')[-1]
=> "BFC043EC-D33F-4E07-BBEA-634CE5DE8A3F.jpg"
If the above route is how you want to go and you are sure that it will work this way, then you need to do something like:
#your_model.images.attach(io: File.open("#{hash['uri']}"), filename: "#{hash['uri'].split('/')[-1]}")
You can find here a complete tutorial on how this should actually work here - https://medium.com/#ashley_foster/react-native-image-uploads-with-activestorage-ec4898317a82
Give it a try and if you get stuck along the way, you can drop a comment or edit/update your question.

How to create a file object with a path in NodeJS?

I want to know if it is possible to create a file object (name, size, data, ...) in NodeJS with the path of existing file ? I know that it is possible in client side but I see nothing for NodeJS.
In others words, I want the same function works in NodeJS :
function srcToFile(src, fileName, mimeType){
return (fetch(src)
.then(function(res){return res.arrayBuffer();})
.then(function(buf){return new File([buf], fileName, {type:mimeType});})
);
}
srcToFile('/images/logo.png', 'logo.png', 'image/png')
.then(function(file){
console.log(file);
});
And ouput will be like :
File {name: "logo.png", lastModified: 1491465000541, lastModifiedDate: Thu Apr 06 2017 09:50:00 GMT+0200 (Paris, Madrid (heure d’été)), webkitRelativePath: "", size: 49029, type:"image/png"…}
For those that are looking for a solution to this problem, I created an npm package to make it easier to retrieve files using Node's file system and convert them to JS File objects:
https://www.npmjs.com/package/get-file-object-from-local-path
This solves the lack of interoperability between Node's fs file system (which the browser doesn't have access to), and the browser's File object type, which Node cannot create.
3 steps are required:
Get the file data in the Node instance and construct a LocalFileData object from it
Send the created LocalFileData object to the client
Convert the LocalFileData object to a File object in the browser.
// Within node.js
const fileData = new LocalFileData('path/to/file.txt')
// Within browser code
const file = constructFileFromLocalFileData(fileData)
So, I search with File Systems and others possibilities and nothing.
I decide to create my own File object with JSON.
var imagePath = path.join('/images/logo.png', 'logo.png');
if (fs.statSync(imagePath)) {
var bitmap = fs.readFileSync(imagePath);
var bufferImage = new Buffer(bitmap);
Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);
magic.detectFile(imagePath, function(err, result) {
if (err) throw err;
datas = [{"buffer": bufferImage, "mimetype": result, "originalname": path.basename(imagePath)}];
var JsonDatas= JSON.parse(JSON.stringify(datas));
log.notice(JsonDatas);
});
}
The output :
{
buffer:
{
type: 'Buffer',
data:
[
255,
216,
255
... 24908 more items,
[length]: 25008
]
},
mimetype: 'image/png',
originalname: 'logo.png'
}
I think is probably not the better solution, but it give me what I want. If you have a better solution, you are welcome.
You can use arrayBuffer (thats what i did to make a downloadable pdf) or createReadStream / createWriteStream under fs(FileSystem objects)

Categories

Resources