Hello,
I need an extension to render Dia files as PNGs. I was using this one: http://www.mediawiki.org/wiki/Extension:Dia
However I saw many problems with it, one of them being the wrong way to calculate the size of the image.
I tried to fix it, but I did not find a good way to do it.
The extension creates a new class that extends ImageHandler. In "doTransform" it calls the "dia" binary with special arguments to convert a .dia file to a .png file. Nothing wrong there.
The problem is that it implements a "getImageSize" method where it implements a method that reads the XML file to try to "guess" the size of the image that "dia" will produce in "doTransform", and the problem is that it guesses wrong.
I think that the best way to do it would be actually to first generate the PNG image by calling "dia", and then later returning the dimensions of this PNG by using "getimagesize". The problem is that, as far as I understood the source code, getImageSize will always be called before doTransform. In fact, it seems to me that the name of the PNG image that doTransform receives will start with the width of the image returned by getImageSize itself.
I implemented a workaround^W^W a dirty hack to fix this issue. In getImageSize, I am calling "dia" (without the size argument) saving it to a tmpfile, then using "getimagesize" to get the dimensions of the PNG in the tmpfile, and then deleting the tmpfile. Then doTransform is called and it will basically do the same again, call "dia" to create the image that will be displayed. It works, but it calls "dia" twice, thus it is twice as slow as it should be.
Is there a way around this? To actually generate the PNG image just once and calculate its size only once it is generated?
Thanks! Filipe
Hi,
I sent this message two days ago but I still haven't gotten any answers.
Basically I want to understand how should I use getImageSize() and doTransform() on a subclass of ImageHandler in a way to defer calculation of the image size only after the transformation is done.
On my specific case, I want to use "dia" to convert .dia files to .png, and then use PHP's getimagesize() to get the dimensions of the resulting .png file. The problem is that, from what I saw, doTransform() is called after getImageSize(). Yes, I'm aware of the "Dia" extension, but I found out that it does not handle the image size correctly.
On the code of ImageHandler, there is a comment that suggests that I could return "false" on getImageSize() if I still don't know the size of the image, but I did not understand how to do that and set the appropriate size later.
If any of you could help me with this or point me to the appropriate resources or point me to another mailing list where this subject could be handled I would really appreciate it.
Thanks! Filipe
-----Original Message----- From: "Filipe Brandenburger" lists.filbranden@idilia.com Sent: Tuesday, September 2, 2008 11:22am To: "Wikimedia developers" wikitech-l@lists.wikimedia.org Subject: [Wikitech-l] Extension to render Dia as a PNG
Hello,
I need an extension to render Dia files as PNGs. I was using this one: http://www.mediawiki.org/wiki/Extension:Dia
However I saw many problems with it, one of them being the wrong way to calculate the size of the image.
I tried to fix it, but I did not find a good way to do it.
The extension creates a new class that extends ImageHandler. In "doTransform" it calls the "dia" binary with special arguments to convert a .dia file to a .png file. Nothing wrong there.
The problem is that it implements a "getImageSize" method where it implements a method that reads the XML file to try to "guess" the size of the image that "dia" will produce in "doTransform", and the problem is that it guesses wrong.
I think that the best way to do it would be actually to first generate the PNG image by calling "dia", and then later returning the dimensions of this PNG by using "getimagesize". The problem is that, as far as I understood the source code, getImageSize will always be called before doTransform. In fact, it seems to me that the name of the PNG image that doTransform receives will start with the width of the image returned by getImageSize itself.
I implemented a workaround^W^W a dirty hack to fix this issue. In getImageSize, I am calling "dia" (without the size argument) saving it to a tmpfile, then using "getimagesize" to get the dimensions of the PNG in the tmpfile, and then deleting the tmpfile. Then doTransform is called and it will basically do the same again, call "dia" to create the image that will be displayed. It works, but it calls "dia" twice, thus it is twice as slow as it should be.
Is there a way around this? To actually generate the PNG image just once and calculate its size only once it is generated?
Thanks! Filipe
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
lists.filbranden@idilia.com wrote:
Basically I want to understand how should I use getImageSize() and doTransform() on a subclass of ImageHandler in a way to defer calculation of the image size only after the transformation is done.
You can't -- doTransform() is told what size it should render at, which means the system needs to already know an appropriate native size of the image.
The native size is used to: * List as image metadata * Establish the aspect ratio for scaling * Establish a default rendering size * Establish a maximum rendering size (for raster images we don't render when scaling up, we just show the original file bigger on screen)
Ideally, you can in fact extract a size from the file. If you can't get it from the file yourself, you should be able to get it from your external program in some way. (Worst case, render to a temporary PNG at "native" size and check *its* size. Probably crappy, but hey.)
Then, when you rasterize to PNG from doTransform() you're passing your external program an exact target size, which it should in fact hit exactly.
On the code of ImageHandler, there is a comment that suggests that I could return "false" on getImageSize() if I still don't know the size of the image, but I did not understand how to do that and set the appropriate size later.
You should only return false if it's not possible to get a size from the file -- that is, if it's not an image file of a type you recognize.
- -- brion
Brion Vibber wrote:
Ideally, you can in fact extract a size from the file. If you can't get it from the file yourself, you should be able to get it from your external program in some way. (Worst case, render to a temporary PNG at "native" size and check *its* size. Probably crappy, but hey.)
Yes, "worst case" is what I am doing now, rendering to a file in /tmp, using PHP's getimagesize() to get its size, and deleting the temporary file. However this is very CPU intensive.
Would there be a way for me to "save" this temporary file somewhere inside the uploads directory, in a way that I could use it later in doTransform?
I mean, in getImageSize() I would write the temporary file to somewhere inside the upload directory (how could I automate the creation of a path for that?) and not remove it after getting its size. Then, in doTransform(), I would check if the requested dimensions match the ones of the temporary file I created, if they do, I would just copy/rename/hardlink the original file to the new one. Would that work? How should I manage creating a path on the upload directory for that? (I'm thinking something such as "math" or "graphviz" under the root of uploads.)
Thanks! Filipe
Hi,
Filipe Brandenburger wrote:
Would there be a way for me to "save" this temporary file somewhere inside the uploads directory, in a way that I could use it later in doTransform?
I mean, in getImageSize() I would write the temporary file to somewhere inside the upload directory (how could I automate the creation of a path for that?) and not remove it after getting its size. Then, in doTransform(), I would check if the requested dimensions match the ones of the temporary file I created, if they do, I would just copy/rename/hardlink the original file to the new one. Would that work? How should I manage creating a path on the upload directory for that? (I'm thinking something such as "math" or "graphviz" under the root of uploads.)
I found a way to do this, but I really did not like it at all!
It goes like this:
function getImageSize( $image, $path ) { #... $uploadData = array_values( $_SESSION['wsUploadData'] ); $imageName = $uploadData[0]['mSrcName']; global $wgUploadDirectory; $imageDir = $wgUploadDirectory . "/dia/" . FileRepo::getHashPathForLevel($imageName, 2); wfMkdirParents($imageDir); $imagePath = $imageDir . $imageName . ".png"; #... }
And then using $imagePath as a destination to save the generated PNG.
In "doTransform()", recalculate "$imagePath" for the temporary one, then use PHP's "getimagesize()" and compare with the requested dimensions. If it matches, then use "link()" to copy the image, without the need to call "dia" again.
The problem is, it depends on undocumented behaviour, and on getting data from the session that was not meant to be seen by extensions.
I believe the "right" solution for that would be adding another method to ImageHandler that would permit this kind of manipulation.
I was thinking of something along these lines:
* If "mustRender()" returns true, then the "doRender()" method will be called (before "getImageSize()" or "doTransform()"). It will be passed a $dstPath parameter with the file name of the PNG to be generated. * If "doRender()" does indeed render the image, it should return the "getimagesize()" output with the dimensions of the image. This will be used by the calling method to know what is the image size. * Optional: the calling method will be responsible for renaming XXX.png into NNNpx-XXX.png. (Is this really necessary?) * The default implementation of "doRender()" just returns false. In that case, the calling method knows that it should use the other methods ("getImageSize()" and then "doTransform()") to create the PNG image.
How does all this sound to you? Is this a patch you would be willing to accept and merge into MediaWiki?
Thanks, Filipe
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Filipe Brandenburger wrote:
Brion Vibber wrote:
Ideally, you can in fact extract a size from the file. If you can't get it from the file yourself, you should be able to get it from your external program in some way. (Worst case, render to a temporary PNG at "native" size and check *its* size. Probably crappy, but hey.)
Yes, "worst case" is what I am doing now, rendering to a file in /tmp, using PHP's getimagesize() to get its size, and deleting the temporary file. However this is very CPU intensive.
Would there be a way for me to "save" this temporary file somewhere inside the uploads directory, in a way that I could use it later in doTransform?
Well, one thing to consider is that you might never see that same image again. You might be running checks on a file whose upload will be canceled later, or which might not go through a standard upload process at all (say, some sort of batch process).
I mean, in getImageSize() I would write the temporary file to somewhere inside the upload directory (how could I automate the creation of a path for that?) and not remove it after getting its size. Then, in doTransform(), I would check if the requested dimensions match the ones of the temporary file I created, if they do, I would just copy/rename/hardlink the original file to the new one. Would that work? How should I manage creating a path on the upload directory for that? (I'm thinking something such as "math" or "graphviz" under the root of uploads.)
You might create yourself a temp rendering directory, store rendered files by hash, and just check it later if you need it again or at upload time.
Unless rendering is really slow, however, it's probably not worth the effort; rendering twice at upload time is probably not super-painful and it's not likely to be a time-critical code path. I recommend you check how long this takes in practice before investing more effort in optimization tricks.
- -- brion
wikitech-l@lists.wikimedia.org