Angular/Phonegap App: Cannot Display Image Using File URI - javascript

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.

Related

Adding base64 encoded PNG to PDF is not working

I'm trying to embedd an image into a PDF with jsPDF. For some reason this is not working . This is the Code when I create my PDF:
exportPDF () {
const doc = new jsPDF('p', 'pt')
var footer = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAC...'
var header = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...'
/* Some other stuff */
doc.addImage(this.output, 'PNG', 400, 400, 500, 500) #This does not work
doc.addImage(header, 'PNG', 0, 0, 600, 139.86) #For some reason these images work
doc.addImage(footer, 'PNG', 0, 800, 600, 54.68)
/* Some other stuff */
doc.save('Containertreppen Teileliste.pdf')
}
The Variable output is passed from another page and therefore not created in the method (I'm using vuejs). In this Variable the Screenshot of a Babylonjs Scene is stored, encoded in base64.
This is the Code when a take the Screenshot:
printDiv() {
this.scene.render();
const self = this
const options = {
type: "dataURL",
};
this.$html2canvas(document.getElementById("renderCanvas"), options).then(function(canvas){
self.output = canvas
})
},
I'm able to display the screenshot in an HTML-element and I can download it as a normal png but for some reason when I try to add it to my PDF the following error occurs in my console:
Error in v-on handler: "Error: Supplied Data is not a valid base64-String jsPDF.convertStringToImageData"
I also tried to put the String as src for an HTML-image-element but it changed nothing.
This is the beginning of the Variable output:
"data:image/png;base64,iVBORw..."
Can someone help me with this?

Cordova App : Image not showing

In my app I have a functionality of clicking an image from camera plugin and then navigate to a different view and show the image there. I am saving the dataurl of the image in localStorage and then in the other view I am calling the getItem method to get the dataurl of the image clicked. After that I am assigning this dataurl to src of the image to be shown in the view. But the problem is that the image is not showing!!
I checked the localstorage while debugging, the dataurl is there under localStorage.
What can be the problem, and how to solve it ??
Controller for initiating the camera...
init_camera: function() {
var controller = this;
navigator.camera.getPicture(onSuccess, onFail, {
quality: 80,
destinationType: Camera.DestinationType.DATA_URL
});
function onSuccess(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
localStorage.setItem('initial', image.src);
controller.redirectTo('Preview');
}
function onFail(message) {
alert('Failed because: ' + message);
}
}
Code to get the dataurl in the other view.. (in ExtJS)
items: [{
xtype: 'image',
cls: 'prev_img',
src: localStorage.getItem('initial'),
flex: 2
},

Ionic: show image from file path from device

In an Ionic app the user can select an image from his device (using this plugin). Then, with the path from the image (file://whatever), I need to show the image in the webview.
plugins.imagePicker.getPictures(
results => {
this.avatar_path = results[0]
}
)
I cannot use its path (results[0]) in the src of the image:
<img src="{{ avatar_path }}" />
Won't work. Do I need to get the binary from the file (using File API) and set as <img> src?
Well I'm using this plugin to get access to images stored on the device:
https://github.com/apache/cordova-plugin-camera
Then in the controller use something like this:
$scope.chooseFile = function() {
var cameraOptions = { quality: 100,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.SAVEDPHOTOALBUM,
targetWidth: 600,
targetHeight: 600,
encodingType: Camera.EncodingType.JPEG};
navigator.camera.getPicture(function (imageURI) {
var nameArr = imageURI.split("/");
$scope.attachment.name = nameArr[nameArr.length-1];
$scope.attachment.imageURI = imageURI;
DbLocalValueService.insertLocalValue("HomeImagePath",$scope.attachment.imageURI);
}, function(err) {
console.log(JSON.stringify(err));
}, cameraOptions);
};
And on HTML side use something like this:
<img ng-src="{{attachment.imageURI}}" />
Also make sure to use ng-src istead of src if you want to change the src of the image on run-time.
With the function DbLocalValueService.insertLocalValue I store the path of the image in a sqlite database and get the value of it on initialization of the view via resolve. You can decide on your own how do you want to store the path of the image.
Just use
<img src={{ avatar_path }} />
It's work for me but I'm using ionic 1 and same plugin ImagePicker.

Cropping a profile picture in Node JS

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).

Recent Camera gets overrided with the default image

I have an image grid, which was designed to have Add more button, when clicked on it. A new image placeholder should appear with a default image, when clicked on it the camera gets invoked and should update the default image with the picture taken. In my case, the camera picture is not getting updated but the default picture stays. When clicked on the add more, instead of the default picture the recent camera picture is getting appeared. I think there is a problem with rendering part of the code.
Here is my code
var Summary = React.createClass({
getInitialState: function(){
return {
picTriggers: [],
number:0,
image:"https://www.bignerdranch.com/img/blog/2014/07/Button-2.png"
}
},
camera: function(){
var that = this;
var image = this.state.image;
navigator.camera.getPicture(onSuccess, onFail, { quality: 50,
destinationType: Camera.DestinationType.DATA_URL
});
function onSuccess(imageData) {
console.log(imageData);
var finalimage = "data:image/jpeg;base64," + imageData;
that.setState({image: finalimage});
}
function onFail(message) {
alert('Failed because: ' + message);
}
},
newButton: function(){
var number = this.state.number;
number = number+1;
var picTriggers = this.state.picTriggers;
picTriggers.push(<img id={"div"+number} src={this.state.image} onClick={this.camera} className="addpicture"/>);
this.setState({picTriggers: picTriggers, number:number});
},
render: function(){
return(
<div>
{this.state.picTriggers}
<button onClick={this.newButton}>
{this.state.number>0?"Add More":"Add a picture"}
</button>
<button className="uploadselected"> Upload Selected </button>
</div>);
}
});
If I'm following this correctly, the flow here looks like:
First render: Add a picture button is rendered
If that button is clicked, a default image is shown via #newButton
If that image is clicked, the #camera function gets an image asynchronously and updates state with the image.
This will trigger #render. But you haven't done anything at this point to add a new item to picTriggers with the new image, so the old image displays.
When you click Add More, it runs #newButton again and you get your image rendered.
I think you could make your life much easier by just maintaining an array of imgSrcs instead of an array of rendered components. When you get the camera image, add to the array:
var finalImage = "data:image/jpeg;base64," + imageData;
// Better not to mutate state directly, so make a new array
// with slice, dropping the default image
var imgSrcs = this.state.imgSrcs.slice(0, -1);
imgSrcs.push(finalImage);
this.setState({ imgSrcs: imgSrcs });
And in #newButton, you just add the default image to the end of the array:
var imgSrcs = this.state.imgSrcs.concat([this.state.defaultImage]);
this.setState({ imgSrcs: imgSrcs });
Now you have a simple rendering problem, rendering a list of images, instead of a hard state problem, making sure your pre-rendered components are in sync each time #render is called.

Categories

Resources