Class Imagem
Importante: O ficheiro da classe tem de estar guardado como UTF-8 sem BOM ou ANSI.
/* Críticas e sugestões são bem-vindas.
*
* No caso de teres gostado desta classe e te tenha sido útil, podes sempre fazer
* uma pequena contribuição monetária... Abaixo, segue o link para doações.
* https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SK9NXWHWLGGHW
*
* @author Luís Coutinho <Luis@lfscoutinho.net>
* @link http://lfscoutinho.net
* @version 1.0
* @package lfscoutinho
*/
/**
* Imagem Lfscoutinho
* A Imagem Lfscoutinho é uma classe que permite criar e redimensionar imagens,
* criar miniaturas, colocar uma marca d'água, fazer upload, etc. Para além disso,
* está adaptada para sites que estejam em vários idiomas. Os únicos requisitos
* são: ter a função gettext e a biblitoteca GD activas no servidor.
*
* @property array $formatos Formatos autorizados
* @property int $max_tamanho Tamanho máximo da imagem a ser carregada (em bytes)
* @property int $max_largura Largura máxima da imagem a ser carregada (em pixels)
* @property int $max_altura Altura máxima da imagem a ser carregada (em pixels)
* @property int $qualidade Qualidade da imagem nova (0 a 100)
* @property bool $redimensionar Indica se é possível redimensionar a imagem, caso as medidas sejam superiores às permitidas
* @property bool $encriptarNome Indica se é para encriptar ou não o nome (de modo a não criar imagens com o mesmo nome)
* @property null|string $destino Indica se é para mostrar ou carregar uma imagem. Se for null, mostra a imagem. Caso contrário, carrega-a
* @property string $destinoImg Caminho de destino das imagens
* @property string $destinoMini Caminho de destino das miniaturas
* @property bool $colocarMarcaDagua Indica se é para colocar uma marca d'água ou não
* @property array $marcaDagua Dados da marca d'água [src = caminho, posx = posição horizontal, posy = posição vertical]
* @property array $imagemOriginal Imagem antiga
* @property array $imagemNova Imagem nova
* @property array $erros Erros que possam ocorrer
* @property bool $mostrarErros Indica se é para mostrar os erros ou não, caso ocorram
*
* @package lfscoutinho
* @subpackage classes
*/
class Imagem {
private $formatos = array( IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF );
private $formatosDesc = array( 'JPEG', 'PNG', 'GIF' );
private $max_tamanho = 100000;
private $max_largura = 800;
private $max_altura = 600;
private $qualidade = 100;
private $redimensionar = false;
private $encriptarNome = true;
private $destino = null;
private $destinoImg = 'C:/wamp/www/imagem/fotos/';
private $destinoMini = 'C:/wamp/www/imagem/minis/';
private $colocarMarcaDagua = false;
private $marcaDagua = array( 'src' => 'http://127.0.0.1/imagem/php.png',
'posx' => 0,
'posy' => 0 );
private $imagemOriginal;
private $imagemNova;
private $erros = array();
private $mostrarErros = true;
/**
* Método constructor. Neste método é possível alterar algumas propriedades
* que estão atribuídas por defeito.
*
* @param int func_get_arg(0) Qualidade da imagem (0 - 100). Para usar o valor por defeito, colocar -1
* @param int func_get_arg(1) Tamanho máximo. Para usar o valor por defeito, colocar -1
* @param int func_get_arg(2) Largura máxima. Para usar o valor por defeito, colocar -1
* @param int func_get_arg(3) Altura máxima. Para usar o valor por defeito, colocar -1
* @param string|bool func_get_arg(4) Redimensionar automaticamente. Para usar o valor por defeito, colocar uma string vazia
* @param string func_get_arg(5) Caminho de destino. Para usar o valor por defeito, colocar uma string vazia
*/
public function __construct() {
// Qualidade
if( func_num_args() > 0 && func_get_arg( 0 ) > -1 ) {
$this->max_tamanho = (int) func_get_arg( 0 );
}
// Tamanho máximo
if( func_num_args() > 1 && func_get_arg( 1 ) > -1 ) {
$this->max_tamanho = (int) func_get_arg( 1 );
}
// Largura máxima
if( func_num_args() > 2 && func_get_arg( 2 ) > -1 ) {
$this->max_largura = (int) func_get_arg( 2 );
}
// Altura máxima
if( func_num_args() > 3 && func_get_arg( 3 ) > -1 ) {
$this->max_altura = (int) func_get_arg( 3 );
}
// Redimensionar
if( func_num_args() > 4 && func_get_arg( 4 ) !== '' ) {
$this->redimensionar = (bool) func_get_arg( 4 );
}
// Caminho de destino
if( func_num_args() > 5 && func_get_arg( 5 ) !== '' ) {
$this->setDestino( (string) func_get_arg( 5 ) );
}
}
/**
* Método que faz algumas verificações e atribuições em relação à imagem
*
* @param string $caminho Caminho de origem da imagem
*/
public function setImagem( $imagem ) {
if( is_array( $imagem ) ) {
if( $this->verificarFormato( $imagem['tmp_name'] ) ) {
$this->imagemOriginal['caminho'] = $imagem['tmp_name'];
$this->setNome( $imagem['name'] );
$this->setDestino( '' );
$this->setMedidas( $imagem['tmp_name'] );
$this->verificarTamanho( $imagem['size'] );
$this->verificarMedidas();
}
} elseif( is_string( $imagem ) ) {
if( $this->verificarFormato( $imagem ) ) {
$this->imagemOriginal['caminho'] = $imagem;
$this->setDestino( null );
$this->setMedidas( $imagem );
$this->redimensionar();
}
}
}
/**
* Método que define se é para encriptar o nome da imagem nova ou não
*
* @param bool $simOUnao true para encriptar e false para não encriptar
*/
public function setEncriptarNome( $simOUnao ) {
if( is_bool( $simOUnao ) ) {
$this->encriptarNome = $simOUnao;
return true;
} else {
return false;
}
}
/**
* Método que define o nome da imagem nova
*
* @param string $nome Nome da imagem antiga
*/
public function setNome( $nome ) {
if( $this->getEncriptarNome() ) {
$this->imagemNova['nome'] = md5( $nome . microtime( true ) ) .
$this->imagemOriginal['extensao'];
} else {
$this->imagemNova['nome'] = $nome;
}
}
/**
* Método que define as medidas da imagem original e, verifica ou não, se
* são permitidas
*
* @param string $caminho Caminho da imagem original
*/
private function setMedidas( $caminho ){
list($largura, $altura) = getimagesize( $caminho );
$this->imagemOriginal['largura'] = $largura;
$this->imagemOriginal['altura'] = $altura;
}
/**
* Método que define os caminhos de destino das imagens/miniaturas. O valor
* null, significa que é para mostrar uma imagem e não para fazer upload. Para
* utilizar os caminhos por defeitos (tanto para imagens como miniaturas),
* utiliza-se uma string vazia (''). E, para dizer se é para carregar uma
* imagem ou uma miniatura atribui-se à variável $mini, false ou true,
* respectivamente. O valor por defeito é false (carregar imagens).
*
* @param string $caminho Caminho de destino da imagem
* @param bool $mini false para mudar o destino da imagem e true para mudar o destino da miniatura
* @return bool Retorna true, se o caminho novo for definido. Caso contrário, false.
*/
public function setDestino( $caminho, $mini = false ){
if( $caminho === '' ) {
if( $mini ) {
$this->destino = $this->destinoMini;
} else {
$this->destino = $this->destinoImg;
}
$this->destino .= $this->getNome();
} elseif( $caminho && file_exists( $caminho ) ) {
$this->destino = $caminho . $this->getNome();
} elseif( $caminho === null ) {
$this->destino = null;
} else {
$this->erros[] = _('O caminho de destino não existe.');
return false;
}
return true;
}
/**
* Método que define a colocação ou não da marca d'água.
*
* @param bool $simOUnao true para colocar e false para não colocar
* @return bool Retorna true, se o valor for definido com sucesso. Caso contrário, false
*/
public function setColocarMarcaDagua( $simOUnao ) {
if( is_bool( $simOUnao ) ) {
$this->colocarMarcaDagua = $simOUnao;
return true;
} else {
return false;
}
}
/**
* Método que define a imagem da marca d'água e as posições onde vai ser
* colocada. As posições positivas alinham a imagem da esquerda para a direita
* e de cima para baixo, já as posições negativas alinham a imagem da direita
* para a esquerda e de baixo para cima.
*
* @param array $opcoes Opções da marca d'água [src = caminho, posx = posição horizontal, posy = posição vertical]
* @return bool Retorna verdadeiro, se os valores forem definidos com sucesso. Caso contrário, false
*/
public function setMarcaDagua( $opcoes ) {
if( is_array( $opcoes ) ) {
if( isset( $opcoes['src'] ) &&
exif_imagetype( $caminho ) === IMAGETYPE_PNG ) {
$this->marcaDagua['src'] = $opcoes['src'];
}
if( isset( $opcoes['posx'] ) && is_int( $opcoes['posx'] ) ) {
$this->marcaDagua['posx'] = $opcoes['posx'];
}
if( isset( $opcoes['posy'] ) && is_int( $opcoes['posy'] ) ) {
$this->marcaDagua['posy'] = $opcoes['posy'];
}
return true;
} else {
return false;
}
}
/**
* Método que retorna o objectivo de encriptar o nome da imagem nova
*
* @return bool Retorna true, se for para encriptar. Caso contrário, false.
*/
public function getEncriptarNome() {
return $this->encriptarNome;
}
/**
* Método que retorna o nome da imagem/miniatura nova
*
* @return string Retorna o nome da imagem/miniatura nova
*/
public function getNome() {
return $this->imagemNova['nome'];
}
/**
* Método que retorna o caminho de destino das imagens/miniaturas
*
* @return string Retorna o destino da imagem/miniatura
*/
public function getDestino() {
return $this->destino;
}
/**
* Método que retorna o objectivo de colocar a marca d'água
*
* @return bool Retornar true, se for para colocar a marca d'água. Caso contrário, false
*/
public function getColocarMarcaDagua() {
return $this->colocarMarcaDagua;
}
/**
* Método que verifica se há erros e, se necessário, mostra-os
*
* @return bool Retorna false, se não existirem erros. Caso contrário, retorna-os
*/
public function getErros() {
if( $this->erros ) {
$html = '<div id="errosImagem">';
foreach( $this->erros as $erro ) {
$html.= "nt<p>{$erro}</p>";
}
$html.= "n</div>";
return $html;
} else {
return false;
}
}
/**
* Método que verifica se o ficheiro é uma imagem e se o formato é permitido
*
* @param string $caminho Caminho da imagem
* @return bool Retorna verdadeiro, se o formato for permitido. Caso contrário, false
*/
public function verificarFormato( $caminho ) {
$formato = exif_imagetype( $caminho );
if( $formato && in_array( $formato, $this->formatos ) ) {
switch( $formato ) {
case IMAGETYPE_JPEG :
$this->imagemOriginal['extensao'] = '.jpg';
break;
case IMAGETYPE_PNG :
$this->imagemOriginal['extensao'] = '.png';
break;
case IMAGETYPE_GIF :
$this->imagemOriginal['extensao'] = '.gif';
break;
}
$this->imagemOriginal['formato'] = $formato;
return true;
} else {
$this->erros[] = sprintf( _('Não é possível carregar ficheiros do formato escolhido. Os únicos formatos permitidos são: %s'), implode( ', ', $this->formatosDesc ) );
return false;
}
}
/**
* Método que verifica se o tomanho do ficheiro é permitido
*
* @param int $tamanho Tamanho do ficheiro
* @return bool Retorna true, se o tamanho for permitido. Caso contrário, false
*/
public function verificarTamanho( $tamanho ) {
if( $this->max_tamanho > $tamanho || $this->max_tamanho === 0 ) {
return true;
} else {
$this->erros[] = sprintf( _('A imagem é muito grande. O tamanho da imagem deve ser, no máximo, %d KB.'), $this->max_tamanho );
return false;
}
}
/**
* Método que verifica se as medidas da imagem original (largura e altura)
* são permitidas. Se não forem, verifica se é possível redimensionar a imagem.
*
* @return bool Retorna true, se as medidas forem permitidas ou se for possível redimensionar a imagem. Caso contrário, false
*/
public function verificarMedidas() {
if( $this->redimensionar ) {
$this->redimensionar();
} else {
if( $this->max_largura &&
$this->imagemOriginal['largura'] > $this->max_largura ) {
$this->erros[] = sprintf( _('A imagem é muito larga. A largura
deve ter, no máximo, %d pixels.'),
$this->max_largura );
return false;
}
if( $this->max_altura &&
$this->imagemOriginal['altura'] > $this->max_altura ) {
$this->erros[] = sprintf( _('A imagem é muito alta. A altura deve
ter, no máximo, %d pixels.'),
$this->max_altura );
return false;
}
}
$this->imagemNova['largura'] = $this->imagemOriginal['largura'];
$this->imagemNova['altura'] = $this->imagemOriginal['altura'];
return true;
}
/**
* Método que calcula as medidas de uma imagem a ser redimensionada. No caso
* de serem indicadas a largura e a altura, as medidas da nova imagem serão
* essas. Se for indicada só a largura ou a altura, o redimensionamento será
* feito com base nessa medida. E, se não for indicada nenhuma das medidas,
* o redimensionamento será feito com base na medida maior.
*
* @param int $largura Largura da imagem
* @param int $altura Altura da imagem
*/
public function redimensionar( $largura = 0, $altura = 0 ) {
if( $largura === 0 && $altura === 0 ) {
if( ( $this->max_largura &&
$this->imagemOriginal['largura'] > $this->max_largura ) ||
( $this->max_altura &&
$this->imagemOriginal['altura'] > $this->max_altura ) ) {
if( $this->imagemOriginal['largura'] > $this->imagemOriginal['altura'] ) {
$largura = $this->max_largura;
} else {
$altura = $this->max_altura;
}
} else {
// No caso de ser para mostrar a imagem (em vez de fazer upload)
// e a imagem esteja dentro dos limites
$largura = $this->imagemOriginal['largura'];
$altura = $this->imagemOriginal['altura'];
}
}
if( $largura && $altura === 0 ) {
$altura = $this->imagemOriginal['altura'] * $largura / $this->imagemOriginal['largura'];
} elseif( $largura === 0 && $altura ) {
$largura = $this->imagemOriginal['largura'] * $altura / $this->imagemOriginal['altura'];
}
$this->imagemNova['largura'] = $largura;
$this->imagemNova['altura'] = $altura;
}
/**
* Cria o resource de uma imagem
*
* @param string $caminho Caminho da imagem original
* @param string $formato Formato da imagem original
* @return resource|bool Em caso de sucesso, retorna o resource da imagem. Caso contrário, false
*/
private function criarImagem( $caminho, $formato ) {
if( $formato === IMAGETYPE_JPEG ) {
$original = imagecreatefromjpeg( $caminho );
} elseif( $formato === IMAGETYPE_PNG ) {
$original = imagecreatefrompng( $caminho );
} elseif( $formato === IMAGETYPE_GIF ) {
$original = imagecreatefromgif( $caminho );
}
return $original;
}
/**
* Método que carrega ou mostra uma imagem
*
* @param resource $imagem Resource da imagem
*/
private function carregarOUmostrar( $imagem ) {
if( $this->imagemOriginal['formato'] === IMAGETYPE_JPEG ) {
imagejpeg( $imagem, $this->getDestino(), $this->qualidade );
} elseif ( $this->imagemOriginal['formato'] === IMAGETYPE_PNG ) {
imagepng( $imagem, $this->getDestino(), round( $this->qualidade * 9 / 100 ) );
} elseif ( $this->imagemOriginal['formato'] === IMAGETYPE_GIF ) {
imagegif( $imagem, $this->getDestino() );
}
}
/**
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge();
* This is a function like imagecopymerge but it handle alpha channel well!!!
*
* A fix to get a function like imagecopymerge WITH ALPHA SUPPORT
* Main script by aiden dot mail at freemail dot hu
* Transformed to imagecopymerge_alpha() by rodrigo dot polo at gmail dot com
*
* // Adicionei um pouco de código, de modo a que seja possível posicionar
* // a imagem da esquerda para a direita e de baixo para cima. Para isso,
* // basta utilizar medidas negativas
*/
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x = 0, $src_y = 0, $src_w = 0, $src_h = 0, $pct = 100){
if(!isset($pct)){
return false;
}
$pct /= 100;
// Get image width and height
$w = imagesx( $src_im );
$h = imagesy( $src_im );
// Posicionar imagem da esquerda para a direita e de baixo para cima
if( $dst_x < 0 ) {
$dst_x = imagesx($dst_im) - $w - abs($dst_x) + 1;
}
if( $dst_y < 0 ) {
$dst_y = imagesy($dst_im) - $h - abs($dst_y) + 1;
}
// Turn alpha blending off
imagealphablending( $src_im, false );
// Find the most opaque pixel in the image (the one with the smallest alpha value)
$minalpha = 127;
for( $x = 0; $x < $w; $x++ )
for( $y = 0; $y < $h; $y++ ){
$alpha = ( imagecolorat( $src_im, $x, $y ) >> 24 ) & 0xFF;
if( $alpha < $minalpha ){
$minalpha = $alpha;
}
}
//loop through image pixels and modify alpha for each
for( $x = 0; $x < $w; $x++ ){
for( $y = 0; $y < $h; $y++ ){
//get current alpha value (represents the TANSPARENCY!)
$colorxy = imagecolorat( $src_im, $x, $y );
$alpha = ( $colorxy >> 24 ) & 0xFF;
//calculate new alpha
if( $minalpha !== 127 ){
$alpha = 127 + 127 * $pct * ( $alpha - 127 ) / ( 127 - $minalpha );
} else {
$alpha += 127 * $pct;
}
//get the color index with new alpha
$alphacolorxy = imagecolorallocatealpha( $src_im, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha );
//set pixel with the new color + opacity
if( !imagesetpixel( $src_im, $x, $y, $alphacolorxy ) ){
return false;
}
}
}
// The image copy
imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $w, $h);
}
/**
* Método que cria a imagem. Quando definido o modo de corte, a imagem será
* cortada de modo a que fique proporcional.
*
* @param string $corte Modo de corte (horizontal (h) / vertical (v) / automático (a))
*/
public function criar( $corte = null ) {
if( $erros = $this->getErros() ) {
if( $this->mostrarErros ) {
echo $erros;
}
return false;
}
$dst_img = imagecreatetruecolor( $this->imagemNova['largura'],
$this->imagemNova['altura'] );
$src_img = $this->criarImagem( $this->imagemOriginal['caminho'],
$this->imagemOriginal['formato'] );
$src_w = $this->imagemOriginal['largura'];
$src_h = $this->imagemOriginal['altura'];
$dst_x = $dst_y = $src_x = $src_y = $dst_w = $dst_h = 0;
$racio_original = $this->imagemOriginal['largura'] / $this->imagemOriginal['altura'];
$racio_novo = $this->imagemNova['largura'] / $this->imagemNova['altura'];
if( $corte === 'h' || ( $corte === 'a' && $racio_novo > $racio_original ) ) {
$racio = $this->imagemNova['altura'] / $this->imagemOriginal['altura'];
$dst_h = $this->imagemNova['altura'];
$dst_w = $this->imagemOriginal['largura'] * $racio;
$dst_x = ( $this->imagemNova['largura'] - $dst_w ) / 2;
} elseif( $corte === 'v' || ( $corte === 'a' && $racio_novo < $racio_original ) ) {
$racio = $this->imagemNova['largura'] / $this->imagemOriginal['largura'];
$dst_w = $this->imagemNova['largura'];
$dst_h = $this->imagemOriginal['altura'] * $racio;
$dst_y = ($this->imagemNova['altura'] - $dst_h) / 2;
} else {
$dst_w = $this->imagemNova['largura'];
$dst_h = $this->imagemNova['altura'];
}
imagecopyresampled( $dst_img, $src_img , $dst_x, $dst_y, $src_x,
$src_y,$dst_w, $dst_h, $src_w, $src_h );
if( $this->getColocarMarcaDagua() ) {
$src_im = $this->criarImagem( $this->marcaDagua['src'], IMAGETYPE_PNG );
$this->imagecopymerge_alpha( $dst_img, $src_im,
$this->marcaDagua['posx'],
$this->marcaDagua['posy'] );
imagedestroy( $src_im );
}
$this->carregarOUmostrar( $dst_img );
imagedestroy( $dst_img );
imagedestroy( $src_img );
return true;
}
}
?>
Exemplo 1
Fazer upload de uma imagem
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->criar();
?>
<html>
<head>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="imagem" />
<input type="submit" name="enviar" value="Enviar" />
</form>
</body>
</html>
Exemplo 2
Redimensionar uma imagem para a largura indicada e carregá-la
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->redimensionar( 400 );
$img->criar();
?>
Exemplo 3
Redimensionar uma imagem, criar uma miniatura e carregá-las
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->redimensionar( 400 );
$img->criar();
$img->redimensionar( 100 );
$img->setDestino( '', true );
$img->criar();
?>
Exemplo 4
**Redimensionar uma imagem utilizando o corte automático (redimensiona-a proporcionalmente) e carregá-la **
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->redimensionar( 400, 200 );
$img->criar( 'a' );
?>
Exemplo 5
**Redimensionar uma imagem, adicionar uma marca d'água e carregá-la **
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->redimensionar( 400, 200 );
$img->setColocarMarcaDagua(true);
$img->criar( 'a' );
?>
Exemplo 6
Carregar uma imagem, redimensioná-la e adicionar uma marca d'água (alinhando-a da esquerda para a direita e de baixo para cima)
<?php
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( $_FILES['imagem'] );
$img->redimensionar( 400, 200 );
$img->setColocarMarcaDagua(true);
$img->setMarcaDagua( array('posx' => -1, 'posy' => -1) );
$img->criar( 'a' );
?>
Exemplo 7
Criar uma imagem para mostrar, mas não carregar Nota: o ficheiro teste.php tem de estar como UTF-8 sem BOM ou AINSI.
<html>
<head>
</head>
<body>
<img src="teste.php" />
</body>
</html>
<?php
header("Content-type: image/jpeg");
require_once'imagem.class.php';
$img = new Imagem();
$img->setImagem( 'http://url_da_imagem.extensao' );
$img->redimensionar( 400, 200 );
$img->setColocarMarcaDagua( true );
$img->criar('a');
?>