Firefox issue with jquery.post - javascript

I have a function which retrieves a base64 encoded image from a controller and displays the image in a new window. It is working perfectly in Chrome, but fails in Firefox with the errors 'not well-formed' and 'Request method 'GET' not supported'. I don't understand why this would be the case given that I am using post, not get...
The relevant code section is:
function showPicture(label) {
$.post( 'picture-view', { labelname: label }, function(ImageSrc) {
var img = new Image;
img.src = "data:image/png;base64," + ImageSrc;
img.style.position = 'fixed';
img.style.left = '0';
img.style.top = '0';
img.onload = function() {
var newWindow = window.open("", label,"scrollbars=0, toolbar=0, width="+myImage.width+", height="+myImage.height);
creativeWindow.document.documentElement.innerHTML='';
creativeWindow.document.documentElement.appendChild(img);
}​
});}
Edit Also, any recommendations for accessible books or websites to learn more about this material would be gratefully received.
Edit #2 I should also add that when I tried writing img.src to the console it came out as [objectXMLDocument].
Edit #3 I have tracked the error down to the fact that the ImageSrc being returned should be a String but is being interpreted as an XML object. The fact that it contains back slashes is causing the 'not well-formed' error. My question is now: how do I get $.post or $.ajax to return a String in Firefox (they already do so in Chrome).

Id probably try using .ajax instead. It'll allow you to offer fallback content too.
Rather than sending the images using post, why not host the images on your server and load the images by src. It will be a much cleaner approach.
For example
$.ajax({
type: "POST",
data: "",
url: yourURL,
error: function() {
//The call was unsuccessful
//Place fallback content/message here
},
success: function(data) {
//The call was successful
//Open new window
var newWindow = window.open("", label,"scrollbars=0, toolbar=0, width="+myImage.width+", height="+myImage.height);
creativeWindow.document.documentElement.innerHTML='';
//Create the image
var image = document.createElement("img");
image.src = data;
//Attach image to new window
creativeWindow.document.documentElement.appendChild(image);
}
});

In the interest of not leaving an unanswered question...
I ended up using a lightbox to display the image rather than generating a new window.

Related

open image in new window blank page appearing javascript

after taking the reference from this answer
Open image in new window
i did the the same code.
function openImage() {
var largeImage = document.getElementById('viewImage');
largeImage.style.display = 'block';
largeImage.style.width = 200 + "px";
largeImage.style.height = 200 + "px";
var url = largeImage.getAttribute('src');
window.open(url, 'Image', 'width=largeImage.stylewidth,height=largeImage.style.height,resizable=1');
}
but when this function executed, blank page is showing
when i view image src in console, it is showing proper data.
my img element is also showing me image properly,
but this is how my page is being shown
what do you think what is wrong in my code?
That solution is for image with actual url as src, in your case image src is a base64 encoded string not url.
Base64 support for Window.open is not same across all browsers, it works on firefox but it won't work on chrome and IE.
So, you can try this instead
function openImage() {
var largeImage = document.getElementById('viewImage');
largeImage.style.display = 'block';
largeImage.style.width = 200 + "px";
largeImage.style.height = 200 + "px";
var w = window.open("");
w.document.write(largeImage.outerHTML);
}

jCrop resize with correct coords when changing image

Hoping this doesn't get flagged as a duplicate because none of the other q/as on SO have helped me fix this, I think I need a more specific line of help.
I have a profile page on my site that allows the user to change their profile picture without page reloads (via AJAX / jQuery).
This all works fine. The user opens the "Change Profile Picture" modal, selects a file to upload and presses "Crop this image". When this button is pressed, it uploads a file to the website, using the typical way of sending the file and formData (which I append the file data to).
It gets sent backend with the following jQuery:
// Upload the image for cropping (Crop this Image!)
$("#image-upload").click(function(){
// File data
var fileData = $("#image-select").prop("files")[0];
// Set up a form
var formData = new FormData();
// Append the file to the new form for submission
formData.append("file", fileData);
// Send the file to be uploaded
$.ajax({
// Set the params
cache: false,
contentType: false,
processData: false,
// Page & file information
url: "index.php?action=uploadimage",
dataType: "text",
type: "POST",
// The data to send
data: formData,
// On success...
success: function(data){
// If no image was returned
// "not-image" is returned from the PHP script if we return it in case of an error
if(data == "not-image"){
alert("That's not an image, please upload an image file.");
return false;
}
// Else, load the image on to the page so we don't need to reload
$(profileImage).attr("src", data);
// If the API is already set, then we should apply a new image
if(jCropAPI){
jCropAPI.setImage(data + "?" + new Date().getTime());
}
// Initialise jCrop
setJCrop();
//$("#image-profile").show();
$("#send-coords").show();
}
})
});
setJcrop does the following
function setJCrop(){
// Get width / height of the image
var width = profileImage.width();
var height = profileImage.height();
// Var containing the source image
var imgSource = profileImage.attr("src");
// New image object to work on
var image = new Image();
image.src = imgSource;
// The SOURCE (ORIGINAL) width / height
var origWidth = image.width;
var origHeight = image.height;
// Set up the option to jCrop it
$(profileImage).Jcrop({
onSelect: setCoords,
onChange: setCoords,
setSelect: [0, 0, 51, 51],
aspectRatio: 1, // This locks it to a square image, so it fits the site better
boxWidth: width,
boxHeight: height, // Fixes the size permanently so that we can load new images
}, function(){jCropAPI = this});
setOthers(width, height, origWidth, origHeight);
}
And once backend, it does the following:
public function uploadImage($file){
// See if there is already an error
if(0 < $file["file"]["error"]){
return $file["file"]["error"] . " (error)";
}else{
// Set up the image
$image = $file["file"];
$imageSizes = getimagesize($image["tmp_name"]);
// If there are no image sizes, return the not-image error
if(!$imageSizes){
return "not-image";
}
// SIZE LIMIT HERE SOON (TBI)
// Set a name for the image
$username = $_SESSION["user"]->getUsername();
$fileName = "images/profile/$username-profile-original.jpg";
// Move the image which is guaranteed a unique name (unless it is due to overwrite), to the profile pictures folder
move_uploaded_file($image["tmp_name"], $fileName);
// Return the new filename
return $fileName;
}
}
Then, the user selects their area on the image with the selector and pressed "Change Profile Picture" which does the following
// Send the Coords and upload the new image
$("#send-coords").click(function(){
$.ajax({
type: "POST",
url: "index.php?action=uploadprofilepicture",
data: {
coordString: $("#coords").text() + $("#coords2").text(),
imgSrc: $("#image-profile").attr("src")
},
success: function(data){
if(data == "no-word"){
alert("Can not work with this image type, please try with another image");
}else{
// Append a date to make sure it reloads the image without using a cached version
var dateNow = new Date();
var newImageLink = data + "?" + dateNow.getTime();
$("#profile-picture").attr("src", newImageLink);
// Hide the modal
$("#profile-picture-modal").modal("hide");
}
}
});
})
The backend is:
public function uploadProfilePicture($coordString, $imgSrc){
// Target dimensions
$tarWidth = $tarHeight = 150;
// Split the coords in to an array (sent by a string that was created by JS)
$coordsArray = explode(",", $coordString);
//Set them all from the array
$x = $coordsArray[0];
$y = $coordsArray[1];
$width = $coordsArray[2];
$height = $coordsArray[3];
$newWidth = $coordsArray[4];
$newHeight = $coordsArray[5];
$origWidth = $coordsArray[6];
$origHeight = $coordsArray[7];
// Validate the image and decide which image type to create the original resource from
$imgDetails = getimagesize($imgSrc);
$imgMime = $imgDetails["mime"];
switch($imgMime){
case "image/jpeg":
$originalImage = imagecreatefromjpeg($imgSrc);
break;
case "image/png":
$originalImage = imagecreatefrompng($imgSrc);
break;
default:
return "no-work";
}
// Target image resource
$imgTarget = imagecreatetruecolor($tarWidth, $tarHeight);
$img = imagecreatetruecolor($newWidth, $newHeight);
// Resize the original image to work with our coords
imagecopyresampled($img, $originalImage, 0, 0, 0, 0,
$newWidth, $newHeight, $origWidth, $origHeight);
// Now copy the CROPPED image in to the TARGET resource
imagecopyresampled(
$imgTarget, // Target resource
$img, // Target image
0, 0, // X / Y Coords of the target image; this will always be 0, 0 as we do not want any black nothingness
$x, $y, // X / Y Coords (top left) of the target area
$tarWidth,
$tarHeight, // width / height of the target
$width,
$height // Width / height of the source image crop
);
$username = $_SESSION["user"]->getUsername();
$newPath = "images/profile/$username-profile-cropped.jpg";
// Create that shit!
imagejpeg($imgTarget, $newPath);
// Return the path
return $newPath;
}
So basically this the returns the path of the new file, which gets changed to the user's profile picture (same name every time) and uploaded live with a time appended after ? to refresh the image properly (no cache).
This all works fine, however if the user selects another image to upload, after already uploading one, the coords get all messed up (e.g. they go from 50 to 250) and they end up cropping a totally different part of the image, leaving most of it black nothing-ness.
Really sorry for the ridiculous amount of code that is in this question but I'd appreciate any help from people who might have worked around this before.
Some of the code may seem out of place but that's just me trying to debug it.
Thanks, and again, sorry for the size of this question.
-Edit-
My setCoords() and setOthers() functions look like so:
//Set the coords with this method, that is called every time the user makes / changes a selection on the crop panel
function setCoords(c){
$("#coords").text(c.x + "," + c.y + "," + c.w + "," + c.h + ",");
}
//This one adds the other parts to the second div; they will be concatenated in to the POST string
function setOthers(width, height, origWidth, origHeight){
$("#coords2").text(width + "," + height + "," + origWidth + "," + origHeight);
}
I have now resolved this issue.
The problem for me was that when using setJCrop(); - it was not re-loading the image. The reason for this is that the image uploaded and then loaded in to the JCrop window had the same name every time (username as a prefix, and then profile-cropped.jpg).
So to try and resolve this, I used the setImage method which loaded a full-sized image instead.
I got around this by setting the boxWidth / boxHeight params but they just left me with the issue of the coordinates being incorrect every time I loaded a new image in.
Turns out, it was loading the image from the cache every time, even when I was using new Image(); within jQuery.
To solve this, I have now used destroy(); on the jCropAPI and then re-initialised it every time, witout using setImage();
I set a max-width in the CSS on the image itself, which stopped it from being locked to a specific width.
The next problem was that every time I loaded an image a second time, it left the width / height of the old image there, which made the image look all skewed and wrong.
To solve this, I reset the width & height of the image that I use jCrop on, to "" with $(profileImage).css("width", ""); $(profileImage).css("height", ""); before re-setting the source of the image from the new uploaded image.
But I was still left with the issue of using the same name on the images, and then causing it to load from cache every time.
My solution to this was to add an "avatar" column in the database and save the image name in the Database each time. The image was named as $username-$time.jpg and $username-$time.jpg-cropped.jpg where $username is the username of the user (derp) and $time is simply time(); inside PHP.
This meant that every time I uploaded an image, it had a new name, so when any calls were made to this image, there was no cache of it.
Appending like imageName + ".jpg?" + new Date.getTime(); worked for some things but then when sending the image name backend, it didn't work properly, and deciding when to append it / not append it was a pain, and then one thing required it to be appended to force a re-load, but then when appended it didn't work properly, so I had to re-work it.
So the key: (TL;DR)
Don't use the same image name with jCrop, if you are loading a new image; upload an image with a different name and then refer to that one. Cache problems are a pain, and you can't really work around them properly without just using a new name every time, as this ensures that there will be absolutely no more problems (so long as the name is always unique).
Then, when you initialise jCrop, destroy the previous one beforehand if there is one. Use max-width instead of width on an image to stop it from locking the width, and re-set the width / height of the image if you're loading a new one in to the same <img> or <div>
Hope this helps somebody!
I used jcrop and I think this has happened to me. When there is a new image, you have to "reset" jcrop. Try something like this:
function resetJCrop()
{
if (jCropAPI) {
jCropAPI.disable();
jCropAPI.release();
jCropAPI.destroy();
}
}
$("#image-upload").click(function(){
success: function(data){
...
resetJCrop(); // RESETTING HERE
// If the API is already set, then we should apply a new image
if(jCropAPI){
jCropAPI.setImage(data + "?" + new Date().getTime());
}
// Initialise jCrop
setJCrop();
...
}
});
I can't remember the details about why I have to use disable() AND release() AND destroy() in my particular case. May be you can use only one of those. Just try it, and see if that works for you!

saving an image that has been manipulated with caman.js

guys im really struggling with this ive been trying for days but no luck, I have manipulated an image with camanjs and then save it to disk with canvas.toblob(), here is the code
Caman("#theCanvas", "images/1.jpg", function () {
this.greyscale()
.noise(33.3)
.render(function(){
for(i=1;i<=3;i++){
draw(2);
draw(3);
draw(4);
draw(8);
}
for(i=1;i<=29;i++){
draw(1);
draw(5);
draw(6);
draw(7);
}
var canvas = document.getElementById("theCanvas");
canvas.toBlob(function(blob) {
saveAs(blob, "image.jpg");
});
});
});
when the image is saved, it is saved with the .greyscale effects and the .noise() effects, but the changes i make to the image inside the render() function are not present in the image, and I am not sure how to get over this, I have tried using .reloadCanvasData() but it didnt work i think I am not using it properly, anyone with a solution?
Maybe you can try
.render(function(){
var base64 = this.toBase64()
download(base64, 'image.jpg', 'image/jpeg')
})
The download function comes from http://danml.com/download.html
I have solved this problem with my following trick. You can use it
Caman("#canvas", function() {
//console.log(this.toBase64());
let a = document.createElement('a');
a.href = this.toBase64();
a.download = Date() +'_image.png';
a.click();
});

Broken Youtube thumbnails do not fire error callback

Will an image error callback fire if an image is 404, but the host returns an image anyway?
I am trying to determine on the client whether a Youtube thumbnail is valid before submitting the URL to the server. Normally you can generate a thumbnail URL without querying their API with the format http://img.youtube.com/vi/**ID**/maxresdefault.jpg
Some videos do not have high-res thumbnails, for example, this one:
http://img.youtube.com/vi/ty62YzGryU4/maxresdefault.jpg
However, a lower quality thumbnail always exists:
http://img.youtube.com/vi/ty62YzGryU4/default.jpg
Ideally I would be able to detect whether the thumbnail did load via this code snippet, which would call "done" when it loaded a valid thumbnail:
var id = "ty62YzGryU4"
var tries = 0
var thumb = "http://img.youtube.com/vi/" + id + "/maxresdefault.jpg"
var img = new Image ()
img.onload = function(){ console.log('ok'); done(id, thumb) }
img.onerror = function(){
switch (tries++){
case 0:
img.src = thumb = "http://img.youtube.com/vi/" + id + "/hqdefault.jpg"
break;
case 1:
img.src = thumb = "http://img.youtube.com/vi/" + id + "/default.jpg"
break;
case 2:
done(id, thumb)
break;
}
}
img.src = thumb
if (img.complete) img.onload()
However this is not the case -- while I see a 404 error in the console, neither the onload nor the onerror callbacks fire, and thus done is never called.
If I set img.crossOrigin = "Anonymous" the onerror callback fires... for every thumbnail, because of the accursed Cross-Origin Resource Sharing policy.
I have also tried crafting an XMLHttpRequest, but to no avail:
xmlhttp = new XMLHttpRequest()
xmlhttp.onreadystatechange = function() {
console.log(xmlhttp.readyState)
console.log(xmlhttp.status)
};
xmlhttp.open('GET', url, true);
xmlhttp.send(null);
Whether I set X-Requested-With: XMLHttpRequest or not, the readyState goes from 1 to 4 but status is always zero!
Is there any way to see if this particular image gave a 404 without using the API?
YouTube thumbnails will not fire the onerror() function because YouTube sends another base64 gif image which shows the empty video icon which has the resolution of 120X90. (this is the key to the solution)
Note that you should load the image tag with the maxresdefault image and give it or (them) a certain class, e.g. "youtube-thumb".
For info: maxresdefault 1080, sddefault 720, hqdefault 480, mqdefault 360, default 240.
According to limited experiments, 0.jpg is 480 or the best low-res image available for a video.
$(function()
{
$('.youtube-thumb').each(function(ix, it){
if($(it)[0].naturalHeight <= 90 )
{
var path = $(it).attr('src');
var altpath = path.replace('maxresdefault.jpg','0.jpg');
$(it).attr('src', altpath);
}
});
});
I know this question is a bit older but I had the same problem today and I want to give you my solution which tries all of the YouTube thumbnails from best to worst.
My "ranking" of the different options is:
maxresdefault
mqdefault -> only one besides 1) that doesn't have black borders
sddefault
hqdefault
default -> works 100%
This is my code.
function youtube_check(e) {
var thumbnail = ["maxresdefault", "mqdefault", "sddefault", "hqdefault", "default"];
var url = e.attr("src");
if (e[0].naturalWidth === 120 && e[0].naturalHeight === 90) {
for (var i = 0, len = thumbnail.length - 1; i < len; i++) {
if (url.indexOf(thumbnail[i]) > 0) {
e.attr("src", url.replace(thumbnail[i], thumbnail[i + 1]));
break;
}
}
}
}
<img onload="youtube_check($(this))" src="https://i3.ytimg.com/vi/---ID---/maxresdefault.jpg">

Getting an image width and height from Phonegap before upload

This should be easy but I can't find the answer. I need to get the width and height of an image, grabbed via a fileURI in Phonegap, before uploading it to our server. Certainly there's got to be some html5 / Phonegap magic that will do this before uploading. Here is some really reduced code to show where I'm at:
function got_image(image_uri) {
// Great, we've got the URI
window.resolveLocalFileSystemURI(image_uri, function(fileEntry) {
// Great, now we have a fileEntry object.
// How do we get the image width and height?
})
}
// Get the image URI using Phonegap
navigator.camera.getPicture(got_image, fail_function, some_settings)
Any idea what the missing piece is? I wish I had Simon MacDonald or Shazron on speed dial, but I do not.
Here is a proper solution.
Pass this function an imageURI. URIs are returned from both of PhoneGap's getPicture() methods.
Like this:
get_image_size_from_URI(imageURI)
function get_image_size_from_URI(imageURI) {
// This function is called once an imageURI is rerturned from PhoneGap's camera or gallery function
window.resolveLocalFileSystemURI(imageURI, function(fileEntry) {
fileEntry.file(function(fileObject){
// Create a reader to read the file
var reader = new FileReader()
// Create a function to process the file once it's read
reader.onloadend = function(evt) {
// Create an image element that we will load the data into
var image = new Image()
image.onload = function(evt) {
// The image has been loaded and the data is ready
var image_width = this.width
var image_height = this.height
console.log("IMAGE HEIGHT: " + image_height)
console.log("IMAGE WIDTH: " + image_width)
// We don't need the image element anymore. Get rid of it.
image = null
}
// Load the read data into the image source. It's base64 data
image.src = evt.target.result
}
// Read from disk the data as base64
reader.readAsDataURL(fileObject)
}, function(){
console.log("There was an error reading or processing this file.")
})
})
}
The following code solves the same problem for me today (tested on iOS):
function got_image(image_uri)
{
$('<img src="'+image_uri+'"/>').on('load',function(){
alert(this.naturalWidth +" "+ this.naturalHeight);
});
}
Hope it helps!
I think you can use target width and height of getPicture() to limit the maximum dimension.
If you need to send them to server, I think server code would help to get those dimension.
If you really need to get those dimension by js, you can
var img = new Image;
img.onload = function(){
myCanvasContext.drawImage(img,0,0);
};
img.src = "data:YOUR_BASE64_DATA";
And you can do it with img
1.Phonegap supply a way to specific the size of the image you choose
Click here to see the options
2.If you need to know the original size and do not want to specific, you may try the code below:
function got_image(image_uri) {
window.resolveLocalFileSystemURI(image_uri, function(fileEntry) {
fileEntry.file(function (fileObj) {
var fileName = fileObj.fullPath;
var originalLogo = new Image();
originalLogo.src =fileName;
//get the size by: originalLogo.width,originalLogo.height
});
})
}
one way you can do this is by using the MediaFile from the Capture API.
var mediaFile = new MediaFile("myfile.jpg", "/path/to/myfile.jpg");
mediaFile.getFormatData(function(data) {
console.log("width: " data.width);
console.log("height: " data.height);
});
Should be a lot less code than the current accepted solution.

Categories

Resources