本文介绍了iOS平台上的HTML5画布缩放问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发一个在phonegap的项目,试图构建Android和iOS。主要想法是访问手机库上保存的图片,将该图片保存到HTML img元素,然后将该img元素绘制到画布上。从那里,用户可以缩放和旋转图像。

I've been developing a project in phonegap, attempting to build for Android and iOS. The main idea is to access a saved picture on the phone library, save that picture to an HTML img element, and then draw that img element onto a canvas. From there, the user can scale and rotate the image.

我在Android上没有问题。我已经使用仿真器和设备进行了测试,并测试了各种设备(不同的像素比率,密度等),并且所得到的画布转换总是给出预期的结果。

I've had no issues on the Android. I've tested using emulators and devices, and have tested a wide array of devices (different pixel ratios, densities, etc.) and the resulting canvas transformations always give the expected result.

另一方面,iOS版本没有那么成功。缩放/旋转画布看起来很好,直到我缩放画布略大于其原始大小(比原始大约4-5像素)。在将画布放大后,在画布上绘制的图像将更改。

The iOS version, on the other hand, has not been as successful. Scaling/Rotating the canvas looks fine, until I scale the canvas slightly larger than its original size (about 4-5 pixels larger than original). After scaling the canvas up in size, the image drawn on the canvas changes. Instead of now seeing the entire image displayed, I usually get a small portion of the image (usually the top-left corner) drawn over the entire canvas.

我的画布在整个画布上绘制,而不是现在看到整个图像显示,我通常会得到一小部分的图像(通常是左上角) html:

My canvas in html:

<canvas id="sourceImgCanvas" width="200" height="200" style="z-index:1; position:absolute; left:5%; top:100px;"></canvas>

我从手机库收到的图片对手机屏幕来说总是太大。我缩放图像并记录我缩小图像的比率(如果没有缩放,drawRatio为1,如果图像缩小到适合屏幕,则大于1)。 PhoneGap处理从手机库中抓取图片,我只是使用从照片返回的imageURI,并将其设置为img元素:

The image I receive from the phone library is almost always too large for the phone screen. I scale the image down and record the ratio by which I shrank the image (drawRatio is 1 if no scaling occured, greater than 1 if image was shrank to fit screen). PhoneGap handles grabbing the picture from the phone library, and I simply use the imageURI returned from the photo and set it to an img element Phonegap Camera API:

// Called when a photo is successfully retrieved
function onPhotoURISuccess(imageURI)
{
    sourceImage = document.getElementById('sourceImg');
    sourceImage.src = imageURI;

    //signal that user can manipulate photo with touch inputs
    b_editPhotoAllowed = true;
}

为了缩放画布,我在右下角有一个箭头画布。在被拖动时,它记录它离画布左上角有多远,并根据距离设置画布高度/宽度。

To scale the canvas, I have an arrow on the bottom-right corner of the canvas. Upon being dragged, it records how far away it is from the top-left corner of the canvas and sets the canvas height/width based on the distance.

//Calls when user is dragging the arrow resize button.  Updates the source image size
function ResizeSourceImage() {
    var horizontalDistanceFromTopLeft = parseFloat(ovalCanvas.style.left) + ovalCanvas.width - endX;
    var verticalDistanceFromTopLeft = parseFloat(ovalCanvas.style.top) + ovalCanvas.height - endY;

    //update canvas size with new length
    sourceImgCanvas.width = originalSrcImgWidth - horizontalDistanceFromTopLeft;
    sourceImgCanvas.height = originalSrcImgHeight - verticalDistanceFromTopLeft;

    //re-draw based on new size
    sourceImgContext.drawImage(sourceImg, 0, 0, pictureWidth * drawRatio * drawRatioMod, pictureHeight * drawRatio * drawRatioMod, 0, 0, sourceImgCanvas.width, sourceImgCanvas.height);
}

上述drawRatio是重新调整图像大小)

The above drawRatio is the ratio I store upon re-sizing an image (code not shown here; it's rather long, but simple.)

drawRatioMod 是我在试验时设置的值,并且是我的问题的主要焦点。在Android上,我设置 drawRatioMod = 1 ,以便绘图不受影响。在iPhone4 / iPad(我可以测试的设备),我设置 drawRatioMod = 0.5 。这解决了我在iOS上使用html5画布时遇到的一些初始问题:由于iPhone4的分辨率实际上是屏幕尺寸的两倍,所以我将源图像的长度/宽度减少了一半。

The drawRatioMod is a value I set while experimenting, and is the main focus of my question. On Android, I set drawRatioMod = 1 so that drawing is not affected. On iPhone4/iPad (the devices I have available to test with), I set drawRatioMod = 0.5. This solved some initial issues I was experiencing with the html5 canvas on the iOS: since the iPhone4's resolution is actually twice it's screen size, I reduced the length/width of the source image to be drawn by half.

上面的 ResizeSourceImage()函数在每次用户移动调整大小箭头工具时调用,从而更新画布大小。只有缩小时,图片才会正确调整为新的画布大小。 如果我将画布缩放超过大约5-6像素,画布不再绘制整个源图像;

The above ResizeSourceImage() function is called everytime the user moves the resize arrow tool, thus updating the canvas size. The image adjusts properly to the new canvas size only if I scale down. If I scale the canvas up more than about 5-6 pixels, the canvas no longer draws the entire source image; instead, the canvas draws only the top-left corner of the image over the entire canvas.

我一直在处理这个问题几天,没有运气。我最初认为它与设备像素比率有关(通过Javascript window.devicePixelRatio ),但我已经测试了几个Android设备的不同比率,从来没有这个结果。

I've been tackling this issue for a few days and have had no luck. I initially thought it had something to do with the device pixel ratio (accessible thru Javascript window.devicePixelRatio) but I've tested on several Android devices of varying ratios and have never had this result.

我觉得我非常接近解决,因为在iOS上放大时,图片只会不正确地显示。任何指针/提示是非常感激!我尝试了与 window.devicePixelRatio 相关的几个修复,但我的iPad的iPhone4模拟器总是返回一个pixelRatio为1(这似乎不正确),我没有运气这样的修复。

I feel like I'm very close to solving, as the image only displays incorrectly when scaling up on the iOS. Any pointers/tips are greatly appreciated! I've tried several fixes related to window.devicePixelRatio but my iPad's iPhone4 simulator always returns a pixelRatio of 1 (which seems incorrect) and I've had no luck with such fixes.

干杯! (我试图发布一个简单的代码处理canvas的缩放和绘图如果你想看到更多的代码,我可以发布更多;希望有一个不像中国的长城的帖子:))

Cheers! (I attempted to post the bare-bones code dealing with the scaling and drawing of the canvas. If you would like to see additional code, I can post more; was hoping to have a post that didn't resemble the great wall of China :) )

推荐答案

测试了几天后,我终于找到了罪魁祸首:using myContext.drawImage()切片图像只是一个很大的痛苦在iOS(可能是由于视网膜显示,但我不能100%确定)。

After testing this for a few days, I've finally found the culprit: using myContext.drawImage() to slice an image is just a big pain in iOS (perhaps due to the retina display, but I'm not 100% sure).

我做的是双缓冲和使用 myContext.drawImage()缩放,而不是slice 。

What I did instead was a combination of double buffering and using myContext.drawImage() to only scale, not slice.

FelineSoft在一些关于画布的事情上有一篇很棒的文章。双缓冲解释如下:

FelineSoft has a great post on several things canvas related. Double buffering is explained here: http://www.felinesoft.com/blog/index.php/2010/09/accelerated-game-programming-with-html5-and-canvas/

所以,不是像这样切分原始图像:

So, instead of slicing the original image like so:

sourceImgContext.drawImage(sourceImg, 0, 0, pictureWidth * drawRatio * drawRatioMod, pictureHeight * drawRatio * drawRatioMod, 0, 0, sourceImgCanvas.width, sourceImgCanvas.height);

我将图像绘制到缓冲区,然后绘制到用户在屏幕上看到的画布。回过头来看,缓冲区可能没有必要修复这个缩放问题,但是习惯这是一个很好的习惯:

I instead draw the image to a buffer and then draw that to the canvas the user sees on screen. Looking back, the buffer may not be necessary to fix this scaling issue I had, but it's a good habit to get used to:

//buffer to draw the image to before drawing on-screen
var bufferCanvas = document.createElement('canvas');
var bufferContext = bufferCanvas.getContext('2d');

bufferContext.drawImage(sourceImg, 0, 0, bufferCanvas.width, bufferCanvas.height);

//later, I draw the image stored in buffer to a canvas user will see on-screen
//if this call is coming right after the command to draw image to buffer, would be best
//to add a check to make sure buffer has finished drawing image.
sourceImgContext.drawImage(bufferCanvas, 0, 0, sourceImgCanvas.width, sourceImgCanvas.height);

正如你所看到的,我不再使用 canvas.drawImage / code>切片源图像,我只是缩放它适合画布。

As you can see, I no longer use canvas.drawImage() to slice the source image, I simply scale it to fit the canvas.

似乎我是以错误的方式,但希望任何遇到类似问题的人都会发现此方法很有帮助。

Seems I was going about it the wrong way, but hopefully anyone else experiencing similar issues will find this method helpful.

这篇关于iOS平台上的HTML5画布缩放问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 00:13