I try to render a local image loaded with a FileReader object on a Canvas on Safari Mobile on iOS6. But every image with data-URL gets rendered vertically scaled. Is this a bug? On Chrome it's rendered correctly.
Demo Script
ScreenShot from iOS6 (above: Canvas, below: Original Image)
Is there any way to work-around this bug? Is this a bug?
If I resize the image on the device first with the "PhotoWizard" App (scale it down to 720px width), the Canvas renders it correctly. It seems to be a problem with image size or images taken with the Camera App:
Working Demo Script
Tried suggestions from Jake Archibald, looks a bit better, but still gets vertically scaled:
Modified Demo Script
ScreenShot from iOS6
I tried it today on a Galaxy Nexus with Android 4.1.1 installed. Works like expected, so this really looks like a mobile Safari issue:
ScreenShot from Android 4.1.1
This might be related to the restriction which resides in iOS Safari resource limitation. According to following link, JPEG files over 2M pixels will be subsampled.
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html#//apple_ref/doc/uid/TP40006482-SW15
I'm doubting that canvas in Safari cannot deal with this subsampling correctly.
I've created some workaround detecting whether the image is subsampled or not and stretching it to original size.
https://github.com/stomita/ios-imagefile-megapixel
var cnv = document.createElement("canvas");
ctx = cnv.getContext("2d");
image = new Image();
image.src = src;
image.onload = function() {
var size = scaleSizeRatio(image.width,image.height);
cnv.width = size[0];
cnv.height = size[1];
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width , image.height);
var div = container;
div.appendChild(cnv);
}
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width , image.height); This function will fix the squeezing issue in iPod more than 3Mb. First if your image is more than 3Mb then calculate the scaled width and height for the image and set that width and height to the canvas. Then call the drawImage function. It will give the final image what you expected...
Related
EDIT: I've made a video showing the current issue. Recorded it on an old macbook so it took a while haha. Anyway, In the video you can see me uploading an image, cropping it and generating a pdf with it. The preview does not have a black border whatsoever, the pdf DOES have a black border. Hope this helped.
So I got a webapplication that lets the user upload a profile picture and later generate a pdf with the profile picture. The problem is that I would like to have the profile picture displayed with rounded corners / in a circle.
I am using jspdf to generate the pdf. With that library I can add an image with the addImage method, that takes a base64 encoded DataUrl. Unfortunately, there isn't a native method to display the image with rounded corners / in a circle, so I decided to let the user crop their image before encoding the url to base64. That's when the weird behavior starts... If the cropped image is displayed in a img tag, it's all good, a nice circle profile picture is displayed. When that dataUrl is used to generate a pdf, for some reason a 1px black border is generated around the image... If I inspect the dataurl in the browser or with a online base64 previewer, no black border is visible, only when it gets generated as a pdf...
For demonstration purposes I made a codesandbox. Images with a white background show the problem best. For example, use this image: profilepicture
This method is most likely what is causing the problem (I took this one directly from the cropperjs examples on github):
function getRoundedCanvas(sourceCanvas) {
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var width = sourceCanvas.width;
var height = sourceCanvas.height;
canvas.width = width;
canvas.height = height;
context.imageSmoothingEnabled = true;
context.drawImage(sourceCanvas, 0, 0, width, height);
context.globalCompositeOperation = "destination-in";
context.beginPath();
context.arc(
width / 2,
height / 2,
Math.min(width, height) / 2,
0,
2 * Math.PI,
true
);
context.fill();
return canvas;
}
This method is used in the crop method like this: roundedCanvas = getRoundedCanvas(croppedCanvas); If I take out that method and just use roundedCanvas = croppedCanvas; the image gets cropped to a square and is displayed without the black borders.
I have no idea how I can resolve this issue, and if it is even possible to resolve. Any help in the right direction is very much appreciated. Even alternative methods to display rounded / circle images on a pdf are welcome (I already tried html2canvas and that didn't work).
I'm having a problem with loading image into canvas - the image is somehow scaled.
Background: I've got several canvases on my web page, I want to load images into them. When constructing, I'm not sure about the dimension, because the size depends on the screen size.
So I create div and canvas, use css to have it in the size that I want it to have and print an image onto the canvas. There would couple more things to do with the image (i.e. decide based on the ratio if I need to center it vertically or horizontally), but those are not really important at this point. The problem is that the image is rendered "zoomed".
Example: the javascript piece is here:
$("canvas").each(function() {
var context = $(this)[0].getContext('2d');
var img = new Image;
img.src = 'http://i67.tinypic.com/n38zdv.jpg';
$(img).load(function() {
context.drawImage(this, 0, 0);
});
//img will print 400 (correct, thats the width of the img)
//canvas will print based on the screen size (correct)
//img displayed in the canvas shows 300px out of 400px, it's zoomed (not correct)
$(this).parent().append(
'img width: '+img.width+
', canvas width: '+$(this).width());
});
I put the whole example with HTML and CSS to https://jsfiddle.net/7zdrfe58/11/.
I'm trying on Mac. Safari and Chrome work the same (i.e. with the zoom).
I would very appreciate help with this!! Thanks a lot
drawImage lets you specify the width and height of the image. You can get the canvas width like so:
$("canvas").each(function() {
var canvas = this;
var context = canvas.getContext('2d');
var img = new Image;
img.src = 'http://i67.tinypic.com/n38zdv.jpg';
$(img).load(function() {
context.drawImage(this, 0, 0, canvas.width, canvas.height);
});
});
Check out your working code here:
https://jsfiddle.net/ucxdLsq9/
The documentation of the drawImage signatures can be found here:
https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage
Give proper width and height to drawImage.
context.drawImage(this, 0, 0 ,300 ,160);
Updated Fiddle
I basically want to transform my SVG into a PNG image. So I turn the SVG into an SVG image and try to draw that on a canvas to be able to get it as a PNG via the toDataURL() method. This works fine in Chrome, but in Firefox it produces a very uninformative error: NS_ERROR_NOT_AVAILABLE
After searching and experimenting a bit, I tried a different SVG source and all of a sudden everything worked fine. Any ideas what could cause the method to work fine for the first SVG string but fail for the second one? How can I change my SVG so that it will work?
Fiddle: http://jsfiddle.net/3AXwb/
var image = new Image();
image.src = 'data:image/svg+xml,' + escape(xml);
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
document.getElementById('container').appendChild(canvas);
context.drawImage(image, 0, 0);
}
Add a width attribute to the outer <svg> element. E.g. width="450"
The first case has width and height, the second only height and Firefox currently required both width and height to be present.
Sort of a small issue here that I've been struggling to find an answer to.
I am using the ios native camera to take a photo which I am then sending to phonegap to run some javascript on.
I pass the image into javascript, then draw it onto the left side of a small canvas element I have prepared in which the right side I will produce an altered image of the original (a side by side comparison). I realize that the images between the iphone4 and the iphone4s are differently sized pixel-wise but are at least the same proportion. My draw code:
function imageLoaded(img, frontCamera) {
element = document.getElementById("canvas1");
c = element.getContext("2d");
// read the width and height of the canvas- scaled down
width = element.width; //188 94x2
height = element.height; //125
//used for side by side comparison of images
w2 = width / 2;
// stamp the image on the left of the canvas
if (frontCamera) {
c.drawImage(img, 0, 0, 94, 125);} else{
c.drawImage(img, 0, 0, 94, 125)}
// get all canvas pixel data
imageData = c.getImageData(0, 0, width, height);
//more stuff here
}
When I execute this code on an iphone4, the image appears as should, side by side with the corrected image. When I use an iphone4s, the image draws out with the correct width, but it is a super squashed image, occupying the top sliver of the canvas.
Both devices are registering a screen.height and screen.width of 480 and 320 respectively with a window.devicePixelRatio of 2.
I figured the drawImage function would inherently scale the image appropriately.
I cannot seem to figure out what I am doing wrong. Thanks for the help!
"I realize that the images between the iphone4 and the iphone4s are differently sized pixel-wise but are at least the same proportion."
iPhone 4 and iPhone 4s have the exact same screen size and pixel ratio and number of pixels, etc. They are esentially the same. If you're drawing each one different, then there's your problem.
The iPhone 3gs and below have non-retina displays.
The iPhone 5 has retina but is taller.
If that's not the case, then it's something in your code (which means unless you publish it we can't help all that much).
I doubt very much that the issue is with Phonegap itself.
Given a PNG in a web context with some transparent pixels and some non-transparent pixels, is there a way in Javascript to determine if a user has clicked on a non-transparent pixel? A webkit-only solution would be perfectly acceptable.
1) Create HTML5 canvas of same size as your image
2) Get Canvas's context, drawImage(yourImage, 0, 0)
3) d = context.getImageData(0, 0, w of img, h of img)
4) d.data[(y*width+x)*4+3] for the alpha
canvas = document.createElement("canvas"); //Create HTML5 canvas: supported in latest firefox/chrome/safari/konquerer. Support in IE9
canvas.width = img.width; //Set width of your rendertarget
canvas.height = img.height; // \ height \ \ \
ctx = canvas.getContext("2d"); //Get the 2d context [the thing you draw on]
ctx.drawImage(img, 0, 0); //Draw the picture on it.
id = ctx.getImageData(0,0, img.width, img.height); //Get the pixelData of image
//id.data[(y*width+x)*4+3] for the alpha value of pixel at x,y, 0->255
I know these things are out of fashion these days, but HTML image maps are still valid, and can accomplish adding hit targets to nearly-arbitrary shapes within an image. If you don't actually want to reload another page on click, you could probably change the anchor in the URL with this technique and pick up the change with a Javascript interval.
Canvas is the way to go for this purpose. But also remember that older internet explorer versions will not be capable of the getImageData() function. Even if you include excanvas.
I made a small jquery plugin exactly for this purpose, maybe it will help you solving your problem without to completely reinvent the wheel. http://www.cw-internetdienste.de/pixelselection/