Подтвердить что ты не робот

Автоматическое масштабирование изображения с помощью jQuery

У меня есть 100 000 изображений, которые не под моим контролем. Некоторые из этих изображений превосходны тем, что изображение простирается до границ, в то время как некоторые из них имеют избыточное количество пробелов.

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

Вы можете видеть, что я имею в виду здесь:

http://www.fitness-saver.com/uk/shop/mountain-bikes/

То, что я искал, - это метод jQuery для обрезки изображений и автоматического удаления пробелов.

1) Количество пробелов различно в каждом изображении 2) Соотношения изображений различны 3) Я хочу использовать javascript вместо предварительной обработки изображений.

Надеюсь, вы сможете помочь!

Изменить: Вот пример изображения - http://images.productserve.com/preview/3395/128554505.jpg. Обратите внимание, что изображения поступают с разных партнерских сайтов и определенно из другого домена.

4b9b3361

Ответ 1

Для анализа пробелов в изображении я знаю только один способ - загрузить это изображение в canvas:

var img = new Image(),
    $canvas = $("<canvas>"), // create an offscreen canvas
    canvas = $canvas[0],
    context = canvas.getContext("2d");

img.onload = function () {
   context.drawImage(this, 0, 0); // put the image in the canvas
   $("body").append($canvas);
   removeBlanks(this.width, this.height);
};

// test image
img.src = 'http://images.productserve.com/preview/1302/218680281.jpg';

Затем используйте метод getImageData(). Этот метод возвращает объект ImageData, который можно использовать для проверки данных каждого цвета (цвет).

var removeBlanks = function (imgWidth, imgHeight) {
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height),
             data = imageData.data,
           getRBG = function(x, y) {
                      return {
                        red:   data[(imgWidth*y + x) * 4],
                        green: data[(imgWidth*y + x) * 4 + 1],
                        blue:  data[(imgWidth*y + x) * 4 + 2]
                      };
                    },
          isWhite = function (rgb) {
                      return rgb.red == 255 && rgb.green == 255 && rgb.blue == 255;
                    },
            scanY = function (fromTop) {
                      var offset = fromTop ? 1 : -1;

                      // loop through each row
                      for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {

                        // loop through each column
                        for(var x = 0; x < imgWidth; x++) {
                            if (!isWhite(getRBG(x, y))) {
                                return y;                        
                            }      
                        }
                    }
                    return null; // all image is white
                },
            scanX = function (fromLeft) {
                      var offset = fromLeft? 1 : -1;

                      // loop through each column
                      for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {

                        // loop through each row
                        for(var y = 0; y < imgHeight; y++) {
                            if (!isWhite(getRBG(x, y))) {
                                return x;                        
                            }      
                        }
                    }
                    return null; // all image is white
                };


        var cropTop = scanY(true),
            cropBottom = scanY(false),
            cropLeft = scanX(true),
            cropRight = scanX(false);
    // cropTop is the last topmost white row. Above this row all is white
    // cropBottom is the last bottommost white row. Below this row all is white
    // cropLeft is the last leftmost white column.
    // cropRight is the last rightmost white column.
};

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

Это не ошибка, это целевая функция. Из спецификаций:

ToDataURL(), toDataURLHD(), toBlob(), getImageData() и Методы getImageDataHD() проверяют флаг и выдают ошибку SecurityError исключение, а не утечка данных из разных источников.

Это происходит, когда drawImage() загружает файлы из внешних доменов, в результате чего для флага источника-чистоты холста устанавливается значение false, что предотвращает дальнейшие манипуляции с данными.

Боюсь, что вы столкнетесь с той же проблемой, но в любом случае вот код.

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


Изменить: Мне было любопытно посмотреть, действительно ли мой код обрезает изображение, и это действительно так. enter image description here

Вы можете проверить это здесь

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

// define here an image from your domain
img.src = 'http://localhost/strawberry2.jpg'; 

Очевидно, вам нужно будет запустить код из своего домена, а не из jsFiddle.


Edit2: Если вы хотите обрезать и масштабировать, чтобы сохранить то же соотношение сторон, то измените это

var $croppedCanvas = $("<canvas>").attr({ width: cropWidth, height: cropHeight });

// finally crop the guy
$croppedCanvas[0].getContext("2d").drawImage(canvas,
    cropLeft, cropTop, cropWidth, cropHeight,
    0, 0, cropWidth, cropHeight);

в

var $croppedCanvas = $("<canvas>").attr({ width: imgWidth, height: imgHeight });

// finally crop the guy
$croppedCanvas[0].getContext("2d").drawImage(canvas,
    cropLeft, cropTop, cropWidth, cropHeight,
    0, 0, imgWidth, imgHeight);

Edit3: Один из быстрых способов обрезать изображения в браузере - это распараллелить рабочую нагрузку с помощью Web Workers, как объясняется в этой превосходной статье.

Ответ 2

Основываясь на великолепном ответе, предоставленном Jose Rui Santos, я изменил его код для работы только с объектом image без библиотеки jQuery для загрузки.

Возвращением этой функции является URL-адрес данных обрезанного изображения, который будет использоваться непосредственно в элементе изображения.

/*
    Source: http://jsfiddle.net/ruisoftware/ddZfV/7/
    Updated by: Mohammad M. AlBanna
    Website: MBanna.info 
    Facebook: FB.com/MBanna.info
*/

var myImage = new Image();
myImage.crossOrigin = "Anonymous";
myImage.onload = function(){
    var imageData = removeImageBlanks(myImage); //Will return cropped image data
}
myImage.src = "IMAGE SOURCE";



//-----------------------------------------//
function removeImageBlanks(imageObject) {
    imgWidth = imageObject.width;
    imgHeight = imageObject.height;
    var canvas = document.createElement('canvas');
    canvas.setAttribute("width", imgWidth);
    canvas.setAttribute("height", imgHeight);
    var context = canvas.getContext('2d');
    context.drawImage(imageObject, 0, 0);

    var imageData = context.getImageData(0, 0, imgWidth, imgHeight),
        data = imageData.data,
        getRBG = function(x, y) {
            var offset = imgWidth * y + x;
            return {
                red:     data[offset * 4],
                green:   data[offset * 4 + 1],
                blue:    data[offset * 4 + 2],
                opacity: data[offset * 4 + 3]
            };
        },
        isWhite = function (rgb) {
            // many images contain noise, as the white is not a pure #fff white
            return rgb.red > 200 && rgb.green > 200 && rgb.blue > 200;
        },
                scanY = function (fromTop) {
        var offset = fromTop ? 1 : -1;

        // loop through each row
        for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {

            // loop through each column
            for(var x = 0; x < imgWidth; x++) {
                var rgb = getRBG(x, y);
                if (!isWhite(rgb)) {
                    if (fromTop) {
                        return y;
                    } else {
                        return Math.min(y + 1, imgHeight);
                    }
                }
            }
        }
        return null; // all image is white
    },
    scanX = function (fromLeft) {
        var offset = fromLeft? 1 : -1;

        // loop through each column
        for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {

            // loop through each row
            for(var y = 0; y < imgHeight; y++) {
                var rgb = getRBG(x, y);
                if (!isWhite(rgb)) {
                    if (fromLeft) {
                        return x;
                    } else {
                        return Math.min(x + 1, imgWidth);
                    }
                }      
            }
        }
        return null; // all image is white
    };

    var cropTop = scanY(true),
        cropBottom = scanY(false),
        cropLeft = scanX(true),
        cropRight = scanX(false),
        cropWidth = cropRight - cropLeft,
        cropHeight = cropBottom - cropTop;

    canvas.setAttribute("width", cropWidth);
    canvas.setAttribute("height", cropHeight);
    // finally crop the guy
    canvas.getContext("2d").drawImage(imageObject,
        cropLeft, cropTop, cropWidth, cropHeight,
        0, 0, cropWidth, cropHeight);

    return canvas.toDataURL();
}