PHP: Как със сървърен софтуер да растеризираме векторни графики
Posted by: Nick in ПрограмиранеНаскоро ми се наложи да мисля начин как в уебстраница при upload на векторна графика автоматично да й се създава растерен вариант (PNG). На пръв поглед има една камара конзолен софтуер за целта, но при всеки имаше проблеми.
Едното изискване при растеризирането е когато оригиналният вектор е с прозрачен фон, и PNG-то да е прозрачно. Другото изискване е да се спази пропорцията на изображението. Та ей тези две неща все бяха проблемни.
Първо мъчих с convert (ImageMagick) - според документацията му трябва безпроблемно да се справя с растеризиране на EPS и AI формати (посредством ghostscript), което за съжаление не беше така - не се запазваше прозрачността. След дълго главоблъскане установих, че всъщност convert подава грешен параметър "sDEVICE" към ghostscript ("pnmraw" вместо "pngalpha"). Очевидно решението беше да работя директно с ghostscript без да минавам през convert. Това пък ме затрудняваше, щото нямаше как да задам коректно размерите в пиксели, в които искам растерния файл. Наложи се всеки път чрез identify (ImageMagick) да взимам резолюцията на изображението, за да изчисля пропорцията. С това проблемът с EPS форматът беше решен (AI така и не успях да подкарам, и аз не знам защо).
Паралелно с това, исках чрез inkscape да правя същото със SVG и SVGZ файлове. За съжаление се оказа, че наистина трябва да правя същото (проблемът със запазването на пропорцията). Тук обаче identify не можеше да помогне с намирането на резолюцията и трябваше сам да прочитам първите еди-колко-си реда от файла, за да намеря пропорцията.
И тъй като наистина ми беше много зор докато стигна до някакъв задоволителен работещ вариант, мисля да го споделя...
define( 'GHOSTSCRIPT', '/usr/local/bin/gs' ); define( 'INKSCAPE', '/usr/bin/inkscape' ); define( 'IDENTIFY', '/usr/local/imagemagick/bin/identify' );
function rasterize_eps($source, $destination_png, $w=FALSE, $h=FALSE)
{
if( FALSE == file_exists($source) ) {
return FALSE;
}
$w = intval( $w );
$h = intval( $h );
$in_cmd = '';
if( $w>0 && $h>0 ) {
$file_w = FALSE;
$file_h = FALSE;
$res_x = FALSE;
$res_y = FALSE;
exec( IDENTIFY.' -verbose '.$source.' | grep "x" ', $output );
foreach( $output as $line ) {
if( preg_match( '/Geometry:s([0-9]+)x([0-9]+)(+|-)/', $line, $matches ) ) {
$file_w = intval( $matches[1] );
$file_h = intval( $matches[2] );
}
if( preg_match( '/Resolution:s([0-9]+)x([0-9]+)/', $line, $matches ) ) {
$res_x = intval( $matches[1] );
$res_y = intval( $matches[2] );
}
if( FALSE!=$file_w && FALSE!=$file_h && FALSE!=$res_x && FALSE!=$res_y ) {
break;
}
}
if( intval($file_w)>0 && intval($file_h)>0 && intval($res_x)>0 && intval($res_y)>0 && $res_x==$res_y ) {
if( $file_w/$file_h > $w/$h ) {
$res_x *= $w / $file_w;
$res_y = $res_x;
}
else {
$res_y *= $h / $file_h;
$res_x = $res_y;
}
$res_x = round( $res_x, 5 );
$res_y = round( $res_y, 5 );
$in_cmd = '-r'.$res_x.'x'.$res_y;
}
}
$command = GHOSTSCRIPT.' -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha '.$in_cmd.' -dEPSCrop -sOutputFile='.$destination_png.' '.$source;
exec( $command );
if( FALSE == file_exists($destination_png) ) {
return FALSE;
}
chmod($destination_png, 0777);
return TRUE;
}
function rasterize_svg($source, $destination_png, $w=FALSE, $h=FALSE)
{
if( FALSE == file_exists($source) ) {
return FALSE;
}
$w = intval( $w );
$h = intval( $h );
$in_cmd = '--export-width='.$w;
if( $w>0 && $h>0 && preg_match('/.svg$/i', $source) ) {
$file_w = FALSE;
$file_h = FALSE;
$handle = fopen($source, 'r');
$i = 0;
$j = 6;
while( FALSE==feof($handle) && $i++<$j ) {
$line = strtolower( fgets( $handle ) );
if( FALSE !== strpos( $line, 'viewbox' ) ) {
$line = str_replace( array('"', '''), '', $line );
preg_match( '/viewbox(s)?=(s)?('|\")?([0-9.,]+)s([0-9.,]+)s([0-9.,]+)s([0-9.,]+)('|\")?/', $line, $matches );
$file_w = floatval( $matches[6] );
$file_h = floatval( $matches[7] );
break;
}
$line = trim($line);
if( empty($line) || preg_match('/^<!--.*-->$/', $line) ) {
$j ++;
}
}
fclose($handle);
if( intval($file_w)>0 && intval($file_h)>0 ) {
$in_cmd = $file_w/$file_h>$w/$h ? ( '--export-width='.$w ) : ( '--export-height='.$h );
}
}
elseif( $w>0 && $h>0 && preg_match('/.svgz$/i', $source) ) {
$file_w = FALSE;
$file_h = FALSE;
$handle = gzopen($source, 'r');
$i = 0;
$j = 6;
while( FALSE==gzeof($handle) && $i++<$j ) {
$line = strtolower( gzgets( $handle ) );
if( FALSE !== strpos( $line, 'viewbox' ) ) {
$line = str_replace( array('"', '''), '', $line );
preg_match( '/viewbox(s)?=(s)?('|\")?([0-9.,]+)s([0-9.,]+)s([0-9.,]+)s([0-9.,]+)('|\")?/', $line, $matches );
$file_w = floatval( $matches[6] );
$file_h = floatval( $matches[7] );
break;
}
$line = trim($line);
if( empty($line) || preg_match('/^<!--.*-->$/', $line) ) {
$j ++;
}
}
gzclose($handle);
if( intval($file_w)>0 && intval($file_h)>0 ) {
$in_cmd = $file_w/$file_h>$w/$h ? ( '--export-width='.$w ) : ( '--export-height='.$h );
}
}
$command = INKSCAPE.' --without-gui --file='.$source.' --export-area-drawing '.$in_cmd.' --export-png='.$destination_png;
exec( $command );
if( FALSE == file_exists($destination_png) ) {
return FALSE;
}
chmod($destination_png, 0777);
return TRUE;
}
Tags: convert, eps, ghostscript, imagemagick, inkscape, php, png, raster, svg, vector



Entries (RSS)