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
|
# coding: utf-8
# typed: strict
# frozen_string_literal: true
module PDF
class Reader
# PDFs represent rectangles all over the place. They're 4 element arrays, like this:
#
# [A, B, C, D]
#
# Four element arrays are yucky to work with though, so here's a class that's better.
# Initialize it with the 4 elements, and get utility functions (width, height, etc)
# for free.
#
# By convention the first two elements are x1, y1, the co-ords for the bottom left corner
# of the rectangle. The third and fourth elements are x2, y2, the co-ords for the top left
# corner of the rectangle. It's valid for the alternative corners to be used though, so
# we don't assume which is which.
#
class Rectangle
#: PDF::Reader::Point
attr_reader :bottom_left
#: PDF::Reader::Point
attr_reader :bottom_right
#: PDF::Reader::Point
attr_reader :top_left
#: PDF::Reader::Point
attr_reader :top_right
#: (Numeric, Numeric, Numeric, Numeric) -> void
def initialize(x1, y1, x2, y2)
@bottom_left = Point.new(0,0) #: PDF::Reader::Point
@bottom_right = Point.new(0,0) #: PDF::Reader::Point
@top_left = Point.new(0,0) #: PDF::Reader::Point
@top_right = Point.new(0,0) #: PDF::Reader::Point
set_corners(x1, y1, x2, y2)
end
#: (Array[Numeric]) -> PDF::Reader::Rectangle
def self.from_array(arr)
if arr.size != 4
raise ArgumentError, "Only 4-element Arrays can be converted to a Rectangle"
end
PDF::Reader::Rectangle.new(
arr[0].to_f,
arr[1].to_f,
arr[2].to_f,
arr[3].to_f,
)
end
#: (PDF::Reader::Rectangle) -> bool
def ==(other)
to_a == other.to_a
end
#: () -> Numeric
def height
top_right.y - bottom_right.y
end
#: () -> Numeric
def width
bottom_right.x - bottom_left.x
end
#: (PDF::Reader::Point) -> bool
def contains?(point)
point.x >= bottom_left.x && point.x <= top_right.x &&
point.y >= bottom_left.y && point.y <= top_right.y
end
# A pdf-style 4-number array
#: () -> Array[Numeric]
def to_a
[
bottom_left.x,
bottom_left.y,
top_right.x,
top_right.y,
]
end
#: (Integer) -> void
def apply_rotation(degrees)
return if degrees != 90 && degrees != 180 && degrees != 270
if degrees == 90
new_x1 = bottom_left.x
new_y1 = bottom_left.y - width
new_x2 = bottom_left.x + height
new_y2 = bottom_left.y
elsif degrees == 180
new_x1 = bottom_left.x - width
new_y1 = bottom_left.y - height
new_x2 = bottom_left.x
new_y2 = bottom_left.y
elsif degrees == 270
new_x1 = bottom_left.x - height
new_y1 = bottom_left.y
new_x2 = bottom_left.x
new_y2 = bottom_left.y + width
end
set_corners(new_x1 || 0, new_y1 || 0, new_x2 || 0, new_y2 || 0)
end
private
#: (Numeric, Numeric, Numeric, Numeric) -> void
def set_corners(x1, y1, x2, y2)
@bottom_left = PDF::Reader::Point.new(
[x1, x2].min,
[y1, y2].min,
)
@bottom_right = PDF::Reader::Point.new(
[x1, x2].max,
[y1, y2].min,
)
@top_left = PDF::Reader::Point.new(
[x1, x2].min,
[y1, y2].max,
)
@top_right = PDF::Reader::Point.new(
[x1, x2].max,
[y1, y2].max,
)
end
end
end
end
|