tamaño subir redimensionar imagenes imagen comprimir cambiar antes php image gd jpeg

subir - Eficiente cambio de tamaño de imagen JPEG en PHP



comprimir imagenes php (9)

¿Cuál es la forma más eficiente de cambiar el tamaño de imágenes grandes en PHP?

Actualmente estoy usando la función de imagen de GD que se tomaron imágenes para tomar imágenes de alta resolución, y cambiar su tamaño de forma limpia para un tamaño de visualización web (aproximadamente 700 píxeles de ancho por 700 píxeles de alto).

Esto funciona muy bien en fotos pequeñas (menos de 2 MB) y toda la operación de cambio de tamaño lleva menos de un segundo en el servidor. Sin embargo, el sitio eventualmente dará servicio a los fotógrafos que puedan estar cargando imágenes de hasta 10 MB de tamaño (o imágenes de hasta 5000x4000 píxeles de tamaño).

Hacer este tipo de operación de cambio de tamaño con imágenes grandes tiende a aumentar el uso de la memoria por un margen muy grande (las imágenes más grandes pueden aumentar el uso de memoria para el script más allá de 80 MB). ¿Hay alguna forma de hacer que esta operación de cambio de tamaño sea más eficiente? ¿Debo usar una biblioteca de imágenes alternativa como ImageMagick ?

En este momento, el código de cambio de tamaño se ve algo como esto

function makeThumbnail($sourcefile, $endfile, $thumbwidth, $thumbheight, $quality) { // Takes the sourcefile (path/to/image.jpg) and makes a thumbnail from it // and places it at endfile (path/to/thumb.jpg). // Load image and get image size. $img = imagecreatefromjpeg($sourcefile); $width = imagesx( $img ); $height = imagesy( $img ); if ($width > $height) { $newwidth = $thumbwidth; $divisor = $width / $thumbwidth; $newheight = floor( $height / $divisor); } else { $newheight = $thumbheight; $divisor = $height / $thumbheight; $newwidth = floor( $width / $divisor ); } // Create a new temporary image. $tmpimg = imagecreatetruecolor( $newwidth, $newheight ); // Copy and resize old image into new image. imagecopyresampled( $tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height ); // Save thumbnail into a file. imagejpeg( $tmpimg, $endfile, $quality); // release the memory imagedestroy($tmpimg); imagedestroy($img);


Aquí hay un fragmento de los documentos de php.net que he usado en un proyecto y que funciona bien:

<? function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) { // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled. // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled". // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting. // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain. // // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero. // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect. // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized. // 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3. // 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster. // 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled. if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; } if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) { $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1); imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h); imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality); imagedestroy ($temp); } else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); return true; } ?>

http://us.php.net/manual/en/function.imagecopyresampled.php#77679


He escuchado grandes cosas acerca de la biblioteca de Imagick, desafortunadamente no pude instalarlo en mi computadora de trabajo ni en mi casa (y créanme, pasé horas y horas en todo tipo de foros).

Afterwords, he decidido probar esta clase de PHP:

http://www.verot.net/php_class_upload.htm

Es genial y puedo cambiar el tamaño de todo tipo de imágenes (también puedo convertirlas a JPG).


ImageMagick tiene múltiples subprocesos, por lo que parece ser más rápido, pero en realidad usa muchos más recursos que GD. Si ejecutó varios scripts PHP en paralelo, todos usaron GD, entonces vencieron ImageMagick en velocidad para operaciones simples. ExactImage es menos potente que ImageMagick pero mucho más rápido, aunque no está disponible a través de PHP, tendrá que instalarlo en el servidor y ejecutarlo a través de exec .


La gente dice que ImageMagick es mucho más rápido. En el mejor de los casos, simplemente compare ambas bibliotecas y mida eso.

  1. Prepare 1000 imágenes típicas.
  2. Escriba dos scripts: uno para GD, y otro para ImageMagick.
  3. Ejecuta a ambos un par de veces.
  4. Compare los resultados (tiempo total de ejecución, uso de CPU y E / S, calidad de imagen del resultado).

Algo que los mejores todos los demás, no podría ser lo mejor para ti.

Además, en mi opinión, ImageMagick tiene una interfaz API mucho mejor.



Para imágenes más grandes, utilice libjpeg para cambiar el tamaño de la carga de la imagen en ImageMagick y, por lo tanto, reducir significativamente el uso de memoria y mejorar el rendimiento, no es posible con GD.

$im = new Imagick(); try { $im->pingImage($file_name); } catch (ImagickException $e) { throw new Exception(_(''Invalid or corrupted image file, please try uploading another image.'')); } $width = $im->getImageWidth(); $height = $im->getImageHeight(); if ($width > $config[''width_threshold''] || $height > $config[''height_threshold'']) { try { /* send thumbnail parameters to Imagick so that libjpeg can resize images * as they are loaded instead of consuming additional resources to pass back * to PHP. */ $fitbyWidth = ($config[''width_threshold''] / $width) > ($config[''height_threshold''] / $height); $aspectRatio = $height / $width; if ($fitbyWidth) { $im->setSize($config[''width_threshold''], abs($width * $aspectRatio)); } else { $im->setSize(abs($height / $aspectRatio), $config[''height_threshold'']); } $im->readImage($file_name); /* Imagick::thumbnailImage(fit = true) has a bug that it does fit both dimensions */ // $im->thumbnailImage($config[''width_threshold''], $config[''height_threshold''], true); // workaround: if ($fitbyWidth) { $im->thumbnailImage($config[''width_threshold''], 0, false); } else { $im->thumbnailImage(0, $config[''height_threshold''], false); } $im->setImageFileName($thumbnail_name); $im->writeImage(); } catch (ImagickException $e) { header(''HTTP/1.1 500 Internal Server Error''); throw new Exception(_(''An error occured reszing the image.'')); } } /* cleanup Imagick */ $im->destroy();


Por tu comentario, parece que eres nuevo en GD, compartiré algo de mi experiencia, tal vez esto esté un poco fuera de tema, pero creo que será útil para alguien nuevo en GD como tú:

Paso 1, valida el archivo. Use la siguiente función para verificar si el $_FILES[''image''][''tmp_name''] es válido:

function getContentsFromImage($image) { if (@is_file($image) == true) { return file_get_contents($image); } else { throw new /Exception(''Invalid image''); } } $contents = getContentsFromImage($_FILES[''image''][''tmp_name'']);

Paso 2, obtenga el formato de archivo Pruebe la siguiente función con la extensión finfo para verificar el formato del archivo (contenido). $_FILES["image"]["type"] por qué no utilizas $_FILES["image"]["type"] para verificar el formato del archivo? Como SOLAMENTE verifica la extensión de archivo no el contenido del archivo, si alguien renombra un archivo originalmente llamado world.png a world.jpg , $_FILES["image"]["type"] devolverá jpeg no png, entonces $_FILES["image"]["type"] puede devolver resultados incorrectos.

function getFormatFromContents($contents) { $finfo = new /finfo(); $mimetype = $finfo->buffer($contents, FILEINFO_MIME_TYPE); switch ($mimetype) { case ''image/jpeg'': return ''jpeg''; break; case ''image/png'': return ''png''; break; case ''image/gif'': return ''gif''; break; default: throw new /Exception(''Unknown or unsupported image format''); } } $format = getFormatFromContents($contents);

Paso 3, Obtener recursos de GD Obtener recursos de GD de los contenidos que tenemos antes:

function getGDResourceFromContents($contents) { $resource = @imagecreatefromstring($contents); if ($resource == false) { throw new /Exception(''Cannot process image''); } return $resource; } $resource = getGDResourceFromContents($contents);

Paso 4, obtener la dimensión de la imagen Ahora puede obtener la dimensión de la imagen con el siguiente código simple:

$width = imagesx($resource); $height = imagesy($resource);

Ahora, veamos qué variable obtuvimos de la imagen original:

$contents, $format, $resource, $width, $height OK, lets move on

Paso 5, calcule los argumentos de imagen redimensionados Este paso está relacionado con su pregunta, el propósito de la siguiente función es obtener los argumentos de tamaño para la función GD imagecopyresampled() , el código es un poco largo, pero funciona muy bien, incluso tiene tres opciones: estirar, encoger y rellenar.

stretch : la dimensión de la imagen de salida es la misma que la nueva dimensión que configura. No mantendrá la relación alto / ancho.

contracción : la dimensión de la imagen de salida no excederá la nueva dimensión que proporcione, y mantendrá la relación altura / ancho de la imagen.

fill : la dimensión de la imagen de salida será la misma que la nueva dimensión que proporciones, recortará y redimensionará la imagen si es necesario, y mantendrá la relación altura / ancho de la imagen. Esta opción es lo que necesitas en tu pregunta.

function getResizeArgs($width, $height, $newwidth, $newheight, $option) { if ($option === ''stretch'') { if ($width === $newwidth && $height === $newheight) { return false; } $dst_w = $newwidth; $dst_h = $newheight; $src_w = $width; $src_h = $height; $src_x = 0; $src_y = 0; } else if ($option === ''shrink'') { if ($width <= $newwidth && $height <= $newheight) { return false; } else if ($width / $height >= $newwidth / $newheight) { $dst_w = $newwidth; $dst_h = (int) round(($newwidth * $height) / $width); } else { $dst_w = (int) round(($newheight * $width) / $height); $dst_h = $newheight; } $src_x = 0; $src_y = 0; $src_w = $width; $src_h = $height; } else if ($option === ''fill'') { if ($width === $newwidth && $height === $newheight) { return false; } if ($width / $height >= $newwidth / $newheight) { $src_w = (int) round(($newwidth * $height) / $newheight); $src_h = $height; $src_x = (int) round(($width - $src_w) / 2); $src_y = 0; } else { $src_w = $width; $src_h = (int) round(($width * $newheight) / $newwidth); $src_x = 0; $src_y = (int) round(($height - $src_h) / 2); } $dst_w = $newwidth; $dst_h = $newheight; } if ($src_w < 1 || $src_h < 1) { throw new /Exception(''Image width or height is too small''); } return array( ''dst_x'' => 0, ''dst_y'' => 0, ''src_x'' => $src_x, ''src_y'' => $src_y, ''dst_w'' => $dst_w, ''dst_h'' => $dst_h, ''src_w'' => $src_w, ''src_h'' => $src_h ); } $args = getResizeArgs($width, $height, 150, 170, ''fill'');

Paso 6, redimensionar la imagen Use $args , $width , $height , $format y $ resource que obtuvimos de arriba en la siguiente función y obtengamos el nuevo recurso de la imagen redimensionada:

function runResize($width, $height, $format, $resource, $args) { if ($args === false) { return; //if $args equal to false, this means no resize occurs; } $newimage = imagecreatetruecolor($args[''dst_w''], $args[''dst_h'']); if ($format === ''png'') { imagealphablending($newimage, false); imagesavealpha($newimage, true); $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127); imagefill($newimage, 0, 0, $transparentindex); } else if ($format === ''gif'') { $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127); imagefill($newimage, 0, 0, $transparentindex); imagecolortransparent($newimage, $transparentindex); } imagecopyresampled($newimage, $resource, $args[''dst_x''], $args[''dst_y''], $args[''src_x''], $args[''src_y''], $args[''dst_w''], $args[''dst_h''], $args[''src_w''], $args[''src_h'']); imagedestroy($resource); return $newimage; } $newresource = runResize($width, $height, $format, $resource, $args);

Paso 7, obtenga nuevos contenidos , use la siguiente función para obtener contenidos del nuevo recurso de GD:

function getContentsFromGDResource($resource, $format) { ob_start(); switch ($format) { case ''gif'': imagegif($resource); break; case ''jpeg'': imagejpeg($resource, NULL, 100); break; case ''png'': imagepng($resource, NULL, 9); } $contents = ob_get_contents(); ob_end_clean(); return $contents; } $newcontents = getContentsFromGDResource($newresource, $format);

Paso 8 obtener la extensión , use la siguiente función para obtener la extensión del formato de la imagen (tenga en cuenta que el formato de la imagen no es igual a la extensión de la imagen):

function getExtensionFromFormat($format) { switch ($format) { case ''gif'': return ''gif''; break; case ''jpeg'': return ''jpg''; break; case ''png'': return ''png''; } } $extension = getExtensionFromFormat($format);

Paso 9, guarde la imagen Si tenemos un usuario llamado mike, puede hacer lo siguiente, se guardará en la misma carpeta que este script php:

$user_name = ''mike''; $filename = $user_name . ''.'' . $extension; file_put_contents($filename, $newcontents);

Paso 10 destruir el recurso ¡No olvides destruir el recurso GD!

imagedestroy($newresource);

o puede escribir todo su código en una clase, y simplemente use lo siguiente:

public function __destruct() { @imagedestroy($this->resource); }

CONSEJOS

Recomiendo no convertir el formato de archivo que carga el usuario, encontrará muchos problemas.


Sugiero que trabajes algo en esta línea:

  1. Realice un getimagesize () en el archivo cargado para verificar el tipo y el tamaño de la imagen
  2. Guarde cualquier imagen JPEG cargada de menos de 700x700px en la carpeta de destino "tal como está"
  3. Utilice la biblioteca de GD para imágenes de tamaño mediano (consulte este artículo para ver ejemplos de código: Cambiar el tamaño de las imágenes usando PHP y la biblioteca de GD )
  4. Use ImageMagick para imágenes grandes. Puede usar ImageMagick en segundo plano si lo prefiere.

Para utilizar ImageMagick en segundo plano, mueva los archivos cargados a una carpeta temporal y programe un trabajo CRON que "convierta" s todos los archivos a jpeg y los cambie según corresponda. Ver la sintaxis del comando en: imagemagick-command line processing

Puede solicitar al usuario que el archivo se cargue y programe para su procesamiento. El trabajo CRON podría programarse para ejecutarse diariamente en un intervalo específico. La imagen de origen podría eliminarse después del procesamiento para garantizar que una imagen no se procese dos veces.


phpThumb usa ImageMagick siempre que sea posible para la velocidad (volviendo a GD si es necesario) y parece almacenar en caché bastante bien para reducir la carga en el servidor. Es bastante liviano para probar (para cambiar el tamaño de una imagen, simplemente llame a phpThumb.php con una consulta GET que incluya el nombre del archivo gráfico y las dimensiones de salida), por lo que puede intentarlo para ver si satisface sus necesidades.