<?php 
    /**
    *
    * copyright (c) 2015-2023 Heliac Technologies
    * license http://opensource.org/licenses/gpl-license.php GNU GPL v3 
    *
    * Classe per eseguire operazioni con le immagini, utilizza le funzioni della libreria
    * dispone di metodi per ritagliare, ridurre o ingrandire immagini. Dispone anche di metodi
    * per creare semplici immagini.
    * 
    * Supporta i formati gif, jpg e png
    */

    class ElaboratoreImmagini {
        public $altezza;
        public $larghezza;
        public $tipoImmagine;
        public $immagine;
        public $sorgente;
        
        /**
         * @param type $sorgente 
         * campo in cui viene inserito il sordente dell'immagine, che può essere un path,
         * oppure una stringa o ancora una stringa in base64
         * 
         * @param type $tipo
         * questo parametro deve essere specificato solo se si sta cercando di creare un'immagine
         * da stringa, base64 o url remota
         */
        function __construct($sorgente, $tipo = "file") {
            $this->sorgente = $sorgente;
            if($tipo==="file") {
                $this->tipoImmagine = strtolower(pathinfo($sorgente, PATHINFO_EXTENSION));
                
                if($this->tipoImmagine == 'jpeg') {
                    $this->tipoImmagine = 'jpg';
                }
                $this->carica();
            }
            else {
                switch($tipo) {
                    case 'stringa': 
                        $this->immagine = imagecreatefromstring($sorgente); 
                        break;
                    case 'base64': 
                        $this->immagine = imagecreatefromstring($sorgente); 
                        break;
                    case 'urlRemota': 
                        $stringaImmagine = file_get_contents($sorgente);
                        $this->immagine = imagecreatefromstring($stringaImmagine); 
                        break;
                    default : return "Tipo immagine non supportato!";
                }
            }
            $this->setAltezza(imagesy($this->immagine));
            $this->setLarghezza(imagesx($this->immagine));
        }

        public function carica() {
            switch($this->tipoImmagine) {
                case 'gif': $this->immagine = imagecreatefromgif($this->sorgente); break;
                case 'jpg': $this->immagine = imagecreatefromjpeg($this->sorgente); break;
                case 'webp': $this->immagine = imagecreatefromwebp($this->sorgente); break;
                case 'png': $this->immagine = imagecreatefrompng($this->sorgente); break;
                default : return "Tipo immagine non supportato!";
            }
        }
        
        public function salva($percorso) {
            switch($this->tipoImmagine) {
              case 'gif': imagegif($this->immagine, $percorso); break;
              case 'jpg': imagejpeg($this->immagine, $percorso); break;
              case 'webp': imagewebp($this->immagine, $percorso); break;
              case 'png': imagepng($this->immagine, $percorso); break;
            }
        }

        /*
         * questo metodo consente di ridurre o ingrandire in scala l'immagine presente nel
         * valore $this->immagine. Calcola la scala dell'immagine 
         * in base ai parametri dati, poi calcola le nuove dimensioni e crea
         * la nuova immagine
         * 
         * Prende in input tre campi:
         * @parametro   può essere altezza o larghezza
         * @valore      il valore in pixel del parametro specificato sopra
         * @percorso    il percorso dove salvare l'immagine
         * 
         * Esempio di funzionamento: Immagine base di 1600 * 1200
         * il metodo riceve questi valori:
         * @parametro = larghezza
         * @valore    = 1000
         * @percorso  = un percorso qualsiasi
         * 
         * il metodo calcolerà la scala considerando la larghezza, ovvero:
         * $scala = 1000 / 1600
         * 
         * conseguentemente calcolerà le immagini e creerà la nuova immagine
         */
        public function modificaInScala($parametro,$valore, $percorso) {
            $scala = 1;
            if($parametro=="larghezza") {
                $scala = $valore / $this->getLarghezza();
            }
            else {
                $scala = $valore / $this->getAltezza();
            }
            $larghezzaNuovaImmagine = ceil($this->getLarghezza() * $scala);
            $altezzaNuovaImmagine   = ceil($this->getAltezza() * $scala);
            $thumb = imagecreatetruecolor($larghezzaNuovaImmagine,$altezzaNuovaImmagine);
            imagecopyresampled($thumb, $this->immagine, 0, 0, 0, 0, $larghezzaNuovaImmagine, $altezzaNuovaImmagine, $this->getLarghezza(), $this->getAltezza());
            switch($this->tipoImmagine) {
                case 'gif': 
                    imagegif($thumb, $percorso); 
                    break;
                case 'jpg': 
                    imagejpeg($thumb, $percorso); 
                    break;
                case 'png': 
                    imagepng($thumb, $percorso); 
                    break;
            }
        }

        public function riduciInPercentuale($percentuale,$percorso) {
            $altezza   = round($this->altezza*$percentuale/100);
            $larghezza = round($this->larghezza*$percentuale/100);
            $thumb = imagecreatetruecolor($larghezza,$altezza);
            imagecopyresampled($thumb, $this->immagine, 0, 0, 0, 0, $larghezza, $altezza, $this->getLarghezza(), $this->getAltezza());
            switch($this->tipoImmagine) {
                case 'gif': 
                    imagegif($thumb, $percorso); 
                    break;
                case 'jpg': 
                    imagejpeg($thumb, $percorso); 
                    break;
                case 'png': 
                    imagepng($thumb, $percorso); 
                    break;
            }
        }

        /*
         * Consente di applicare un logo su un'immagine scegliendo tra le varie posizioni in cui applicarlo
         * 
         * Prende in input tre campi:
         * @percorsoLogo il percorso dell'immagine
         * @posizione    la posizione dove inserire il logo. Si può scegliere tra i seguenti valori:
         *               -> centrato
         *               -> sinistraInAlto
         *               -> sinistraInBasso
         *               -> destraInAlto
         *               -> destraInBasso
         *               il valore predefinito per questo campo è "centrato"
         * @percorso     il percorso dove salvare l'immagine, se non specificato verrà sovrascritta l'immagine sorgente
         */
        public function aggiungiLogoInSovraimpressione($percorsoLogo, $posizione="centrato", $percorso="") {
            $immagineLogo = imagecreatefrompng($percorsoLogo);
            
            if($percorso=="") {
            	$percorso = $this->sorgente;
            }
            
            // Set the margins for the stamp and get the height/width of the stamp image
            $larghezzaLogo = imagesx($immagineLogo);
            $altezzaLogo   = imagesy($immagineLogo);

            if($posizione=="centrato") {
            	$posizioneAsseX = ($this->larghezza / 2) - ($larghezzaLogo/2);
            	$posizioneAsseY = ($this->altezza/2) - ($altezzaLogo/2);
            }
            else if($posizione=="sinistraInAlto") {
                $posizioneAsseX = 0;
            	$posizioneAsseY = 0;
            }
            else if($posizione=="sinistraInBasso") {
                $posizioneAsseX = 0;
            	$posizioneAsseY = $this->altezza - $altezzaLogo;
            }
            else if($posizione=="destraInAlto") {
                $posizioneAsseX = $this->larghezza - $larghezzaLogo;
            	$posizioneAsseY = 0;
            }
            else if($posizione=="destraInBasso") {
                $posizioneAsseX = $this->larghezza - $larghezzaLogo;
            	$posizioneAsseY = $this->altezza - $altezzaLogo;
            }
            
            imagecopy($this->immagine, $immagineLogo, $posizioneAsseX, $posizioneAsseY, 0, 0, $larghezzaLogo, $altezzaLogo);            
            
            switch($this->tipoImmagine) {
                case 'gif': 
                    imagegif($this->immagine, $percorso); 
                    break;
                case 'jpg': 
                    imagejpeg($this->immagine, $percorso); 
                    break;
                case 'png': 
                    imagepng($this->immagine, $percorso); 
                    break;
            }
        }
        
        /*
         * metodo per il ritaglio di un'immagine. Prende in input i seguenti parametri
         * 
         * @puntoIniziale: array contenente le coordinate x,y del punto di partenza
         * @larghezza:     
         * @altezza:
         * @destinazione:  percorso di destinazione del file
         */
        public function ritagliaImmagine($puntoIniziale,$larghezza,$altezza,$destinazione) {
            if($this->larghezza < $larghezza or $this->altezza < $altezza) {
                return "L'immagine è troppo piccola!";
                exit();
            }
            $x = $puntoIniziale[0];
            $y = $puntoIniziale[1];

            // se è una png o una gif preserva la transparenza
            if($this->tipoImmagine == "gif" || $this->tipoImmagine == "png"){
                imagecolortransparent($immagineDestinazione, imagecolorallocatealpha($new, 0, 0, 0, 127));
                imagealphablending($immagineDestinazione, false);
                imagesavealpha($immagineDestinazione, true);
            }
            $immagineDestinazione = imagecrop($this->immagine, array('x' => $x, 'y' => $y, 'width' => $larghezza, 'height' => $altezza));

            switch($this->tipoImmagine){
                case 'gif': imagegif($immagineDestinazione, $destinazione); break;
                case 'jpg': imagejpeg($immagineDestinazione, $destinazione); break;
                case 'png': imagepng($immagineDestinazione, $destinazione); break;
            }
        }
        
        /*
         * consente di ruotare l'immagine di una data quantità di dati
         * se @param $nonSovrascrivere = false la variabile istanza
         * $this->immagine viene sovrascritta con i dati dell'immagine ruotata, 
         * altrimenti l'immagine ruotata viene restituita
         */
        public function ruotaImmagine($gradi,$nonSovrascrivere=false) {
            if($nonSovrascrivere) {
                return imagerotate($this->immagine, $gradi, 0);
            }
            else {
                $this->immagine = imagerotate($this->immagine, $gradi, 0);
                return true;
            }
        }

        // metodi dedicati alla gestione dei dati exif
        public function datiExif() {
            return exif_read_data($this->sorgente);
        }
        
        /*
         * Questo metodo restituisce solo l'orientamento impsotato nei metadati, dato che si tratta
         * di uno dei dati più richiesti è stato creato un metodo apposta
         */
        public function orientamentoExif() {
            $exif = $this->datiExif();
            return $exif["Orientation"];
        }
        
        // getter & setter
        public function getAspectRatio() {
            return $this->larghezza/$this->altezza;
        }
        
        public function getStringaImmagineBase64() {
            $datiImg = file_get_contents($this->percorsoImmagne);
            return base64_encode($datiImg);
        }

        public function getAltezza() {
            return $this->altezza;
        }

        public function setAltezza($altezza) {
            $this->altezza = $altezza;
        }

        public function getLarghezza() {
            return $this->larghezza;
        }

        public function setLarghezza($larghezza) {
            $this->larghezza = $larghezza;
        }

        public function getTipoImmagine() {
            return $this->tipoImmagine;
        }

        public function setTipoImmagine($tipoImmagine) {
            $this->tipoImmagine = $tipoImmagine;
        }

        public function getPercorsoImmagne() {
            return $this->percorsoImmagne;
        }

        public function setPercorsoImmagne($sorgente) {
            $this->percorsoImmagne = $sorgente;
        }
    }