Программирование на языке Ruby.
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("\001August 2001\001", :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 Address\n\n",
: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, имейте в виду, что библиотека еще развивается и пока не поддерживает спецификацию в полном объеме.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 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.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 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.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.
- 472.
- 473.
- 474.
- 475.
- 476.
- 477.
- 478.
- 479.
- 480.
- 481.
- 482.
- 483.
- 484.
- 485.
- 486.
- 487.
- 488.
- 489.
- 490.
- 491.
- 492.
- 493.
- 494.
- 495.
- 496.
- 497.
- 498.
- 499.
- 500.
- 501.
- 502.
- 503.
- 504.
- 505.
- 506.
- 507.
- 508.
- 509.
- 510.
- 511.
- 512.
- 513.
- 514.
- 515.
- 516.
- 517.
- 518.
- 519.
- 520.
- 521.
- 522.
- 523.
- 524.
- 525.
- 526.
- 527.
- 528.
- 529.
- 530.
- 531.
- 532.
- 533.
- 534.
- 535.
- 536.
- 537.
- 538.
- 539.
- 540.
- 541.
- 542.
- 543.
- 544.
- 545.
- 546.
- 547.
- 548.
- 549.
- 550.
- 551.
- 552.
- 553.
- 554.
- 555.
- 556.
- 557.
- 558.
- 559.
- 560.
- 561.
- 562.
- 563.
- 564.
- 565.
- 566.
- 567.
- 568.
- 569.
- 570.
- 571.
- 572.
- 573.