tavinus / pdfScale

Bash Script to Scale and Resize PDFs using Ghostscript
MIT License
246 stars 37 forks source link

Colour the created margins (by scaling) #9

Closed TimSoethout closed 6 years ago

TimSoethout commented 6 years ago

Wow, your tool is really what I needed for sending an poster to a publisher for fixing the margins. Thanks.

I was wondering if it is also possible/easy to colour the margins created (using scale 0.95) in a specific color, so the resulting image has that colour on all borders for nicer printing/cutting edge? This is for example useful if the background colour of your poster is not white and to let it flow until the new edge.

tavinus commented 6 years ago

Hi there...

That is an interesting idea.
I am not so sure what path to take on that though.

Some things to consider

  1. This only applies to scaling since resizing uses fit-to-page
  2. The positioning is done by scaling and then translating everything and that happens inside a /BeginPage setpagedevice PS command. AFAIK that creates a new/blank PDF canvas every time.
  3. I think the generated PDFs actually get a transparent bleed (which shows as white on screen). I have inspected a generated PDF file on Illustrator just now and there is actually no info on background or any elements working as background.
  4. Ghostscript does not seem to have an option to set background color for PDF files (it has for PNG files). So we would probably need to do that inside the PS script.

I was trying to find a GS option or at least a PS command that would just magically set the background color, but could not really find that.

So it seems like we will need to actually insert a colored box behind the PDF to work as a background if we want that functionality. So the user would use some command like --add-background 000000 (hex? rgb? cmyk?) and we would add that to the PDF.

Any ideas or advices on this would be appreciated.
Seems not so easy to implement, but I will keep checking.

I will keep this post updated on the progress.

Cheers! Gus

tavinus commented 6 years ago

I found this post about a way to do it and it seems to work.

Example PS call: This is using RGB as in 1 / 0.7 / 0.8 (some pink)

1 0.7 0.8 setrgbcolor clippath fill 

I have inserted that in the PS command on setpagedevice.

Example successfull gs run

$ gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER -dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" -dColorImageResolution=300 -dGrayImageResolution=300 -dColorImageDownsampleType="/Bicubic" -dGrayImageDownsampleType="/Bicubic" -dColorConversionStrategy=/LeaveColorUnchanged -dSubsetFonts=true -dEmbedAllFonts=true -dDEVICEWIDTHPOINTS=842 -dDEVICEHEIGHTPOINTS=595 -sOutputFile="../input-nup.TT.pdf" -c "<</BeginPage{1 0.7 0.8 setrgbcolor clippath fill 0.95 0.95 scale 22.157230 15.657425 translate}>> setpagedevice" -f "../input-nup.pdf"

The change was from

-c "<</BeginPage{0.95 0.95 scale 22.157230 15.657425 translate}>> setpagedevice"

To

-c "<</BeginPage{1 0.7 0.8 setrgbcolor clippath fill 0.95 0.95 scale 22.157230 15.657425 translate}>> setpagedevice"

Adding the needed command before anything else.

First tests show that yes, we had transparent backgrounds. I say that because on text documents that will paint the background of the text, unless the document actually has a white box behind it.

Now I need to do more tests and check the other color modes and how to deal with that.
Postscript has setgray, setcolor, setrgbcolor, setcmykcolor, sethsbcolor each with one or multiple uses (function overloading). Using only RGB or CMYK would obviously make it easier to implement.

Because this goes inside the PS command and the command name itself may change, the complexity is a little bit higher. Not that hard though.

TimSoethout commented 6 years ago

Nice idea's and thanks for the quick response.

Is the current pdfScale color-type-agnostic? Meaning it just passes through the original's PDF RGB/CMYK? Maybe the PDFInfo and other methods can read this and use the type of the original?

As for the command line input --add-background 000000, could use the format of the color-type of the original PDF. If this is a lot of work though, just pick the easiest variant to implement/maintain. + showing a warning in the terminal if color types don't make sense.

tavinus commented 6 years ago

Aright mate, I have pushed v2.4.0 which implements Backgrounding.

It can run with gray, cmyk or rgb modes for the background.

This is from the help:

 --background-gray <percentage>
             Creates a background with a gray color setting
             Percentage is a floating point percentage number between 0(white) and 1(black)
 --background-cmyk <"C M Y K">
             Creates a background with a CMYK color setting
             Must be quoted into a single parameter as in "0.2 0.2 0.2 0.2"
             Each color parameter is a floating point percentage number (between 0 and 1)
 --background-rgb <"R G B">
             Creates a background with a RGB color setting
             Must be quoted into a single parameter as in "100 100 200"
             Postscript accepts both percentages or RGB numbers, but not mixed
             Percentages are floating point numbers between 0 and 1 (1 0.5 0.2)
             RGB numbers are integers between 0 and 255 (255 122 50)

Please note that some documents may have white boxes that will not be painted (will remain white). This may not affect you but will certainly affect others trying to paint their documents.

Please test the new release and let me know if that works for your use case. :)
You should be able to just run pdfscale --upgrade to get the new version.

Cheers!
Gus

tavinus commented 6 years ago

humm... was testing a bit more and checking and then realised that the RGB param actualy only runs with percentages (no RGB numbers from 0 to 255 like photoshop).

Also, to use RGB properly we should also set HSB (Hue Saturation Brightness). Or should at least be able to set it on top of the RGB setting.

The CMYK option is more complete on itself.
For example, even for half-gray it is as easy as CMYK "0 0 0 0.5".

I am honestly thinking of shaving off the whole RGB implementation and keeping only CMYK and GRAY.

Or we need a way to set HSB at least and also to fix the RGB numbers thing.

Ideas? 💡

Cheers!
Gus

TimSoethout commented 6 years ago

Thanks for fast addition of the feature. :)

~/Downloads/pdfScale/pdfScale.sh -v -r a0 -s 0.95 --image-resolution 600 --background-cmyk "0 0 0 .14" poster.pdf seems to work for me.

Using this test poster created with Keynote pdf export: poster.pdf

~/Downloads/pdfScale/pdfScale.sh -v -r a0 -s 0.95 --image-resolution 600 --background-gray 0 poster.pdf produces black --background-gray 1 produces white, so it seems the documentation is the other way around. :)

--background-rgb "216 216 216" indeed seems to not work. With percentages is does seem to work: --background-rgb ".847058824 .847058824 .847058824"

TimSoethout commented 6 years ago

I'm not a color expert, but if RGB only is useful with HSB, I guess that should be added.

From a usability view I would think that 0-255 RGB values are mandatory, maybe we can convert them? $IN_RED / 255.0 or something? (if possible in bash)

With output: Background: RGB Mode > 216 216 216 > (converted) .847058824 .847058824 .847058824

Alternatively (as you suggest) drop RGB support for now, and put in a nice to have feature request issue with some pointers/design/knowledge that we currently have.

tavinus commented 6 years ago

Pushed v2.4.1, please update and test.
I actually did basically what you said (even though I didn't read it beforehand).

I have fixed RGB parsing in 255-based numbers and I convert them internally to percentages (which is what postscript likes). There is currently no way to pass RGB percentages directly (not sure if it ever will).

It seems to work without HSB, but CMYK is still recommended since it is easy and complete.
I am still messing with it so v2.4.2 is probably coming soon as well.

I may implement the HSB parameter but then that is even more complexity since it should only be added on top of an RGB config. For now it is staying without it.

PS: Thanks for the gray white/black inversion mention, fixed!

Edit1: Just pushed v2.4.2 cleaned and finalised, please test (no HSB mode yet).

Cheers! Gus

tavinus commented 6 years ago

Ok, I was tripping on HSB, which is just like a shortcut to RGB.

Meaning it is just another way to reference the RGB color space but adds nothing to it.

Internally Ghostscript/Postscript will use RGB if HSB is used. I was even implementing HSB but then realised this and decided to not include it since we already have 3 modes to set the background color.

This is from the Postscript manual:

Note that the HSB parameter values supplied to sethsbcolor are immediately converted into RGB color components. HSB is not a color space in its own right, but merely an alternate way of specifying color values in the DeviceRGB color space.

So I think this should be done for now.
Can you confirm we have no errors and all works now?

PS/Edit: I actually wanted to have an automatic color pick for the background, but could not really find any way to do it. We would probably need a PS script that would scan for the most used color (not trivial at all).

PS2: v2.4.3 is out with minor fixes to help messages about how backgrounding works

Cheers!
Gus

TimSoethout commented 6 years ago

Yes it seems to work great! Thanks!

Maybe an easy way is to just grab the most upper left pixel:

$ convert poster.pdf[1x1] txt:
# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (54289,54583,55118.5,65535)  #D411D537D74EFFFF  srgba(82.8396%,83.2883%,84.1054%,1)

But I guess that would be another feature. ;) I'll close the issue for now.

TimSoethout commented 6 years ago

Or using image magick to reduce the number of colors to 1... (https://www.imagemagick.org/discourse-server/viewtopic.php?t=28963) Although I'm sure if it is correct.

$ convert poster.pdf +dither -colors 1 -unique-colors txt:
# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (53804.2,54168.4,54898,65535)  #D22CD398D672FFFF  srgba(82.1%,82.6556%,83.769%,1)
tavinus commented 6 years ago

Interesting...
That could be just scripted to feed pdfScale though.

But now we would need the RGB as percentage again, LOL.
I will probably implement a --background-rgbp for that, even though I am trying to cut on excessive options and we already have a lot of them.

Anyways, auto-picking the color will probably NEVER be perfect. It would be cool nonetheless.

Edit: I was thinking that I can go back on checking if both 3 RGB params are floats. But that requires that 0 and 1 are passed as 0.0 and 1.0 when used as percentage (MUST have a dot on every entry so we know which mode we are using). The problem I see is that this can be confusing, but we save on an extra command for RGB-percentage.

Cheers!
Gus