Skip to content

Instantly share code, notes, and snippets.

@Poetro
Created February 13, 2012 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Poetro/d00c364ee6b1e4592879 to your computer and use it in GitHub Desktop.
Save Poetro/d00c364ee6b1e4592879 to your computer and use it in GitHub Desktop.
Áttetsző képek kezelése PHP alatt

Aki már dolgozott PHP alatt áttetsző képekkel (azaz olyan képekkel, amelyek részben átlátszóak), az tudhatja, hogy a beépített GD rendszer nem igazán segíti munkáját. A GD2 bevezetésével ugyan javultak a dolgok, de messze van még a rendszer attól, hogy igazán jól használható legyen áttetsző képek kezelésében.

Az odáig rendben van, hogy nagyszerűen kezelhetünk benne nem áttetsző képeket, erre minden lehetőségünk megvan. Ugyanakkor áttetsző képek esetén a következő problémákba ütközünk:

  1. Ha a képünk áttetsző, akkor a rendszer hajlamos eldobni az átlátszóságot a pixelekről, azaz képkockánként csak 24 bitet használ.
  2. Nincs támogatás arra, hogy egy már áttetsző képnek módosítsuk az átlátszóságát.

Áttetsző képek esetén a legfontosabb, hogy egy olyan üres vászonnal (képpel) kezdjünk a munkát, ami true color és csak átlátszó pixeleket tartalmazzon. Ehhez írtam egy egyszerű, de nagyszerű függvényt, ami ezt szépen megvalósítja:

/**
 * Create a new true color image with solid color background.
 *
 * @param $width
 *   The image's width.
 * @param $height
 *   The image's height.
 * @param $color
 *   24 bit color of the background.
 * @param $opacity
 *   Opacity of the background from 0 to 100 where 100 means totally opaque
 *   and 0 is transparent.
 * @return
 *   An image link resource.
 */
function image_generate($width, $height, $color = 0, $opacity = 100) {
  $im = imagecreatetruecolor($width, $height);
  // Handle transparency.
  imagealphablending($im, true);
  imagesavealpha($im, true);

  // Generate RGBA components for the color.
  $r = ($color >> 16) & 0xFF;
  $g = ($color >> 8) & 0xFF;
  $b = $color & 0xFF;
  // $a is between 0 - 127 where 0 is totally opaque and 127 is transparent.
  $a = 127 - round(127 * $opacity / 100);

  if ($a) {
    $fill = imagecolorallocatealpha($im, $r, $g, $b, $a);
  }
  else {
    $fill = imagecolorallocate($im, $r, $g, $b);
  }

  // Fill the background, and prepare for drawing.
  imagefill($im, 0, 0, $fill);
  imageantialias($im, true);
  return $im;
}

Az image_generate függvény az imagecreatetruecolor függvény segítségével létrehoz egy true color képet, majd azt kiszínezi a megfelelő színűre. Amennyiben az $opacity értéknek 0-t adunk meg, akkor teljesen átlátszó képet kapunk, ekkor a szín mellékessé válik. Vagyis csak válna, ugyanis például az imagecopymerge függvény, ha megadunk neki 0 és 127 közötti $ptc értéket (azaz átlátszóságot), akkor, mivel ez a függvény eldobja a kép eredeti áttetszőségre vonatkozó információit, ezzel a teljesen átlátszatlan színnel fogja másolni a képet. Azaz, ha az áttetsző színünk, amivel a vásznak kiszíneztük fekete volt, akkor az átlátszatlan feketévé, ha fehér, akkor fehérré válik.

A függvény még beállít pár lényeges információt a képpel kapcsolatban. Ezek pedig a következők:

  • A kép tartalmazzon áttetszőséget.
  • Tartsa meg az áttetszőségre vonatkozó információt mentéskor.
  • A rajta végzett műveletekkor az anti-alias függvényeket is használja (átméretezéskor és áttetsző képek egymásra másolásakor van jelentősége).

Ahhoz, hogy egy egy képnek megváltoztassuk az átlátszóságát, két dolgot kell tennünk. Mivel az imagecopymerge, amivel elméletileg az áttetszőséget is tudjuk módosítani (a $ptc paraméter megadásával), nem működik már korábban is áttetsző képeken, ezért létre kell hozni egy átlátszó vásznat (például az image_generate függvény segítségével), majd erre kell pixelenként átmásolni az képünk adatait, miközben azoknak megváltoztatjuk az átlátszóságát. Erre jött létre az imagecopy_opacity függvény:

/**
 * Copy an image to destination with changing it's opacity.
 *
 * @param $dst_im
 *   Destination image link resource.
 * @param $src_im
 *   Source image link resource.
 * @param $dst_x
 *   x-coordinate of destination point.
 * @param $dst_y
 *   y-coordinate of destination point.
 * @param $src_x
 *   x-coordinate of source point.
 * @param $src_y
 *   y-coordinate of source point.
 * @param $src_w
 *   Source width.
 * @param $src_h
 *   Source height.
 * @param $opacity
 *   Opacity from 0 to 100 where 100 means totally opaque 0 is transparent.
 */
function imagecopy_opacity($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity) {
  // Calculate the width/height to be copied based on the source width/height,
  // the destination width/height, and the specified width/height, to only copy
  // available pixels to available destinations.
  $width = min($src_w, imagesx($src_im), imagesx($dst_im) - $dst_x);
  $height = min($src_h, imagesy($src_im), imagesy($dst_im) - $dst_y);
  $alpha = $opacity / 100;

  for ($x = 0; $x < $width; $x++) {
    for ($y = 0; $y < $height; $y++) {
      // Get color at (x, y) pixel on the source, and change it's opacity.
      $color = imagecolorat($src_im, $x + $src_x, $y + $src_y);
      $r = ($color >> 16) & 0xFF;
      $g = ($color >> 8) & 0xFF;
      $b = $color & 0xFF;
      // $a is between 0 - 127 where 0 is totally opaque and 127 is transparent.
      $a = 127 - round((127 - (($color >> 24) & 0x7F)) * $alpha);

      $newcolor = imagecolorexactalpha($dst_im, $r, $g, $b, $a);
      // Set the color at the same pixel on destination.
      imagesetpixel($dst_im, $x + $dst_x, $y + $dst_y, $newcolor);
    }
  }
}

A függvénynek meg kell adni a cél és a forrás képet, valamint az eltolást ezeken a képeken, a forrás kép másolandó darabját, valamint természetesen az átlátszóságot. A PHP átlátszóságkezelése egy kicsit fura ezen a téren. Ugyanis a dokumentáció nem írja, de az imagecolorat függvény a színen kívül visszaadja az átlátszóságot is a 24. bit feletti információban 7 bites pontossággal, azaz 0-127-es skálán, ahol a 0 átlátszatlant, 127 pedig teljesen átlátszót jelent.

Azaz a függvényünk nem tesz mást, mint a megadott régióban végighalad a forráskép összes pixelen, azoknak kiszedi a színinformációját (az átlátszósággal egyetemben), majd az átlátszóságot módosítva felülírja a célképen a megadott pixeleket. Ekkor ugye a régióba eső összes pixel felülírásra kerül, de az eredeti imagecopy esetében is pontosan ugyanezt a működést kapjuk. Ezek után, ha ezt a módosított képet használni akarjuk, nem kell mást tennünk, mint az imagecopymerge használatával (a $ptc értéket mellőzve) rámásoljuk arra a képre, amit szeretnénk.

Összefoglalás

Ahhoz, hogy PHP-ban áttetsző képpel tudjunk dolgozni a következőket kell tennünk tehát.

  1. Betöltjük a használni kívánt forrás képet az imagecreatefrom* segítségével.
  2. Létrehozunk egy teljesen átlátszó képet (például az image_generate függvény segítségével).
  3. Rámásoljuk forrás képet az átlátszó képre (imagecopy, imagecopymerge, imagecopyresampled, illetve imagecopy_opacity).
  4. Elkezdünk vele dolgozni, mint bármilyen más képpel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment