How do I display a user-uploaded image with Express and EJS? - node.js

Basically what the title says. Here's what I have got:
I read the images from a form using multer, which I set up like this:
var multer = require('multer');
var express = require('express');
var path = require('path');
var router = express.Router();
var storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, './imgs/')
},
filename: function(req, file, callback) {
callback(null, "tmp" + path.extname(file.originalname));
}
});
router.route('/items/item-create/:cat_id')
.post(upload.single('img'), itemController.postItem);
This works as intended, so I'll not provide the code for itemController.postItem.
I saved the images in a folder called "imgs", which I have made static, like so:
var app = express();
app.use(express.static(path.join(__dirname, 'imgs')));
The images each correspond to a mongoDB document(called "item"), so they are named as "item._id.jpg". I wrote a basic ejs template("item.ejs") which accepts the item document and uses its _id to generate the filename and use it in an "img" tag:
<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
</head>
<body>
<p><%=it.name%></p>
<img src="<%= it._id.toString() + '.jpg' %>" alt="image">
</body>
</html>
This is the function which renders the template, invoked on a GET request to /items/:item_id :
exports.getItem = function(req, res){
Item.findOne({ _id:req.params.item_id }, function(err, item){
if(err) res.send(err);
console.log("In getItem...");
console.log(req.params.item_id);
console.log(item);
res.render('item', { it: item });
});
};
It shows the item name correctly, but it refuses to load the image, and somehow the program sends another GET request to the same url, but with the image name as the :item_id parameter, which obviously throws an error about being unable to read property "name" of "undefined". What am I doing wrong here?
I tried this, but it threw an 'ERR_HTTP_HEADERS_SENT'.

I solved it, turns out I had mounted the static folder incorrectly. As I needed the images at /items/ (and also at /categories/:cat_id/cat-details, which I did not mention in my question), I mounted it as follows:
app.use(['/items/', '/categories/:cat_id/details/'], express.static(path.join(__dirname, 'imgs')));

Related

How to get uploaded image in react by url?

I want to realize uploading files for my users. I use CKEDITOR 5 in my react project. Back-end on nodeJS.
So, i can upload file, can get its Url, but, can't display one in VIEW page.
//my server code
const express = require('express');
//for uploading i use this module
const multiparty = require('connect-multiparty');
const multipartyMiddleware = multiparty({uploadDir: '/var/www/group0384.ru/public_html/server/uploads'}) //here is whole path to my upload folder on server
const app = express();
const port = 3555;
const path = require('path');
const moment = require('moment');
const fs = require('fs');
//so, here i have route /upload, which is indicated in configuration of ckeditor as route to send pictures
app.use(express.static("uploaded"));
app.post('/upload', multipartyMiddleware, (req, res) => {
var TempFile = req.files.upload;
var TempPathfile = TempFile.path;
const targetPathUrl = path.join(__dirname,"./uploaded/"+TempFile.name);
if(path.extname(TempFile.originalFilename).toLowerCase() === ".png" || ".jpg"){
fs.rename(TempPathfile, targetPathUrl, err =>{
res.status(200).json({
uploaded: true,
url: `${__dirname}/uploaded/${TempFile.originalFilename}`
}); // this path is the same as in 5th row (except folder, here it change, but it's no matter)
if(err) return console.log(err);
})
}
})
//------------CKEDITOR CODE---//
<CKEditor
editor={ClassicEditor}
data={this.state.data}
onChange={(event, editor) => {
this.setState({
data: editor.getData(),
});
}}
config={
{
ckfinder: {
uploadUrl: '/upload'
} // here, /upload - the route to send pictures
}
}
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
On my VIEW page, i getting this
screenshot
So, i've tried to change paths, but still couldn't get the picture.
please explain why I can't just get and output a file that is already uploaded on my own server
P.S. Sorry for my english
It seems from the screenshot that you are getting the absolute path to the image, if you want to show the image on the client-side and you are sure the image is saved on your server, you have to send it back as a public URL address of your image!
example: "http://example.com/images/image1.png"
Thank you all for answers, i resolved the problem.
In this part i change url for uploaded images
res.status(200).json({
uploaded: true,
url: `/files/${TempFile.originalFilename}`
});
Then, i created route with this url
app.get('/files/:url(*)', (req, res) => {
console.log(req.params.url)
res.sendFile(path.resolve(__dirname + '/uploaded/' + req.params.url))
})
And it works!

how can i upload an image(using NodeJs) as an input to my image classifier api in flask or image classifier running at XYZ.com using upload button

I am having hard time finding how i can upload an image to my image classifier api and do prediction on it.
in node js i copy paste many code examples but it only saves a copy of the file to an upload folder but there is no option to add the file to an api.
I am running both server( NodeJs and flask(api)) on my localhost.
Eg.I need something similar like AWS Rekognition makes us select an image and show the response.
This is the code that I copy pasted but don't know how add the api and send the image selected on the page
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
console.log(oldpath);
console.log('Fields', fields)
console.log('Files', files)
var newpath = 'C:/Users/Pratham Nishad/Desktop/' +
files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<form action="fileupload" method="post"
enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(4000);
What I want- Lets say that I have an Image Classifier ready to make classify image at XYZ.com and I want to make user select an image(PROBLEM HERE) from his/her storage and process it and post the result.
All the tutorial that i watched just selects the image from one location and paste it to destination location, no information how the image classifier running at XYZ.com will get the image.
Check out multer package on npm:
https://www.npmjs.com/package/multer
As requested I'll demonstrate how I actually used this tool.
Front-end Code:
<!DOCTYPE html>
<html>
<body>
<p>Click on the "Choose File" button to upload a file:</p>
<form action="xyz.com" method="post">
<input type="file" id="myFile" name="filename">
<input type="submit">
</form>
</body>
</html>
Backend Code:
const multer = require('multer');
//Multer DiskStorage Config
const diskStorage = multer.diskStorage({
destination: 'path/to/your/desired/folder',
filename: (req, file, call_back) => {
//Prepend date to the filename
//or anything that can uniquely identify the file
//so it won't get overwritten by the new ones
call_back(null, Date.now() + '_' + file.originalname);
}
});
//Create Multer Instance
const upload = multer({ storage: diskStorage });
//Upload picture
router.post('/uploadpic', upload.single('file'), (req, res) => {
res.status(200);
});
After the file has been saved, you can use it with the image classifier.
You are really free to create your own file structure. There are no specific constraints or rules that you have to follow.

Display uploaded file using Node and Express

I have some code written that takes a single image file from index.html through an HTML form, adds a border to it using the gm module and saves it on the server. Now I'm trying to find a way to display it back to the user, preferably on the same page it was uploaded.
const express = require('express');
const app = express();
const multer = require('multer');
const gm = require('gm').subClass({imageMagick: true});
app.use(express.static(__dirname + '/public'))
app.use(express.static(__dirname + '/output'))
const upload = multer({
dest: 'temp/'
});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
app.post('/', upload.single('file-to-upload'), (req, res) => {
var temp = req.file['path'];
var output = __dirname + '/output/' + req.file['filename'] + '.png'
console.log(req.file)
gm(temp)
.setFormat('png')
.resizeExact(512,512)
.composite(__dirname + '/masks/border.png')
.write(temp, function() {
gm(512, 512, 'none')
.fill(temp)
.drawCircle(256, 256, 256, 0)
.write(output, function(err) {
console.log(err || 'done');
});
});
});
app.listen(3000);
Right now your Express route never responds, it leaves the connection to the browser hanging. The key here is to respond with an HTML document. The laziest way to do that is (continuing at the end of your function):
.write(output, function(err) {
console.log(err || 'done');
return res.send(`
<title>My Image Is Neat!</title>
<h1>My Image Is Neat!</h1>
<img src="/${req.file['filename'] + '.png'}" />
`);
});
/${req.file['filename'] + '.png'} works because your use of express.static is mapping the /output folder into the root. You might want to add /uploads as the first argument so that the paths begin with /uploads and are less easily confused with other things.
As for including it in the page from which they uploaded it, you can write a function to send a similar backticked string for the original form, or you can get a little less lazy and use a templating language like Pug or Nunjucks to break these out to separate files.
Your approach so far implies you are not creating a single-page application with React, Vue, etc. but rather building old-school HTML forms. But if your real goals involve those frameworks you will need to change your approach to create an API rather than render pages.

Error in using "vaadin file upload"(polymer) via nodejs with express

I am trying to upload a simple file using the vaadin file upload element(refer https://vaadin.com/elements/-/element/vaadin-upload)
I am using nodejs and express with multer as middle-ware on the server side.
The nodejs simplified code is as follows:
var express = require("express");
var multer = require('multer');
var app = express();
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('userPhoto');
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/api/photo',function(req,res){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
I tried with an HTML element in my index.html and this code works
<form id = "uploadForm"
enctype = "multipart/form-data"
action = "/api/photo"
method = "post"
>
<input type="file" name="userPhoto" />
<input type="submit" value="Upload Image" name="submit">
</form>
But I want to use the vaadin upload element. I wrote the code
<link rel="import" href="../bower_components/vaadin-upload/vaadin-upload.html">
<vaadin-upload id="userPhoto" target="/api/photo"></vaadin-upload>
When I use this, it does not work as expected. I am able to see the vaadin element. But I am unable to upload a file. As I select the file, the server responds with the string 'Error uploading file'. I am pretty new to polymerjs and web development. Could someone please point me where I am going wrong?
In your backend code, you have to change the file parameter name from 'userPhoto' to 'file'.
In case of the native HTML form, it sends a file in the parameter declared by the name attribute of the <input type="file">.
When using the Vaadin Upload element, the files are sent in the same manner as by the HTML form. But instead of the provided name, they are sent in the parameter called "file".
Note that you have the id="userPhoto" attribute for the upload. The id is a different attribute, that does not act like a name.
Unfortunately, the file parameter name for the upload requests cannot be easily customized for now. We are planning to add more upload request customization features in future.

node.js upload with multer not working

I am trying to implement file uploads with node.js and the multer middleware, but it doesn't seem to work. This is my code:
var express = require('express');
var multer = require('multer');
var done = false;
var app = express();
app.use(multer( {dest:'./uploads/',
onFileUploadStart : function(file){
console.log('File recieved:');
console.log(file);
},
onFileUploadData:function (file,data){
console.log('Data recieved');
},
onParseEnd: function(req,next){
next();
}
}));
app.use(express.static(__dirname+"/public"));
app.post('/upload',require(__dirname+'/upload.js').upload);
app.listen(3000);
My form looks like this:
<html>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name ="file">
<input type="submit" value="Upload selected file to server">
</form>
</body>
</html>
And upload.js looks like this:
exports.upload = function (req,res)
{
console.dir(req.files);
};
I think the problem is that my form is being submitted with "application/x-www-form-urlencoded" in the Content-Type header instead of "multipart/form-data", since this is what appears when I use Fiddler to monitor the request, but I have no idea why. Can anyone shed any light on this?
I got it working by adding an accept attribute to my tag in my html. I don't know why in some examples this is not used.
Here's the code for my entire form:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name ="file" accept="application/x-zip-compressed,image/*">
<input type="submit" value="Upload selected file to server">
</form>
Check the entire project eventually: https://github.com/tutiplain/quickupload
I can see you are doing everything right. I used multer sometime back, you can look into my working implementation here. In this EJS file i have an image upload functionality and then i wrote some logic to store the file to some other location.
Make sure you have appropriate router, for example you can use router.post(..)
exports.upload= function(req,res){
// get the temporary location of the file
var tmp_path = req.files.file.path;
// set where the file should actually exists - in this case it is in the "images" directory
var target_path = '/..provide path to store photos../' + req.files.file.name;
// move the file from the temporary location to the intended location
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) {
throw err;
}else{
//response logic ...
};
});
});
};
You can try this. It works for me. If any issues then let me know
var multer = require('multer');
var upload = multer({ dest: './uploads' });
router.post('/register',upload.single('profileimage'),function(req,res,next){
if (req.file) {
console.log('Uploading File');
var profileImageOriginlName=req.file.originalname;
var profileImageName=req.file.name;
var profileImageMime=req.file.mimetype;
var profileImagePath=req.file.path;
var profileImageExt=req.file.extension;
var profileImageSize=req.file.size;
}
else
{
var profileImageName='noimage.png';
}
});

Resources