Обрезать пробелы из изображения в PHP

можно ли удалить пробелы, окружающие изображение в PHP?

Примечание: чтобы уточнить, я имею в виду что-то вроде функции обрезки фотосессий.

спасибо.

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");

скрипт Gnud избыточно вызывает 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
);
}

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

Обрезать Изображения


библиотека 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 здесь.


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

$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 пикселей с обоих концов. Это было после того, как на самом деле видеть, как этот ублюдок делает это.

дополнительные сведения:

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


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

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