Im trying to create a pdf based on a html, which has 3 images. The html can be seen and there is a button that downloads the html as a pdf file, but only the first image is shown on the downloaded pdf. This is the function that downloads the file (im using jsPDF library):
const savePDF = () => {
const doc = new jsPDF('p', 'pt', 'a4');
const margin = 10;
const certificate = document.querySelector('#doc');
const scale = (doc.internal.pageSize.width - margin * 2) / certificate.offsetWidth;
doc.internal.write(0, 'Tw');
doc.html(certificate, {
x: margin,
y: margin,
html2canvas: {
scale: scale
},
callback: function(doc) {
doc.output('save', {filename: 'pdfFile.pdf'});
}
})
}
Everything else is allright, the text, the tables and the first image of the doc. But for some reason the second and third image arent shown on the downloaded pdf file. I get console message: "Error loading image". All these images are on the public folder of the project, locally. Im working on NextJS.
Btw, all images are set the same way:
<Image src='/image1.png' alt='' width={500} height={500}/>
I have been using compress.js for single image upload. But, now i want to use this for multiple image uploads.
What i want to achieve is to select multiple image from html input element and then compress it using this library and also preview those compressed images in dynamically generated tag.
like this:-
<img id="preview0">
<img id="preview1">
<img id="preview2">
....depending on number of image selected.
This is how i was using it for single image upload
<input type="file" accept="image/*" id="image">
<img id="preview">
const options = {
targetSize: 0.2,
quality: 0.75,
maxWidth: 800,
maxHeight: 600
}
const compress = new Compress(options)
const upload = document.getElementById("image")
upload.addEventListener(
"change",
(evt) => {
const files = [...evt.target.files]
compress.compress(files).then((conversions) => {
// Conversions is an array of objects like { photo, info }.
// 'photo' has the photo data while 'info' contains metadata
// about that particular image compression (e.g. time taken).
const { photo, info } = conversions[0]
console.log({ photo, info })
// was using this to append to the form data
newblob = photo.data;
// Create an object URL which points to the photo Blob data
const objectUrl = URL.createObjectURL(photo.data)
// Set the preview img src to the object URL and wait for it to load
Compress.loadImageElement(preview, objectUrl).then(() => {
// Revoke the object URL to free up memory
URL.revokeObjectURL(objectUrl)
})
})
},
false
)
i have been trying to achieve it from past 2 days.
i tried to run this in a for loop
<input type="file" accept="image/*" multiple id="image">
<div id="" class="col previewdiv"></div>
$(function() {
var imgPreviewUpld = function(input, divId) {
if (input.files) {
var numberOfImages = input.files.length;
for (i = 0; i < numberOfImages; i++) {
$($.parseHTML('<img>')).attr({id : "preview"+i, class:"img-fluid"}).css({"max-height":"200px","max-width":"300px"}).appendTo(divId);
const options = {
targetSize: 0.2,
quality: 0.75,
maxWidth: 800,
maxHeight: 600
}
const compress = new Compress(options)
const files = [...input.files]
// const files = [evt.files];
compress.compress(files).then((conversions) => {
// Conversions is an array of objects like { photo, info }.
// 'photo' has the photo data while 'info' contains metadata
// about that particular image compression (e.g. time taken).
const { photo, info } = conversions[0]
console.log({ photo, info })
//to append to the form data
newblob+i = photo.data;
// Create an object URL which points to the photo Blob data
const objectUrl = URL.createObjectURL(photo.data)
// Set the preview img src to the object URL and wait for it to load
Compress.loadImageElement(preview+i, objectUrl).then(() => {
// Revoke the object URL to free up memory
// URL.revokeObjectURL(objectUrl)
})
})
}
}
};
$('#image').on('change', function(evt) {
imgPreviewUpld(this, 'div.previewdiv');
});
});
Please guys help me. I am a beginner in javascript world but i want to do this for one of my own project.
Thank you
I need to open gallery to select image in my android app. Here's my code and it works fine.
But by using PHOTOLIBRARY, it will open image from the device's photo libraryand by using SAVEDPHOTOALBUM will chose image only from the device's Camera Roll album - as i can read here https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/
I want to open my app specific folder instead of gallery folder (ex: i create a folder called 'MYAPPIMAGES' contains images from my app and i want to show only images from 'MYAPPIMAGES' folder, not all of images in gallery). How can I achieve this behaviour? Is there any chance to do that? Thanks in Advance.
var picOptions = {
destinationType: navigator.camera.DestinationType.FILE_URI,
quality: 80,
targetWidth: 800,
targetHeight: 800,
maximumImagesCount: 5,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
};
$cordovaImagePicker.getPictures(picOptions).then(function (imageURI) {
for (var i = 0; i < imageURI.length; i++) {
var str = imageURI[i];
var n = str.lastIndexOf('/');
var splitStr = str.substring(n+1);
var dir = str.substring(0,n+1);
console.log(imageURI[i]+' '+splitStr+' '+dir);
convert64(imageURI[i], splitStr, dir);
}
The only values allowed in that options are:
Camera.PictureSourceType : enum
Defines the output format of Camera.getPicture call. Note: On iOS passing PictureSourceType.PHOTOLIBRARY or PictureSourceType.SAVEDPHOTOALBUM along with DestinationType.NATIVE_URI will disable any image modifications (resize, quality change, cropping, etc.) due to implementation specific.
Kind: static enum property of Camera
Properties
Name Type Default Description
PHOTOLIBRARY number 0 Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android)
CAMERA number 1 Take picture from camera
SAVEDPHOTOALBUM number 2 Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android)
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/#module_camera.CameraOptions
This will aslo solve your problem if your image in gallery are not showing instead they might showing a 404 type bitmap in midle.
please add all the tags that are in my code with your image because there must some meta data in order to show image in gallery.
NOTE:
This is valid for Android 9 and below ,For Android Q, you can use this tag with android Q to store you img in specific folder in gallery values.put(MediaStore.Images.Media.RELATIVE_PATH, "yourfoldernaeme");
String resultPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES)+
getString(R.string.directory) + System.currentTimeMillis() + ".jpg";
new File(resultPath).getParentFile().mkdir();
try {
OutputStream fileOutputStream = new FileOutputStream(resultPath);
savedBitmap.compress(CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e2) {
e2.printStackTrace();
}
savedBitmap.recycle();
File file = new File(resultPath);
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "Photo");
values.put(MediaStore.Images.Media.DESCRIPTION, "Edited");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis ());
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
values.put(MediaStore.Images.ImageColumns.BUCKET_ID, file.toString().toLowerCase(Locale.US).hashCode());
values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, file.getName().toLowerCase(Locale.US));
values.put("_data", resultPath);
ContentResolver cr = getContentResolver();
cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
return resultPath;
I want the user on my site to be able to crop an image that they will use as a profile picture. I then want to store this image in an uploads folder on my server.
I've done this using php and the JCrop plugin, but I've recently started to change the framework of my site to use Node JS.
This is how I allowed the user to crop an image before using JCrop:
$("#previewSub").Jcrop({
onChange: showPreview,
onSelect: showPreview,
aspectRatio: 1,
setSelect: [0,imgwidth+180,0,0],
minSize: [90,90],
addClass: 'jcrop-light'
}, function () {
JcropAPI = this;
});
and I would use php to store it in a folder:
<?php
$targ_w = $targ_h = 300;
$jpeg_quality = 90;
$img_r = imagecreatefromjpeg($_FILES['afile']['tmp_name']);
$dst_r = ImageCreateTrueColor( $targ_w, $targ_h );
imagecopyresampled($dst_r,$img_r,0,0,$_POST['x'],$_POST['y'],
$targ_w,$targ_h,$_POST['w'],$_POST['h']);
header("Content-type: image/jpeg");
imagejpeg($dst_r,'uploads/sample3.jpg', $jpeg_quality);
?>
Is there an equivalent plugin to JCrop, as shown above, using Node JS? There are probably multiple ones, if there are, what ones would you recommend? Any simple examples are appreciated too.
EDIT
Because the question is not getting any answers, perhaps it is possible to to keep the JCrop code above, and maybe change my php code to Node JS. If this is possible, could someone show me how to translate my php code, what would would be the equivalent to php above?
I am very new to Node, so I'm having a difficult time finding the equivalent functions and what not.
You could send the raw image (original user input file) and the cropping paramenters result of JCrop.
Send the image enconded in base64 (string), when received by the server store it as a Buffer :
var img = new Buffer(img_string, 'base64');
ImageMagick Doc : http://www.imagemagick.org/Usage/files/#inline
(inline : working with base64)
Then the server has the image in a buffer and the cropping parameters.
From there you could use something like :
https://github.com/aheckmann/gm ...or...
https://github.com/rsms/node-imagemagick
to cast the modifications to the buffer image and then store the result in the file system.
You have other options, like manipulating it client-side and sending the encoded image result of the cropping.
EDIT : First try to read & encode the image when the user uses the input :
$('body').on("change", "input#selectImage", function(){readImage(this);});
function readImage(input) {
if ( input.files && input.files[0] ) {
var FR = new FileReader();
FR.onload = function(e) {
console.log(e.target.result);
// Display in <img> using the b64 string as src
$('#uploadPreview').attr( "src", e.target.result );
// Send the encoded image to the server
socket.emit('upload_pic', e.target.result);
};
FR.readAsDataURL( input.files[0] );
}
}
Then when received at the server use the Buffer as mentioned above
var matches = img.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/), response = {};
if (matches.length !== 3) {/*invalid string!*/}
else{
var filename = 'filename';
var file_ext = '.png';
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
var saveFileAs = 'storage-directory/'+ filename + file_ext;
fs.unlink(saveFileAs, function() {
fs.writeFile(saveFileAs, response.data, function(err) {if(err) { /* error saving image */}});
});
}
I would personally send the encoded image once it has been edited client-side.
The server simply validates and saves the file, let the client do the extra work.
As promised, here is how I used darkroom.js with one of my Express projects.
//Location to store the image
var multerUploads = multer({ dest: './uploads/' });
I upload the image first, and then allow the user to crop it. This is because, I would like to keep the original image hence, the upload jade below:
form(method='post', action='/user/image/submit', enctype='multipart/form-data')
input(type='hidden', name='refNumber', value='#{refNumber}')
input(type='file', name='photograph' accept='image/jpeg,image/png')
br
input(type='submit', value='Upload image', data-role='button')
Here is the form I use to crop the image
//- figure needed for darkroom.js
figure(class='image-container', id='imageContainer')
//specify source from where it should load the uploaded image
img(class='targetImg img-responsive', src='/user/image/view/#{photoName}', id='target')
form(name='croppedImageForm', method='post', enctype='multipart/form-data', id='croppedImageForm')
input(type='hidden', name='refNumber', id='refNumber', value='#{refNumber}')
input(type='hidden', id='encodedImageValue', name='croppedImage')
br
input(type='submit', value='Upload Cropped Image', id='submitCroppedImage' data-role='button')
The darkroom.js is attached to the figure element using this piece of javascript.
new Darkroom('#target', {
// Canvas initialization size
minWidth: 160,
minHeight: 160,
maxWidth: 900,
maxHeight: 900,
});
});
Once you follow the STEP 1, STEP 2 and finally STEP 3 the base64 value of the cropped region is stored in under figure element see the console log shown in the screenshot below:
I then have a piece of javascript that is triggered when the Upload Cropped Image is clicked and it then copy/paste the base64 value of the img from figure into the input element with id encodedImageValue and it then submit it to the server. The javascript function is as follow:
$("#submitCroppedImage").click(function() {
var img = $('#imageContainer img');
var imgSrc = img.attr('src');
if(imgSrc !== undefined && imgSrc.indexOf('base64') > 0) {
$('#encodedImageValue').val(img.attr('src'));
$.ajax({
type: "POST",
url: "/user/image/cropped/submit",
data: $('#croppedImageForm').serialize(),
success: function(res, status, xhr) {
alert('The CROPPED image is UPLOADED.');
},
error: function(xhr, err) {
console.log('There was some error.');
}
});
} else {
alert('Please follow the steps correctly.');
}
});
Here is a screenshot of POST request with base64 field as its body
The post request is mapped to the following route handler in Express app:
router.post('/user/image/cropped/submit',
multerUploads,
function(req, res) {
var photoName = null;
var refNumber = req.body.refNumber;
var base64Data = req.body.croppedImage.replace(/^data:image\/png;base64,/, "");
fs.writeFile("./uploads/cropped-" + 'profile_image.png', base64Data, 'base64',
function(err) {
logger.info ("Saving image to disk ...");
res.status(200).send();
});
});
I have the following .js files relating to awesome Fabric.js and darkroom.js
script(src='/static/js/jquery.min.js')
script(src='/static/js/bootstrap.min.js')
//get the js files from darkroom.js github
script(src='/static/js/fabric.js')
script(src='/static/js/darkroom.js')
script(src='/static/js/plugins/darkroom.crop.js')
script(src='/static/js/plugins/darkroom.history.js')
script(src='/static/js/plugins/darkroom.save.js')
link(href='/static/css/darkroom.min.css', rel='stylesheet')
link(href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css', rel='stylesheet')
//get this from darkroom.js github
link(href='/static/css/page.css', rel='stylesheet')
Lastly, also copy the svg icons for selecting, cropping, saving, etc (from darkroo.js github page).
I'm using Phonegap's getPicture() method to save the File URI to an image, which I then try to display in an img element, but can't. Here's more detail.
I have a view with the following image element: <img id='myImage' ng-src="{{imageSrc}}" style='width:320px;display:block'/>
When I push a button in the view it calls the getPhoto() method in the view's controllers. Here's the code for the controller:
.controller('captureController',function($scope,$rootScope,$state,$document){
$scope.getPhoto = function() {
navigator.camera.getPicture(
captureSuccess,
captureError,
{
quality:5,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.PNG
}
);
}
function captureSuccess(imageURI) {
var image = document.getElementById('myImage');
$rootScope.imageSrc=imageURI
$rootScope.$apply()
alert($rootScope.imageSrc)
}
function captureError(error) {
var msg = 'An error occurred during capture: ' + error.code;
alert('there was an error')
}
})
When I take a picture, the resulting alert returns the path to the photo (file:///var/mobile/Applications//tmp/cdv_photo_069.png), but the photo doesn't appear in the image element.
I've verified that photos are in the phone's tmp directory,and I've also tried replacing the image element's ng-src attribute with src="file:///....cdv_photo.png". The image element is still not rendering the picture.
Any advice would be greatly appreciated.