Save google map as an image - using javascript (able to take screenshot) - javascript

I referred to the following SO questions to capture a screenshot of google maps using javascript (html2canvas). feedback.js, screen-capturing-using-html2canvas, create-screen-shot, capture-div-into-image, html2canvas-github.
I used static maps to get the image, but I have close to 150 markers and the total length of the URL went way beyond the 2048 character limit.
I am able to capture a screenshot using event listeners in javascript. The code I used to capture the image is below. I tried using window.save, but there is no such method in html2canvas.js. Any suggestions on how to save the image to the local filesystem?
function takeImage() {
html2canvas($("#map-canvas"), {
onrendered: function( canvas ) {
var img = canvas.toDataURL("image/png")
window.open(img);
//window.save(img); /*does not work.*/
}
});
}
The event listener:
google.maps.event.addListener(map, 'tilesloaded', function() {
takeImage();
});

I had problems with IE9 and, in Chrome, some images are downloaded but they are corrupted. The only solution I found for IE9 was opening the image on a new tab, then I was able to right click and save as.
I made the next code for download the div area (container of the map) as an image using html2canvas.
function download_image() {
if($.browser.safari) {// Fix for Chrome
var transform=$(".gm-style>div:first>div").css("transform");
var comp=transform.split(","); //split up the transform matrix
var mapleft=parseFloat(comp[4]); //get left value
var maptop=parseFloat(comp[5]); //get top value
$(".gm-style>div:first>div").css({ //get the map container. not sure if stable
"transform":"none",
"left":mapleft,
"top":maptop,
});
}
html2canvas([$("#div_id")[0]], {
logging: false,
useCORS: true,
onrendered: function (canvas) {
if ($("#downloadimg").length > 0)
$("#downloadimg").remove();
var fileName = "file_name.png";
if (/\bMSIE|Trident\b/.test(navigator.userAgent) && $.browser.version.match(/9.0|10.0|11.0/)) {//Only for IE 9, 10 and 11
download_image_IE(canvas, fileName);
}
else {
$("body").append("<a id='downloadimg' download='" + fileName + "' href='" + canvas.toDataURL("image/png").replace("image/png", "image/octet-stream") + "'><a/>");
}
if ($("#downloadimg").length > 0)
$("#downloadimg")[0].click();
if($.browser.safari) {// Fix for Chrome
$(".gm-style>div:first>div").css({
left:0,
top:0,
"transform":transform
});
}
}
});
}
function download_image_IE(canvas, filename) {
if ($.browser.version.match(/9.0/)){ //Only for IE9
var w = window.open();
$(w.document.body).html('<img src="'+ canvas.toDataURL() +'"/>');
}
else{
var image = canvas.toDataURL();
image = image.substring(22); // remove data stuff
var byteString = atob(image);
var buffer = new ArrayBuffer(byteString.length);
var intArray = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
var blob = new Blob([buffer], { type: "image/png" });
window.navigator.msSaveOrOpenBlob(blob, filename);
}
}

Related

Jcrop does not refresh newly selected image

I work a form that would let users to select an image on their computer, crop it and finally upload as profile image. I use JCrop to crop the photo. After a lot of struggles, now everything seems to work fine, except that if the user changes its mind and would like to browse in a second image, the image is not replaced on my form. I do replace the src attribute of the 'preview' image, but it seems that somehow JCrop still stores the previous image and this somehow "covers" the new image. I tried to use the JCrop setImage method to replace the image, but it does not seem to work. Any hints on how to fix this? Please see the code samples below.
var currentFile;
var file;
var options;
// convert bytes into friendly format
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};
// check for selected crop region
function checkForm() {
if (parseInt($('#w').val())) return true;
jQuery('.error').html('Please select a crop region and then press Upload').show();
return false;
};
// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
jQuery('#x1').val(e.x);
jQuery('#y1').val(e.y);
jQuery('#x2').val(e.x2);
jQuery('#y2').val(e.y2);
jQuery('#w').val(e.w);
jQuery('#h').val(e.h);
};
// clear info by cropping (onRelease event handler)
function clearInfo() {
jQuery('.info #w').val('');
jQuery('.info #h').val('');
};
function fileSelectHandler(evt) {
// hide all errors
jQuery('.error').hide();
// grabbing image
evt.preventDefault()
var target = evt.target
file = target && target.files && target.files[0]
if (!file) {
jQuery('.error').html('Image not found.').show();
jQuery('#main_photo').val('');
return;
}
var oFile = target.files[0];
// check for image type (jpg is allowed)
var rFilter = /^(image\/jpeg)$/i;
if (! rFilter.test(oFile.type)) {
jQuery('.error').html('Please select a valid image file (jpg)').show();
jQuery('#main_photo').val('');
return;
}
// check for file size
if (oFile.size > 5 * 1024 * 1024) {
jQuery('.error').html('You have selected too big file (max: 5 MB), please select a one smaller image file').show();
jQuery('#main_photo').val('');
return;
}
//setting options for image loader
options = {
orientation: true,
maxWidth: 400
}
// preview element
var oImage = document.getElementById('preview');
// adding onload event handler to initialize JCrop
oImage.onload = function () {
// Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
console.log(oImage);
// destroy Jcrop if it is existed
if (typeof jcrop_api != 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
}
// initialize Jcrop
jQuery('#preview').Jcrop({
minSize: [32, 32], // min crop size
aspectRatio : 200/250, // keep aspect ratio 1:1
bgFade: true, // use fade effect
bgOpacity: .3, // fade opacity
trueSize: [oImage.naturalWidth,oImage.naturalHeight],
onChange: updateInfo,
onSelect: updateInfo,
onRelease: clearInfo
}, function(){
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
console.log(jQuery('#preview').attr('src'));
jcrop_api.setImage(jQuery('#preview').attr('src'));
});
};
displayImage(file, options);
}
/**
* Updates the results view
*
* #param {*} img Image or canvas element
* #param {object} [data] Meta data object
*/
function updateResults(img, data) {
var fileName = currentFile.name
var href = img.src
var dataURLStart
var content
if (!(img.src || img instanceof HTMLCanvasElement)) {
content = jQuery('<span>Loading image file failed</span>')
} else {
if (!href) {
href = img.toDataURL(currentFile.type + 'REMOVEME')
// Check if file type is supported for the dataURL export:
dataURLStart = 'data:' + currentFile.type
if (href.slice(0, dataURLStart.length) !== dataURLStart) {
fileName = fileName.replace(/\.\w+$/, '.png')
}
}
content = jQuery('<a target="_blank">')
.append(img)
.attr('download', fileName)
.attr('href', href)
}
jQuery('#preview').attr("src", href);
}
/**
* Displays the image
*
* #param {File|Blob|string} file File or Blob object or image URL
* #param {object} [options] Options object
*/
function displayImage(file, options) {
currentFile = file
if (!loadImage(file, updateResults, options)) {
jQuery('.error').html('Incompatible browser. Image cannot be displayed.').show();
jQuery('#main_photo').val('');
return;
}
}
I created a wrapper like this
<div id="wrapper_img">
<img id="img">
</div>
and clean de wrapper and recreate de img to reload new image
$('#wrapper_img').empty();
var img = $('<img id="img">');
img.attr('src', 'my_image.png');
img.appendTo('#wrapper_img');
after that y create a new JCrop
img.Jcrop({....})

Change image orientation before upload

I am using this answer to display the uploaded image in an img tag and also I am able to change the orientation of the image using the loadImage() mentioned in the answer.
My problem is that I am not able to replace the re-oriented image with the uploaded image in the input tag.
The image is not saved unless the form is submitted. So I am not able to do this in AJAX also. Any help is much appreciated.
$('img#image-pre').click(function(e) {
var loadingImage = loadImage($('input#uploadform-file')[0].files[0], function(img) {
var dataURI = img.toDataURL();
document.getElementById("image-pre").src = img.toDataURL();
$('input#uploadform-file')[0].files[0] = function(dataURI) { // create the new blob from the changed image.
var binary = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
type: mimeString
});
};
}, {
orientation: or,
maxWidth: 500,
maxHeight: 300,
minWidth: 100,
minHeight: 50,
});
or = or <= 8 ? or + 1 : 1;
console.log($('input#uploadform-file')[0].files[0]);
});
You may want to look at this:
https://stackoverflow.com/a/20285053/1990724
You can parse the image to base64 string and then using ajax you could post the base64 string to the server. This could be done after you had the user orientate the image the correct way.

Saving a image which is captured by a camera on local machine on a folder

I am using HTML5 inputs to take a picture from camera using below line,
<input id="cameraInput" type="file" accept="image/*;capture=camera"></input>
and getting used image in blob:, using following javascript,
var mobileCameraImage = function() {
var that = this
;
$("#cameraInput").on("change", that.sendMobileImage);
if (!("url" in window) && ("webkitURL" in window)) {
window.URL = window.webkitURL;
}
});
var sendMobileImage = function( event ) {
var that = this;
if (event.target.files.length == 1 && event.target.files[0].type.indexOf("image/") == 0) {
var capturedImage = URL.createObjectURL(event.target.files[0])
;
alert( capturedImage );
}
});
Here, I am getting proper image url but the problem i am facing is to send this image url to the server, After reading blogs i found i can not send Blob: url to the server due to its local instance. Does anyone can help to save the clicked image on local machine on a folder or any where, or to help how i can send this image url to the server.
Thanks in advance.
You may need to submit your form every time via Ajax or you may upload the image data manually. In order to do that, you may draw the image unto a canvas, then obtain the canvas data.
// create an image to receive the data
var img = $('<img>');
// create a canvas to receive the image URL
var canvas = $('<canvas>');
var ctx = canvas[0].getContext("2d");
$("#cameraInput").on("change", function () {
var capturedImage = URL.createObjectURL(this.files[0]);
img.attr('src', capturedImage);
ctx.drawImage(img);
var imageData = canvas[0].toDataURL("image/png");
// do something with the image data
});
Or use a FileReader
// only need to create this once
var reader = new FileReader();
reader.onload = function () {
var imageData = reader.result;
// do something with the image data
};
$("#cameraInput").on("change", function () {
reader.readAsDataURL(this.files[0]);
});
Then you can upload that data to the server.

drag and drop images from `dropbox` account to html canvas - `not working in chrome`

This code is to drag images from image gallery and drop inside canvas (fabric.js is used) and also drag and drop images from dropbox account which is opend in another tab. This works fine in firefox, I can drag images from my drop box account and drop in inside canvas. But not in chrome. e.dataTransfer.getData("Text") gives an empty value in chrome. I thought it's a problem of same-origin-policy and tried a lot to fix it. But no luck. Please help me to get a work around for this.
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
// handle local images
if(e.dataTransfer.files.length > 0){
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (f.type.match('image.*')) {
// Read the File objects in this FileList.
var reader = new FileReader();
// listener for the onload event
reader.onload = function(evt) {
// create img element
var img = document.createElement('img');
img.src= evt.target.result;
// put image on canvas
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
};
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
}
// handle dropbox images
else{
var img = e.dataTransfer.getData("Text");
console.log(img);
var img = e.dataTransfer.getData("Text");
if (img.indexOf('jpg')>0 ||img.indexOf('png')>0){
var temp = '<img draggable="true" src="'+img+'" width="250" height="250"></img>';
$('#before').append(temp);
var i = document.querySelector('img[src="'+img+'"]');
console.log('i: ',i);
var nI = new fabric.Image(i,{
width: i.width,
height:i.height,
left:e.layerX,
top:e.layerY
});
canvas.add(nI);
}
}
return false;
}

Displaying multiple Thumbnails not working

So I am making this "drop-zone" for a website.
The user can drag and drop images over this area and all jpegs that are dropped on the area are displayed as thumbnailes. I made a List of all jpegs that are dropped on the area and that is working fine. Now everytime a new jpeg is added to that list I want to display all jpegs as thumbnailes of the size 100x150px.
Here is my code for that.
And here is a like to the fiddle http://jsfiddle.net/cJkYj/2/
function displayThumbnailes( ) {
//Clear the div.
var outerDiv = document.getElementById('fileChooserDiv');
while (outerDiv.hasChildNodes()) {
outerDiv.removeChild(outerDiv.lastChild);
}
var div = document.createElement('div');
outerDiv.appendChild(div);
//Go over the Files and add Thumbnails for all jpegs.
for( var i = 0; i < files.size(); i++) {
if( files.get(i).type == "image/jpeg") {
var reader = new FileReader();
reader.onloadend = function() {
var result = reader.result;
displayThumbnail( result, div );
}
reader.readAsDataURL(files.get(i));
}
}
}
function displayThumbnail( src, div ) {
var img = new Image();
img.onload = function () {
var cv = document.createElement('canvas');
cv.style.border = "1px solid #ffffff";
cv.width = 100;
cv.height = 150;
var ctx = cv.getContext( "2d" );
ctx.drawImage(img, 0, 0, 100, 150);
div.appendChild(cv);
}
img.src = src;
}
MY PROBLEM: I believe this code would display all thumbnailes in the area of the div but I only see the last one.
This looks like I am messing up some synchronisation or something.
"files" is an Object that manages the files dragged on the "drop-zone".
I want every Thumbnail to have his own canvas so I can add an onclick event to them later.
Any help would be appriciated ^^
Your code:
reader.onloadend = function() {
var result = reader.result;
displayThumbnail( result, div );
}
reader.readAsDataURL(files.get(i));
was failing because of the async onloadend callback. Each pass through the loop updated the outer reader variable, so each event used only the last reference.
You could either change your code to wrap that in a closure:
(function(reader) {
reader.onloadend = function() {
var result = reader.result;
displayThumbnail( result, div );
}})(reader);
or (preferred) change your code to use the event specific data :
reader.onloadend = function(evt) {
var result = evt.target.result;
displayThumbnail( result, div );
};
-- or using onload --
reader.onload = function (evt) {
var result = evt.target.result;
displayThumbnail(result, div);
}
reader.readAsDataURL(files.get(i));
works: example
I should also note that I rearranged your code to completely run within an onload handler.

Categories