() translation by (you can also view the original English article)
Vždycky jsi chtěl univerzální, snadno použitelnou metodu pro změnu velikosti obrázků v PHP? No na to jsou PHP třídy - opakovaně použitelné částí funkcí, které zavoláme pro udělání špinavé práce za scénou. Dozvíme se, jak vytvořit vlastní třídu, která bude dobře sestavená, jakož i rozšiřitelná. Změna velikosti by měla být snadná. Jak snadná? Co takhle ve třech krocích!
Úvod
Dám vám rychlý pohled na to, čeho se snažíme dosáhnout s naší třídou, třída by měla být:
- Snadná k použití
- Formátově nezávislá. Tj. otevřít, změnit velikost a uložit řadu různých formátů obrázků.
- Inteligentní nastavení velikosti - bez zkreslení obrazu!
Poznámka: Toto není návod k vytvoření třídy a objektů, a přestože by pomohla tato dovednost, není nezbytná pro tento kurz.
Je toho hodně k probrání - začněme.
Krok 1 Příprava
Začneme zlehka. Ve vašem pracovním adresáři vytvořte dva soubory: jeden nazvaný index.php, druhý resize-class.php



Krok 2 Voláním objektu
Dám vám představu čeho se snažíme dosáhnout, začneme tím, že nakódujeme volání, které použijeme k změně velikosti obrázků. Otevřete soubor index.php a přidejte následující kód.
Jak můžete vidět, je tu logika v tom co tady děláme. Otevřeme soubor obrázku, nastavily jsme rozměry které chceme změnit ve velikost obrázku a typ změny velikosti.
Pak můžeme uložit obrázek, vybereme formátu obrazu který chceme a kvalitu obrazu. Uložte a zavřete soubor index.php.
1 |
|
2 |
// *** Include the class
|
3 |
include("resize-class.php"); |
4 |
|
5 |
// *** 1) Initialize / load image
|
6 |
$resizeObj = new resize('sample.jpg'); |
7 |
|
8 |
// *** 2) Resize image (options: exact, portrait, landscape, auto, crop)
|
9 |
$resizeObj -> resizeImage(150, 100, 'crop'); |
10 |
|
11 |
// *** 3) Save image
|
12 |
$resizeObj -> saveImage('sample-resized.gif', 100); |
V kódu výše můžete vidět že jsme otevřely souboru jpg, ale uložily jsme ho ve formátu gif. Pamatujte si, že je to všechno o pružnosti.
Krok 3 Třídy kostry
Je to Object-Oriented Programming (OOP), která umožní tento pocit pohody. Myslete na třídy jako na vzor; můžete zapouzdřit data - v jiném žargonu ten termín znamená skrytí dat. Můžeme využít této třídy znovu a znovu bez nutnosti přepisovat změny v kódu změny velikosti - potřebujete volat odpovídající metody, stejné jako jsou v kroku dvě. Jakmile je náš vzor vytvořen, vytvoříme instance tohoto vzoru, nazývané objekty.
"Konstrukt funkcí, známí jako konstruktor, jsou speciální metoda tříd , která získává volanou třídu, když vytvoříte nový objekt."
Začněme, vytvořením naší resize třídy. Otevřete soubor resize-class.php. Níže je opravdu základní kostra struktury třídy, kterou jsem pojmenoval "resize". Všimněte si řádku třídy proměnné s komentářem; to je místo kde začneme později přidávat pro nás důležité třídy proměnných.
Funkce konstrukce, známá jako konstruktor, je speciální třída metody (termín "method" je stejná jako funkce, Nicméně, když mluvíme o třídách a objektech, termín metoda se často používá), která volá třídu, když vytvoříte nový objekt. Díky tomu je pro nás vhodné udělat nějaké inicializace - uděláme je v dalším kroku.
1 |
|
2 |
Class resize |
3 |
{
|
4 |
// *** Class variables
|
5 |
|
6 |
public function __construct() |
7 |
{
|
8 |
|
9 |
}
|
10 |
}
|
Všimněte si, že je dvojité podtržítko pro metodu konstrukce.
Krok 4 Konstruktor
Chceme změnit metodu konstruktoru výše. Za prvé, zrušíme jméno souboru (a cestu) vašeho obrázku se velikost. Zavoláme proměnou $fileName.
Potřebujeme otevřít soubor předaný pomocí PHP (přesněji řečeno GD knihovna PHP) takže PHP může číst obrázek. Děláme to s vlastní metodou "openImage". Dostanu se k tomu jak metoda
funguje za chvíli, ale prozatím, musíme uložit výsledek jako proměnné třídy. Proměnná třídy je proměnná - ale to je specifické pro danou třídu. Pamatujte si komentář proměnné třídy, o kterém jsem se zmínil dříve? Přidejtete 'image' jako soukromou proměnnou zadáním "private $image;". Nastavením proměnné jako "Private" si nastavíte působnosti dané proměnné, takže ji lze zpřístupnit pouze třídou. Od nynějška můžeme zavolat náš otevřený obraz, známý jako prostředek, který budeme potřebovat později když budeme měnit velikost.
Když už jsme u toho, tak vyplňme výšku a šířku obrázku. Mám pocit, že to bude později užitečné.
Nyní byste měli mít následující.
1 |
|
2 |
Class resize |
3 |
{
|
4 |
// *** Class variables
|
5 |
private $image; |
6 |
private $width; |
7 |
private $height; |
8 |
|
9 |
function __construct($fileName) |
10 |
{
|
11 |
// *** Open up the file
|
12 |
$this->image = $this->openImage($fileName); |
13 |
|
14 |
// *** Get width and height
|
15 |
$this->width = imagesx($this->image); |
16 |
$this->height = imagesy($this->image); |
17 |
}
|
18 |
}
|
Metody imagesx a imagesy jsou postaveny ve funkcích, které jsou součástí knihovny GD. Získají šířku a výšku vašeho obrazu, respektive.
Krok 5 Otevření obrázku
V předchozím kroku, jsme volali vlastní metodu openImage. V tomto kroku budeme vytvářet tuto metodu. Chceme po skriptu aby za nás přemýšlel, takže podle toho, jaký typ souboru je mu předán, skript by měl určit, jakou funkci GD knihovny volá pro otevření obrázku. Toho lze snadno dosáhnout srovnáním rozšíření souborů pomocí příkazu switch.
Zrušily jsme v našem souboru co chceme převzorkovat a vrátily jsme výsledek souboru.
1 |
|
2 |
private function openImage($file) |
3 |
{
|
4 |
// *** Get extension
|
5 |
$extension = strtolower(strrchr($file, '.')); |
6 |
|
7 |
switch($extension) |
8 |
{
|
9 |
case '.jpg': |
10 |
case '.jpeg': |
11 |
$img = @imagecreatefromjpeg($file); |
12 |
break; |
13 |
case '.gif': |
14 |
$img = @imagecreatefromgif($file); |
15 |
break; |
16 |
case '.png': |
17 |
$img = @imagecreatefrompng($file); |
18 |
break; |
19 |
default: |
20 |
$img = false; |
21 |
break; |
22 |
}
|
23 |
return $img; |
24 |
}
|
Krok 6 Jak změnit velikost
To je to co si zamilujete. Tento krok je opravdu jen vysvětlení toho, co budeme dělat - takže žádné úkoly. V dalším kroku musíme vytvořit veřejnou metodu, která budeme volat k provádění naší velikosti; tak to dává smysl pro předávání v Šířka a výška, stejně jako informace o jak chceme změnit velikost obrázku. Promluvme si o tom za chvíli. Bude existovat scénář, kde chcete změnit velikost obrázku na přesnou velikost. Skvělé, tak to patří. Ale bude také chvíle, kdy budete muset změnit velikost stovky snímků a každý obrázek má jiný poměr stran - například portrétní snímky. Změna velikosti na přesnou velikost způsobí závažná zkreslení. Pokud se podíváme na naše možnosti, aby nedošlo ke zkreslení můžeme:
- Velikost obrazu tak blízko, jak můžeme na naše nové rozměry obrázku a zachovat poměr stran.
- Změnit velikost obrázku, tak blízko, jak můžeme na naše nové rozměry obrazu a ořízne zbývající.
Obě možnosti jsou životaschopné, podle vašich potřeb.
Jo. budeme se pokoušet zpracovávat všechny výše uvedené. Pro připomenutí, budeme poskytovat možnosti:
- Změnit velikost na přesnou šířku/výšku. (přesný)
- Změna velikosti podle šířky - přesná šířka bude nastavena, bude upravena výška podle poměru stran. (na šířku)
- Změna velikosti podle výšky - jako změnit velikost šířky, ale nastaví se výška a dynamicky se upraví šířka. (na výšku)
- Automaticky určit možnosti 2 a 3. Pokud procházíte složky s fotografiemi různých velikostí, ať skriptu určí, jak to udělá. (auto)
- Změna velikosti a oříznutí. To je moje oblíbená. Přesná velikost, bez zkreslení. (oříznutí)
Krok 7 Změna velikosti. Jdeme na to!
Existují dvě části převzorkovací metody. První nastavuje optimální šířku a výšku pro náš nový obrázek vytvořením nějaké vlastní metody - a samozřejmě předání naší velikosti "možnosti" jak je popsáno výše. Šířka a výška jsou vráceny jako pole a nastavení jejich příslušných proměnných. Nebojte se "pass as reference"- ale já nejsem toho velký fanoušek .
Druhá část je co provádí se skutečnou velikostí. V zájmu zachování tohoto kurzu snížení velikost, dám vám přečíst o následující funkci GD:
Také jsme uložili výstup metody imagecreatetruecolor (a new true color image) jako proměnné třídy. Přidat 'private $imageResized;' s vaší jinou proměnnou třídou.
Změna velikosti se provádí pomocí PHP modul, který je známý jako GD knihovny. Mnoho metod, které používáme jsou k dispozici v této knihovně.
1 |
|
2 |
// *** Add to class variables
|
3 |
private $imageResized; |
1 |
|
2 |
public function resizeImage($newWidth, $newHeight, $option="auto") |
3 |
{
|
4 |
|
5 |
// *** Get optimal width and height - based on $option
|
6 |
$optionArray = $this->getDimensions($newWidth, $newHeight, strtolower($option)); |
7 |
|
8 |
$optimalWidth = $optionArray['optimalWidth']; |
9 |
$optimalHeight = $optionArray['optimalHeight']; |
10 |
|
11 |
// *** Resample - create image canvas of x, y size
|
12 |
$this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight); |
13 |
imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height); |
14 |
|
15 |
// *** if option is 'crop', then crop too
|
16 |
if ($option == 'crop') { |
17 |
$this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight); |
18 |
}
|
19 |
}
|
Krok 8 Rozhodovací strom
Čím více práce, kterou děláte nyní, tím méně musíte udělat při změně velikosti. Tato metoda vybere trasu přijmutí s cílem získat optimální velikost šířky a výšky založenou na možnosti převzorkování. To bude volat odpovídající metodu, kterou budeme vytvářet v dalším kroku.
1 |
|
2 |
private function getDimensions($newWidth, $newHeight, $option) |
3 |
{
|
4 |
|
5 |
switch ($option) |
6 |
{
|
7 |
case 'exact': |
8 |
$optimalWidth = $newWidth; |
9 |
$optimalHeight= $newHeight; |
10 |
break; |
11 |
case 'portrait': |
12 |
$optimalWidth = $this->getSizeByFixedHeight($newHeight); |
13 |
$optimalHeight= $newHeight; |
14 |
break; |
15 |
case 'landscape': |
16 |
$optimalWidth = $newWidth; |
17 |
$optimalHeight= $this->getSizeByFixedWidth($newWidth); |
18 |
break; |
19 |
case 'auto': |
20 |
$optionArray = $this->getSizeByAuto($newWidth, $newHeight); |
21 |
$optimalWidth = $optionArray['optimalWidth']; |
22 |
$optimalHeight = $optionArray['optimalHeight']; |
23 |
break; |
24 |
case 'crop': |
25 |
$optionArray = $this->getOptimalCrop($newWidth, $newHeight); |
26 |
$optimalWidth = $optionArray['optimalWidth']; |
27 |
$optimalHeight = $optionArray['optimalHeight']; |
28 |
break; |
29 |
}
|
30 |
return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); |
31 |
}
|
Krok 9 Optimální rozměry
Už jsme již probrali, co tyto čtyři metody dělají. Je tu jen základní matematika, opravdu, vypočítává naši nejlepší shodu.
1 |
|
2 |
private function getSizeByFixedHeight($newHeight) |
3 |
{
|
4 |
$ratio = $this->width / $this->height; |
5 |
$newWidth = $newHeight * $ratio; |
6 |
return $newWidth; |
7 |
}
|
8 |
|
9 |
private function getSizeByFixedWidth($newWidth) |
10 |
{
|
11 |
$ratio = $this->height / $this->width; |
12 |
$newHeight = $newWidth * $ratio; |
13 |
return $newHeight; |
14 |
}
|
15 |
|
16 |
private function getSizeByAuto($newWidth, $newHeight) |
17 |
{
|
18 |
if ($this->height < $this->width) |
19 |
// *** Image to be resized is wider (landscape)
|
20 |
{
|
21 |
$optimalWidth = $newWidth; |
22 |
$optimalHeight= $this->getSizeByFixedWidth($newWidth); |
23 |
}
|
24 |
elseif ($this->height > $this->width) |
25 |
// *** Image to be resized is taller (portrait)
|
26 |
{
|
27 |
$optimalWidth = $this->getSizeByFixedHeight($newHeight); |
28 |
$optimalHeight= $newHeight; |
29 |
}
|
30 |
else
|
31 |
// *** Image to be resizerd is a square
|
32 |
{
|
33 |
if ($newHeight < $newWidth) { |
34 |
$optimalWidth = $newWidth; |
35 |
$optimalHeight= $this->getSizeByFixedWidth($newWidth); |
36 |
} else if ($newHeight > $newWidth) { |
37 |
$optimalWidth = $this->getSizeByFixedHeight($newHeight); |
38 |
$optimalHeight= $newHeight; |
39 |
} else { |
40 |
// *** Sqaure being resized to a square
|
41 |
$optimalWidth = $newWidth; |
42 |
$optimalHeight= $newHeight; |
43 |
}
|
44 |
}
|
45 |
|
46 |
return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); |
47 |
}
|
48 |
|
49 |
private function getOptimalCrop($newWidth, $newHeight) |
50 |
{
|
51 |
|
52 |
$heightRatio = $this->height / $newHeight; |
53 |
$widthRatio = $this->width / $newWidth; |
54 |
|
55 |
if ($heightRatio < $widthRatio) { |
56 |
$optimalRatio = $heightRatio; |
57 |
} else { |
58 |
$optimalRatio = $widthRatio; |
59 |
}
|
60 |
|
61 |
$optimalHeight = $this->height / $optimalRatio; |
62 |
$optimalWidth = $this->width / $optimalRatio; |
63 |
|
64 |
return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); |
65 |
}
|
Krok 10 Oříznutí
Pokud jste se rozhodla pro "crop" - to znamená, že jste použili možnost oříznutí, pak máte o další malý krok navíc. Jdeme oříznout obrázek od
středu. Oříznutí je velmi podobný proces změny velikosti, ale s pár na víc nastavení parametru velikostí.
1 |
|
2 |
private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight) |
3 |
{
|
4 |
// *** Find center - this will be used for the crop
|
5 |
$cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 ); |
6 |
$cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 ); |
7 |
|
8 |
$crop = $this->imageResized; |
9 |
//imagedestroy($this->imageResized);
|
10 |
|
11 |
// *** Now crop from center to exact requested size
|
12 |
$this->imageResized = imagecreatetruecolor($newWidth , $newHeight); |
13 |
imagecopyresampled($this->imageResized, $crop , 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight); |
14 |
}
|
Krok 11 Uložení obrázku
Dostáváme se tam; téměř hotovo. Nyní je čas k uložení obrázku. Dalším krokem je jakou kvalitu obrazu bychom rádi v rozmezí od 0-100, 100 je nejlepší a zavoláme odpovídající metody. Pár postřehů o kvalitě obrazu: JPG používá stupnici od 0-100, 100 je nejlepší. GIF obrázky nemají nastavení kvality obrazu. PNG má, ale používá se stupnice 0-9, 0 je nejlepší. To není dobré, přece nemůžeme od nás očekávat si to budeme pamatovat pokaždé, když chceme uložit obrázek. Uděláme trochu kouzlo a vše standardizujeme.
1 |
|
2 |
public function saveImage($savePath, $imageQuality="100") |
3 |
{
|
4 |
// *** Get extension
|
5 |
$extension = strrchr($savePath, '.'); |
6 |
$extension = strtolower($extension); |
7 |
|
8 |
switch($extension) |
9 |
{
|
10 |
case '.jpg': |
11 |
case '.jpeg': |
12 |
if (imagetypes() & IMG_JPG) { |
13 |
imagejpeg($this->imageResized, $savePath, $imageQuality); |
14 |
}
|
15 |
break; |
16 |
|
17 |
case '.gif': |
18 |
if (imagetypes() & IMG_GIF) { |
19 |
imagegif($this->imageResized, $savePath); |
20 |
}
|
21 |
break; |
22 |
|
23 |
case '.png': |
24 |
// *** Scale quality from 0-100 to 0-9
|
25 |
$scaleQuality = round(($imageQuality/100) * 9); |
26 |
|
27 |
// *** Invert quality setting as 0 is best, not 9
|
28 |
$invertScaleQuality = 9 - $scaleQuality; |
29 |
|
30 |
if (imagetypes() & IMG_PNG) { |
31 |
imagepng($this->imageResized, $savePath, $invertScaleQuality); |
32 |
}
|
33 |
break; |
34 |
|
35 |
// ... etc
|
36 |
|
37 |
default: |
38 |
// *** No extension - No save.
|
39 |
break; |
40 |
}
|
41 |
|
42 |
imagedestroy($this->imageResized); |
43 |
}
|
Nyní je také vhodná doba k zničení našeho zdroje obrazu pro uvolnění paměťi. Pokud byste to chtěli použít v produkci, může to být vhodné k zachycení a vrácení výsledku uloženého obrazu.
Závěr
No a je to, přátelé. Děkuji Vám za projití tohoto kurzu, doufám, že vám to bylo užitečné. Ocenil bych vaši zpětnou vazbu, a to prostřednictvím níže uvedených komentářů.