Module: Prawn::SoftMask

Included in:
Document
Defined in:
lib/prawn/soft_mask.rb

Overview

This module is used to create arbitrary transparency in document. Using a soft mask allows creating more visually rich documents.

Stable API collapse

Instance Method Details

#soft_mask { ... } ⇒ void

This method returns an undefined value.

Apply soft mask.

You must group soft mask and graphics it’s applied to under save_graphics_state because soft mask is a part of graphic state in PDF.

Note that soft mask is applied only to the following content in the graphic state. Anything that comes before soft_mask is drawn without mask.

Conceptually, soft mask is an alpha channel. Luminosity of the drawing in the soft mask defines the transparency of the drawing the mask is applied to. 0.0 mask luminosity (“black”) results in a fully opaque target image and 1.0 mask luminosity (“white”) results in a fully transparent target image. Grey values result in some semi-transparent target image.

Note: you can use color in mask drawings but it makes harder to reason about the resulting value of alpha channel as it requires an additional luminosity calculation. However, this also allows achieving some advanced artistic effects (e.g. full-color photos in masks to get an effect similar to double exposure).

Examples:

pdf.save_graphics_state do
  pdf.soft_mask do
    pdf.fill_color "444444"
    pdf.fill_polygon [0, 40], [60, 10], [120, 40], [60, 68]
  end
  pdf.fill_color '000000'
  pdf.fill_rectangle [0, 50], 120, 68
end

Yields:

  • Mask content.

Source Code
lib/prawn/soft_mask.rb, line 42
42
def soft_mask(&block)
43
  renderer.min_version(1.4)
44
45
  group_attrs = ref!(
46
    Type: :Group,
47
    S: :Transparency,
48
    CS: :DeviceRGB,
49
    I: false,
50
    K: false,
51
  )
52
53
  group = ref!(
54
    Type: :XObject,
55
    Subtype: :Form,
56
    BBox: state.page.dimensions,
57
    Group: group_attrs,
58
  )
59
60
  state.page.stamp_stream(group, &block)
61
62
  mask = ref!(
63
    Type: :Mask,
64
    S: :Luminosity,
65
    G: group,
66
  )
67
68
  g_state = ref!(
69
    Type: :ExtGState,
70
    SMask: mask,
71
72
    AIS: false,
73
    BM: :Normal,
74
    OP: false,
75
    op: false,
76
    OPM: 1,
77
    SA: true,
78
  )
79
80
  registry_key = {
81
    bbox: state.page.dimensions,
82
    mask: [group.stream.filters.normalized, group.stream.filtered_stream],
83
    page: state.page_count,
84
  }.hash
85
86
  if soft_mask_registry[registry_key]
87
    renderer.add_content("/#{soft_mask_registry[registry_key]} gs")
88
  else
89
    masks = page.resources[:ExtGState] ||= {}
90
    id = masks.empty? ? 'GS1' : masks.keys.max.succ
91
    masks[id] = g_state
92
93
    soft_mask_registry[registry_key] = id
94
95
    renderer.add_content("/#{id} gs")
96
  end
97
end