обрезать изображение на его содержимое [дубликат]

21
задан usertest 3 November 2009 в 21:02
поделиться

6 ответов

Чтобы обрезать все пробелы, как вы его называете, окружая интересную часть изображения, сначала мы узнаем, где останавливается «пробел», а затем мы копируем все внутри этих границ.

//load the image
$img = imagecreatefromjpeg("http://ecx.images-amazon.com/images/I/413XvF0yukL._SL500_AA280_.jpg");

//find the size of the borders
$b_top = 0;
$b_btm = 0;
$b_lft = 0;
$b_rt = 0;

//top
for(; $b_top < imagesy($img); ++$b_top) {
  for($x = 0; $x < imagesx($img); ++$x) {
    if(imagecolorat($img, $x, $b_top) != 0xFFFFFF) {
       break 2; //out of the 'top' loop
    }
  }
}

//bottom
for(; $b_btm < imagesy($img); ++$b_btm) {
  for($x = 0; $x < imagesx($img); ++$x) {
    if(imagecolorat($img, $x, imagesy($img) - $b_btm-1) != 0xFFFFFF) {
       break 2; //out of the 'bottom' loop
    }
  }
}

//left
for(; $b_lft < imagesx($img); ++$b_lft) {
  for($y = 0; $y < imagesy($img); ++$y) {
    if(imagecolorat($img, $b_lft, $y) != 0xFFFFFF) {
       break 2; //out of the 'left' loop
    }
  }
}

//right
for(; $b_rt < imagesx($img); ++$b_rt) {
  for($y = 0; $y < imagesy($img); ++$y) {
    if(imagecolorat($img, imagesx($img) - $b_rt-1, $y) != 0xFFFFFF) {
       break 2; //out of the 'right' loop
    }
  }
}

//copy the contents, excluding the border
$newimg = imagecreatetruecolor(
    imagesx($img)-($b_lft+$b_rt), imagesy($img)-($b_top+$b_btm));

imagecopy($newimg, $img, 0, 0, $b_lft, $b_top, imagesx($newimg), imagesy($newimg));

//finally, output the image
header("Content-Type: image/jpeg");
imagejpeg($newimg);

Мой старый пример, который предполагает идентичную «границу» со всех сторон изображения, просто для уточнения комментариев:)

//load the image
$img = imagecreatefromjpeg("img.jpg");

//find the size of the border.
$border = 0;
while(imagecolorat($img, $border, $border) == 0xFFFFFF) {
  $border++;
}

//copy the contents, excluding the border
//This code assumes that the border is the same size on all sides of the image.
$newimg = imagecreatetruecolor(imagesx($img)-($border*2), imagesy($img)-($border*2));
imagecopy($newimg, $img, 0, 0, $border, $border, imagesx($newimg), imagesy($newimg));

//finally, if you want, overwrite the original image
imagejpeg($newimg, "img.jpg");
49
ответ дан gnud 24 August 2018 в 09:26
поделиться
  • 1
    Хороший пример ... Как вы указываете (просто для уточнения), это предполагает, что граница вокруг изображения имеет фиксированную границу белого. – jheddings 3 November 2009 в 20:53
  • 2
    Привет, граница не является фиксированным. Я думаю о чем-то вроде функции обрезки photoshop. – usertest 3 November 2009 в 20:59
  • 3
    Я просто попробовал код, он отсекает часть изображения. – usertest 3 November 2009 в 21:01
  • 4
    Этот код не предполагает фиксированный размер границы (например, все границы равны 14px), но он предполагает, что граница имеет одинаковый размер со всех сторон изображения. Однако вы можете использовать это как отправную точку. Помните, что проверка всех пикселей со всех сторон будет медленной - не делайте этого каждый раз, когда вы показываете изображение, делайте это, когда пользователь загружает его в первый раз :) – gnud 3 November 2009 в 21:01
  • 5
    Это то, что я искал. – Ankit 13 February 2016 в 00:37

Я знаю, что это довольно старый, но если у вас включен ImageMagick, вы можете использовать этот метод

Trim Image

6
ответ дан Bill H 24 August 2018 в 09:26
поделиться
  • 1
    Imagick :: trimImage теперь имеет параметр fuzz: & quot; По умолчанию цель должна точно соответствовать определенному цвету пикселей. Однако во многих случаях два цвета могут отличаться небольшим количеством. Элемент fuzz изображения определяет, насколько допустима допустимость считать два цвета одинаковыми. Этот параметр представляет изменение на квантовом диапазоне. – jjwdesign 27 February 2017 в 14:17
  • 2
    Я хочу вырезать белую рамку из изображений, потому что она выглядит уродливой на не-белом фоне (красный, черный и т. Д.). Библиотека Php's Imagick имеет только функцию Imagick- & gt; trimImage (), который только разделяет границы, которые совпадают с фоном, - бесполезен для меня. – a20 30 November 2017 в 12:42
  • 3
    Попробуйте использовать Imagick :: shave (). Пока границы равны, это должно помочь. – Bill H 30 November 2017 в 20:52

Проверьте библиотеку ImageMagick в PHP. Он имеет хорошие методы работы с изображениями (в том числе crop ).

Вам нужно выяснить, где «пробелы» вокруг изображения. Это может быть сложной задачей, поскольку «пробел» может быть цветом белого, другого цвета, прозрачности и т. Д. ...

1
ответ дан jheddings 24 August 2018 в 09:26
поделиться
  • 1
    Я хочу вырезать белую рамку из изображений, потому что она выглядит уродливой на не-белом фоне (красный, черный и т. Д.). Библиотека Php's Imagick имеет только функцию Imagick- & gt; trimImage (), который только разделяет границы, которые совпадают с фоном, - бесполезен для меня. – a20 30 November 2017 в 12:42

Я понимаю, что это довольно старый, но я немного по-другому беру на обрезку изображения через GD. Вместо того, чтобы делать только одну сторону за раз - все четыре. В какой-то степени это быстрее и дешевле cpu-wise. Однако, если вы остановите цикл FOR в тот момент, когда вы найдете стороны верхнего и нижнего левого правого угла - это быстрее, чем это.

Итак, сначала есть:

#
#   Do all four sides at once
#
        echo "Finding the top-left-bottom-right edges of the image...please wait.\n";
        $top = 99999;
        $bot = -99999;
        $left = 99999;
        $right = -99999;
        for( $x=$offset; $x<($w-$offset); $x++ ){
            for( $y=$offset; $y<($h-$offset); $y++ ){
                $rgb = imagecolorat( $gd, $x, $y );
                if( $color != $rgb ){
                    $left = ($x < $left) ? $x : $left;
                    $right = ($x > $right) ? $x : $right;
                    $top = ($y < $top) ? $y : $top;
                    $bot = ($y > $bot) ? $y : $bot;
                    }
                }
            }

а затем есть:

#
#   Top
#
            echo "Finding the top of the image\n";
            $top = null;
            for( $y=$offset; $y<($h-$offset); $y++ ){
                for( $x=$offset; $x<($w-$offset); $x++ ){
                    $rgb = imagecolorat( $gd, $x, $y );
                    if( $color != $rgb ){ $top = $y; break; }
                    }

                if( !is_null($top) ){ break; }
                }
#
#   Bottom
#
            echo "Finding the bottom of the image\n";
            $bot = null;
            for( $y=($h-$offset); $y>$offset; $y-- ){
                for( $x=$offset; $x<($w-$offset); $x++ ){
                    $rgb = imagecolorat( $gd, $x, $y );
                    if( $color != $rgb ){ $bot = $y; break; }
                    }

                if( !is_null($bot) ){ break; }
                }
#
#   Left
#
            echo "Finding the left of the image\n";
            $left = null;
            for( $x=$offset; $x<($w-$offset); $x++ ){
                for( $y=$offset; $y<($h-$offset); $y++ ){
                    $rgb = imagecolorat( $gd, $x, $y );
                    if( $color != $rgb ){ $left = $x; break; }
                    }

                if( !is_null($left) ){ break; }
                }
#
#   right
#
            echo "Finding the right of the image\n";
            $right = null;
            for( $x=($w-$offset); $x>$offset; $x-- ){
                for( $y=$offset; $y<($h-$offset); $y++ ){
                    $rgb = imagecolorat( $gd, $x, $y );
                    if( $color != $rgb ){ $right = $x; break; }
                    }

                if( !is_null($right) ){ break; }
                }

В обоих случаях переменная цвета $ содержит первую цветную точку на изображении:

$color = imagecolorat( $gd, 0, 0 );

Это происходит потому, что в изображениях GIF - первая точка в 99% случаев является прозрачным (или фоновым) цветом. Кроме того, смещение $ (для меня) означает, что я знаю, что изображение будет только таким широким и таким высоким. Поэтому, если я нарисую что-то, что составляет максимум 256 на 256, но я помещаю его на фон 1024 x 1024, я могу отбросить часть этого фона и сделать смещение 255, тем самым делая цикл FOR только от 255 до (1024 -255) или 769.

Хорошо - до того, как кто-то спросит - ПОЧЕМУ Я бы сделал такое - потому что некоторые шрифты (например, Bastarda) не имеют в них правильной информации о шрифтах, а выход 256pt буква «z» создает изображение, в котором дно «z» проходит мимо 256 (вплоть до примерно 512), поэтому, чтобы получить весь образ, который вы должны запустить (или закончить) дальше, чем то, что вы думаете шрифт пойдет. Поэтому я разделил разницу и ударил 255 пикселей с обоих концов. Это означало, что Bastarda делает это.

Некоторые дополнительные примечания:

1. Изображения PNG, которые вы можете настроить как изображения GIF, но обычно вам нужно будет указать, что цвет фона будет. 2. Изображения JPEG НЕ разматывают точно так же каждый раз. Поэтому даже сравнение того же изображения, которое вы загрузили дважды, может не работать одинаково и может давать разные размеры. 3. Эти процедуры лучше всего работают на простых черно-белых (или двухцветных) изображениях. Несколько цветов могут отбросить эти процедуры. Особенно, если вы решите использовать допуски. 4. Чтобы использовать допуски, чтобы определить, нашли ли вы край изображения, все, что вам нужно сделать, это предварительно вычислить как высокий, так и низкий допуск (т. Е. Если у вас есть допущение пяти (5) на красном компоненте , то вы можете вычислить допуск как X-5-x-x + 5 или x-2,5-x + 2,5 в зависимости от того, хотите ли вы, чтобы допуск был диапазоном WHOLE или только диапазоном +/-). Вы можете иметь допуск для красных, зеленых, голубых и ALPHA частей цвета или всего цвета. Таким образом, существует несколько разных допусков, которые вы можете вычислить, если хотите, и все они - правильный способ сделать это в зависимости от ваших потребностей.

2
ответ дан Mark Manning 24 August 2018 в 09:26
поделиться

Сценарий Гнуда избыточно вызывает imagesx и imagesy. Он также выполняет итерацию каждого пикселя со всех сторон, даже когда углы перекрываются. Эта улучшенная версия исключает избыточные вызовы функций и проверяет каждый пиксель только один раз, обеспечивая значительное увеличение скорости. Функция возвращает статус ($ result ['#']), равный 2, если каждый пиксель обрезается.

example();
function example(){
    $img = imagecreatefromjpeg("http://ecx.images-amazon.com/images/I/413XvF0yukL._SL500_AA280_.jpg");

    // find the trimmed image border
    $box = imageTrimBox($img);

    // copy cropped portion
    $img2 = imagecreate($box['w'], $box['h']);
    imagecopy($img2, $img, 0, 0, $box['l'], $box['t'], $box['w'], $box['h']);

    // output cropped image to the browser
    header('Content-Type: image/png');
    imagepng($img2);

    imagedestroy($img);
    imagedestroy($img2);
}



function imageTrimBox($img, $hex=null){
if (!ctype_xdigit($hex)) $hex = imagecolorat($img, 0,0);
$b_top = $b_lft = 0;
$b_rt = $w1 = $w2 = imagesx($img);
$b_btm = $h1 = $h2 = imagesy($img);

do {
    //top
    for(; $b_top < $h1; ++$b_top) {
        for($x = 0; $x < $w1; ++$x) {
            if(imagecolorat($img, $x, $b_top) != $hex) {
                break 2;
            }
        }
    }

    // stop if all pixels are trimmed
    if ($b_top == $b_btm) {
        $b_top = 0;
        $code = 2;
        break 1;
    }

    // bottom
    for(; $b_btm >= 0; --$b_btm) {
        for($x = 0; $x < $w1; ++$x) {
            if(imagecolorat($img, $x, $b_btm-1) != $hex) {
                break 2;
            }
        }
    }

    // left
    for(; $b_lft < $w1; ++$b_lft) {
        for($y = $b_top; $y <= $b_btm; ++$y) {
            if(imagecolorat($img, $b_lft, $y) != $hex) {
                break 2;
            }
        }
    }

    // right
    for(; $b_rt >= 0; --$b_rt) {
        for($y = $b_top; $y <= $b_btm; ++$y) {
            if(imagecolorat($img, $b_rt-1, $y) != $hex) {
                break 2;
            }
        }

    }

    $w2 = $b_rt - $b_lft;
    $h2 = $b_btm - $b_top;
    $code = ($w2 < $w1 || $h2 < $h1) ? 1 : 0;
} while (0);

// result codes:
// 0 = Trim Zero Pixels
// 1 = Trim Some Pixels
// 2 = Trim All Pixels
return array(
    '#'     => $code,   // result code
    'l'     => $b_lft,  // left
    't'     => $b_top,  // top
    'r'     => $b_rt,   // right
    'b'     => $b_btm,  // bottom
    'w'     => $w2,     // new width
    'h'     => $h2,     // new height
    'w1'    => $w1,     // original width
    'h1'    => $h1,     // original height
);
}
11
ответ дан skibulk 24 August 2018 в 09:26
поделиться
  • 1
    Спасибо за это. Я столкнулся с некоторыми проблемами, пытаясь получить доступ к пикселям вне диапазона. Как если бы изображение было 1500 пикселей в ширину, то оно попыталось бы вызвать imagecolorat ($ img, 1500, 5); $ b_rt & amp; $ b_btm должно быть на 1 меньше ширины & amp; высота, соответственно. – Mike Odie 14 October 2014 в 01:31

В gd-библиотеке PHP есть функция imagecropauto:

<?php 
$img=imagecreatefrompng("tux.png"); // Load and instantiate the image
if($img) {
  $cropped=imagecropauto($img,IMG_CROP_DEFAULT); // Auto-crop the image

  imagedestroy($img); // Clean up as $img is no longer needed

  header("Content-type: image/png"); // Set the appropriate header so the browser
                                     // knows how to present it
  imagepng($cropped); // Return the newly cropped image
}

По умолчанию imagecropauto будет пытаться обрезать с использованием прозрачности, а затем вернуться к использованию с помощью 4-х углов изображения, чтобы попытаться определить фон для обрезки; У меня также был успех со следующими константами вместо IMG_CROP_AUTO в приведенном выше примере:

  • IMG_CROP_BLACK - Полезно для изображений с черным фоном
  • IMG_CROP_WHITE - Полезно для изображений с белым фоном
  • IMG_CROP_THRESHOLD - Позволяет установить цвет и порог для использования при обрезке

Включен imagecropauto в php с версии 5.5, для получения дополнительной информации см. документацию PHP для imagecropauto здесь .

2
ответ дан SteJ 24 August 2018 в 09:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: