It is currently Fri Apr 26, 2024 9:23 am


All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: Exporting multi page PDF in Python....
PostPosted: Fri May 01, 2015 7:16 pm  (#1) 
Offline
GimpChat Member

Joined: Jan 22, 2012
Posts: 31
I'm trying to export multi-page PDF's through Python in GIMP. I've created a gimp.Image object, and tried the following.

>>> img
<gimp.Image 'bla.xcf'>
>>> img.ID
6
>>> pdb.file_pdf_save_multi([img.ID], 0, 0, 1, 1, "/tmp/test.pdf", "/tmp/test.pdf")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
RuntimeError: Procedure 'file-pdf-save-multi' returned no return values


In the terminal I launched Gimp from, it says "/usr/lib/gimp/2.0/plug-ins/file-pdf-save: fatal error: Segmentation fault"

The first input is supposed to be an int array of images, so I assume it's the image ID of loaded images.

How do you use this command correctly?

Opening the PDF export interface manually through Script-Fu with (file-pdf-save-multi 0 #(0) 0 0 0 0 "" "") works, but I want to try to include it as part of Gimp Book. Any ideas?


Share on Facebook Share on Twitter Share on Orkut Share on Digg Share on MySpace Share on Delicious Share on Technorati
Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Fri May 01, 2015 9:08 pm  (#2) 
Offline
Script Coder
User avatar

Joined: Apr 23, 2010
Posts: 1553
Location: not from Guildford after all
Quote:
pdb.file_pdf_save_multi([img.ID], 0, 0, 1, 1, "/tmp/test.pdf", "/tmp/test.pdf")

You are specifying a count of "0" images/pages. There must be at least one page for non-interactive use.

_________________
Any sufficiently primitive technology is indistinguishable from a rock.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 7:01 am  (#3) 
Offline
Script Coder
User avatar

Joined: Oct 25, 2010
Posts: 4739
Might be a bug. If the array contains image ids (ints), the python support segfaults. But if you use image objects (as you would do in most PDB calls that are documented as taking image ids) you get a "TypeError: subscript of wrong type" from a routine that checks that the array indeed contains ints.

_________________
Image


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 9:12 am  (#4) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
Hmmm.. this is an odd one!
It looks like the PDB interface for file-pdf-save-multi has been mis-specified.

By Gimp's libgimp interface definition, any sort of ARRAY parameter should be preceded by an INT32 which contains the number of entries in the following ARRAY.
Thus, for example, in the convolution-matrix plugin (plug-in-convmatrix) the PDB parameters are:

Image

Similarly in the other standard plugins which use ARRAY parameters such as plug-in-film.
But file-pdf-save-multi has the number of images after the ARRAY like this:

Image

And that will very likely cause a segmentation fault. (I had exactly that problem when I was hacking the wavelet-denoise plugin for Dinasset.)
What is curious is that this plugin actually works at all - by all rights it should crap-out with a segmentation fault when invoked from Script-Fu as well!


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 10:58 am  (#5) 
Offline
Script Coder
User avatar

Joined: Apr 23, 2010
Posts: 1553
Location: not from Guildford after all
ofnuts wrote:
Might be a bug. If the array contains image ids (ints), the python support segfaults. But if you use image objects (as you would do in most PDB calls that are documented as taking image ids) you get a "TypeError: subscript of wrong type" from a routine that checks that the array indeed contains ints.

I do not believe it is possible for the Python interface with the PDB to distinguish between arrays of images, layers, channels, paths, et cetera. While there are specific types dedicated to these objects when they appear as individual/non-array parameters (and this info can be used to map the types to/from Python objects), for arrays the only type information available is whether the array is comprised of 8-bit integers, 32-bit integers, floats, or strings.

_________________
Any sufficiently primitive technology is indistinguishable from a rock.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 11:14 am  (#6) 
Offline
Script Coder
User avatar

Joined: Apr 23, 2010
Posts: 1553
Location: not from Guildford after all
jontait2 wrote:
And that will very likely cause a segmentation fault. (I had exactly that problem when I was hacking the wavelet-denoise plugin for Dinasset.)
What is curious is that this plugin actually works at all - by all rights it should crap-out with a segmentation fault when invoked from Script-Fu as well!

The position of the array size argument in the list of parameters should not cause any difficulty from a PDB standpoint. The array itself is just a C pointer, which is the same size regardless of the size of the array. As long as neither the plug-in nor libgimp tries to access the array before checking its size, there should be no segfault.

_________________
Any sufficiently primitive technology is indistinguishable from a rock.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 11:23 am  (#7) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
saulgoode wrote:
The position of the array size argument in the list of parameters should not cause any difficulty from a PDB standpoint.

Have you actually tried doing an ARRAY param without an INT32 preceding it? Because I did when I was hacking wavelet-denoise and it just crapped-out every time!


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 12:14 pm  (#8) 
Offline
Script Coder
User avatar

Joined: Apr 23, 2010
Posts: 1553
Location: not from Guildford after all
jontait2 wrote:
Have you actually tried doing an ARRAY param without an INT32 preceding it?

No, I have not (at least not in the last five or six years). :oops:

_________________
Any sufficiently primitive technology is indistinguishable from a rock.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 6:30 pm  (#9) 
Offline
GimpChat Member

Joined: Jan 22, 2012
Posts: 31
I did try with the number of pages following the image ID array, but the result is the same; a segfault in the terminal. I also tried with an array of image objects, and this gave me "TypeError: subscript of wrong type", like ofnuts said it would.

Here is what I've been trying:

img = pdb.gimp_file_load('/tmp/test.xcf', '/tmp/test.xcf')
ids = []
ids.append(img.ID)
pdb.file_pdf_save_multi(ids, 1, 0, 1, 1, "/tmp/test.pdf", "/tmp/test.pdf")


Doing the same thing in Script-Fu, also segfaults (the image in this case had ID 1):

(file-pdf-save-multi 1 #(1) 1 0 1 1 "/tmp/test.pdf" "/tmp/test.pdf")


From what you say, it seems I may simply have stepped on a bug. :(

Is there a smart way around this?


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 7:14 pm  (#10) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
ragtag wrote:
From what you say, it seems I may simply have stepped on a bug.

At least one!
The procedures file_pdf_save and file_pdf_save_multi are in the same source file (file-pdf-save.c) and share a lot of code. One of the _multi procedure's subroutines was using the wrong parameter list definition, and trying to interpret the "vectorize" parameter as the "filename"; if vectorize was set to 0 (FALSE), the plugin would see this as a null filename and so abort prematurely with the nice friendly warning "You must select a file to save!", but if vectorize was set to 1 (TRUE), the plugin would take that as the memory address of the filename string, try to read it and get a segfault (trying to access forbidden memory location).
I've cleared that bug in a hacked copy of the plugin, and can now get it to work non-interactively from both Script-Fu and Python, but it will only process one image for some reason.

As far as I can see, this plugin has, in fact, never worked properly in non-interactive mode - it was only ever used interactively and it's now been taken out of the menu heirarchy altogether.

More anon.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sat May 02, 2015 10:31 pm  (#11) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
Okay, ragtag, I've got it working now.
As I suspected, the PDB interface has been mis-specified: the count parameter should precede the array, not follow it.
[It was taking the run-mode parameter as the length of the array, so with run-mode=0 (INTERACTIVE) it did nothing, but that didn't matter; with run-mode=1 (NON-INTERACTIVE), only the first image ID in the array was copied to the plugin, so only the first image actually came out in the output file!]

What is quite clear now is that this plugin has never worked at all in NON-INTERACTIVE mode.

More anon.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sun May 03, 2015 2:13 pm  (#12) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
saulgoode wrote:
The position of the array size argument in the list of parameters should not cause any difficulty from a PDB standpoint.

I hate to teach Gran to suck eggs, LOL, but FYI:

In gimp-2.8.14/app/plug-in/plug-in-params.c function plug_in_params_to_args()
  for (i = 0; i < n_params; i++)
    {
      :
      :
      switch (gimp_pdb_compat_arg_type_from_gtype (type))
        {
          :
          :
        case GIMP_PDB_INT32ARRAY:
          count = g_value_get_int (&args->values[i - 1]);   <------THIS IS ASSUMED TO BE THE LENGTH
          if (full_copy)
            gimp_value_set_int32array (&value,
                                       params[i].data.d_int32array,
                                       count);
          else
            gimp_value_set_static_int32array (&value,
                                              params[i].data.d_int32array,
                                              count);
          break;

Similarly for other *ARRAY parameters.
(The above function is called by various routines in gimpplugin-message.c, to process both the parameters passed to a plugin and the return values from the plugin.)

In other words, an array-type parameter is not simply passed-through to the plugin by pointer (as you were assuming), it is actively copied (along with all simple non-array parameters) into a dynamically-allocated message buffer and it is that buffer which gets sent to the plugin (as an inter-task message); and the procedure which does the copying implicitly assumes that the parameter immediately preceding an array is a simple numeric type with value set to the number of elements in the array - if it isn't, mayhem ensues (there is no sanity checking!). If you're lucky, the plugin call will fail benignly; if you're not so lucky you get a segfault.

[This is the problem I hit before when adapting the wavelet-denoise plugin for Dinasset. My first attempt used FLOATARRAYs without preceding length values and it just seg-faulted every time; in that case, the value preceding the first array was in fact a drawable ID which generally had value much greater than the length of the first array (just 2 elements) so the copying would try to access unallocated memory and hence the segfault; I soon came across a doc which explicitly stated that arrays must be preceded by a length field in an INT32 parameter, corrected my source and had no further problems (but eventually decided arrays were too much trouble for that particular application anyway and ended-up using individual float values!).]

In this case (file-pdf-save-multi), the plugin call was actually failing benignly - the parameter before the array was the run-mode, either 0 or 1; if set to 0 (ie. INTERACTIVE), the array was ignored completely, but that didn't matter because the user then selected the images in the interactive GUI; and if set to 1 (ie. NON-INTERACTIVE), the plugin would only take the first image ID in the array and so produce a one-page output file. So no memory violation. The segfault was actually caused by another totally unrelated (but co-existent) bug which just happened to produce the same net result.

And this is, of course, why some plugins have length fields which appear to be entirely superfluous, eg.plug-in-convmatrix where the argc-matrix field should always be set to 25.

By grepping the source directories for Gimp plugins and looking thru the Procedure Browser entries, I find that there are, in fact, relatively few plugins which do actually take ARRAY parameters, and they all use a preceding INT32 length field:
INT8ARRAY:
file-gih-save
gimp-curves-explicit
gimp-curves-spline
gimp-drawable-set-pixel
gimp-image-convert-set-dither-matrix
gimp-image-set-colormap
plug-in-curve-bend
plug-in-metadata-decode-exif

INT32ARRAY:
plug-in-convmatrix
plug-in-film
plug-in-gap-move-path-ext

FLOATARRAY:
gimp-airbrush
gimp-clone
gimp-convolve
gimp-dodgeburn
gimp-eraser
gimp-heal
gimp-image-select-polygon
gimp-paintbrush
gimp-vectors-stroke-new-from-points
plug-in-convmatrix
plug-in-curve-bend
plug-in-gap-move-path-ext

STRINGARRAY:
extension-gimp-help-browser
file-gih-save
plug-in-metadata-set

(There are, of course, many Gimp internal procedures and quite a few plugins which return arrays, and they do so always with a preceding INT32 length field.)


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Sun May 03, 2015 4:14 pm  (#13) 
Offline
Script Coder
User avatar

Joined: Dec 27, 2014
Posts: 508
@Ragtag:
As far as I can see you have two options:

1. Use existing plugin but run interactively
Python always runs plugins non-interactively by default, but you can opt for interactive use just by appending "run_mode=0" to the argument list like this:
pdb.file_pdf_save_multi(0, [], 0, 1, 1, "", "",run_mode=0)
Unfortunately, because of the bugs in the plugin, the user will have to set the filename and select all the images manually. But this does give the user the opportunity to arrange the images in sequence, and reproduce an image more than once if they wish to.

2. Upgrade the plugin
We could report the bugs on bugzilla but it's unlikely that the Gimp developers will pick it up because this -multi procedure in the plugin is now pretty much deprecated anyway. (The Gimp devs made a policy decision way back in 2007-ish to take the Multi-page PDF out of the menu heirarchy because it did not fit with their vision of Gimp - as far as they're concerned Gimp is an Image Manipulation Program, not a Desktop Publishing program.)
At the risk of incurring the wrath of the Gimp devs, I could provide you with a fully-functional corrected source and binary for Linux x64 and perhaps somebody else could compile it for other platforms (Windows, OSX, etc). But we/you are then going to have to provide those binaries to anybody wanting to use your Gimp-Book plugin.


Top
 Post subject: Re: Exporting multi page PDF in Python....
PostPosted: Mon May 04, 2015 3:30 pm  (#14) 
Offline
GimpChat Member

Joined: Jan 22, 2012
Posts: 31
jontait2 thanks a lot for taking the time to look into this, much appreciated.

I think I'll go for option 3, which is simply to not implement multi-page PDF export in my Gimp Book plug-in. :mrgreen:

It's not that hard to combine exported TIFF or PNG files, into a PDF if the users wants to, so even though it would be nice to have PDF export, it's not critical.


Top
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


   Similar Topics   Replies 
No new posts Exporting as PSD from Python?

2

No new posts Performance of adjusting layers and exporting with Python Fu

5

No new posts Attachment(s) Exporting problem

1

No new posts Trouble exporting to .psd

2

No new posts Filled path not exporting with fill

4



* Login  



Powered by phpBB3 © phpBB Group