Przycinanie białych znaków z obrazu w PHP

Czy możliwe jest usunięcie białych znaków otaczających obraz w PHP?

Uwaga: dla wyjaśnienia mam na myśli coś w rodzaju funkcji przycinania photoshopów.

Dzięki.
Author: usertest, 2009-11-03

6 answers

Aby przyciąć wszystkie białe spacje, jak to nazywasz, otaczające interesującą część obrazu, najpierw dowiadujemy się, gdzie kończy się "biała spacja", a następnie kopiujemy wszystko wewnątrz tych granic.

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

Mój stary przykład, który zakłada identyczną "obramowanie" ze wszystkich stron obrazu, tylko dla wyjaśnienia komentarzy:)

//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");
 48
Author: gnud,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-05 10:07:37

Skrypt Gnuda redundantnie nazywa imagesx i imagesy. Powtarza również każdy piksel z każdej strony, nawet gdy rogi zachodzą na siebie. Ta ulepszona wersja eliminuje zbędne wywołania funkcji i sprawdza każdy piksel tylko raz, zapewniając znaczny wzrost prędkości. Funkcja zwraca status ($result ['# ' ]) równy 2, jeśli każdy piksel jest przycięty.

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
Author: skibulk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-15 18:27:26

Wiem, że to dość stare, ale jeśli masz włączony ImageMagick, możesz użyć tej metody

Trim Image

 6
Author: Bill H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 22:20:13

Biblioteka GD PHP posiada funkcję 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
}

Domyślnie imagecropauto będzie próbował przyciąć za pomocą przezroczystości, a następnie wycofać się przy użyciu 4 rogów obrazu, aby spróbować wykryć tło do przycięcia; odniosłem również sukces z następującymi stałymi zamiast IMG_CROP_AUTO w powyższym przykładzie:

  • IMG_CROP_BLACK - przydatne dla obrazów z czarnym tłem
  • IMG_CROP_WHITE - przydatne dla obrazów z białym tłem
  • IMG_CROP_THRESHOLD - pozwala ustawić kolor i próg do użycia podczas kadrowania

imagecropauto jest zawarte w php od wersji 5.5, aby uzyskać więcej informacji zobacz dokumentacja PHP dla imagecropauto tutaj .

 3
Author: SteJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-15 00:22:36

Zdaję sobie sprawę, że jest to dość stare, ale mam nieco inne podejście do przycinania obrazu przez GD. Zamiast robić tylko jedną stronę na raz - zrobić wszystkie cztery. Jest szybszy i tańszy pod pewnymi względami. Jeśli jednak zatrzymasz pętle FOR w momencie, gdy znajdziesz górne-dolne-lewe-prawe strony - to jest szybciej.

Więc najpierw jest:

#
#   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;
                    }
                }
            }

I jest jeszcze:

#
#   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; }
                }

W obu przypadkach zmienna $color zawiera pierwszą kropkę koloru w image:

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

Dzieje się tak dlatego, że w obrazach GIF-pierwsza kropka jest w 99% przezroczystym (lub tłem) kolorem. Również offset $jest (dla mnie) sposobem na stwierdzenie, że wiem, że obraz będzie tylko tak szeroki i tak wysoki. Więc jeśli narysuję coś, co jest tylko maksimum 256 na 256, ale umieszczę to na tle 1024 x 1024, mogę Walić trochę tego tła i zrobić przesunięcie 255, dzięki czemu pętle FOR idą tylko z 255 do (1024-255) lub 769.

Ok-zanim ktoś pyta-dlaczego miałbym to zrobić - ponieważ niektóre czcionki (jak Bastarda) nie mają w sobie prawidłowej informacji o czcionce i wyjście 256pt z litery " z " tworzy obraz, w którym dno "z" przechodzi przez 256 (w dół do czegoś takiego jak 512), więc aby uzyskać cały obraz, musisz zacząć (lub zakończyć) dalej niż myślisz, że czcionka pójdzie. Więc podzieliłem różnicę i walnąłem 255 pikseli z obu końców. To było po tym, jak zobaczył, że Bastarda robi to.

Niektóre dodatkowe uwagi:

1. Obrazy PNG możesz skonfigurować tak, aby były jak obrazy GIF, ale zwykle musisz określić, jaki będzie kolor tła.
2. Obrazy JPEG nie dekompresują dokładnie w ten sam sposób za każdym razem. Więc nawet porównanie tego samego obrazu, który załadowałeś dwa razy, może nie działać tak samo i może dać różne rozmiary.
3. Te procedury działają najlepiej na prostych czarno-białych (lub dwukolorowych) obrazach. Wiele kolorów może odrzucić te procedury. Szczególnie jeśli zdecydujesz się na stosowanie tolerancji.
4. Aby użyć tolerancji do określenia, czy krawędź obrazu została znaleziona, wystarczy wstępnie obliczyć zarówno wysoką, jak i niską tolerancję (np. jeśli na czerwonym komponencie jest tolerancja 5 (5), można ją obliczyć jako X-5-do-x+5 lub X-2.5-do-x+2.5 W zależności od tego, czy tolerancja ma być całym zakresem, czy tylko+/ -). Możesz mieć tolerancję dla czerwonych, zielonych, niebieskich i Alfa części koloru lub całego kolor sam w sobie. Tak więc istnieje kilka różnych tolerancji, które można obliczyć, jeśli chcesz, a wszystkie z nich są poprawnym sposobem, aby to zrobić w zależności od potrzeb.

 2
Author: Mark Manning,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-29 07:23:51

Sprawdź bibliotekę ImageMagick w PHP. Posiada dobre metody pracy i manipulowania obrazami (w tym crop).

Będziesz musiał dowiedzieć się, gdzie jest "biała spacja" wokół obrazu. Może to być trudne, ponieważ "whitespace" może być kolor biały, inny kolor, przezroczystość itp...

 1
Author: jheddings,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 19:50:30