i am trying to increase the file size limit in nodejs server. after searching and making changes also iam still getting same error. Tried everything mentioned on stackoverflow and also other sites but couldn't solve the issue. i have been wasting more time on this. please some one help me with this
app.js :
var express = require("express");
var Middlewares = require("./config/middlewares/middleware");
var bodyParser = require('body-parser');
var app = express();
var port = parseInt(process.env.PORT, 10) || 5000;
app.set("port", port);
app.use(Middlewares.configuration);
app.listen(port, function () {
console.log("Node app is running at localhost:" + port);
});
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
package.json :
{
"name": "dinely.api",
"version": "2.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "dinely",
"license": "ISC",
"dependencies": {
"express": "*",
"body-parser": "*",
"file-system": "^2.2.2",
"jsonwebtoken": "^7.4.1",
"jwt-simple": "^0.5.1",
"method-override": "*",
"mongoose": "*",
"passport": "^0.3.2",
"passport-jwt": "^2.2.1"
}
}
front-end
html :
<div class="column">
<p class="label">Logo<span class="required">*</span></p>
<div >
<input type="file" name="logo" required (change)="fileChange(input)" #input style="text-indent: 0px;"/>
<img [attr.src]='file_srcs' alt="" style="width:15%;margin-top:10px;"/>
<div *ngIf="logoValid" class="help-block" style="color:red">Select Image</div>
</div>
</div>
component.ts :
fileChange(input) {
debugger;
this.readFiles(input.files);
}
readFiles(files) {
let reader = new FileReader();
this.readFile(files[0], reader, (result) => {
var img = document.createElement("img");
img.src = result;
this.fileExtension = files[0].type.replace("image/","");
this.resize(img, 250, 250, (resized_jpeg, before, after) => {
this.debug_size_before.push(before);
this.debug_size_after.push(after);
console.log("before : " + this.debug_size_before + " after : " + this.debug_size_after)
this.file_srcs = resized_jpeg;
var formdata = new FormData();
formdata.append("formImg",resized_jpeg);
console.log(formdata);
});
});
}
// for image compression
resize(img, MAX_WIDTH: number, MAX_HEIGHT: number, callback) {
return img.onload = () => {
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataUrl = canvas.toDataURL('image/' + this.fileExtension);
callback(dataUrl, img.src.length, dataUrl.length);
};
}
readFile(file, reader, callback) {
reader.onload = () => {
callback(reader.result);
this.imageURL = reader.result;
this.uploadImgToServer(reader.result);
}
reader.readAsDataURL(file);
}
// upload image to server api call
uploadImgToServer(url){
return this._dataService.uploadImage({
"imgUrl" : url,
"path" : "/images/RestaurantLogos",
"name" : this.generateRandomImgName(),
"extension" : this.fileExtension
}).then(
data => {
console.log("iamge uploaded");
},
error => {
});
}
// generates random string for image name
generateRandomImgName(){
var dt = new Date();
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++){
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
this.imagepath = text;
return text;
}
Check in this link
https://expressjs.com/en/resources/middleware/body-parser.html
https://www.npmjs.com/package/bytes
limit
Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the bytes library for parsing. Defaults to '100kb'.
They mentioned limit values is in bytes
app.use(bodyParser.json({limit: '50mb'}));
you have to set the limit in bytes.
Related
I'm having an issue with ZXing-js. Its returning a ChecksumException no matter what QR Code I put into it. So its detecting the QRCode but throws an Exception. The following is my vuejs 2.0 code. Please help.
Almost all if this code works. Its just the reading of the QR code part that doesn't
import { BarcodeFormat, DecodeHintType, NotFoundException, ChecksumException, FormatException } from '#zxing/library';
const ZXing = require('#zxing/browser');
Vue.component('qr_scanner_modal',{
prop: [
'videoSource'
],
data: function ()
{
return {
qr_error: null,
qrcanvas: null,
context: null,
qrvideo: null,
hints: null,
formats: null,
videoSource: {},
qr: null,
selected_source: null,
polling: null,
localMediaStream: null,
scanLineDirect: 'down',
scanlineOffset: 0,
qr_title: "",
visible: false,
focused: true,
qr_result: ""
};
},
mixins: [ focusMixin ],
created: function ()
{
EventBus.$on('trigger-qrcode-scanner', (qrTitle) => this.show(qrTitle));
},
mounted: function ()
{
let self = this;
this.$root.$on('bv::modal::show', () => this.$nextTick(() => this.mountQRReader()));
},
methods: {
mountQRReader: function ()
{
const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX/*, ...*/];
hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(DecodeHintType.TRY_HARDER, true);
hints.set(DecodeHintType.CHARACTER_SET, 'UTF-8');
hints.set(DecodeHintType.ALSO_INVERTED, true);
this.qr = new ZXing.BrowserQRCodeReader(hints);
this.qrcanvas = this.$refs['qrcanvas'];
this.qrcanvas.width = 400;
this.qrcanvas.height = 400;
// this.qrcanvas = this.$refs;
console.log(this.$refs['qrcanvas']);
this.context = this.$refs['qrcanvas'].getContext('2d');
this.qrvideo = this.$refs['qrvideo'];
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices)
{
this.qr_error = "This browser does not support MediaStreamTrack. Try Chrome.";
console.log("enumerateDevices() not supported.");
}
else
{
this.qr_error = null;
}
let self = this;
navigator.mediaDevices
.enumerateDevices()
.then(function (sourceInfos)
{
let videosource = [];
for (var index = 0; index !== sourceInfos.length; index++)
{
var sourceInfo = sourceInfos[index];
if (sourceInfo.kind === 'videoinput')
{
videosource.push({
id: sourceInfo.deviceId,
name: sourceInfo.label || 'Camera ' + index
});
console.log(sourceInfo);
console.log(videosource);
}
}
self.videoSource = videosource;
})
.catch(function (err)
{
console.log(err.name + ": " + err.message);
});
},
show: function (qrTitle)
{
console.log("Show modal called.");
this.qr_title = qrTitle + " - QR / Magstripe Reader";
this.$bvModal.show('qr_code_scanner');
},
dismiss: function()
{
this.stopScan();
this.$bvModal.hide('qr_code_scanner');
},
selectSource: function (source)
{
this.selected_source = source;
let constraints = {
audio: false,
video: {
facingMode: "environment",
sourceId: source
}
};
navigator.getUserMedia(constraints, this.startScan, this.scanError);
},
read: function (value)
{
console.log('read callback called.');
console.log(value);
if (value !== null && value !== undefined)
{
this.qr_result = value.text;
EventBus.$emit('qr_code_returned', value.text);
this.stopScan();
return;
}
},
startScan: function (stream)
{
this.qrvideo.srcObject = stream;
this.localMediaStream = stream;
this.qrvideo.play();
this.polling = setInterval(this.scan, 400);
},
scanError: function (err)
{
if (err)
{
this.qr_error = err;
}
},
stopScan: function ()
{
clearInterval(this.polling);
if (this.localMediaStream)
{
let track = this.localMediaStream.getVideoTracks();
track[0].stop();
}
},
transposeRect: function (width, height)
{
const rectWidth = width * 0.8;
const rectHeight = height * 0.8;
const xPos = (width - rectWidth) / 2;
const yPos = (height - rectHeight) / 2;
this.context.beginPath();
this.context.strokeStyle = 'red';
this.context.lineWidth = '3';
this.context.rect( xPos,
yPos,
rectWidth,
rectHeight);
this.context.stroke();
this.drawScanLine(yPos,
xPos,
xPos + rectWidth,
yPos + rectHeight);
},
drawScanLine: function (top, left, right, bottom)
{
if (this.scanLineDirect === 'down')
{
this.scanlineOffset = this.scanlineOffset + 4;
}
if (this.scanLineDirect === 'up')
{
this.scanlineOffset = this.scanlineOffset - 4;
}
if (top + this.scanlineOffset > bottom)
{
this.scanLineDirect = 'up';
this.scanlineOffset = this.scanlineOffset - 4;
}
if (top + this.scanlineOffset < top)
{
this.scanLineDirect = 'down';
this.scanlineOffset = this.scanlineOffset + 4;
}
this.context.beginPath();
this.context.strokeStyle = 'red';
this.context.lineWidth = '3';
this.context.moveTo(left, top + this.scanlineOffset);
this.context.lineTo(right, top + this.scanlineOffset);
this.context.closePath();
this.context.stroke();
},
scan: async function ()
{
try
{
if (this.localMediaStream)
{
console.log("Scanning Video Feed.");
const width = this.qrcanvas.getAttribute('width');
const height = this.qrcanvas.getAttribute('height');
this.context.drawImage(this.qrvideo, 0, 0, width, height);
console.log("width: " + width);
console.log("height: " + height);
const code = await this.qr.decodeFromCanvas(this.qrcanvas);
// const code = await this.qr.decode(this.qrcanvas);
this.read(code);
this.transposeRect(width, height);
}
}
catch(err)
{
if (err instanceof NotFoundException) {
console.log('No QR code found.')
}
if (err instanceof ChecksumException) {
console.log('A code was found, but it\'s read value was not valid.')
}
if (err instanceof FormatException) {
console.log('A code was found, but it was in a invalid format.')
}
}
}
},
template: `
<b-modal id="qr_code_scanner"
v-bind:title="qr_title"
v-bind:videoSource='videoSource'
hide-footer >
<div class="alert alert-danger" v-show="qr_error != null">
{{qr_error}}
</div>
<div>
<a href='#' v-for="source in videoSource" v-on:click='selectSource(source.id)' class='btn btn-primary'>#{{source.name}}</a>
</div>
<div class="large-centered col-lg-12 col-md-12 col-sm-12" style="overflow: hidden;">
<input type="text" ref="qr_result" name='qr_result' v-focus="focused" v-model='qr_result' class="form-control" />
<video id="qrvideo" ref="qrvideo" controls="false" style="display: none;"></video>
<canvas id="qrcanvas" ref='qrcanvas' style="overflow: hidden;" width="400" height="400"></canvas>
</div>
<div class="modal-footer">
<a href='#' v-on:click='dismiss()' class='btn btn-primary'>Cancel</a>
</div>
</b-modal>
`
});
I'm expecting it to return a QR Code.
I have a ReactJS APP. The logic in the APP needs to make an http post request to nodejs uploading image api,
capturing the response from api give some errors and sometimes uploads, and then refreshed the browser instantly. My problem is capturing the http response from nodejs api asynchronously and returning it to the image/display list without a browser refresh.
When I try to upload more than 6MB to 46MB then a browser refresh must be occured.
--- ImageComponent.js
function EditImageSlider({ breadcrumb, pageName, setLoader, showToast }) {
const history = useHistory();
const list = useSelector((state) => state.imagecrop.list);
const detail = useSelector((state) => state.imagecrop.detail);
const row = useSelector((state) => state.imagecrop.row);
const imageCropWidth = useSelector((state) => state.imagecrop.imageCropWidth);
const imageCropHeight = useSelector((state) => state.imagecrop.imageCropHeight);
const croppedImage = useSelector((state) => state.imagecrop.croppedImage);
const Image = useSelector((state) => state.imagecrop.Image);
const ImageName = useSelector((state) => state.imagecrop.ImageName);
const errorMessage = useSelector((state) => state.imagecrop.errorMessage);
const umodalShow = useSelector((state) => state.imagecrop.umodalShow);
const cropSize = useSelector((state) => state.imagecrop.cropSize);
const IsDisabled = useSelector((state) => state.imagecrop.IsDisabled);
const [currentImage, setCurrentImage] = useState("");
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const singlefileSelectedHandler = async (e) => {
//debugger;
e.preventDefault();
//setIsDisabled(true);
dispatch(imageCropActions.setIsDisabled({ IsDisabled: true }));
content = "";
if (!e.target.files || e.target.files.length <= 0) {
return -1;
}
if (detail && detail.Content) {
content = detail.Content;
}
//let imageList = "";
const selectedImage = e.target.files[0];
let imageSizeInMBs = selectedImage.size ? selectedImage.size / 1024 / 1024 : 0;
if (selectedImage && imageSizeInMBs > 50) {
dispatch(imageCropActions.setIsDisabled({ IsDisabled: false }));
showToast("Information!", "Image size can't be greater than 8MB.");
return -1;
}
const filename =
selectedImage && selectedImage.name
? new Date().valueOf() +
"_" +
selectedImage.name.replace(/\\/g, "").replace(/ /g, "").replace(/'/g, "").replace(/"/g, "").replace(/`/g, "")
: "";
imageCropHeight ? parseInt(imageCropHeight) : 0 });
setCurrentImage(selectedImage);
const localconvertedImage = URL.createObjectURL(selectedImage);
dispatch(
imageCropActions.setImageAttributes({
Image: localconvertedImage,
ImageName: filename,
croppedImage: localconvertedImage,
show: true,
width: imageCropWidth ? parseInt(imageCropWidth) : 0,
height: imageCropHeight ? parseInt(imageCropHeight) : 0,
IsDisabled: false,
})
);
};
const onSaveImage = async (event) => {
//debugger;
event.preventDefault();
if (validate() < 0) {
return -1;
}
try {
let filename = ImageName ? ImageName : "";
if (currentImage) {
//debugger;
dispatch(sendImageData(filename, croppedAreaPixels, currentImage));
}
} catch (err) {
debugger;
dispatch(imageCropActions.setImage(""));
dispatch(imageCropActions.setImageName(""));
console.log(err);
}
};
return (
<>
<label className="form-label" htmlFor="customFile">
Upload image
</label>
<div className="custom-file">
<input type="file" className="custom-file-input" id="customFile" onChange={singlefileSelectedHandler} />
<label className="custom-file-label" htmlFor="customFile">
Choose file
</label>
</div>
<div className="form-row justify-content-end">
<Button className="btn btn-secondary" disabled={IsDisabled} onClick={onSaveImage }>
Save
</Button>
</div>
</>
);
}
--- ImageActions.js
export const sendImageData = (filename, croppedAreaPixels, cropImage) => {
return async (dispatch) => {
const sendRequest = async () => {
//debugger;
let uploadedImageUrl = "";
let uploadedImageName = "";
let uploadedServerPath = "";
let uploadurl = "";
const formData = new FormData();
formData.append("coord", JSON.stringify(croppedAreaPixels));
formData.append("image", cropImage);
let submitUrl = process.env.REACT_APP_SERVER_DOMAIN + `/uploaddetail`;
//debugger;
const responseWebApi = await axios.post(submitUrl, formData, {
timeout: 30000,
timeoutErrorMessage: "The request timeout has been occured during the Image Upload",
headers: {
Accept: "application/json",
"Content-Type": "multipart/form-data",
},
});
const jsonRes = responseWebApi ? responseWebApi.data : "";
if (jsonRes) {
return {
ImageName: jsonRes.imagename,
ImageServerPath: jsonRes.serverpath,
ImageFullUrl: jsonRes.fullurl,
ImageUrl: jsonRes.url,
};
}
};
try {
const returnData = await sendRequest();
dispatch(imageCropActions.updateCropImage({ newRow: returnData, show: false, IsDisabled: false }));
debugger;
return 0;
} catch (error) {
debugger;
}
};
};
The error I get here is Uncaught TypeError:
Browser Headers:
Request URL: http://localhost:8001/uploaddetail
Request Method: POST
Status Code: 200 OK
Remote Address: [::1]:8001
Referrer Policy: strict-origin-when-cross-origin
Browser Response tab:
Failed to load response data : No resource is given identifier found.
After that a browser refresh occurs. Any help is appreciated.
. I understand why I'm getting the error (because apiRes is out of scope), I just can't figure out how to do it right. Any help much appreciated!
-- PAckage.json
{
"name": "admin-panel",
"version": "0.1.0",
"private": true,
"dependencies": {
"#reduxjs/toolkit": "^1.7.2",
"#testing-library/jest-dom": "^5.12.0",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"axios": "^0.26.0",
"bootstrap": "^4.6.0",
"faker": "^5.5.3",
"node-sass": "^4.14.1",
"rangeslider-pure": "^0.4.11",
"react": "^17.0.2",
"react-bootstrap": "^1.6.1",
"react-bootstrap-sweetalert": "^5.2.0",
"react-data-table-component": "^6.11.7",
"react-dom": "^17.0.2",
"react-easy-crop": "^4.0.0",
"react-hook-form": "^7.12.2",
"react-icons": "^4.2.0",
"react-nestable": "^2.0.0",
"react-redux": "^7.2.6",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"styled-components": "^5.3.0",
"web-vitals": "^1.1.2",
"yup": "^0.32.9"
},
"scripts": {
"start": "set PORT=3001 &&react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
}
I have tried to create a full sample code example at
https://codesandbox.io/s/vigorous-heisenberg-vbdwo?file=/src/EditImageSlider.js
Is there any restriction in the react for uploading image file size ?
I found a link and image is not being uploaded there as well.
https://codepen.io/ccnokes/pen/wyBYOd
I have added more code in the sample code.
If anyone can see it then please
I am trying to trouble shoot/fix my nodejs upload image api:
My service is being stuck at somewhere.
My service is too simple, just uploading the image by resizing through sharp api in a directory and return the full path of that file.
When I select some image at first time then everything works fine and image upload successfully with a response
but When I try to crop that image after clicking on the image and try to save it (at second time) then nodejs service return following response.
I don't why it is being happened, I tried to debug the service code and It didn't stop at anywhere. Flow has been passed/executed successfully, I didn't catch any exception/error in code.
What can be the issue in it because it still displaying
> Blockquote failed to load response data. no resource with given identifier found
Problem area is in the code of onSaveImage when a server side call is being served/requested. I am using the plugin for image cropping is react-easy-crop. Browser is getting refresh/reload at this line of code
const jsonRes = await responseMain.json();
I am sharing my nodejs service code as well as reactjs code. please look into it.
Thank you.
-----------------package.json of nodejs
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-validator": "^6.12.0",
"handlebars": "^4.7.7",
"jsonwebtoken": "^8.5.1",
"mysql": "^2.18.1",
"nodemailer": "^6.6.1",
"nodemon": "^2.0.12",
"sharp": "^0.29.3"
},
"devDependencies": {},
"scripts": {
"start": "nodemon --inspect index.js",
"debug": "node --nolazy --inspect-brk=9229 index.js"
},
"license": "ISC"
}
------ index.js---------------------------NodeJs
const express = require("express");
const app = express();
const cors = require("cors");
var fs = require("fs");
const fsp = fs.promises;
var path = require("path");
const sharp = require("sharp");
var $pathContentBuilder = path.join(__dirname, "../", "/public/roughdata/uploads/");
var $urlpathContentBuilder = "/roughdata/uploads/"; // URL path
app.use(express.json({ limit: "20mb" }));
app.use(cors());
app.use(
express.urlencoded({
extended: true,
})
);
function processImage(image, metadata, filename, isResizeAllow) {
return new Promise((resolve, reject) => {
if (isResizeAllow && isResizeAllow === true) {
// 0.8 MB
return image
.resize({
width: Math.round(metadata.width / 2),
height: Math.round(metadata.height / 2),
fit: "cover",
})
.toBuffer((err, buf) => {
if (err) {
console.log("Error occured ", err);
return reject(err);
} else {
return resolve(buf.toString("base64"));
}
});
} else {
return image.toBuffer((err, buf) => {
if (err) {
console.log("Error occured ", err);
return reject(err);
} else {
return resolve(buf.toString("base64"));
}
});
}
});
}
app.post("/uploaddetail", async (req, res, next) => {
const base64Data = req.body.image;
const filename = req.body.filename;
let imageResizeResult = "";
try {
var inputbuf = Buffer.from(base64Data, "base64"); // Ta-da
const image = await sharp(inputbuf);
let metadata = await image.metadata();
let convertedbase64Data = "";
convertedbase64Data = await processImage(image, metadata, filename, false);
await fsp.writeFile($pathContentBuilder + filename, convertedbase64Data, "base64");
let resultResponse = JSON.stringify({
success: true,
fullurl: `${$urlpathContentBuilder}${filename}`,
url: `${filename}`,
imagename: `${filename}`,
serverpath: `${$urlpathContentBuilder}`,
});
//res.type("json");
res.status(200).json(resultResponse);
//res.end();
//next();
} catch (e) {
console.log(e);
const error = new HttpError(e, 404);
return next(error);
}
});
and following is my reactjs code.
import React, { useState, useEffect, useCallback } from "react";
import { withRouter, useParams, useHistory } from "react-router-dom";
import { Card, Button } from "react-bootstrap";
import Page from "./Page";
import TitleBar from "./TitleBar";
import SingleGalleryRow from "./SingleGalleryRow";
import CenteredPopup from "../common/CenteredPopup";
import { MdDelete, MdOutlineCrop, MdOutlineCircle } from "react-icons/md";
import Cropper from "react-easy-crop";
import getCroppedImg from "../shared/util/cropImage";
import b64toBlob from "../shared/util/blobToImage";
function EditImage({ breadcrumb, pageName, setLoader, showToast }) {
const [list, setList] = useState([]);
const history = useHistory();
const [umodalShow, setUModalShow] = useState(false);
const [row, setRow] = useState({
ImageName: "",
ImageServerPath: "",
ImageFullUrl: "",
ImageUrl: "",
SiteId: 1,
CreatedBy: 1,
CreatedOn: "",
Id: 0,
Name: "",
IsDeleted: 0,
IsVisible: 1,
ModifiedBy: 1,
ModifiedOn: "",
});
const [isSubmitClicked, setIsSubmitClicked] = useState(false);
const [IsDisabled, setIsDisabled] = useState(false);
const [nameError, setNameError] = useState("");
const [validated, setValidated] = useState(0);
const [ImageName, setImageName] = useState("");
const [base64SelectedImage, setBase64SelectedImage] = useState("");
const { id } = useParams();
let content = "";
const [detail, setDetail] = useState({
Content: "",
CreatedBy: 1,
CreatedOn: "",
Id: 0,
IsDeleted: 0,
IsVisible: 1,
ModifiedBy: 1,
ModifiedOn: "",
Name: "",
SiteId: 1,
});
useEffect(() => {
let abortController = new AbortController();
let mounted = true;
const fetchData = async () => {
try {
setLoader(true);
let apiUrl = process.env.REACT_APP_IMAGEGALLERYAPI + "/getbyId/" + id;
const response = await fetch(apiUrl, {
signal: abortController.signal,
});
const json = await response.json();
const resultPages = json ? json.list : "";
if (resultPages && resultPages.length > 0) {
//debugger;
let firstRow = resultPages[0];
let isEnabled = false;
if (firstRow.IsVisible === 1 || firstRow.IsVisible === true) {
isEnabled = true;
}
let newDetailPage = {
Id: firstRow.Id,
Name: firstRow.Name,
Content: firstRow.Content
};
if (mounted) {
setDetail(newDetailPage);
}
let itemRows = [];
for (let item of resultPages) {
let row = {
Id: item.DetailId,
ImageSliderId: item.ImageSliderId,
ImageName: item.ImageName,
ImageFullUrl: item.ImageFullUrl,
};
if (item.ImageFullUrl) {
itemRows.push(row);
}
}
if (itemRows && itemRows.length > 0) {
if (mounted) {
setList(itemRows);
}
}
}
setLoader(false);
//abortController = null;
} catch (err) {
setLoader(false);
if (err.name === "AbortError") {
// Handling error thrown by aborting request
}
}
};
fetchData();
// Side-effect logic...
return () => {
// Side-effect cleanup
mounted = false;
abortController.abort();
console.log("unmounting...");
};
}, []);
const [imageCropWidth, setImageCropWidth] = useState(100);
const [imageCropHeight, setImageCropHeight] = useState(100);
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [aspect, setAspect] = useState(1);
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const [cropSize, setCropSize] = useState({ width: 100, height: 100 });
const [Image, setImage] = useState("");
const [rotation, setRotation] = useState(0);
const [cropShape, setCropShape] = useState("rect");
const onSaveImage = useCallback(
async (e) => {
e.preventDefault();
if (validate() < 0) {
return -1;
}
try {
let filename = "";
let base64Image = "";
let blobUrl = "";
debugger;
const cropImage = await getCroppedImg(Image, croppedAreaPixels, rotation);
setCroppedImage(cropImage);
setImage(cropImage);
base64Image = cropImage ? cropImage.replace(/^data:image\/(png|jpeg);base64,/, "") : "";
const contentType = "image/jpeg";
if (cropImage) {
debugger;
setRow((prevState) => {
return {
...prevState,
["ImageFullUrl"]: cropImage,
["ImageName"]: ImageName ? ImageName : "",
};
});
filename = ImageName ? ImageName : "";
const settings = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
filename: filename,
image: base64Image,
}),
};
setLoader(true);
let submitUrl = process.env.REACT_APP_SERVER_DOMAIN + `/uploaddetail`;
const responseMain = await fetch(submitUrl, settings);
const jsonRes = await responseMain.json();
if (jsonRes) {
let convertedJson = jsonRes;
if (convertedJson) {
setLoader(false);
const uploadedImageUrl = convertedJson.fullurl; // get saved image url
const uploadedImageName = convertedJson.imagename;
const uploadedServerPath = convertedJson.serverpath;
const uploadurl = convertedJson.url;
setImageName(convertedJson.imagename);
setRow((prevState) => {
return {
...prevState,
["ImageName"]: uploadedImageName,
["ImageServerPath"]: uploadedServerPath,
["ImageFullUrl"]: uploadedImageUrl,
["ImageUrl"]: uploadurl,
};
});
if (uploadedImageUrl) {
setIsDisabled(false);
}
setUModalShow(false);
setDetail((prevState) => {
return {
...prevState,
["Content"]: content,
};
});
}
}
}
} catch (err) {
console.log(err);
showToast("Error!", "Image couldn't be saved");
} finally {
}
},
[croppedAreaPixels, rotation]
);
const showImageForCrop = useCallback(
async (e) => {
debugger;
let localSrc = e.ImageFullUrl; //e.target.src;
setImage(localSrc);
setUModalShow(true);
setImageName(e.ImageName);
setCropSize({ width: imageCropWidth ? parseInt(imageCropWidth) : 0, height: imageCropHeight ? parseInt(imageCropHeight) : 0 });
if (list && list.length > 0) {
const selectedIndex = list.findIndex((item) => item.Id === e.Id);
if (selectedIndex > -1) {
setRow(list[selectedIndex]);
}
}
},
[row]
);
const singlefileSelectedHandler = async (e) => {
//debugger;
e.preventDefault();
setIsDisabled(true);
content = "";
if (!e.target.files || e.target.files.length <= 0) {
return -1;
}
if (detail && detail.Content) {
content = detail.Content;
}
//let imageList = "";
const selectedImage = e.target.files[0];
let imageSizeInMBs = selectedImage.size ? selectedImage.size / 1024 / 1024 : 0;
if (selectedImage && imageSizeInMBs > 8) {
setIsDisabled(false);
setRow((prevState) => {
return {
...prevState,
["ImageName"]: "",
["ImageServerPath"]: "",
["ImageFullUrl"]: "",
["ImageUrl"]: "",
};
});
showToast("Information!", "Image size can't be greater than 8MB.");
return -1;
}
const filename =
selectedImage && selectedImage.name
? new Date().valueOf() +
"_" +
selectedImage.name.replace(/\\/g, "").replace(/ /g, "").replace(/'/g, "").replace(/"/g, "").replace(/`/g, "")
: "";
setUModalShow(false);
setCropSize({ width: imageCropWidth ? parseInt(imageCropWidth) : 0, height: imageCropHeight ? parseInt(imageCropHeight) : 0 });
setImageName(filename);
setUModalShow(true);
let convertedImageFile = await convertImage(selectedImage);
setBase64SelectedImage(convertedImageFile);
};
async function convertImage(file) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
e.preventDefault();
let base64 = e.target.result;
base64 = base64.replace(/^data:image\/(png|jpeg);base64,/, "");
setImage(reader.result);
resolve(base64);
//resolve(reader.result);
};
reader.onerror = function (error) {
console.log("Error: ", error);
reject(error);
};
});
}
const onAddSide = (e) => {
//debugger;
let newImageList = [...list];
if (row.Id && row.Id > 0) {
if (newImageList && newImageList.length > 0) {
const selectedIndex = newImageList.findIndex((item) => item.Id === row.Id);
if (selectedIndex > -1) {
newImageList[selectedIndex] = row;
}
}
} else {
row.Id = Math.max.apply(
Math,
newImageList.map(function (o) {
return o.Id + 1;
})
);
if (!row.Id || (row.Id && row.Id === 0) || row.Id === -Infinity) {
row.Id = 1;
}
newImageList.push(row);
}
setList(newImageList);
};
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
//debugger;
setCroppedAreaPixels(croppedAreaPixels);
}, []);
const onClose = useCallback(() => {
setCroppedImage(null);
}, []);
const onCropperZoomChange = (e) => {
if (e && e.currentTarget && e.currentTarget.value) {
let lZoomValue = e.currentTarget.value;
if (lZoomValue && lZoomValue < 0.4) {
//setZoom(0.28);
setZoom(0.4);
} else if (lZoomValue && lZoomValue > 1) {
setZoom(1);
} else {
setZoom(lZoomValue);
}
}
};
return (
<Page breadcrumb={breadcrumb} pageName={pageName} fluid>
<form noValidate validated={validated} onSubmit={HandleSaveMenu} className="user-form">
<Card>
<Card.Header>
<TitleBar title="Edit Gallery" />
</Card.Header>
<Card.Body>
<div className="form-row">
<div className="form-group col-md-2">
<label className="form-label" htmlFor="ImageCropWidth">
Width
</label>
<input
name="ImageCropWidth"
id="ImageCropWidth"
className={`form-control`}
value={imageCropWidth}
onChange={(e) => setImageCropWidth(e.target.value)}
/>
</div>
<div className="form-group col-md-2">
<label className="form-label" htmlFor="ImageCropWidth">
Height
</label>
<input
name="ImageCropWidth"
id="ImageCropWidth"
className={`form-control`}
value={imageCropHeight}
onChange={(e) => setImageCropHeight(e.target.value)}
/>
</div>
</div>
<SingleGalleryRow
data={row}
setRow={setRow}
onUpload={singlefileSelectedHandler}
onAddSide={onAddSide}
IsDisabled={IsDisabled}
/>
<ul className="slide-list">
{list &&
list.map(function (item, i) {
//debugger;
return (
<li key={i}>
<div className="slide-row">
<div className="img-holder">
<img
className="thumbnail"
src={item.ImageFullUrl}
alt={item.ImageName}
onClick={() => showImageForCrop(item)}
/>
</div>
</div>
</li>
);
})}
</ul>
</Card.Body>
<Card.Footer>
<div className="btn-holder text-right">
<Button type="submit" variant="primary" disabled={isSubmitClicked}>
Save
</Button>
</div>
</Card.Footer>
</Card>
</form>
<CenteredPopup
show={umodalShow}
onHide={() => setUModalShow(false)}
title="Crop Image"
content=""
closetext="Close"
savetext="Apply"
onSaveChanges={onSaveImage}
>
<div className="cropimage-container">
<div className="cropimage-tools">
<span className="cropimage-icons" onClick={(e) => setCropShape("rect")}>
<MdOutlineCrop />
<span className="cropimage-text">Crop</span>
</span>
<span className="cropimage-icons" onClick={(e) => setCropShape("round")}>
<MdOutlineCircle />
<span className="cropimage-text">Circle</span>
</span>
</div>
<div className="crop-container">
<Cropper
image={Image}
crop={crop}
cropSize={cropSize}
cropShape={cropShape}
zoom={zoom || 1}
showGrid={true}
zoomWithScroll={false}
objectFit="horizontal-cover"
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={onCropperZoomChange}
/>
</div>
</div>
<div className="form-row ic_rangeslider">
<div className="form-group col-md-12">
<label className="form-label" htmlFor="ZoomBtn">
{zoom || 1}
</label>
<span className="range-slider__wrap">
<input
id="zoomrangeid"
type="range"
className="slider range-slider range-slider--light"
value={zoom || 1}
min={0.4}
max={1}
step={0.1}
aria-labelledby="Zoom"
onChange={onCropperZoomChange}
/>
</span>
</div>
</div>
</CenteredPopup>
</Page>
);
}
export default withRouter(EditImage);
I am trying for quite some time to stream a video from MongoDB. Read tons of api DOCs and examples just can't get it to work
This is my front-end video Handler :
import { useState, useEffect } from "react";
import ReactPlayer from "react-player";
const CatVideos = () => {
const [videoList, setvideoList] = useState(null);
useEffect(() => {
const getVideos=async ()=> {
const response = await fetch('http://localhost:8000/cat-videos/videos');
const data = await response.json();
setvideoList(data);
console.log(data);
}
getVideos();
}, [])
return (
<div>
<h1>Cat videos</h1>
{videoList!=null && videoList.map((video)=>{
return <ReactPlayer key={video._id} url={'http://localhost:8000/cat-videos/videos/'+video._id}/>
})}
</div>
);
};
export default CatVideos;
Backend stream function :
exports.getVideoStream = (req, res, next) => {
var id = req.params.id;
let gfs = Grid(conn.db, mongoose.mongo);
gfs.collection("videos");
gfs.files
.findOne({
_id: mongoose.Types.ObjectId(id),
})
.then((result) => {
const file = result;
if (!file) {
return res.status(404).send({
err: "Unavailable.",
});
}
if (req.headers["range"]) {
var parts = req.headers["range"].replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : file.length - 1;
var chunksize = end - start + 1;
res.header("Accept-Ranges", "bytes");
res.header("Content-Length", chunksize);
res.header(
"Content-Range",
"bytes " + start + "-" + end + "/" + result.length
);
console.log(result.contentType)
res.header("Content-Type", result.contentType);
gfs.createReadStream({
_id: result._id,
range: {
startPos: start,
endPos: end,
},
}).readStream.pipe(res);
} else {
console.log("#################before####################");
res.header("Content-Length", result.length);
res.header("Content-Type", result.contentType);
console.log(result._id);
gfs
.createReadStream({
_id: result._id,
})
.pipe(res);
}
})
.catch((err) => {
res.json(err);
});
};
I do get a response from this function , and it appears that the "Content-Type" remains unchanged.
HTTP/1.1 206 Partial Content
X-Powered-By: Express
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Date: Thu, 23 Dec 2021 19:38:25 GMT
Content-Type: application/json; charset=utf-8
ETag: W/"2-vyGp6PvFo4RvsFtPoIWeCReyIC8"
Content-Range: bytes 0-1/2
Content-Length: 2
Backend dependencies:
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.1",
"cors": "^2.8.5",
"ejs": "^3.1.6",
"express": "^4.17.2",
"gridfs-stream": "^1.1.1",
"method-override": "^3.0.0",
"mongodb": "^4.2.2",
"mongoose": "^6.1.2",
"multer": "^1.4.4",
"multer-gridfs-storage": "^5.0.2"
}
Frontend dependencies:
"axios": "^0.24.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-player": "^2.9.0",
"react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"
I managed to fix the issue. Note that GridFSBucket has a default bucket name.
Going over the API docs it says it appends the bucket name ".files".
My issues were that I did not define it and start end inside download stream were not defined correctly causing an error.
You may use it as well to stream Images,videos just change the content type on the frontend. Pretty generic stream.
exports.getVideoStream = (req, res, next) => {
mongodb.MongoClient.connect(url, function (error, client) {
if (error) {
res.status(500).json(error);
return;
}
// Check for range headers to find our start time
const range = req.headers.range;
if (!range) {
res.status(400).send("Requires Range header");
}
const db = client.db('videos');
// GridFS Collection
console.log(req.params.id);
db.collection('videos.files').findOne({_id:mongoose.Types.ObjectId(req.params.id)}, (err, video) => {
if (!video) {
res.status(404).send("No video uploaded!");
return;
}
// Create response headers
const videoSize = video.length;
const start = Number(range.replace(/\D/g, ""));
const end = videoSize - 1;
const contentLength = end - start + 1;
const headers = {
"Content-Range": `bytes ${start}-${end}/${videoSize}`,
"Accept-Ranges": "bytes",
"Content-Length": contentLength,
"Content-Type": "video/mp4",
};
// HTTP Status 206 for Partial Content
res.writeHead(206, headers);
// Get the bucket and download stream from GridFS
const bucket = new mongodb.GridFSBucket(db,{bucketName:"videos"});
const downloadStream = bucket.openDownloadStream(video._id, {
start:start,
end:end
});
// Finally pipe video to response
console.log(streamCounter," start ",start," end ",end)
streamCounter++;
downloadStream.pipe(res);
});
});
};
I am trying to build collaborative canvas with socket-io and with react-canvas-draw
, but when I take a low opacity on brush-color, it just draws multiple circles on other screen, as shown here :
when I draw on one screen slowly, it just over draws on same location or something with many many circles,
Drawing.js
import DrawableCanvas from "react-canvas-draw";
import { Button } from "reactstrap";
import {SocketContext} from './context/socket';
const { Component } = require("react");
var canvas, context;
/* VARIABLES */
var drawing = false;
// determines the current x or y position
var current = {x: 0, y: 0};
export class Drawing extends Component {
// this.context refers to socket.io making it available for all components
static contextType = SocketContext;
constructor(props) {
super(props);
this.state = {
canvasWidth: 1400,
canvasHeight: 1400,
catenaryColor: "rgba(0,0,0,0.68)",
brushColor: "rgba(0,0,0,0.68)",
brushRadius: 1,
lazyRadius: 0,
clear: false,
hideInterface: false,
onChange: null,
loadTimeOffset: 5,
backgroundColor: "#FFF",
hideGrid: false,
disabled: false,
saveData: "",
immediateLoading: true,
usingType: "draw",
};
}
componentDidMount() {
canvas = document.getElementsByName("canvas")[0].children[0].children[1];
context = canvas.getContext("2d");
this.context.on('drawing', data => this.onDrawingEvent(data))
}
onDrawingEvent(data) {
this.drawLine(
data.x0,
data.y0,
data.x1,
data.y1,
data.color,
data.brushRadius,
false,
true,
);
}
drawLine(x0, y0, x1, y1, color,brushRadius, emit,duplicate) {
// Gets the offset so it fits to any window size
var canvasTopPosition = document.getElementsByName("canvas")[0].offsetTop;
var canvasLeftPosition = document.getElementsByName("canvas")[0].offsetLeft;
// If Duplicate is false, it will draw on both monitors and cause duplication.
if(duplicate)
{
context.beginPath();
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.strokeStyle = color;
context.lineWidth = brushRadius * 2;
context.lineCap = 'round';
context.stroke();
context.closePath();
}
if (!emit) {
return;
}
this.context.emit('drawing', {
x0: x0 - canvasLeftPosition,
y0: y0 - canvasTopPosition,
x1: x1 - canvasLeftPosition,
y1: y1 - canvasTopPosition,
color: color,
brushRadius : this.state.brushRadius,
type: this.state.usingType,
globalCompositeOperation: context.globalCompositeOperation,
message_type: "draw"
});
}
onMouseDown = (e) => {
drawing = true;
current.x = e.clientX || e.touches[0].clientX;
current.y = e.clientY || e.touches[0].clientY;
};
onMouseUp = (e) => {
if (!drawing) {
return;
}
drawing = false;
this.drawLine(
current.x,
current.y,
e.clientX,
e.clientY,
this.state.brushColor,
this.state.brushRadius,
true,
false,
);
};
onMouseMove = (e) => {
if (!drawing) {
return;
}
this.drawLine(current.x, current.y, e.clientX || e.touches[0].clientX, e.clientY || e.touches[0].clientY,this.state.brushColor,this.state.brushRadius,true,false);
current.x = e.clientX || e.touches[0].clientX;
current.y = e.clientY || e.touches[0].clientY;
};
render() {
return (
<div
name="canvas"
onMouseDown={this.onMouseDown}
onMouseUp={this.onMouseUp}
onMouseMove={this.onMouseMove}
onMouseLeave={() => drawing = false} // Determines if the mouse is outside the div
>
<DrawableCanvas
/>
</div>
);
}
}
export default Drawing;
server.js
const express = require('express');
const http = require("http");
const port = process.env.PORT || 5000;
const cors = require("cors");
const app = express();
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server, {
cors: true,
});
app.use(cors());
io.on('connection', onConnection);
function onConnection(socket){
socket.on('drawing', (data) => socket.broadcast.emit('drawing', data));
}
server.listen(port, () => console.log('server is running on port 5000'));
socket.js
import io from "socket.io-client";
import React from 'react';
const SOCKET_URL = "http://localhost:5000";
export const socket = io.connect(SOCKET_URL, { secure: true });
export const SocketContext = React.createContext(socket);