Class: Minicomic::BookletLayout

Inherits:
Object
  • Object
show all
Defined in:
lib/minicomic.rb

Instance Method Summary collapse

Constructor Details

#initialize(stream, *pages) ⇒ BookletLayout

Returns a new instance of BookletLayout.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/minicomic.rb', line 98

def initialize( stream, *pages )
  @bboxes = {}
  @stream = stream

  pages.push nil if pages.size % 2 != 0 # pad to even number of pages

  # move the back cover to the beginning, to be paired with the front cover
  pages.unshift pages.pop

  # pair up adjacent pages into spreads
  spreads = (0...(pages.size/2)).map { |i| [ pages[i*2], pages[i*2+1] ] }

  # format each spread, breaking spreads back into invdividual pages after
  pages = spreads.inject( [] ) do |acc, spread|
    is_cover = acc.empty?
    acc.push *format_pages( is_cover, *spread )
  end

  # return the back cover to the end
  pages.push pages.shift

  emit_document pages
end

Instance Method Details

#bbox(i, n, document) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/minicomic.rb', line 163

def bbox( i, n, document )
  rx, ry = @bboxes[document] ||= (
    rx, ry = 0.0..(FORMAT_WIDTH.to_f * n), 0.0..(FORMAT_HEIGHT.to_f)
    File.open( document, "r" ) do |stream|
      stream.each_line do |line|
        case line
        when /^%%BoundingBox: (\d+) (\d+) (\d+) (\d+)/
          rx, ry = ($1.to_f)..($3.to_f), ($2.to_f)..($4.to_f)
          break
        when /^%%EndComments/
          break
        end
      end
    end
    [ rx, ry ]
  )
  width = rx.end - rx.begin
  [ ( rx.begin + width * i / n )..( rx.begin + width * ( i + 1 ) / n ), ry ]
end

#bottom_margin(height) ⇒ Object



183
184
185
# File 'lib/minicomic.rb', line 183

def bottom_margin( height )
  ( FORMAT_HEIGHT.to_f - height ) / PHI
end

#emit_clip_rect(x0, y0, x1, y1) ⇒ Object



235
236
237
238
239
240
241
242
# File 'lib/minicomic.rb', line 235

def emit_clip_rect( x0, y0, x1, y1 )
  @stream.puts "newpath"
  @stream.puts "#{ x0 } #{ y0 } moveto"
  @stream.puts "#{ x0 } #{ y1 } lineto"
  @stream.puts "#{ x1 } #{ y1 } lineto"
  @stream.puts "#{ x1 } #{ y0 } lineto"
  @stream.puts "closepath eoclip newpath"
end

#emit_document(pages) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/minicomic.rb', line 216

def emit_document( pages )
  @stream.puts "%!PS-Adobe-3.0"
  emit_dsc 'Creator', 'minicomic'
  emit_dsc 'Pages', pages.size
  #emit_dsc 'Orientation', 'Portrait'
  #bbox = "0 0 #{ FORMAT_WIDTH } #{ FORMAT_HEIGHT }"
  #emit_dsc 'BoundingBox', bbox
  #emit_dsc 'HiResBoundingBox', bbox
  emit_dsc 'EndComments'
  pages.each_with_index do |page, n|
    if page
      emit_page( n, *page )
    else
      emit_empty_page( n )
    end
  end
  emit_dsc 'EOF'
end

#emit_dsc(name, value = nil) ⇒ Object



208
209
210
211
212
213
214
# File 'lib/minicomic.rb', line 208

def emit_dsc( name, value=nil )
  if value
    @stream.puts "%%#{ name }: #{ value }"
  else
    @stream.puts "%%#{ name }"
  end
end

#emit_empty_page(n) ⇒ Object



270
271
272
273
# File 'lib/minicomic.rb', line 270

def emit_empty_page( n )
  emit_dsc 'Page', "#{ n } #{ n }"
  @stream.puts "showpage"
end

#emit_page(n, bbox, translate, document) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/minicomic.rb', line 244

def emit_page( n, bbox, translate, document )
  emit_dsc 'Page', "#{ n } #{ n }"

  @stream.puts "save"

  emit_clip_rect( 0, 0, FORMAT_WIDTH, FORMAT_HEIGHT )

  @stream.puts <<EOS
#{ bbox.map { |r| -r.begin }.join( ' ' ) } translate 
#{ PAGE_SCALE } #{ PAGE_SCALE } scale
#{ translate.join( ' ' ) } translate
EOS

  emit_clip_rect( bbox[0].begin, bbox[1].begin, bbox[0].end, bbox[1].end )

  emit_dsc 'BeginDocument', File.basename( document )
  File.open( document, 'r' ) do |input|
    input.each_line do |line|
      @stream.puts line
    end
  end
  emit_dsc 'EndDocument'
  emit_dsc 'PageTrailer'
  @stream.puts "restore"
end

#format_pages(is_cover, *pages) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/minicomic.rb', line 122

def format_pages( is_cover, *pages )
  spread = pages.map do |page|
    if page
      [ bbox(*page), page[2] ]
    else
      nil
    end
  end.map do |page|
    if page
      bbox, document = page
      dims = (0..1).map { |d| ( bbox[d].end - bbox[d].begin ) * PAGE_SCALE }
      [ bbox, dims, document ]
    else
      nil
    end
  end

  if spread.all? # i.e. both?
    spread_dims = spread.map { |page| page[1] }
    left_document = spread[LEFT][2]
    right_document = spread[RIGHT][2]
    if left_document == right_document
      tx = translate_spread( *spread_dims )
    elsif is_cover
      tx = spread_dims.map { |dims| translate_single( dims ) }
    else
      tx = translate_facing( *spread_dims )
    end
    [ [ spread[LEFT][0], tx[LEFT], left_document ],
      [ spread[RIGHT][0], tx[RIGHT], right_document ] ]
  else
    spread.map do |page|
      if page
        [ page[0], translate_single( page[1] ), page[2] ]
      else
        nil
      end
    end
  end
end

#horizontal_margin(width) ⇒ Object



187
188
189
# File 'lib/minicomic.rb', line 187

def horizontal_margin( width )
  ( FORMAT_WIDTH.to_f - width ) / 2
end

#translate_facing(left, right) ⇒ Object



195
196
197
198
199
200
201
# File 'lib/minicomic.rb', line 195

def translate_facing( left, right )
  left_margin = horizontal_margin( left[0] )
  right_margin = horizontal_margin( right[0] )
  gutter = [ [ left_margin, right_margin ].min, 0 ].max
  [ [ left_margin + ( gutter / 3 ), bottom_margin( left[1] ) ],
    [ right_margin - ( gutter / 3 ), bottom_margin( right[1] ) ] ]
end

#translate_single(dims) ⇒ Object



191
192
193
# File 'lib/minicomic.rb', line 191

def translate_single( dims )
  [ horizontal_margin( dims[0] ), bottom_margin( dims[1] ) ]
end

#translate_spread(left, right) ⇒ Object



203
204
205
206
# File 'lib/minicomic.rb', line 203

def translate_spread( left, right )
  [ [ FORMAT_WIDTH.to_f - left[0], bottom_margin( left[1] ) ],
    [ 0, bottom_margin( right[1] ) ] ]
end