Screencaster Transmitindo conhecimento




Criando mosaico de imagens com PHP + GD

Depois que lançamos o Gallery, recebi diversas questões de pessoas interessadas em saber como o sistema funcionava “por baixo do capô”, como manipulava as imagens enviadas, etc.

O principal que faz com que o sistema funcione é a biblioteca GD, uma biblioteca que serve para manipular imagens, e que está presente na maioria das instalações de PHP atualmente.

Para ajudar aqueles que têm vontade de usar GD, resolvi começar a postar aqui alguns códigos de coisas bacanas que usam a biblioteca. Hoje vou deixar aqui para vocês um código que serve para criar um mosaico de imagens, como este.

Basicamente é um script onde você define uma pasta que contém as imagens a serem utilizadas para gerar o mosaico, e então o script pega as imagens, redimensiona, sorteia suas posições dentro do mosaico, e gera numa pasta de saída uma imagem png com seu mosaico.

Todas as características do mosaico podem ser alteradas modificando algumas variáveis do script.

Segue então o código:

<?php
 
function imagecreatefromwhatever($image)
{
	$info = pathinfo($image);
	$extension = strtolower($info['extension']);
	switch($extension) {
		case "jpg":
			return imagecreatefromjpeg($image);
		break;
		case "jpeg":
			return imagecreatefromjpeg($image);
		break;
		case "png":
			return imagecreatefrompng($image);
		break;
		case "gif":
			return imagecreatefromgif($image);
		break;
		default:
			return imagecreatefromjpeg($image);
	}
}
 
//diretório de onde pegar as imagens
$input_dir = "imagens/";
 
//diretório onde salvar o mosaico
$output_dir = "mosaicos/";
 
//tamanho aproximado do mosaico final
$mosaic_size = array(1280,800);
$mosaic_proportion = $mosaic_size[0]/$mosaic_size[1];
 
//cor de fundo do mosaico
$mosaic_background = array(
	"red" => "255",
	"green" => "255",
	"blue" => "255"
);
 
ob_start();
 
$d = dir($input_dir);
 
$extensions = array("jpg","jpeg","png","psd","gif");
 
while(false !== ($entry = $d->read())) {
	if($entry != "." && $entry != "..") {
		$info = pathinfo($entry);
		$ext = strtolower($info['extension']);
		$name = $info['filename'];
		if(in_array($ext,$extensions) && $striped == 0) {
			$photos[] = $entry;
		}
	}
}
 
//quanto maior o número de fotos, mais reduzidas elas ficarão no mosaico
$number_of_photos = count($photos);
 
$reduce_factor = 0.5;
 
//o trecho abaixo calcula as posições possíveis das imagens dentro do mosaico
$actual_x = 0;
$actual_y = 0;
$possible_positions[] = array("x" => 0, "y" => 0);
 
foreach($photos as $thephoto):
	list($image_width, $image_height, $image_type, $image_attr) = getimagesize($input_dir.$thephoto);
	$image_res_width = round($image_width*$reduce_factor);
	$image_res_height = round($image_height*$reduce_factor);
 
	$actual_x = $actual_x + $image_res_width;
	if(($actual_x+$image_res_width) > $mosaic_size[0]) {
		$actual_y = $actual_y + $image_res_height;
		$actual_x = 0;
	}
 
	$possible_positions[] = array("x" => $actual_x, "y" => $actual_y);
endforeach;
 
//definir posições máximas das imagens no mosaico para criar imagem true color no tamanho final
arsort($possible_positions);
foreach($possible_positions as $position):
	$final_positions[] = $position;
endforeach;
 
$max_image_position = $final_positions[0];
 
//cria imagem true color que será o mosaico em si, já com as dimensões calculadas acima
$mosaic = imagecreatetruecolor($max_image_position["x"], $mosaic_size[1]);
//preenche a imagem com uma cor de fundo
$background_alloc = imagecolorallocate($mosaic,$mosaic_background["red"],$mosaic_background["green"],$mosaic_background["blue"]);
imagefill($mosaic,0,0,$background_alloc);
 
//sorteia as posições dentro do mosaico para que nunca fique igual
shuffle($possible_positions);
 
$i=0;
 
foreach($photos as $thephoto):
 
	list($image_width, $image_height, $image_type, $image_attr) = getimagesize($input_dir.$thephoto);
 
	$image_res_width = round($image_width*$reduce_factor);
	$image_res_height = round($image_height*$reduce_factor);
 
	$handler = imagecreatefromwhatever($input_dir.$thephoto);
 
	$actual_x = $possible_positions[$i]["x"];
	$actual_y = $possible_positions[$i]["y"];
 
	imagecopyresampled($mosaic , $handler, $actual_x, $actual_y, 0, 0, $image_res_width, $image_res_height, $image_width, $image_height);
 
	$i++;
 
endforeach;
 
//salva a imagem final do mosaico
	imagepng($mosaic);
	$output_buffer = ob_get_contents();
	$output_filename = substr(uniqid(sha1(md5(base64_encode(rand(0,100)*time()+microtime()*1000)))),0,10).".png";
	$output_handler = fopen($output_dir.$output_filename,"a+");
	fwrite($output_handler,$output_buffer);
	fclose($output_handler);
ob_clean();
 
?>

Aqui vai uma lista de algumas variáveis que você deve/pode alterar:

input_dir: A pasta de onde pegar as imagens (não se esqueça da barra no final “/”)
output_dir: A pasta onde salvar o mosaico
mosaic_size: Width,height do mosaico. Aqui vale uma observação: a largura do mosaico vai variar dependendo de quantas imagens você tiver para formá-lo e também de qual o tamanho delas. A altura, no entanto, será fixa.
reduce_factor: O padrão é 0.5, o que significa que as imagens serão reduzidas a 50% do seu tamanho original

Basicamente é isso, o script faz um bocado de cálculos e exige um bocado de processamento no servidor, então é bom tomar cuidado quando o utiliza. Está longe de ser perfeito, você pode por exemplo usar fórmulas matemáticas para calcular a área total do mosaico e redimensionar as figuras para que todas caibam dentro desta área direitinho, que tal?

Fica aí este script para que você estude um pouco sobre GD, e tome gosto pela coisa. Na documentação no próprio site do PHP tem bastante informação a respeito. Pretendo postar mais sobre o assunto futuramente.

Até mais!

Eu consigo produzir conteúdo gratuito para o blog graças à ajuda do pessoal que compra as aulas pagas. Se você puder, compre uma das aulas pro e ajude a manter este blog no ar.


3 pessoas comentaram

  1. Tutorial City disse:

    No começo da função poderia usar:
    ——————–
    case:”jpg”
    case:”jpeg”
    return imagecreatefromjpeg($image);
    ——————–
    visto que os dois direcionam pro mesmo resultado.

    Na hora de definir o nome do arquivo percebi um pouco de fanatismo, me parece um pouco exagerado… rs

    Abraços

  2. Rui disse:

    Obrigado pela partilha.

    Para usar a gd as imagens têm de estar no meu servidor ?
    E se as minhas imagens não estiverem no meu servidor mas eu tiver uma array com o url de cada uma.

    Seria possivél fazer esta classe funcionar? Com o php eu consigo fazer um echo de todas elas no meu html … tenho centenas de thumbs 50x50px mas gostaria q o meu visitante pudesse descarregar um mosaico com todas elas.

    • inside disse:

      Rui, dependendo do servidor é possível utilizar imagens externas com o gd, acho que depende da configuração do PHP permitir o carregamento de arquivos externos. Se o seu servidor não permite este processo será necessário baixar a imagem para seu servidor para depois montar o mosaico.

Agora é a sua vez: