Как перевернуть изображение с помощью HTML5 canvas без масштабирования


Я использую элемент HTML5 canvas для отображения изображения в веб-приложении, и я хочу перевернуть изображение по горизонталибез применения преобразования масштабирования к холсту. Это означает, что я не хочу использовать CanvasRenderingContext2D.scale() для этой цели, потому что я не хочу переворачивать что-либо еще.

// I don't want this, because it breaks the rest of the application. I have
// implemented zooming and landmark placement functionality, which no longer
// work properly after scaling.
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0, image.width, image.height);
ctx.restore();

Мне кажется, что я должен быть в состоянии сделать это с помощью метода CanvasRenderingContext2D.drawImage(), так как эта страница читает:

SWidth: ширина под-прямоугольника исходного изображения, который нужно нарисовать в контексте назначения. Если не задано, то используется весь прямоугольник от координат, заданных SX и sy, до нижнего правого угла изображения. если задано отрицательное значение, то при рисовании изображение переворачивается по горизонтали.

Вот как я рисую изображение:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var image = document.getElementById('source');
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height);

Рабочий пример здесь: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Using_the_drawImage_method

Но если я попытаюсь перевернуть изображение в соответствии с описанием, я получу следующую ошибку в Firefox:

ctx.drawImage(image, 0, 0, -image.width, image.height, 0, 0, image.width, image.height);

IndexSizeError: индекс или размер отрицательный или больше допустимого сумма

Я не понимаю, что я здесь делаю не так. Как перевернуть изображение по горизонтали без масштабирования холста?
2 2

2 ответа:

Отрицательная область, по-видимому, не поддерживается (пока?), или эта строка может повлиять на то, как выполняется реализация, см. Шаг 4:

Данные изображения должны обрабатываться в исходном направлении, даже если приведенные измерения отрицательны.

В любом случае, мы ничего не можем с этим поделать, кроме как посмотреть на альтернативные пути -

Это оставляет вам некоторые варианты, хотя-я предполагаю, что вы хотите избежать использования save / restore, и вы можете -

Преобразование сброса

Это самый быстрый метод, но вы должны знать, что он сбросит любое преобразование. И это может быть нормально в большинстве случаев, так что:
ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);
Последний вызов-сброс матрицы преобразования с использованием матрицы идентификации.

Реверсирование последней операции преобразования

Если вы зависите от других преобразований, вы можете просто отменить последнюю операцию преобразования. Это второй самый быстрый вариант (он нужен чтобы сделать умножение матрицы внутренне):

ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.scale(-1, 1);   // revert scale only

Использование save / restore

Как вы уже знаете... но медленно, так как это сохраняет и восстанавливает все состояние холста, а не только трансформацию.

Листать вручную

Если по какой-то причине требуется вообще не использовать преобразование, вы всегда можете перевернуть его scanline by scanline. Это второй наименее эффективный метод, но он позволяет работать без преобразований, и это действительно позволяет вы должны делать другие вещи, такие как перемещение:

for(var x = 0; x < width; x++)
    ctx.drawImage(img, x, 0, 1, height, width - x, 0, 1, height);

(ширина и высота-это ширина и высота изображения).

Манипуляция пикселями

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

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