<canvas> element in Chrome randomly flipping vertical before toDataURL() - javascript

I present to you, dear reader, a vexing bug that I cannot reproduce locally. However, I have gotten many reports from end-users, which seem to be increasing in frequency.
If you are an advanced user of <canvas> elements in Chrome, please continue reading, as I am completely baffled.
I use <canvas> elements to render full-size iPhone and iPad screenshots. I have a method that renders the canvas, which looks something like:
set the size of the canvas to iPhone resolution (640x1136) — possibly important: this canvas might have been rendered at a smaller resolution before
fill with background color (0, 0, width, height)
draw text at the top
draw an image of a phone in the middle of the bottom
draw a screenshot image on top of that phone image
call toDataURL() on the canvas to extract the image as a JPEG
Recently, after months of nobody reporting any problems, we've had several reports from different people reporting exported images being "messed up".
The images they send us are the correct size, BUT rather than the images containing the canvas area at (0, 0, width, height), the resulting images seem to contain the image data from (0, height, width, height) — offset by the height of the canvas and then flipped vertically for some reason.
Here is what this looks like:
As shown in this image, the content of the <canvas> element itself is seemingly not in the end-result image generated by toDataURL(); rather, the end-result image seems to contain the flipped image data from below the actual area of the <canvas>.
Important debugging information:
There are no calls to setTransform(), scale() or translate() anywhere in my code
These canvas elements are not visible to the end-user
This does not seem to affect Safari
I have users reporting the same output in Chrome incognito windows, so it is probably not the result of an extension
The code seems to be rendering the images in the correct locations on the canvas — the screenshot and phone appear in the correct place, and the background color is not present (since it is only drawn to 0, 0, width, height and not beyond)
Reports seem to be increasing in frequency, but still probably only 5-10% of Chrome end-users
Any ideas as to a root cause?
UPDATE: I have fixed the issue through trial and error. In the original implementation, I borrowed a "preview" low-resolution canvas to render the full-resolution image before calling toDataURL — my fix created a new canvas at the new size for the final rendering, rather than reusing the lower-resolution original canvas.
I'd still love to know the original cause. I think it has something to do with resizing <canvas> elements in code before calling drawImage() or something, but I can't reproduce it in order to investigate further.

Related

How can I optimize HTML canvas and JavaScript to handle large sized images for a web-based image editor

I am building a web-based image editor, and everything seems to work fine until very large images are uploaded (>5mb), and then operations like adjusting the brightness using a slider takes a while to reflect. The issue is quite obvious, and that is because I have to loop through each pixel (step of 4) in context.getImageData().data in order to modify each pixel value.
I checked out a couple of already existing online image editors, and theirs seem to work pretty well without lags.
Initially, my first step was to resize the image to fit the canvas on the screen which worked fine without lags, but why I switched to modifying the original image size was because the original size does not change compared to the one on the screen which changes if the user resizes the screen (or if chrome displays the currently downloading bar at the bottom of the browser), and since it is constant, I can always keep track of all editing operations, and then display on the screen by basing scaling down to fit the screen.
I'd love to know how I can optimize for large-sized images, without losing the quality of the original (due to resizing etc). Thanks!
[UPDATED]
This was copied from a comment under this post.
"JavaScript is not suited for image pixels editing. That is what the GPU is for. Most image manipulation needs can be done using filters, standard 2D canvas as they use the hardware designed for the task. If you have custom PX manipulation needs then WebGL is the solution."

Prevent Image Scaling on HighDPI Displays

As part of a project of mine, I want to write an image-viewer inside a webbrowser.
The images are extracted from video files on the server and sent to the client. The image should be displayed as is and not be scaled (unless the user explicitely chose to do so) by the browser, as this would distort the image.
This image illustrates the problem. The Win32-Application (with disabled DPI-Scaling) Shows a 20x20 image without any scaling (the black area). Chrome shows the 20x20 image (here a green image) scaled by a factor of two. What I want is that the image on the browser has the same area as the black square inside the Win32-Application, regardless of which DPI-Setting the user has chosen on his system.
To be clear: Serving the user an image with higher resolution is not an option. Neither is having the browser scale the image with different Settings acceptable. JavaScript-based solutions however may work as well.
I have not yet been able to find a solution to that problem.
I haven't found a way to disable it, but I found something to basically reverse the scaling. (source)
var factor = 1/window.devicePixelRatio;
document.querySelector('img').style.transform = 'scale(' + factor + ')';
I do not know how accurate this scaling will be and whether the image will still be rendered pixel-perfect. However, assuming the browser does some rounding internally before rendering, it should.

Safari mobile blurry when scale

i have a panel that should be drawn floating over the normal html page.
This object is dynamically created on DOMloaded event and scaled to fit current screen resolution depending on the zoom level of page.
In order to obtain that we have to scale the element, because we fix the width and height.
The scale amount in not mobile friendly website is always bigger than 1. It seems to work in all browsers except for Safari mobile, in which the floating panel is blurry.
How can i solve this problem?
It is the device, not the browser. iPhones have retina displays, which, in plain words, means that the pixels are doubled. Fonts, borders and other CSS styles scale up fine, but images are stretched, that's the reason your image appears blurred.
The simplest way to fix this is to use a bigger image
Of course this has the drawback that well... you will be using a bigger image for all devices/browsers even if you don't need one. Of course, there are many other ways to handle this.
Here is a place to start:
https://www.smashingmagazine.com/2012/08/towards-retina-web/
http://www.mightybytes.com/blog/make-retina-images-website/

Scrolling huge backdrop in canvas

My problem is the company I'm working for has started giving me art for the game I'm making for them and it has a huge world! It has given me a huge backdrop image like 12923x5356 huge!
I've now been able to get it to scroll and work like a backdrop but it's a bit slow on my old computer that's an old thinkcenter (note it can only run crunchbang and barely xp). See we want to be able to support tablets for this. It also further complicates things that they have an overlay as well just as big.
Right now I have it only drawing a canvas sized chunk of the backdrop so it only draws as much as can be seen by using
ctx.drawImage(img, x, y, width, height, dx, dy, dwidth, dheight);
with the dx/dy always drawing to the same spot and x/y scrolling with the main character.
Now realistically, is there any way to possibly do this faster? Another way I can think of is to maybe break the image down to small chunks with getImageData and drawing just so many that fills the screen with ctx.putImageData(img, x, y). I'm pretty sure from experience that the small form of drawImage is a bit faster than the long form but would this be much faster?
Anyone else have any ideas they can shoot at me?
You can make it into smaller tiles, just like how Google Maps does.
I'm not sure if you're handling some huge game map, but the technique should be the same. You can split the map into small tiles of, for example, 256px * 256px. Then you only need several 256px * 256px div to cover the viewport. If you use canvas instead, it's the same. Just render those tiles which are currently shown to the user.

Web: solution for image rotate and zoom

I have a web page which displays a large image, for example a page from a magazine. I have no control over the image size or orientation. It's possible that the image may need to be rotated by the user to orient it correctly.
Are there any Javascript or Flash solutions that will allow someone to rotate and zoom a given image? Ideally I'd specify a single image and the dimensions to use when displaying it. If the image is larger than those dimensions, the user could zoom in and view a portion of the image in greater detail.
I've seen a couple of solutions for rotating images with straight Javascript and CSS. Raphael would do the trick. There is apparently even an example featuring rotating an image. (it uses SVG but is support on all major browsers)
This one is not cross browser, but is an interesting exercise nevertheless.
As for flash rotation etc...
For rotating images, I used jquery-rotate and it works very well.
It is not totally cross-browser, it doesn't work with IE6 (and probably other old browsers).
For zooming, I guess you could make your own implementation using javascript, you can just resize the image (easy with jQuery).

Categories

Resources