>From 3c35f12df9d71d4e91b1d9a47a1a5804e9a4aea1 Mon Sep 17 00:00:00 2001 From: Knut Petersen Date: Thu, 26 Nov 2020 17:33:29 +0100 Subject: [PATCH] Implement transparency for PDFs. Some time ago the SVG backend was taught to handle transparency. This patch now makes it possible to use transparency also when creating PDF files. This can be useful for example to place a transparent stamp on a sheet of music. Creating PNGs with transparency and transparent background also is possible, but only within the limits of the pngalpha device of Ghostscript. Imagemagick convert is clearly superior here. If you want to try it, use the following command: lilypond \ -dpixmap-format="pngalpha" \ -dresolution=600 --png \ tmp_transparency_test.ly A current Ghostscript is required, e.g. 9.53.x or git master. The actually quite good 9.26 is too old, many intermediate versions are buggy. This patch is just a quick test, you would probably rework some postscript programs in ps/music-drawing-routines.ps for better results. If every backend supports transparency via an alpha value, there is also the question if the transparency property should be kept. Status: Proof of concept. Signed-off-by: Knut Petersen --- ps/music-drawing-routines.ps | 10 +++++ scm/backend-library.scm | 1 + scm/framework-ps.scm | 19 +++++++++ scm/output-ps.scm | 12 +++--- tmp_transparency_test.ly | 79 ++++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 tmp_transparency_test.ly diff --git a/ps/music-drawing-routines.ps b/ps/music-drawing-routines.ps index 9c4068da59..5b38453298 100644 --- a/ps/music-drawing-routines.ps +++ b/ps/music-drawing-routines.ps @@ -326,4 +326,14 @@ bind def 0 rmoveto }repeat }bind def + +/setrgbacolor % r g b a +{ + 4 1 roll + setrgbcolor + dup + .setfillconstantalpha + .setstrokeconstantalpha +} bind def + %end music-drawing-routines.ps diff --git a/scm/backend-library.scm b/scm/backend-library.scm index 89994e7795..4771282269 100644 --- a/scm/backend-library.scm +++ b/scm/backend-library.scm @@ -63,6 +63,7 @@ "-dNODISPLAY" ;; see function gs-safe-run below where we use .setsafe instead "-dNOSAFER" + "-dALLOWPSTRANSPARENCY" "-dNOPAUSE" "-dBATCH" (if (and is-eps (not fit-page)) "-dEPSCrop") diff --git a/scm/framework-ps.scm b/scm/framework-ps.scm index bf5c7a3f05..81e0d38d6a 100644 --- a/scm/framework-ps.scm +++ b/scm/framework-ps.scm @@ -109,6 +109,14 @@ (string-append (format #f "%%Page: ~a ~a\n" page-number page-number) "%%BeginPageSetup\n" + "<< /PageUsesTransparency true\n" + " /CompatibilityLevel 1.4\n" + " /PageSpotColors 0\n" + ">> setpagedevice\n" + "0 .pushpdf14devicefilter\n" + "<< >> clippath pathbbox newpath .begintransparencygroup\n" + "1.0 .setfillconstantalpha\n" + "1.0 .setstrokeconstantalpha\n" (if landscape? "page-width output-scale lily-output-units mul mul 0 translate 90 rotate\n" "") @@ -116,6 +124,7 @@ "\n" "gsave 0 paper-height translate set-ps-scale-to-lily-scale\n")) (ly:outputter-dump-stencil outputter page-stencil) + (ly:outputter-dump-string outputter ".endtransparencygroup\n.poppdf14devicefilter\n") (ly:outputter-dump-string outputter "stroke grestore\nshowpage\n")) (define (supplies-or-needs paper load-fonts?) @@ -625,6 +634,16 @@ (display (setup-variables paper) port) ;; adobe note 5002: should initialize variables before loading routines. + (display "systemdict /.setalphaisshape known not +{ + /PageUsesTransparency false def + /.pushpdf14devicefilter {pop} bind def + /.poppdf14devicefilter {} bind def + /.begintransparencygroup {pop pop pop pop pop} bind def + /.endtransparencygroup {} bind def + /.setfillconstantalpha {pop} bind def + /.setstrokeconstantalpha {pop} bind def +} if\n" port) (display (procset "music-drawing-routines.ps") port) (display (procset "lilyponddefs.ps") port) (display "%%EndProlog\n" port) diff --git a/scm/output-ps.scm b/scm/output-ps.scm index 2635709728..f0d4f3a40b 100644 --- a/scm/output-ps.scm +++ b/scm/output-ps.scm @@ -197,12 +197,12 @@ ;; save current color on stack and set new color (define* (setcolor r #:optional (g #f) (b #f) (a #f)) - ;; TODO: figure out a way to support alpha transparency - ;; using /SetTransparency pdfmark - (ly:format "gsave ~4l setrgbcolor\n" - (if (string? r) - (list-head (css->colorlist r) 3) - (list r g b)))) + (if a (ly:format "gsave ~4l setrgbacolor\n" + (list r g b a)) + (ly:format "gsave ~4l setrgbcolor\n" + (if (string? r) + (list-head (css->colorlist r) 3) + (list r g b))))) ;; restore color from stack (define (resetcolor) "grestore\n") diff --git a/tmp_transparency_test.ly b/tmp_transparency_test.ly new file mode 100644 index 0000000000..d921be4c92 --- /dev/null +++ b/tmp_transparency_test.ly @@ -0,0 +1,79 @@ +\version "2.23.0" + +\pointAndClickOff + +\paper { + #(set-paper-size "a4") + indent = 0\cm + left-margin = 2\cm + line-width = 17\cm + top-margin = 1.5\cm + bottom-margin = 1.5\cm + ragged-right = ##f + ragged-bottom = ##f + ragged-last-bottom = ##f + tagline = ##f +} + + \markup { + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 1 0 0 0.1) \filled-box #'(-10 . 20) #'( -20 . 10) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 1 0 0.2) \filled-box #'( 0 . 30) #'( -30 . 0) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 1 0.3) \filled-box #'( 10 . 40) #'( -40 . -10) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 1 0 0 0.4) \filled-box #'( 20 . 50) #'( -50 . -20) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 1 0 0.5) \filled-box #'( 30 . 60) #'( -60 . -30) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 1 0.6) \filled-box #'( 40 . 70) #'( -70 . -40) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 1 0 0 0.7) \filled-box #'( 50 . 80) #'( -80 . -50) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 1 0 0.8) \filled-box #'( 60 . 90) #'( -90 . -60) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 1 0.9) \filled-box #'( 70 . 100) #'(-100 . -70) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.1) \filled-box #'( 60 . 90) #'(-110 . -80) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.2) \filled-box #'( 50 . 80) #'(-120 . -90) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.3) \filled-box #'( 40 . 70) #'(-130 . -100) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.4) \filled-box #'( 30 . 60) #'(-140 . -110) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.5) \filled-box #'( 20 . 50) #'(-150 . -120) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.6) \filled-box #'( 10 . 40) #'(-160 . -130) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.7) \filled-box #'( 0 . 30) #'(-170 . -140) #3 + \with-dimensions #'(-0 . 0) #'(0 . 0) \with-color #(rgb-color 0 0 0 0.8) \filled-box #'(-10 . 20) #'(-180 . -150) #3 +} + +\relative a' { + \override Staff.StaffSymbol.color = #(rgb-color 1 0 0 0.33) + \override Staff.BarLine.color = #(rgb-color 1 0 0 0.33) + \override Score.BarNumber.color = #(rgb-color 1 0 0 0.33) + \override Staff.TimeSignature.color = #(rgb-color 0 0 1 0.33) + \override Staff.Clef.color = #(rgb-color 0 0 1 0.33) + \override Voice.NoteHead.color = #(rgb-color 0 1 0 0.33) + \override Voice.Stem.color = #(rgb-color 0 1 0 0.33) + \override Voice.Beam.color = #(rgb-color 0 1 0 0.33) + \override Lyrics.LyricText.color = #(rgb-color 0 0 0 0.33) + \repeat unfold 2 { a1 2 2 4 4 4 4 8 8 8 8 8 8 8 8} \bar "|." +} \addlyrics { \repeat unfold 30 { foo } } + +\relative a' { + \override Staff.StaffSymbol.color = #(rgb-color 1 0 0 0.66) + \override Staff.BarLine.color = #(rgb-color 1 0 0 0.66) + \override Score.BarNumber.color = #(rgb-color 1 0 0 0.66) + \override Staff.TimeSignature.color = #(rgb-color 0 0 1 0.66) + \override Staff.Clef.color = #(rgb-color 0 0 1 0.66) + \override Voice.NoteHead.color = #(rgb-color 0 1 0 0.66) + \override Voice.Stem.color = #(rgb-color 0 1 0 0.66) + \override Voice.Beam.color = #(rgb-color 0 1 0 0.66) + \override Lyrics.LyricText.color = #(rgb-color 0 0 0 0.66) + \repeat unfold 2 { a1 2 2 4 4 4 4 8 8 8 8 8 8 8 8} \bar "|." +} \addlyrics { \repeat unfold 30 { foo } } + +\relative a' { + \override Staff.StaffSymbol.color = #(rgb-color 1 0 0 1.00) + \override Staff.BarLine.color = #(rgb-color 1 0 0 1.00) + \override Score.BarNumber.color = #(rgb-color 1 0 0 1.00) + \override Staff.TimeSignature.color = #(rgb-color 0 0 1 1.00) + \override Staff.Clef.color = #(rgb-color 0 0 1 1.00) + \override Voice.NoteHead.color = #(rgb-color 0 1 0 1.00) + \override Voice.Stem.color = #(rgb-color 0 1 0 1.00) + \override Voice.Beam.color = #(rgb-color 0 1 0 1.00) + \override Lyrics.LyricText.color = #(rgb-color 0 0 0 1.00) + \repeat unfold 2 { a1 2 2 4 4 4 4 8 8 8 8 8 8 8 8} \bar "|." +} \addlyrics { \repeat unfold 30 { foo } } + +\markup { + \with-dimensions #'(-0 . 0) #'(0 . 0){\column{\vspace #-24 \rotate #55 \with-color #(rgb-color 1 0 1 0.5) \fill-line { \fontsize #18 "Transparency Test" }} +}} -- 2.29.2