() translation by (you can also view the original English article)
Hai mai desiderato un metodo facile da usare per ridimensionare le immagini in PHP? Beh ecco a cosa servono le classi PHP - parti riutilizzabili di funzionalità che possiamo chiamare per fare il lavoro sporco dietro le quinte. Stiamo andando ad imparare come creare la nostra classe che sarà ben costruita, ed anche espandibile. Il ridimensionamento dovrebbe essere facile. Quanto facile? Come circa tre passi!
Introduzione
Per dare un rapido sguardo a ciò che stiamo cercando di realizzare con la nostra classe, la classe deve essere:
- Facile da usare
- Formato indipendente. Cioè, aprire, ridimensionare e salvare un numero di formati di immagini diverse.
- Ridimensionamento intelligente - nessuna distorsione di immagine!
Nota: Questo non è un tutorial su come creare classi e oggetti, e anche se questa abilità avrebbe aiutato, non è necessario al fine di seguire questo tutorial.
C'è un sacco da fare - cominciamo.
Fase 1 preparazione
Cominceremo in modo facile. Nella directory di lavoro creamo due file: uno chiamato index.php, l'altro resize-class.php



Passo 2 Chiamare l'oggetto
Per darti un'idea di che cosa stiamo cercando di ottenere, inizieremo con codificare le chiamate che useremo per ridimensionare le immagini. Aprite il file index.php e aggiungete il codice riportato di seguito.
Come potete vedere, c'è una bella logica per ciò che stiamo facendo. Apriamo il file di immagine, impostiamo le dimensioni che vogliamo per ridimensionare l'immagine e il tipo di ridimensionamento.
Quindi salviamo l'immagine, scegliamo il formato di immagine che vogliamo e la qualità dell'immagine. Salvate e chiudete il file 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); |
Dal codice sopra potete vedere che stiamo aprendo un file jpg ma salviamo un file gif. Ricordate, si tratta di flessibilità.
Passaggio 3 Scheletro della classe
È l'Object-Oriented Programming (OOP) che rende possibile questo senso di facilità. Pensate a una classe come un modello; è possibile incapsulare i dati - un altro termine che significa davvero solo nascondere i dati. Quindi possiamo riutilizzare più e più volte questa classe senza la necessità di riscrivere il codice di ridimensionamento - è sufficiente chiamare i metodi appropriati, proprio come abbiamo fatto nel passo 2. Una volta che il nostro modello è stato creato, creamo istanze di questo modello, chiamati oggetti.
"La funzione di costrutto, conosciuta come costruttore, è un metodo di classe speciale che viene chiamato dalla classe quando si crea un nuovo oggetto".
Iniziamo a creare la nostra classe di ridimensionamento. Aprite il file resize-class.php. Di seguito è riportato uno scheletro di classe davvero essenziale che ho chiamato 'resize'. Notate la riga di commento variabile di classe; questo è dove inizieremo ad aggiungere le variabili di classe importanti in seguito.
La funzione di costrutto, conosciuta come costruttore, è un metodo di classe speciale (il termine "metodo" è la stessa funzione, tuttavia, quando si parla di classi e oggetti spesso viene utilizzato il termine metodo) che viene chiamato dalla classe quando si crea un nuovo oggetto. Questo lo rende adatto per fare alcune inizializzazioni - che faremo nel passaggio successivo.
1 |
|
2 |
Class resize |
3 |
{
|
4 |
// *** Class variables
|
5 |
|
6 |
public function __construct() |
7 |
{
|
8 |
|
9 |
}
|
10 |
}
|
Si noti che c'è un doppio carattere di sottolineatura per il metodo di costrutto.
Fase 4 il costruttore
Stiamo andando a modificare il metodo costruttore sopra. In primo luogo, passeremo il nome (e percorso) della nostra immagine da ridimensionare. Chiameremo questa variabile $fileName.
Abbiamo bisogno di aprire il file passato con PHP (più specificamente la libreria PHP GD) così che PHP possa leggere l'immagine. Lo stiamo facendo con il metodo personalizzato 'openImage'. Vi dirò come funziona questo metodo
in un attimo, ma per ora, abbiamo bisogno di salvare il risultato come una variabile di classe. Una variabile di classe è solo una variabile - ma è specifica per tale classe. Ricordate il commento di variabile di classe che ho citato in precedenza? Aggiungi 'image' come una variabile privata digitando 'private $image;'. Impostando la variabile come 'Private' si sta impostando l'ambito di tale variabile che quindi è accessibile solo dalla classe. Da ora in poi possiamo fare una chiamata alla nostra immagine aperta, nota come una risorsa, che faremo più tardi quando ridimensioneremo.
Visto che siamo in argomento, archiviamo l'altezza e la larghezza dell'immagine. Ho la sensazione che questo sarà utile più tardi.
Si dovrebbe ora avere il seguente.
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 |
}
|
I metodi magesy e imagesx sono costruiti in funzioni che fanno parte della libreria GD. Recuperano la larghezza e l'altezza dell'immagine, rispettivamente.
Passo 5 aprendo l'immagine
Nel passaggio precedente, chiamiamo il metodo personalizzato openImage. In questo passaggio stiamo andando a creare quel metodo. Vogliamo che lo script faccia quello che vogliamo, quindi a seconda del tipo di file che viene passato, lo script dovrebbe determinare quale funzione di libreria GD chiamare per aprire l'immagine. Questo è facilmente ottenibile confrontando l'estensione di file con un'istruzione switch.
Passiamo il file che vogliamo ridimensionare e restituiamo tale risorsa di file.
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 |
}
|
Passaggio 6 come ridimensionare
Questo è dove tutto accade. Questo passaggio è davvero solo una spiegazione di che cosa stiamo andando a fare - quindi nessun compito qui. Nel passaggio successivo, stiamo andando a creare un metodo pubblico che chiameremo per eseguire il nostro ridimensionamento; quindi ha senso passare la larghezza e altezza, nonché informazioni su come vogliamo ridimensionare l'immagine. Parliamone un attimo. Ci saranno scenari dove si desidera ridimensionare un'immagine a una dimensione esatta. Grande, includiamolo. Ma ci saranno anche momenti in cui è necessario ridimensionare centinaia di immagini e ogni immagine ha un rapporto di aspetto diverso - pensiamo ai ritratti. Ridimensionamento di queste a una dimensione esatta causerà gravi distorsioni. Se diamo uno sguardo alle nostre opzioni per evitare la distorsione possiamo:
- Ridimensionare l'immagine quanto più vicino possibile alle nostre nuove dimensioni di immagine, pur mantenendo le proporzioni.
- Ridimensionare l'immagine quanto più vicino possibile alle nostre nuove dimensioni di immagine e ritagliare la parte restante.
Entrambe le opzioni sono possibili, a seconda delle esigenze.
Sì. stiamo per tentare di gestire tutto quanto sopra. Per ricapitolare, stiamo andando a fornire opzioni per:
- Ridimensionare a larghezza/altezza esatta. (esatta)
- Ridimensionamento di larghezza - la larghezza esatta verrà impostata, l'altezza verrà regolata secondo proporzioni. (paesaggio)
- Ridimensionamento di altezza - come ridimensionamento di larghezza, ma verrà impostata l'altezza e larghezza regolata dinamicamente. (ritratto)
- Auto determinare le opzioni 2 e 3. Se stai scorrendo una cartella con foto di diverse dimensioni, lasciare che sia lo script a determinare come gestire tutto. (auto)
- Ridimensionare, poi ritagliare. Questo è il mio preferito. Dimensioni esatte, nessuna distorsione. (ritaglio)
Passo 7 ridimensionamento. Facciamolo!
Ci sono due parti per il metodo di ridimensionamento. La prima è sempre la larghezza ottimale e l'altezza per la nostra nuova immagine creando alcuni metodi personalizzati - e naturalmente passando la nostra 'opzione' di ridimensionamento come descritto sopra. La larghezza e l'altezza sono restituiti come array e impostate nelle loro rispettive variabili. Sentitevi liberi di 'passare come riferimento'- ma io non sono un grande fan.
La seconda parte è quella che esegue il ridimensionamento effettivo. Per mantenere questo tutorial breve, vi farò leggere qualcosa sulle seguenti funzioni di GD:
Inoltre, salviamo l'output del metodo imagecreatetruecolor (una nuova immagine di vero colore) come una variabile di classe. Aggiungete 'private $imageResized;' alle altre variabili di classe.
Il ridimensionamento viene eseguito da un modulo PHP, conosciuto come la libreria GD. Molti dei metodi che utilizziamo sono forniti da questa libreria.
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 |
}
|
Fase 8 l'albero delle decisioni
Più lavoro fai ora, meno dovrai fare quando si ridimensiona. Questo metodo sceglie la strada da prendere, con l'obiettivo di ottenere l'ottimale ridimensionamento di larghezza e altezza basato sulla vostra opzione di ridimensionamento. Potrà chiamare il metodo appropriato, che creeremo nel passaggio successivo.
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 |
}
|
Passaggio 9 dimensioni ottimali
Abbiamo già discusso cosa fanno questi quattro metodi. Sono solo calcoli di base di matematica, davvero, che consentono di calcolare la nostra misura migliore.
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 |
}
|
Passaggio 10 Ritaglio
Se hai optato per un ritaglio - cioè, hai utilizzato l'opzione Ritaglia, hai un piccolo passaggio in più. Stiamo andando a ritagliare l'immagine dal
centro. Il ritaglio è un processo molto simile al ridimensionamento, ma con un paio di parametri in più del ridimensionamento.
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 |
}
|
Passaggio 11 salvare l'immagine
Ci siamo quasi; quasi finito. Ora è il momento di salvare l'immagine. Passiamo il percorso e la qualità dell'immagine che vorremmo che va da 0-100, 100 è il migliore, e chiameremo il metodo appropriato. Un paio di cose da notare riguardo la qualità dell'immagine: JPG utilizza una scala di 0-100, 100 è il migliore. Le immagini GIF non hanno un'impostazione di qualità di immagine. PNG ce l'hanno, ma usano la scala 0-9, 0 è il migliore. Questo non è bene perchè non possiamo aspettarci di ricordare questo ogni volta che vogliamo salvare un'immagine. Facciamo un po' di magia per standardizzare tutto.
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 |
}
|
Ora è anche un buon momento per distruggere la nostra risorsa di immagine per liberare memoria. Se si dovesse usare questo in produzione, potrebbe anche essere una buona idea di catturare e restituire il risultato dell'immagine salvata.
Conclusione
Beh questo è tutto, gente. Grazie per aver seguito questo tutorial, spero che vi sia utile. Gradirei il vostro feedback, attraverso i commenti qui sotto.