Книга: Программирование на языке Ruby

15.4.2. Пример документа

15.4.2. Пример документа

Для демонстрации рассмотренной выше техники мы создадим четыре страницы в четырех разных квадрантах. Три из них — слегка измененные варианты демонстрационных программ, включённых в дистрибутив PDF::Writer:

demo.rb, квадрант 1

individual-i.rb, квадрант 3

gettysburg.rb, квадрант 4

Четвертая страница (в квадранте 2) не имеет прямого аналога среди демонстрационных программ, она ближе всего к программе chunkybacon.rb.

Весь код приведен в листинге 15.11, а результат показан на рис. 15.4. Пример довольно длинный, мы подробно обсудим его ниже.

Листинг 15.11. Создание демонстрационного документа

require 'rubygems'
require 'pdf/writer'
def quadrant(pdf, quad)
 raise unless block_given?
 mx = pdf.absolute_x_middle
 my = pdf.absolute_y_middle
 pdf.save_state
 case quad
  when :ul
   pdf.translate_axis 0, my
  when :ur
   pdf.translate_axis mx, my
  when :ll
   nil # no translation needed
  when :lr
   pdf.translate_axis mx, 0
 end
 pdf.scale_axis(0.5, 0.5)
 pdf.у = pdf.page_height
 yield
 pdf.restore_state
end
pdf = PDF::Writer.new
pdf.select_font("Times-Roman",
 rencoding => "WinAnsiEncoding",
 differences => { 0x01 => "lozenge" })
mx = pdf.absolute_x_middle
my = pdf.absolute_y_middle
pdf.line(0, my, pdf.page_width, my).stroke
pdf.line(mx, 0, mx, pdf.page_height).stroke
# Левый верхний: Demo (UL).
quadrant(pdf, :ul) do
 x = pdf.absolute_right_margin
 r1 = 25
 40.step(1, -3) do |xw|
  tone = 1.0 - (xw / 40.0) * 0.2
  pdf.stroke_style(PDF::Writer::StrokeStyle.new(xw))
  pdf.stroke_color(Color::RGB.from_fraction(1, tone, tone))
  pdf.line(x, pdf.bottom_margin, x,
   pdf.absolute_top_margin).stroke
  x -= xw+2
 end
 40.step(1, -3) do |xw|
  tone = 1.0 - (xw / 40.0) * 0.2
  pdf.stroke_style(PDF::Writer::StrokeStyle.new(xw))
  pdf.stroke_color(Color::RGB.from_fraction(1, tone, tone))
  pdf.circle_at(pdf.left_margin + 10, pdf.margin_height - 15,
   r1).stroke
  r1 += xw
 end
 pdf.stroke_color(Color::RGB::Black)
 x = pdf.absolute_left_margin
 y = pdf.absolute_bottom_margin
 w = pdf.margin_width
 h = pdf.margin_height
 pdf.rectangle(x, y, w, h).stroke
 text = "The Ruby Way"
 y = pdf.absolute_top_margin
 50.step(5, -5) do |size|
  height = pdf.font_height(size)
  y -= height
  pdf.add_text(pdf.left_margin + 10, y, text, size)
 end
 (0...360).step(20) do |angle|
  pdf.fill_color(Color::RGB.from_fraction(rand, rand, rand))
  pdf.add_text(300 + Math.cos(PDF::Math.deg2rad(angle)) * 40,
   300 + Math.sin(PDF::Math.deg2rad(angle)) * 40,
   text, 20, angle)
 end
end
pdf.fill_color Color::RGB::Black
# Правый верхний: Grampian Highlands (UR).
quadrant(pdf, :ur) do
 pdf.image("grampian-highlands.jpg",
  :height => pdf.margin_height,
  :resize => :width)
 pdf.text("The Grampian Highlands, Scotland",
  justification => :center,
  :font_size => 36)
 pdf.text("01August 200101", :justification => :center,
  :font_size => 24)
 pdf.move_pointer(24)
 info = <<-'EOS'.split($/).join(" ").squeeze(" ")
This picture was taken during a driving vacation through the
Scottish highlands in August 2001 by Austin Ziegler.
 EOS
 pdf.text(info, :justification => :full, :font_size => 16,
  :left => 100, :right => 100)
end
pdf.fill_color Color::RGB::Black
# Левый нижний: Individual-I (LL).
quadrant(pdf, :ll) do
 require 'color/palette/monocontrast'
 class IndividualI
  def initialize(size = 100)
   @size = size
  end
  # Размер буквы "i" в пунктах.
  attr_accessor :size
  def half_i(pdf)
   pdf.move_to(0, 82)
   pdf.line_to(0, 78)
   pdf.line_to(9, 78)
   pdf.line_to(9, 28)
   pdf.line_to(0, 28)
   pdf.line_to(0, 23)
   pdf.line_to(18, 23)
   pdf.line_to(18, 82)
   pdf.fill
  end
  private :half_i
  def draw(pdf, x, y)
   pdf.save_state
   pdf.translate_axis(x, y)
   pdf.scale_axis(1 * (@size / 100.0), -1 * (@size / 100.0))
   pdf.circle_at(20, 10, 7.5)
   pdf.fill
   half_i(pdf)
   pdf.translate_axis(40, 0)
   pdf.scale_axis(-1, 1)
   half_i(pdf)
   pdf.restore_state
  end
 end
 ii = IndividualI.new(24)
 x = pdf.absolute_left_margin
 y = pdf.absolute_top_margin
 bg = Color::RGB.from_fraction(rand, rand, rand)
 fg = Color::RGB.from_fraction(rand, rand, rand)
 pal = Color::Palette::MonoContrast.new(bg, fg)
 sz = 24
 (-5..5).each do |col|
  pdf.fill_color pal.background[col]
  ii.draw(pdf, x, y)
  ii.size += sz
  x += sz / 2.0
  y -= sz / 2.0
  pdf.fill_color
  pal.foreground[col]
  ii.draw(pdf, x, y)
  x += sz / 2.0
  y -= sz / 2.0
  ii.size += sz
 end
end
pdf.fill_color Color::RGB::Black
# Правый нижний: Gettysburg Address (LR).
# Это текст Геттисбергского обращения Авраама Линкольна.
quadrant(pdf, :lr) do
 pdf.text("The Gettysburg Addressnn",
  :font_size => 36, justification => :center)
 y0 = pdf.y + 18
 speech = <<-'EOS'.split($/). join(" ").squeeze(" ")
Four score and seven years ago our fathers brought forth on
this continent a new nation, conceived in liberty and
dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war, testing whether
that nation or any nation so conceived and so dedicated can
long endure. We are met on a great battlefield of that war.
We have come to dedicate a portion of that field as a final
resting-place for those who here gave their lives that that
nation might live. It is altogether fitting and proper that
we should do this. But in a larger sense, we cannot
dedicate, we cannot consecrate, we cannot hallow
this ground. The brave men, living and dead who struggled here
have consecrated it far above our poor power to add or
detract. The world will little note nor long remember what
we say here, but it can never forget what they did here. It
is for us the living rather to be dedicated here to the
unfinished work which they who fought here have thus far so
nobly advanced. It is rather for us to be here dedicated to
the great task remaining before us that from these honored
dead we take increased devotion to that cause for which they
gave the last full measure of devotion that we here highly
resolve that these dead shall not have died in vain, that
this nation under God shall have a new birth of freedom, and
that government of the people, by the people, for the people
shall not perish from the earth.
EOS
 pdf.text(speech, justification => :full, :font_size => 14,
  :left => 50, :right => 50)
 pdf.move_pointer(36)
 pdf.text("U.S. President Abraham Lincoln, 19 November 1863",
  :justification => :right, :right => 100)
 pdf.text("Gettysburg, Pennsylvania", :justification => :right,
  :right => 100)
 pdf.rounded_rectangle(pdf.left_margin + 25, y0, pdf.margin_width - 50,
  y0 - pdf.y + 18, 10).stroke
end
pdf.save_as("4page.pdf")


Рис. 15.4. Пример документа, состоящего из четырех страниц в разных квадрантах

Итак, в четырех квадрантах расположены следующие страницы:

• левый верхний: demo.rb;

• правый верхний: фотография Грампианских холмов, Шотландия;

• левый нижний: individual-i.rb;

• правый нижний: Геттисбергское обращение.

Для краткости будем называть эти квадранты UL, UR, LL и LR. В тексте программы используются соответствующие символы (:ul и т.д.).

Первый квадрант (UL) заполнен вертикальными линиями, толщина которых постепенно уменьшается, начиная с 40 единиц, с одновременным осветлением. Затем рисуются круги увеличивающегося радиуса, при этом толщина линий уменьшается, а цвет становится светлее. И наконец, выводятся два набора текстов: один — сверху вниз с постепенным уменьшением размера шрифта, а другой — с поворотом вокруг центральной оси как раз там, где кончаются вертикальные линии.

Страница во втором квадранте (UR) содержит картинку и ее описание. Особый интерес представляет строка с датой. Мы вставляем в поток байт с кодом 0x01; при отображении вместо него будет поставлен символ ромба в соответствии с таблицей замены, заданной при выборе шрифта.

В третьем квадранте (UR) с помощью программы Individual-I мы снова демонстрируем технику переноса осей и масштабирования. Самое интересное здесь — инверсия осей. Если по оси выбирается отрицательный масштаб, то команды вывода текста и рисования меняют направление. Следовательно, при рисовании буквы I достаточно задать лишь правила формирования половины рисунка, а потом инвертировать ось X, вызвав метод pdf.scale_axis(-1, 1), и повторить ту же последовательность операций.

Последний квадрант (LR) заполняется сравнительно легко. Мы форматируем и заключаем в прямоугольник со скругленными углами текст речи, которую президент Линкольн произнес в Геттисберге.

Сохранение PDF-документа — воплощенная простота. Если нужно записать его на диск, мы вызываем метод save_as объекта PDF:

pdf.save_as("4page.pdf")

Нетрудно также отправить PDF-документ браузеру из CGI-программы:

require 'cgi'
cgi = CGI.new
out = pdf.render
puts <<-EOS
Content-Type: application/pdf
Content-Disposition: inline; filename="4page.pdf"
Size: #{out.size}
EOS

Конечно, в этом разделе мы сумели затронуть лишь малую толику библиотеки PDF::Writer. Дополнительную информацию ищите в онлайновой документации. Если вы знакомы с форматом PDF, имейте в виду, что библиотека еще развивается и пока не поддерживает спецификацию в полном объеме.

Оглавление книги


Генерация: 0.542. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз