2013-05-27 11 views
12

Fondamentalmente voglio caricare un'immagine (che ho risolto) e la scala verso il basso per alcuni vincoli, come la larghezza e l'altezza massima, ma mantenere le proporzioni dell'immagine originale.Scala immagine Utilizzo di PHP e mantenendone le proporzioni

io non ho Imagick installato sul server - altrimenti questo sarebbe stato facile.

ogni aiuto è apprezzato, come sempre. Grazie.

EDIT: Non ho bisogno di tutto il codice o altro, solo una spinta nella giusta direzione sarebbe fantastico.

risposta

10

avevo scritto un pezzo di codice come questo per un altro progetto che ho fatto. L'ho copiato qui sotto, potrebbe aver bisogno di un po 'di armeggiare! (Esso richiede la libreria GD)

Questi sono i parametri di cui ha bisogno:

$image_name - Name of the image which is uploaded 
$new_width - Width of the resized photo (maximum) 
$new_height - Height of the resized photo (maximum) 
$uploadDir - Directory of the original image 
$moveToDir - Directory to save the resized image 

Sarà ridimensionare o un'immagine per la larghezza o l'altezza massima

function createThumbnail($image_name,$new_width,$new_height,$uploadDir,$moveToDir) 
{ 
    $path = $uploadDir . '/' . $image_name; 

    $mime = getimagesize($path); 

    if($mime['mime']=='image/png') { 
     $src_img = imagecreatefrompng($path); 
    } 
    if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') { 
     $src_img = imagecreatefromjpeg($path); 
    } 

    $old_x   = imageSX($src_img); 
    $old_y   = imageSY($src_img); 

    if($old_x > $old_y) 
    { 
     $thumb_w = $new_width; 
     $thumb_h = $old_y*($new_height/$old_x); 
    } 

    if($old_x < $old_y) 
    { 
     $thumb_w = $old_x*($new_width/$old_y); 
     $thumb_h = $new_height; 
    } 

    if($old_x == $old_y) 
    { 
     $thumb_w = $new_width; 
     $thumb_h = $new_height; 
    } 

    $dst_img  = ImageCreateTrueColor($thumb_w,$thumb_h); 

    imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y); 


    // New save location 
    $new_thumb_loc = $moveToDir . $image_name; 

    if($mime['mime']=='image/png') { 
     $result = imagepng($dst_img,$new_thumb_loc,8); 
    } 
    if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') { 
     $result = imagejpeg($dst_img,$new_thumb_loc,80); 
    } 

    imagedestroy($dst_img); 
    imagedestroy($src_img); 

    return $result; 
} 
+0

Nice - Grazie mille, sarà utile. Sto parlando con l'host per cercare di ottenere Imagick in ordine ... ottenendo un errore fatale al momento dove dice che non è stata trovata la classe ... –

+0

Se usi ' 'e fare una ricerca per GD, se è abilitato, la funzione sopra dovrebbe funzionare, anche senza imagick :), tuttavia, se si verificano errori, sentitevi liberi di farmelo sapere. –

+0

Non ha funzionato per me. Non ha mantenuto le proporzioni. –

3

Formule è sbagliato per mantenere le proporzioni. dovrebbe essere: altezza originaria larghezza/originale X Nuovo width = nuova altezza

function createThumbnail($imageName,$newWidth,$newHeight,$uploadDir,$moveToDir) 
{ 
    $path = $uploadDir . '/' . $imageName; 

    $mime = getimagesize($path); 

    if($mime['mime']=='image/png'){ $src_img = imagecreatefrompng($path); } 
    if($mime['mime']=='image/jpg'){ $src_img = imagecreatefromjpeg($path); } 
    if($mime['mime']=='image/jpeg'){ $src_img = imagecreatefromjpeg($path); } 
    if($mime['mime']=='image/pjpeg'){ $src_img = imagecreatefromjpeg($path); } 

    $old_x = imageSX($src_img); 
    $old_y = imageSY($src_img); 

    if($old_x > $old_y) 
    { 
     $thumb_w = $newWidth; 
     $thumb_h = $old_y/$old_x*$newWidth; 
    } 

    if($old_x < $old_y) 
    { 
     $thumb_w = $old_x/$old_y*$newHeight; 
     $thumb_h = $newHeight; 
    } 

    if($old_x == $old_y) 
    { 
     $thumb_w = $newWidth; 
     $thumb_h = $newHeight; 
    } 

    $dst_img  = ImageCreateTrueColor($thumb_w,$thumb_h); 

    imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y); 


    // New save location 
    $new_thumb_loc = $moveToDir . $imageName; 

    if($mime['mime']=='image/png'){ $result = imagepng($dst_img,$new_thumb_loc,8); } 
    if($mime['mime']=='image/jpg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); } 
    if($mime['mime']=='image/jpeg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); } 
    if($mime['mime']=='image/pjpeg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); } 

    imagedestroy($dst_img); 
    imagedestroy($src_img); 
    return $result; 
} 
+0

Solo, non mantiene le proporzioni.Se voglio ridimensionare un'immagine 300x300 in una 500x200, verrà creato un 500x200. – vaso123

13

In realtà la soluzione accettata è non la soluzione corretta. Il motivo è semplice: ci saranno casi in cui il rapporto tra l'immagine sorgente e il rapporto dell'immagine di destinazione sarà diverso. Qualsiasi calcolo dovrebbe riflettere questa differenza.

Si prega di notare le linee rilevanti l'esempio dato sul sito PHP.net:

$ratio_orig = $width_orig/$height_orig; 

if ($width/$height > $ratio_orig) { 
    $width = $height*$ratio_orig; 
} else { 
    $height = $width/$ratio_orig; 
} 

L'esempio completo può essere trovato qui: http://php.net/manual/en/function.imagecopyresampled.php

Non ci sono altre risposte (con gli esempi) su StackOverflow a domande simili (la stessa domanda formulata in un modo diverso) che soffrono dello stesso problema.

Esempio:

Diciamo che abbiamo un'immagine di 1630 x 2400 pixel che vogliamo essere auto ridimensionata mantenendo le proporzioni a 160 x 240. Facciamo un po di matematica prendendo la soluzione accettata:

if($old_x < $old_y) 
    { 
     $thumb_w = $old_x*($new_width/$old_y); 
     $thumb_h = $new_height; 
    } 

altezza = 240 larghezza = 1630 * (160/2400) = 1630 * 0,0666666666666667 = 108,6666666666667 108,6 x 240 non è la soluzione corretta.

La soluzione successiva proposta è il seguente:

if($old_x < $old_y) 
    { 
     $thumb_w = $old_x/$old_y*$newHeight; 
     $thumb_h = $newHeight; 
    } 

altezza = 240; larghezza = 1630/2400 * 240 = 163 È migliore (poiché mantiene le proporzioni), ma ha superato la larghezza massima accettata.

Entrambi falliscono.

facciamo la matematica secondo la soluzione proposta da PHP.net: larghezza = 160 altezza = 160/(1630/2400) = 160/0,6791666666666667 = 235,5828220858896 (clausola altro). 160 x 236 (arrotondato) è la risposta corretta.

0
<?php 
Class ResizedImage 
{ 
    public $imgfile; 
    public $string  = ''; 
    public $new_width = 0; 
    public $new_height = 0; 
    public $angle  = 0; 
    public $max_font_size = 1000; 
    public $cropped = false;//whether crop the original image if h or w > new h or w 
    public $font = 'fonts/arialbd.ttf'; 

    private $img; 
    private $trans_colour; 
    private $orange; 
    private $white; 
    private $whitetr; 
    private $blacktr; 

    public function PrintAsBase64() 
    { 
     $this->SetImage(); 
     ob_start(); 
     imagepng($this->img); 
     $b64img = ob_get_contents(); 
     ob_clean(); 
     imagedestroy($this->img); 
     $b64img = base64_encode($b64img); 
     echo($b64img); 
    } 
    public function PrintAsImage() 
    { 
     $this->SetImage(); 

     header('Content-type: image/png'); 

     imagepng($this->img); 
     imagedestroy($this->img); 
    } 

    private function SetImage() 
    { 
     if ($this->imgfile == '') {$this->imgfile='NoImageAvailable.jpg';} 
     $this->img   = imagecreatefromstring(file_get_contents($this->imgfile)); 
     $this->trans_colour = imagecolorallocatealpha($this->img, 0, 0, 0, 127); 
     $this->orange  = imagecolorallocate($this->img, 220, 210, 60); 
     $this->white  = imagecolorallocate($this->img, 255,255, 255); 
     $this->whitetr  = imagecolorallocatealpha($this->img, 255,255, 255, 95); 
     $this->blacktr  = imagecolorallocatealpha($this->img, 0, 0, 0, 95); 

     if ((!$this->cropped) && ($this->string !='')) 
     {$this->watermarkimage();} 

     if (($this->new_height > 0) && ($this->new_width > 0)) {$this->ResizeImage();}; 

     if (($this->cropped) && ($this->string !='')) 
     {$this->watermarkimage();} 

     imageAlphaBlending($this->img, true); 
     imageSaveAlpha($this->img, true); 
    } 
    //// 
    private function ResizeImage() 
    { 
     # v_fact and h_fact are the factor by which the original vertical/horizontal 
     # image sizes should be multiplied to get the image to your target size. 
     $v_fact = $this->new_height/imagesy($this->img);//target_height/im_height; 
     $h_fact = $this->new_width/imagesx($this->img);//target_width/im_width; 
     # you want to resize the image by the same factor in both vertical 
     # and horizontal direction, so you need to pick the correct factor from 
     # v_fact/h_fact so that the largest (relative to target) of the new height/width 
     # equals the target height/width and the smallest is lower than the target. 
     # this is the lowest of the two factors 
     if($this->cropped) 
     { $im_fact = max($v_fact, $h_fact); } 
     else 
     { $im_fact = min($v_fact, $h_fact); } 

     $new_height = round(imagesy($this->img) * $im_fact); 
     $new_width = round(imagesx($this->img) * $im_fact); 

     $img2 = $this->img;  
     $this->img = imagecreatetruecolor($new_width, $new_height);  
     imagecopyresampled($this->img, $img2, 0, 0, 0, 0, $new_width, $new_height, imagesx($img2), imagesy($img2)); 

     $img2 = $this->img;  
     $this->img = imagecreatetruecolor($this->new_width, $this->new_height); 
     imagefill($this->img, 0, 0, $this->trans_colour); 

     $dstx = 0; 
     $dsty = 0; 
     if ($this->cropped) 
     { 
      if (imagesx($this->img) < imagesx($img2)) 
      { $dstx = round((imagesx($this->img)-imagesx($img2))/2); } 

      if (imagesy($this->img) < imagesy($img2)) 
      { $dsty = round((imagesy($this->img)-imagesy($img2))/2); } 
     } 
     else 
     { 
      if (imagesx($this->img) > imagesx($img2)) 
      { $dstx = round((imagesx($this->img)-imagesx($img2))/2); } 

      if (imagesy($this->img) > imagesy($img2)) 
      { $dsty = round((imagesy($this->img)-imagesy($img2))/2); } 
     } 

     imagecopy ($this->img, $img2, $dstx, $dsty, 0, 0, imagesx($img2) , imagesy($img2)); 
     imagedestroy($img2);   
    } 

    //// 

    private function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) 
    { 
     /************ 
     simple function that calculates the *exact* bounding box (single pixel precision). 
     The function returns an associative array with these keys: 
     left, top: coordinates you will pass to imagettftext 
     width, height: dimension of the image you have to create 
     *************/ 
     $rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text); 
     $minX = min(array($rect[0],$rect[2],$rect[4],$rect[6])); 
     $maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6])); 
     $minY = min(array($rect[1],$rect[3],$rect[5],$rect[7])); 
     $maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7])); 

     return array( 
     "left" => abs($minX) - 1, 
     "top" => abs($minY) - 1, 
     "width" => $maxX - $minX, 
     "height" => $maxY - $minY, 
     "box" => $rect); 
    } 

    private function watermarkimage($font_size=0) 
    { 
     if ($this->string == '') 
     {die('Watermark function call width empty string!');} 

     $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle); 
     while (($box['width'] < imagesx($this->img)) && ($box['height'] < imagesy($this->img)) && ($font_size <= $this->max_font_size)) 
     { 
      $font_size++; 
      $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle); 
     } 

     $font_size--; 
     $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle); 

     $vcenter = round((imagesy($this->img)/2) + ($box['height']/2)); 
     $hcenter = round((imagesx($this->img) - $box['width'])/2); 

     imagettftext($this->img, $font_size, $this->angle, $hcenter, $vcenter, $this->blacktr, $this->font, $this->string);  
     imagettftext($this->img, $font_size, $this->angle, $hcenter+1, $vcenter-2, $this->whitetr, $this->font, $this->string); 
    } 
} 
?> 

Inoltre, ho utilizzato la risposta accettata ma in alcuni casi non mantiene il rapporto. Ho trovato alcune buone risposte sul forum e le ho messe insieme e finalmente ho creato una classe che ridimensiona un'immagine. Come funzione extra puoi mettere un testo filigrana.

Si può vedere cosa succede quando si sceglie di ritagliare o meno, se non viene aggiunta un'area trasparente alla nuova immagine ridimensionata.

Questo esempio è più che richiesto, ma penso che sia un buon esempio.

+0

questo sembra essere una buona funzione e funziona come previsto, ma cosa succede se voglio ritagliare sempre .. per esempio la mia immagine di destinazione è quindi 500 400: // W400 H300 = stretchW | stretchH // W400 H500 = stretchW + H dapprima poi raccolto H // W500 H300 = tratto W + H dapprima poi ritagliare W // W500 H500 = cropW | cropH –

+0

Non ho capito bene il tuo punto ma, la funzione funziona. puoi scegliere di ritagliare o meno. Imposta il valore predefinito su "true" quando usi la funzione sulla tua pagina. Se riesci a farlo funzionare meglio con alcuni cambiamenti, sei il benvenuto. BTW Non sono un maestro di php/web, solo un hobbista. – coban

-1

Ecco un'applicazione completa che ho lavorato sodo su di esso per includere le operazioni più comuni come scale up scala & giù, miniatura preservare le proporzioni, convertire il tipo di file, il cambiamento della qualità/dimensione del file e molto altro ancora ...

<?php 
//##// Resize (and convert) image (Scale up & scale down, thumbnail, preserve aspect ratio) //##// 
/////////////////////////////////////////////// 
///////////////// Begin.Setup ///////////////// 
// Source File: 
$src_file = "/your/server/path/to/file.png";// png or jpg files only 

// Resize Dimensions: 
// leave blank for no size change (convert only) 
// if you specify one dimension, the other dimension will be calculated according to the aspect ratio 
// if you specify both dimensions system will take care of it depending on the actual image size 
// $newWidth = 2000; 
// $newHeight = 1500; 

// Destination Path: (optional, if none: download image) 
$dst_path = "/your/server/path/new/"; 

// Destination File Name: (Leave blank for same file name) 
// $dst_name = 'image_name_only_no_extension'; 

// Destination File Type: (Leave blank for same file extension) 
// $dst_type = 'png'; 
$dst_type = 'jpg'; 

// Reduce to 8bit - 256 colors (Very low quality but very small file & transparent PNG. Only for thumbnails!) 
// $palette_8bit = true; 

///////////////// End.Setup ///////////////// 
/////////////////////////////////////////////// 
if (!$dst_name){$dst_name = strtolower(pathinfo($src_file, PATHINFO_FILENAME));} 
if (!$dst_type){$dst_type = strtolower(pathinfo($src_file, PATHINFO_EXTENSION));} 
if ($palette_8bit){$dst_type = 'png';} 
if ($dst_path){$dst_file = $dst_path . $dst_name . '.' . $dst_type;} 

$mime = getimagesize($src_file);// Get image dimensions and type 

// Destination File Parameters: 
if ($dst_type == 'png'){ 
    $dst_content = 'image/png'; 
    $quality = 9;// All same quality! 0 too big file // 0(no comp.)-9 (php default: 6) 
} elseif ($dst_type == 'jpg'){ 
    $dst_content = 'image/jpg'; 
    $quality = 85;// 30 Min. 60 Mid. 85 Cool. 90 Max. (100 Full) // 0-100 (php default: 75) 
} else { 
    exit('Unknown Destination File Type'); 
} 

// Source File Parameters: 
if ($mime['mime']=='image/png'){$src_img = imagecreatefrompng($src_file);} 
elseif ($mime['mime']=='image/jpg'){$src_img = imagecreatefromjpeg($src_file);} 
elseif ($mime['mime']=='image/jpeg'){$src_img = imagecreatefromjpeg($src_file);} 
elseif ($mime['mime']=='image/pjpeg'){$src_img = imagecreatefromjpeg($src_file);} 
else {exit('Unknown Source File Type');} 

// Define Dimensions: 
$old_x = imageSX($src_img); 
$old_y = imageSY($src_img); 

if ($newWidth AND $newHeight){ 
    if($old_x > $old_y){ 
     $new_x = $newWidth; 
     $new_y = $old_y/$old_x * $newWidth; 
    } elseif($old_x < $old_y){ 
     $new_y = $newHeight; 
     $new_x = $old_x/$old_y * $newHeight; 
    } elseif($old_x == $old_y){ 
     $new_x = $newWidth; 
     $new_y = $newHeight; 
    } 
} elseif ($newWidth){ 
    $new_x = $newWidth; 
    $new_y = $old_y/$old_x * $newWidth; 
} elseif ($newHeight){ 
    $new_y = $newHeight; 
    $new_x = $old_x/$old_y * $newHeight; 
} else { 
    $new_x = $old_x; 
    $new_y = $old_y; 
} 

$dst_img = ImageCreateTrueColor($new_x, $new_y); 

if ($palette_8bit){//////// Reduce to 8bit - 256 colors //////// 
    $transparent = imagecolorallocatealpha($dst_img, 255, 255, 255, 127); 
    imagecolortransparent($dst_img, $transparent); 
    imagefill($dst_img, 0, 0, $transparent); 
    imagecopyresampled($dst_img,$src_img,0,0,0,0,$new_x,$new_y,$old_x,$old_y);// Great quality resize. 
    imagetruecolortopalette($dst_img, false, 255); 
    imagesavealpha($dst_img, true); 
} else { 
    // Check image and set transparent for png or white background for jpg 
    if ($dst_type == 'png'){ 
     imagealphablending($dst_img, false); 
     imagesavealpha($dst_img, true); 
     $transparent = imagecolorallocatealpha($dst_img, 255, 255, 255, 127); 
     imagefilledrectangle($dst_img, 0, 0, $new_x, $new_y, $transparent); 
    } elseif ($dst_type == 'jpg'){ 
     $white = imagecolorallocate($dst_img, 255, 255, 255); 
     imagefilledrectangle($dst_img, 0, 0, $new_x, $new_y, $white); 
    } 

    imagecopyresampled($dst_img,$src_img,0,0,0,0,$new_x,$new_y,$old_x,$old_y);// Great quality resize. 
} 

// Skip the save to parameter using NULL, then set the quality; imagejpeg($dst_img);=> Default quality 
if ($dst_file){ 
    if ($dst_type == 'png'){ 
     imagepng($dst_img, $dst_file, $quality); 
    } elseif ($dst_type == 'jpg'){ 
     imagejpeg($dst_img, $dst_file, $quality); 
    } 
} else { 
    header('Content-Disposition: Attachment;filename=' . $dst_name . '.' . $dst_type);// comment this line to show image in browser instead of download 
    header('Content-type: ' . $dst_content); 
    if ($dst_type == 'png'){ 
     imagepng($dst_img, NULL, $quality); 
    } elseif ($dst_type == 'jpg'){ 
     imagejpeg($dst_img, NULL, $quality); 
    } 
} 
imagedestroy($src_img); 
imagedestroy($dst_img); 
//##// END : Resize image (Scale Up & Down) (thumbnail, bigger image, preserve aspect ratio) END //##// 
+0

Questa è una sceneggiatura molto avanzata che ho lavorato duramente per coprire di più e perfezionarla. Ho notato un downvote, l'hai provato? Fammi sapere se c'è qualcosa di sbagliato in questo .... – Tarik

0

So che stai cercando un divisore che consenta di ridimensionare l'immagine in modo proporzionale. Controllare questo demo

Come ottenere il nostro divisore matematicamente

lascia supporre la nostra immagine originale ha x larghezza e l'altezza y; x = 300 e y = 700

Altezza massima e larghezza massima di 200;

Innanzitutto, controlleremo quale dimensione dell'immagine è maggiore dell'altra. La nostra altezza (y) è maggiore della larghezza (x)

In secondo luogo, controlliamo se la nostra altezza è superiore alla nostra altezza massima. Per il nostro caso, la nostra altezza è maggiore dell'altezza massima. In un caso in cui meno che l'altezza massima, abbiamo impostato la nostra nuova altezza alla nostra altezza originale.

Infine, cerchiamo nostro divisore come mostrato sotto

if y is set to maximum height 200 and max-y=200; 
y=max-y, that is 
if y=max-y 
what about 
x=? 
that is, 
if 700 is resized to 200 
what about 300? 
700=200 
300=? 
new width = (200 (new height) * 300(width))/700 (height) 
so our divisor is 
divisor= new height (300)/height(700) 
new width = divisor * width or width/(1/divisor) 

e viceversa per la larghezza se maggiore dell'altezza

if ($width > $height) { 
    if($width < $max_width) 
     $newwidth = $width; 

    else 

    $newwidth = $max_width; 


    $divisor = $width/$newwidth; 
    $newheight = floor($height/$divisor); 
} 
else { 

    if($height < $max_height) 
     $newheight = $height; 
    else 
     $newheight = $max_height; 

    $divisor = $height/$newheight; 
    $newwidth = floor($width/$divisor); 
} 

Vedere l'esempio completo e provare utilizzando il working demo.

Problemi correlati