问题描述
我一直在开发一个在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画布缩放问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!