我一直在开发一个phonegap项目,试图为Android和iOS构建。主要思想是访问手机库中保存的图片,将该图片保存为HTML img元素,然后将该img元素绘制到画布上。从那里,用户可以缩放和旋转图像。
我在Android上没有任何问题。我已经使用仿真器和设备进行了测试,并测试了各种设备(不同的像素比率,密度等),结果画布转换始终给出了预期的结果。
另一方面,iOS版本并没有那么成功。缩放/旋转画布看起来很好,直到我将画布缩放到比原始尺寸略大(比原始尺寸大4-5像素)。在缩小画布大小后,画布上绘制的图像会发生变化。我现在通常只看到整个画布上的一小部分图像(通常是左上角),而不是现在看到整个图像显示。
我在html中的画布:
<canvas id="sourceImgCanvas" width="200" height="200" style="z-index:1; position:absolute; left:5%; top:100px;"></canvas>
我从手机库收到的图像几乎总是对手机屏幕来说太大了。我缩小图像并记录缩小图像的比例(如果没有缩放,则drawRatio为1,如果图像缩小以适合屏幕,则drawRatio大于1)。 PhoneGap处理从手机库中抓取图片,我只需使用照片中返回的imageURI并将其设置为img元素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;
}
要缩放画布,我在画布的右下角有一个箭头。在被拖动时,它会记录距画布左上角的距离,并根据距离设置画布高度/宽度。
//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是我在重新调整图像大小时所存储的比例(此处未显示的代码;它相当长,但很简单。)
drawRatioMod
是我在试验时设定的值,是我问题的主要焦点。在Android上,我设置了drawRatioMod = 1
,以便不会影响绘图。在iPhone4 / iPad(我可以测试的设备)上,我设置了drawRatioMod = 0.5
。这解决了我在iOS上使用html5画布时遇到的一些初始问题:由于iPhone4的分辨率实际上是屏幕尺寸的两倍,因此我将源图像的长度/宽度缩小了一半。
每次用户移动调整大小箭头工具时都会调用上面的ResizeSourceImage()
函数,从而更新画布大小。如果缩小,图像将适当调整为新的画布尺寸 。如果我将画布缩放到大约5-6像素,画布将不再绘制整个源图像;相反,画布仅在整个画布上绘制图像的左上角。
我已经解决了这个问题几天而且没有运气。我最初认为它与设备像素比率有关(可以通过Javascript window.devicePixelRatio
访问),但我已经测试了几种不同比率的Android设备并且从未有过这样的结果。
我觉得我非常接近解决,因为在iOS上放大图像时图像只显示不正确。任何指针/提示非常感谢!我尝试了几个与window.devicePixelRatio
相关的修复程序,但是我的iPad的iPhone4模拟器总是返回一个pixelRatio为1(这看起来不对),而且我没有运气这样的修复。
干杯! (我试图发布处理缩放和绘制画布的简单代码。如果你想看到更多代码,我可以发布更多;希望有一个不像中国长城的帖子:))
答案 0 :(得分:3)
经过几天的测试后,我终于找到了罪魁祸首:使用myContext.drawImage()
切片图像只是iOS中的一大难题(可能是由于视网膜显示,但我不是100肯定的。)
我所做的是双缓冲和使用myContext.drawImage()
到仅比例的组合,而不是切片。
FelineSoft在画布相关的几个方面有很棒的帖子。这里解释了双缓冲:http://www.felinesoft.com/blog/index.php/2010/09/accelerated-game-programming-with-html5-and-canvas/
所以,不要像这样切割原始图像:
sourceImgContext.drawImage(sourceImg, 0, 0, pictureWidth * drawRatio * drawRatioMod, pictureHeight * drawRatio * drawRatioMod, 0, 0, sourceImgCanvas.width, sourceImgCanvas.height);
我将图像绘制到缓冲区,然后将其绘制到用户在屏幕上看到的画布上。回顾过去,我可能没有必要使用缓冲区来解决这个扩展问题,但这是习惯的好习惯:
//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()
来切割源图像,我只是将其缩放以适合画布。
似乎我的方式错误,但希望其他遇到类似问题的人会发现这种方法很有帮助。