Crop whitespace à partir de L'image en PHP

est-il possible de supprimer les espaces entourant une image en PHP?

NOTE: pour clarifier, je veux dire quelque chose comme la fonction de finition photoshops.

Merci.

22
demandé sur usertest 2009-11-03 22:41:51

6 réponses

couper tous les espaces, comme vous l'appelez, entourant la partie intéressante de l'image, nous avons d'abord savoir où les "espaces" s'arrête, et ensuite, on copie tout à l'intérieur de ces frontières.

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

mon ancien exemple, qui suppose une "frontière" identique de tous les côtés de l'image, juste pour clarifier les commentaires:)

//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
répondu gnud 2009-11-05 10:07:37

le script de Gnud appelle de façon redondante imagesx et imagesy. Il itère également chaque pixel de chaque côté, même lorsque les coins se chevauchent. Cette version améliorée élimine les appels de fonction redondants et vérifie chaque pixel une seule fois, accordant une augmentation significative de la vitesse. La fonction renvoie un statut ($result['#']) égal à 2 si chaque pixel est taillée.

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
répondu skibulk 2017-05-15 18:27:26

je sais que c'est assez vieux, mais si vous avez ImageMagick est activé, vous pouvez utiliser cette méthode

Rogner L'Image

6
répondu Bill H 2010-08-26 22:20:13

la bibliothèque GD de PHP a le imagecropauto fonction:

<?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
}

Par défaut imagecropauto essaiera de recadrer en utilisant la transparence, puis retombera en utilisant les 4 coins de l'image pour tenter de détecter l'arrière-plan de recadrer; j'ai aussi eu du succès avec les constantes suivantes à la place de IMG_CROP_AUTO dans l'exemple ci-dessus:

  • IMG_CROP_BLACK - Utile pour les images avec un fond noir
  • IMG_CROP_WHITE - Utile pour les images avec un blanc arrière-plan
  • IMG_CROP_THRESHOLD - Permet de définir une couleur et d'un seuil à utiliser lors du recadrage

imagecropauto est inclus dans php depuis la version 5.5, Pour plus d'informations voir le Documentation PHP pour imagecropauto ici.

3
répondu SteJ 2017-11-15 00:22:36

je me rends compte que c'est assez ancien, mais j'ai un point de vue légèrement différent sur le découpage d'une image via GD. Au lieu de faire juste un côté à la fois - faites tous les quatre. Il est plus rapide et moins coûteux cpu-sage à certains égards. Cependant, si vous arrêtez les boucles FOR au moment où vous trouvez les côtés supérieur-inférieur-gauche-droite - qui est plus rapide que cela.

Donc il y a d'abord:

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

et puis il y a:

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

dans les deux cas, la variable $ color contient la première pastille de couleur dans l'image:

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

c'est parce que dans les images GIF - le premier point est 99% du temps la couleur transparente (ou fond). De plus, le $ offset est (pour moi) une façon de dire que je sais que l'image ne sera que si large et si haute. Donc, si je dessine quelque chose qui est seulement un maximum de 256 par 256 mais je l'ai mis sur un fond 1024 x 1024 je peux frapper une partie de ce fond et faire un décalage de 255 ce qui rend les boucles pour aller seulement de 255 à (1024-255) ou 769.

Ok-avant que quelqu'un demande - pourquoi je ferais une telle chose - parce que certaines polices (comme Bastarda) n'ont pas les bonnes informations de police et une sortie 256pt de la lettre "z" produit une image où le bas du "z" va au-delà de 256 (vers le bas à quelque chose comme 512) donc pour obtenir l'image entière vous devez commencer (ou finir) plus bas que ce que vous pensez que la police irait. Donc je divise la différence et j'enlève 255 pixels de chaque extrémité. Ce fut après en fait voir que Bastarda fait ça.

Quelques notes supplémentaires:

1. Les images PNG que vous pouvez configurer pour être comme des images GIF mais normalement vous devrez spécifier quelle sera la couleur de fond.

2. Les images JPEG ne décompressent pas exactement de la même façon à chaque fois. Donc, même en comparant la même image que vous avez chargée deux fois pourrait ne pas fonctionner le même et peut donner des tailles différentes.

3. Ces routines fonctionnent mieux sur simple noir et blanc (ou deux couleurs) image. Plusieurs couleurs peuvent jeter ces routines. Surtout si vous décidez d'utiliser les tolérances.

4. Pour utiliser les tolérances pour déterminer si vous avez trouvé le bord d'une image, tout ce que vous avez à faire est de pré-calculer à la fois la haute et la basse tolérance (i.e.: si vous avez une tolérance de cinq(5) sur le composant rouge, alors vous pouvez calculer la tolérance comme X-5-to-x+5 ou x-2.5-to-x+2.5 selon que vous voulez que la tolérance soit toute la gamme ou juste la gamme+/ -). Vous pouvez avoir un tolérance pour les parties rouge, verte, bleue et ALPHA de la couleur ou la couleur entière elle-même. Donc il y a plusieurs tolérances différentes que vous pouvez calculer si vous voulez et toutes sont la bonne façon de le faire en fonction de vos besoins.

2
répondu Mark Manning 2015-12-29 07:23:51

découvrez le ImageMagick bibliothèque en PHP. Il dispose de bonnes méthodes de travail et de manipulation des images (y compris culture