Scale Image Using PHP and Maintaining Aspect Ratio

前端 未结 10 1973
孤独总比滥情好
孤独总比滥情好 2020-11-30 07:38

Basically I want to upload an image (which i\'ve sorted) and scale it down to certain constraints such as max width and height but maintain the aspect ratio of the original

10条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-11-30 08:28

     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);
        }
    }
    ?>
    

    Also I have been using the accepted answer but it does not keep the ratio in some cases. I have found some good answers on the forum and have put them in together and finally created a Class which resizes an image. As extra function u can put a watermark text.

    u can see what happens when choose to crop or not, if not a transparent area will be added to the new resized image.

    This example is more than asked, but I think it is a good example.

提交回复
热议问题