Solved

How do you process a WMF image using PHP's Imagick with a transparent background and at a specified resolution?

Posted on 2011-03-01
8
1,512 Views
Last Modified: 2013-11-19
I have a WMF file that I need to convert to a PNG using the Imagick image processing class in PHP.  I have successfully installed both ImageMagick and the WMF component, and now it's just a matter of figuring out which methods to call.

The following code converts the WMF to a PNG with a white background at its original resolution and prints it to the browser:
<?php 
try{ 
    $filename = 'foo.wmf'; 
    $im = new Imagick(); 
    $h = fopen($filename, 'rb'); 
    $im->readImageFile($h); 

    $im->setImageFormat('png');
    header("Content-Type: image/png"); 
    print $im->getImageBlob(); 
}catch(Exception $e){ 
    echo $e->getMessage(); 
} 
?>

Open in new window

When I call "$im->setResolution" before the file is read, I can change the size of the output image before the vector is rasterized:
// …
$im = new Imagick(); 
$im->setResolution(150, 150);
$h = fopen($filename, 'rb'); 
$im->readImageFile($h); 
$im->setImageFormat('png');
// …

Open in new window

However, the resulting file doesn't have the resolution specified in the "$im->setResolution" call.  The image gets proportionally bigger as I increase the x-res and y-res arguments.  There's probably a reason for this, but I'm not an image guru.

I am also trying to figure out how to make the resulting PNG file have a transparent background.  When I perform the same code as above but with an EPS file instead of a WMF file, I get a transparent background; however, when it's performed with a WMF file, I get a while background in my PNG.

Any advice would be appreciated!
0
Comment
Question by:sffc
  • 4
  • 4
8 Comments
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
greetings sffc, , , I am posting here, because no one else has, unfortunately None of the PHP servers I now use has ImageMagick installed, so I can not offer you code examples.

First, I read this question, And was really baffled by someone still using the (to me) extremely out of date WMF and EPS files for vector images. As far as I can tell the SVG (Scalable Vector Graphics) is what is being used these days, , for several many years now. Any reason you still use the old WMF files?

Also, since PHP is a Web Server language, I can not understand why you have non web images WMF, as firefox and google browsers can not display these, I guess that's why you are changing them to PNG.

Next, There is a BIG difference between Vector digital images (WMF, SVG) and Raster digital images (JPG, PNG, BMP), especially in using them for resizing and defining a transparent background. . So your approach for resizing seems off to me.

I believe the call to  $im->setResolution(150, 150); sets the Printing resolution defined in the file header, and has nothing to do with the dimensions of an image, although for some reason  ImageMagick alters the image size in vector images.
I always avoid using anything to do with Printing resolution when using digital images, except to print them.

Digital images are a unchanging memory block on the computer, you can NOT alter them by changing some setting like Resolotion, or Width.
Vector Images do not have an inherent width or height, and do not have a width or height until they are "drawn" onto a raster output (monitor) or raster image.
To change the dimensions of a digital Image you have to create a new Image with the new width and height you need, and then copy (draw) the Old Image onto the new image, in vector images the drawing positions are changes for larger and smaller size raster images.
The  $im->setImageFormat('png');  does that, it copys the vector image to a new raster and then deletes the vector and replaces it with the new raster.
To have control of your PNG output, you should try and create a new image in ImageMagick with the size you need, and then copy (draw) the vector Image to the new image and then save the new image as a PNG file.

I hope some of my explanation will be helpful to you, if not then you'll have to wait for someone else to post here.



0
 
LVL 1

Accepted Solution

by:
sffc earned 0 total points
Comment Utility
Hi Slick812,

Thanks for your explanation.  It helped me understand what the code I wrote does :)

The ImageMagick documentation says that it will "rasterize [a vector] at the currently defined resolution or density," and the way to change the the output dimensions of a vector is to change the ppi resolution of the vector.  So, I wrote the following code that figure out exactly what ppi is required in order to produce the output dimensions I need:

// PHP code to proportionally scale a vector file to a desired width and then display it on
// a transparent background

$filename = 'foo.wmf'; // Path to vector file (SVG, EPS, PDF, WMF if libwmf is installed, etc.)
$desired_width = 200; // Desired width (variable)

function get_vector_scale_info($handle){
	$im = new Imagick(); // Create a dummy Imagick object
	$im->setResolution(100, 100); // Set a 100 ppi square resolution
	$im->readImageFile($handle);
	$width = $im->getImageWidth(); // Get the width and height of the resulting image
	$height = $im->getImageHeight();
	$ret = array(
		"width-mod" => 100/$width, // Make a proportion that can be used to generate a
			// vector-based raster image with a specified width or height
		"height-mod" => 100/$height
	);
	unset($im); // Unset the dummy Imagick object so that it can be removed from memory
	return $ret;
}

$im = new Imagick();
$h = fopen($filename, 'rb'); 

$info = get_vector_scale_info($h);
$ppi = $info['width-mod']*$desired_width; // Apply the proportion
$im->setResolution($ppi, $ppi);

$trans = new ImagickPixel();
$trans->setColorValue(imagick::COLOR_OPACITY, 1);
$im->setBackgroundColor($trans); // Make the background transparent

$im->readImageFile($h); 

$im->setImageFormat('png');
header("Content-Type: image/png"); 
print $im->getImageBlob();

Open in new window


Essentially, what it does is to draw the vector on an image with 100 ppi, calculate the width of the resulting image, and use this information to proportionally scale an image to a desired width or height.

This code also places the WMF on a transparent background.  The resolution and background color must both be defined before the vector image file is read in order to achieve the desired outcome.

Thanks again for your comment.  Before I close this question, is there a better way to achieve this goal that doesn't require loading the WMF image into the PHP memory twice?
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
I have done much with vector and raster images, I do not see why ImageMagick uses this method for handling vector images, I suppose it's mostly a rastor image program, so this is their fallback, , ,  but since it is not changeable that is not relevant here. Most all of the image editing programs I use, PhotoShop, Gimp, Paint ShopPro, other, use a default printing resolution of 72x72, if I remember correctly, but I do not thick this is a universal standard default, since many digital cameras set their default printing res to any wild and wacky amount.
BUT if all of your WMF images are coming from the same creation source, then they all will likely have the same print resolution. As I have said, most people do not ever read or deal with the print resoulution, except to print an image. The print resolution should not make any change to a digital image in raster image manipulations.

But for your problem, if you can get the ppi of your original vector image, maybe with something like -
$res = $im->getResolution();

then you should be able to derive a formula, using your math (or a slight variation) to input the desired dimensions and the current ppi resolution, and get the amounts for the new ppi settings , and then do your -
$im->setResolution($newResW, $newResH);

as a hint for you, it is rare, but for some older printers, the horizontal and vertical print resolutions are NOT equal to get a properly proportioned image printout.
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
Sorry, I needed to add for my last post - -
I looked at your last post code, and the suggestion above about getResolution,  is more about using your original code , not so much for the new code, , only the math formula.

if it does turn out that all of your WMF images have the same ppi, then you can just hard code the adjustment numbers, with out reading the wmf to get the new ppi numbers.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 1

Author Comment

by:sffc
Comment Utility
It seems that all of my files have the standard 72x72 ppi resolution, but regardless, I still need to load the image to find the pixel dimensions of the resulting image in order to make my ratio.

Changing the dimensions of the image after the vector is loaded results in raster-based scaling, indicating that Imagick rasterizes the image at the given resolution as soon as it loads.

And I think you may be correct in saying that ImageMagick's method of handling vectors is a "fallback"; they say this in their documentation:

IM is a 'raster image processor', and while it can read or write images stored in one of the vector formats it does so by converting the image to and from a internal raster image.

Consequently if you are trying to convert a image from a vector format, to another vector format, IM will essentially rasterize this image at the currently defined resolution or density which will hopefully (but unlikely) be suitable for the output device you intend to use it on.

In other words, any output from IM will never be a true vector format. While it can convert its internal raster format into a vector format file, the result is only a superficial vector image wrapper around an image in raster format. And unless the raster image is defined properly (at the right resolution) for the output device, the result will not be particularly good.
0
 
LVL 33

Assisted Solution

by:Slick812
Slick812 earned 200 total points
Comment Utility
sorry about the delay, I had problems getting into EE, server maintainance or something. . . .  .
I have seen this in vector to raster, raster to vector image problem before, there's really no way to do a really correct conversion because of the two entirely different ways that the image information is recorded for storage. But the vector to raster conversion (the operation you need here) is usually very faithful to the original vector, if the image rendering program properly sets the drawing dimensions and placement, to draw the vector to raster bit mapping. I think that imagemagic attempts to to this with the  $im->setResolution($newResW, $newResH);  which you have in your code, if your resultant png images look good to you, and do not have the saw-blade looking lines and edges, then your method is a go. As a tech note for you, there is absolutely no successful conversion of a raster image to a vector format, I have done this and instead of drawing methods in the resultant vector, it does the only thing it can, it goes through each pixel (bit map) one by one, and calls for a single pixel line draw for each pixel, , , , so I never do a raster to vector conversion.

At this point, I have nothing I can think of to add to how you do your conversion in your post ID:35054320 . . I see that my suggestion before did not apply so well to your problem, I would not worry about the  "loading the WMF image into the PHP memory twice", since there does not seem to be a good alternative, and php is good at memory allocation, you seem to properly release the object with unset($im);, , In php GD there is a specific function to clear the image object - imagedestroy($img);, maybe there is not a specific function in imagemagic for that? ?
You look like you've spent time on this, ,  The more you know the better programmer you'll be.
0
 
LVL 1

Author Comment

by:sffc
Comment Utility
In php GD there is a specific function to clear the image object - imagedestroy($img);, maybe there is not a specific function in imagemagic for that?

It looks like there are a couple of functions to achieve this that are Imagick-specific: "removeImage()" and "destroy()".  I might try running each of those first, and then still run my unset().

Thanks for your ideas!  At least my code is working, so I can now apply it to a production environment.
0
 
LVL 1

Author Closing Comment

by:sffc
Comment Utility
My comment above contains the PHP code necessary to solve this question.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction HTML checkboxes provide the perfect way for a web developer to receive client input when the client's options might be none, one or many.  But the PHP code for processing the checkboxes can be confusing at first.  What if a checkbox is…
Developers of all skill levels should learn to use current best practices when developing websites. However many developers, new and old, fall into the trap of using deprecated features because this is what so many tutorials and books tell them to u…
In this Micro Tutorial viewers will learn how to remove an unwanted object using Photoshop’s feature known as content-aware fill.
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now