Проблема масштабирования HTML5-холста на платформах iOS - PullRequest
3 голосов
/ 06 июля 2011

Я разрабатываю проект в 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, если масштабирование не произошло, больше 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.Это решило некоторые первоначальные проблемы, с которыми я столкнулся при работе с холстом html5 на iOS: поскольку разрешение iPhone4 фактически в два раза больше размера экрана, я уменьшил длину / ширину исходного изображения, которое нужно нарисовать, наполовину.

выше ResizeSourceImage() функция вызывается каждый раз, когда пользователь перемещает инструмент изменения размера стрелки, таким образом обновляя размер холста.Изображение корректируется в соответствии с новым размером холста только , если я уменьшу его.Если масштабировать холст более чем на 5-6 пикселей, холст больше не рисует все исходное изображение;вместо этого холст рисует только верхний левый угол изображения по всему холсту.

Я занимался этой проблемой в течение нескольких дней и мне не повезло.Сначала я думал, что это как-то связано с соотношением пикселей устройства (доступно через Javascript window.devicePixelRatio), но я тестировал на нескольких устройствах Android с различным соотношением и никогда не получал такого результата.

Мне кажется, что я очень близок к решению, так как изображение отображается неправильно только при увеличении на iOS.Любые указатели / советы с благодарностью!Я пробовал несколько исправлений, связанных с window.devicePixelRatio, но симулятор iPhone4 на моем iPad всегда возвращает pixelRatio 1 (что кажется неправильным), и мне не повезло с такими исправлениями.

Ура!(Я попытался опубликовать простой код, касающийся масштабирования и рисования холста. Если вы хотите увидеть дополнительный код, я могу опубликовать больше; надеялся получить пост, не похожий на Великую китайскую стену:))

1 Ответ

3 голосов
/ 08 июля 2011

После тестирования этого в течение нескольких дней, я наконец нашел виновника: использование 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() для нарезки исходного изображения, я просто масштабирую его, чтобы он соответствовал холсту.

Кажется, я поступил неправильно, но, надеюсь, любой другой, кто столкнулся с подобными проблемами, сочтет этот метод полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...