2011-08-26 69 views
34

我想創建一個PHP腳本,它的圖像:PHP GD用一個形象來掩蓋另一個圖像,包括透明度

image1
http://i.stack.imgur.com/eNvlM.png

,然後應用PNG圖像:

mask
http://i.stack.imgur.com/iJr2I.png

作爲掩模。

最終的結果需要保持透明度:

result
http://i.stack.imgur.com/u0l0I.png

如果可能的話我想這樣做的GD,ImageMagick的是不是一個真正的選擇權了。

我該怎麼辦?

phalacee's post (in "PHP/GD, how to copy a circle from one image to another?")似乎是沿着正確的路線,但我特別需要使用圖像作爲面具,而不是形狀。

回答

48

馬特,

如果您與橢圓形白色填充黑色背景上的,而不是黑色填充用透明背景下面的函數確實是你的PNG。

<?php 
// Load source and mask 
$source = imagecreatefrompng('1.png'); 
$mask = imagecreatefrompng('2.png'); 
// Apply mask to source 
imagealphamask($source, $mask); 
// Output 
header("Content-type: image/png"); 
imagepng($source); 

function imagealphamask(&$picture, $mask) { 
    // Get sizes and set up new picture 
    $xSize = imagesx($picture); 
    $ySize = imagesy($picture); 
    $newPicture = imagecreatetruecolor($xSize, $ySize); 
    imagesavealpha($newPicture, true); 
    imagefill($newPicture, 0, 0, imagecolorallocatealpha($newPicture, 0, 0, 0, 127)); 

    // Resize mask if necessary 
    if($xSize != imagesx($mask) || $ySize != imagesy($mask)) { 
     $tempPic = imagecreatetruecolor($xSize, $ySize); 
     imagecopyresampled($tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx($mask), imagesy($mask)); 
     imagedestroy($mask); 
     $mask = $tempPic; 
    } 

    // Perform pixel-based alpha map application 
    for($x = 0; $x < $xSize; $x++) { 
     for($y = 0; $y < $ySize; $y++) { 
      $alpha = imagecolorsforindex($mask, imagecolorat($mask, $x, $y)); 
      $alpha = 127 - floor($alpha[ 'red' ]/2); 
      $color = imagecolorsforindex($picture, imagecolorat($picture, $x, $y)); 
      imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $alpha)); 
     } 
    } 

    // Copy back to original picture 
    imagedestroy($picture); 
    $picture = $newPicture; 
} 

?> 
+0

謝謝,這真的有幫助 – Matt

+0

我知道這篇文章已經關閉了一段時間,但運行時看起來像是什麼時候你們運行這個腳本?它平均需要20秒左右...我的源代碼/面具圖像是250 x 170px ...是關於你們正在得到什麼? –

+0

無視,不知道我做錯了什麼,但它現在很好用:P謝謝你們! –

10

這裏有一個小升級,這個腳本 - 我發現,如果源圖像有透明度本身,掩碼(使用上面的腳本)繪製一個回像素,而不是源圖像的透明像素。以下擴展腳本將源圖像透明度考慮在內,並將其保留。

// Load source and mask 
$source = imagecreatefrompng('1.png'); 
$mask = imagecreatefrompng('2.png'); 
// Apply mask to source 
imagealphamask($source, $mask); 
// Output 
header("Content-type: image/png"); 
imagepng($source); 

function imagealphamask(&$picture, $mask) { 
// Get sizes and set up new picture 
$xSize = imagesx($picture); 
$ySize = imagesy($picture); 
$newPicture = imagecreatetruecolor($xSize, $ySize); 
imagesavealpha($newPicture, true); 
imagefill($newPicture, 0, 0, imagecolorallocatealpha($newPicture, 0, 0, 0, 127)); 

// Resize mask if necessary 
if($xSize != imagesx($mask) || $ySize != imagesy($mask)) { 
    $tempPic = imagecreatetruecolor($xSize, $ySize); 
    imagecopyresampled($tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx($mask), imagesy($mask)); 
    imagedestroy($mask); 
    $mask = $tempPic; 
} 

// Perform pixel-based alpha map application 
for($x = 0; $x < $xSize; $x++) { 
    for($y = 0; $y < $ySize; $y++) { 
     $alpha = imagecolorsforindex($mask, imagecolorat($mask, $x, $y)); 

      if(($alpha['red'] == 0) && ($alpha['green'] == 0) && ($alpha['blue'] == 0) && ($alpha['alpha'] == 0)) 
      { 
       // It's a black part of the mask 
       imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, 0, 0, 0, 127)); // Stick a black, but totally transparent, pixel in. 
      } 
      else 
      { 

       // Check the alpha state of the corresponding pixel of the image we're dealing with.  
       $alphaSource = imagecolorsforindex($source, imagecolorat($source, $x, $y)); 

       if(($alphaSource['alpha'] == 127)) 
       { 
        imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, 0, 0, 0, 127)); // Stick a black, but totally transparent, pixel in. 
       } 
       else 
       { 
        $color = imagecolorsforindex($source, imagecolorat($source, $x, $y)); 
        imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $color['alpha'])); // Stick the pixel from the source image in 
       } 


      } 
    } 
} 

// Copy back to original picture 
imagedestroy($picture); 
$picture = $newPicture; 
} 
9

我喜歡你的腳本,當像素完全透明時,可以移除多餘的顏色信息。如果有人想使用這種方法,我應該指出一個小錯誤(IMO)。

$color = imagecolorsforindex($source, imagecolorat($source, $x, $y)); 

應該

$color = imagecolorsforindex($picture, imagecolorat($picture, $x, $y)); 

還我不是100%肯定,爲什麼你在這裏檢查RGB值,如果像素是100%透明

if(($alpha['red'] == 0) && ($alpha['green'] == 0) && ($alpha['blue'] == 0) && ($alpha['alpha'] == 0)) 
... 

和我不確定來自掩碼文件的alpha混合對於您的方法而言可以很好地工作,因爲它僅在rgba值全部等於0時使用。

J ules的腳本也很不錯,儘管它期望mask是一個掩碼的灰度表示(這是很常見的做法)。

在馬特的查詢中,他是在一個腳本後面抓取現有圖像的alpha透明度並將其應用於其他圖像。下面是Jules腳本的一個簡單模塊,用於從掩碼圖像中獲取alpha,並保留源圖像的alpha值。

<?php 
// Load source and mask 
$source = imagecreatefrompng('1.png'); 
$mask = imagecreatefrompng('2.png'); 
// Apply mask to source 
imagealphamask($source, $mask); 
// Output 
header("Content-type: image/png"); 
imagepng($source); 

function imagealphamask(&$picture, $mask) { 
    // Get sizes and set up new picture 
    $xSize = imagesx($picture); 
    $ySize = imagesy($picture); 
    $newPicture = imagecreatetruecolor($xSize, $ySize); 
    imagesavealpha($newPicture, true); 
    imagefill($newPicture, 0, 0, imagecolorallocatealpha($newPicture, 0, 0, 0, 127)); 

    // Resize mask if necessary 
    if($xSize != imagesx($mask) || $ySize != imagesy($mask)) { 
     $tempPic = imagecreatetruecolor($xSize, $ySize); 
     imagecopyresampled($tempPic, $mask, 0, 0, 0, 0, $xSize, $ySize, imagesx($mask), imagesy($mask)); 
     imagedestroy($mask); 
     $mask = $tempPic; 
    } 

    // Perform pixel-based alpha map application 
    for($x = 0; $x < $xSize; $x++) { 
     for($y = 0; $y < $ySize; $y++) { 
      $alpha = imagecolorsforindex($mask, imagecolorat($mask, $x, $y)); 
      //small mod to extract alpha, if using a black(transparent) and white 
      //mask file instead change the following line back to Jules's original: 
      //$alpha = 127 - floor($alpha['red']/2); 
      //or a white(transparent) and black mask file: 
      //$alpha = floor($alpha['red']/2); 
      $alpha = $alpha['alpha']; 
      $color = imagecolorsforindex($picture, imagecolorat($picture, $x, $y)); 
      //preserve alpha by comparing the two values 
      if ($color['alpha'] > $alpha) 
       $alpha = $color['alpha']; 
      //kill data for fully transparent pixels 
      if ($alpha == 127) { 
       $color['red'] = 0; 
       $color['blue'] = 0; 
       $color['green'] = 0; 
      } 
      imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, $color[ 'red' ], $color[ 'green' ], $color[ 'blue' ], $alpha)); 
     } 
    } 

    // Copy back to original picture 
    imagedestroy($picture); 
    $picture = $newPicture; 
} 

?> 
1
for ($y = 0; $y < $ySize; $y++) { 
    $alpha = imagecolorsforindex($mask, imagecolorat($mask, $x, $y)); 
    $alpha = 127 - floor($alpha['red']/2); 
    if (127 == $alpha) { 
    continue; 
    } 
    $color = imagecolorsforindex($picture, imagecolorat($picture, $x, $y)); 
    imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha(
    $newPicture, $color['red'], $color['green'], $color['blue'], $alpha)); 
} 

這裏是第一功能的小升級。由於您已有透明圖像,因此不需要複製蒙版像素。這將有助於執行一點。

0

一種不同的方式來獲得類似的效果是PNG文件具有獨特的背景顏色粘貼到一個新的形象,以暫時刪除的透明度,並設置透明改爲將png圖像的顏色改爲黑色圓圈顏色。然後,當您將它放在jpeg圖像上時,將新的透明顏色設置爲蒙版的顏色。

// Load the Black Circle PNG image 
$png = imagecreatefrompng('mask.png'); 
$width = imagesx($png); 
$height = imagesy($png); 

// Create a mask image 
$mask = imagecreatetruecolor($width, $height); 
// We'll use Magenta as our new transparent colour - set it as the solid background colour. 
$magenta = imagecolorallocate($mask, 255, 0, 255); 
imagefill($mask, 0, 0, $magenta); 

// Copy the png image onto the mask. Destroy it to free up memory. 
imagecopyresampled($mask, $png, 0, 0, 0, 0, $width, $height, $width, $height); 
imagedestroy($png); 

// Set the black portion of the mask to transparent. 
$black = imagecolorallocate($mask, 0, 0, 0); 
imagecolortransparent($mask, $black); 

// Load JPEG image. 
$jpg = imagecreatefromjpeg('image.jpg'); 
$j_width = imagesx($jpg); 
$j_height = imagesx($jpg); 

// Enable alpha blending and copy the png image 
imagealphablending($jpg, true); 
imagecopyresampled($jpg, $mask, 0, 0, 0, 0, $j_width, $j_height, $width, $height); 
imagedestroy($mask); 

// Set the new transparent colour and output new image to browser as a png. 
$magenta = imagecolorallocate($jpg, 255, 0, 255); 
imagecolortransparent($jpg, $magenta); 
imagepng($jpg); 

如果再採樣或半透明像素越來越你下來,而不是使用一個PNG作爲掩模,則可以禁用共混和繪製的透明形狀到$mask圖像來代替。

// Load JPEG Image. 
$jpg = imagecreatefromjpeg('image.jpg'); 
$width = imagesx($jpg); 
$height = imagesx($jpg); 

// Create mask at same size with an opaque background. 
$mask = imagecreatetruecolor($width, $height); 
$magenta = imagecolorallocate($mask, 255, 0, 255); 
imagefill($mask, 0, 0, $magenta); 

// Disable alpha blending and draw a transparent shape onto the mask. 
$transparent = imagecolorallocatealpha($mask, 255, 255, 255, 127); 
imagealphablending($mask, false); 
imagefilledellipse($mask, round($width/2), round($height/2), $width, $height, $transparent); 

// Paste the mask onto the original image and set the new transparent colour. 
imagealphablending($jpg, true); 
imagecopyresampled($jpg, $mask, 0, 0, 0, 0, $width, $height, $width, $height); 
imagedestroy($mask); 
$magenta = imagecolorallocate($jpg, 255, 0, 255); 
imagecolortransparent($jpg, $magenta); 

// Output new image to browser as a png. 
imagepng($jpg); 

注意:上面的代碼沒有經過測試,但應該有希望做你需要的。