parse content streams into a list of operators
This commit is contained in:
parent
13dcea1dab
commit
aba6368948
5 changed files with 1541 additions and 408 deletions
|
|
@ -1,6 +1,813 @@
|
|||
use crate::pdf::object::PdfStream;
|
||||
use crate::{
|
||||
pdf::{
|
||||
PdfObjectOrStreamDictionaryOrOperator, PdfObjects, PdfParser, PdfTokenizer,
|
||||
object::{
|
||||
NameOr, PdfDictionary, PdfMatrix, PdfName, PdfObject, PdfObjectDirect, PdfRectangle,
|
||||
PdfStream, PdfStreamContents, PdfString, PdfStringBytesDebug, PdfStringOrNumber,
|
||||
PdfVec2D,
|
||||
},
|
||||
parse::{
|
||||
GetPdfInputPosition, PdfInputPosition, PdfInputPositionKnown,
|
||||
PdfInputPositionNoCompare, PdfParse, PdfParseError,
|
||||
},
|
||||
},
|
||||
util::ArcOrRef,
|
||||
};
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
pub struct PdfContentStream {
|
||||
stream: PdfStream,
|
||||
// TODO
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PdfOperatorUnparsed {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
bytes: ArcOrRef<'static, [u8]>,
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfOperatorUnparsed {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfOperatorUnparsed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Self::debug_with_name("PdfOperatorUnparsed", &self.bytes, self.pos.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
trait PdfParseIter: Sized {
|
||||
fn parse_iter(iter: impl IntoIterator<Item = PdfObject>) -> Result<Self, PdfParseError>;
|
||||
}
|
||||
|
||||
impl<T: PdfParse> PdfParseIter for Arc<[T]> {
|
||||
fn parse_iter(iter: impl IntoIterator<Item = PdfObject>) -> Result<Self, PdfParseError> {
|
||||
FromIterator::from_iter(iter.into_iter().map(T::parse))
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfOperatorUnparsed {
|
||||
pub fn new(
|
||||
pos: impl Into<PdfInputPositionNoCompare>,
|
||||
bytes: impl Into<ArcOrRef<'static, [u8]>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
bytes: bytes.into(),
|
||||
}
|
||||
}
|
||||
pub const fn new_static(bytes: &'static [u8]) -> Self {
|
||||
Self {
|
||||
pos: PdfInputPositionNoCompare::empty(),
|
||||
bytes: ArcOrRef::Ref(bytes),
|
||||
}
|
||||
}
|
||||
pub fn pos(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
pub fn bytes(&self) -> &ArcOrRef<'static, [u8]> {
|
||||
&self.bytes
|
||||
}
|
||||
fn debug_with_name(
|
||||
name: &str,
|
||||
pdf_name: &[u8],
|
||||
pos: PdfInputPosition,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(f, "{name}(at {pos}, {})", PdfStringBytesDebug(pdf_name))
|
||||
}
|
||||
pub fn bytes_debug(&self) -> PdfStringBytesDebug<'_> {
|
||||
PdfStringBytesDebug(&self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_pdf_operator_enum {
|
||||
(
|
||||
$(#[$($operator_meta:tt)*])*
|
||||
$operator_enum_vis:vis enum $PdfOperator:ident;
|
||||
|
||||
$(#[$($operator_and_operands_meta:tt)*])*
|
||||
$enum_vis:vis enum $PdfOperatorAndOperands:ident {
|
||||
$(#[$($unknown_variant_meta:tt)*])*
|
||||
$Unknown:ident {
|
||||
$(#[$($unknown_operands_meta:tt)*])*
|
||||
$unknown_operands:ident: $unknown_operands_ty:ty,
|
||||
$(#[$($unknown_operator_meta:tt)*])*
|
||||
$unknown_operator:ident: $unknown_operator_ty:ty,
|
||||
},
|
||||
$(
|
||||
#[kw = $kw:literal]
|
||||
$(#[$($variant_meta:tt)*])*
|
||||
$Variant:ident($VariantStruct:ident {
|
||||
$pos:ident: PdfInputPositionNoCompare,
|
||||
$(
|
||||
#[$field_parse:ident($($parse_args:tt)*)]
|
||||
$(#[$($field_meta:tt)*])*
|
||||
$field:ident: $field_ty:ty,
|
||||
)*
|
||||
}),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$($operator_meta)*])*
|
||||
$operator_enum_vis enum $PdfOperator {
|
||||
$(#[$($unknown_variant_meta)*])*
|
||||
$Unknown($unknown_operator_ty),
|
||||
$(
|
||||
$(#[$($variant_meta)*])*
|
||||
$Variant(PdfInputPositionNoCompare),
|
||||
)*
|
||||
}
|
||||
|
||||
impl $PdfOperator {
|
||||
$operator_enum_vis fn parse(self, operands: impl IntoIterator<Item = PdfObject>) -> Result<$PdfOperatorAndOperands, PdfParseError> {
|
||||
let operands = operands.into_iter();
|
||||
Ok(match self {
|
||||
Self::$Unknown(operator) => $PdfOperatorAndOperands::$Unknown {
|
||||
operands: FromIterator::from_iter(operands.map(Into::into)),
|
||||
operator,
|
||||
},
|
||||
$(Self::$Variant(pos) => $VariantStruct::parse(pos, operands)?.into(),)*
|
||||
})
|
||||
}
|
||||
$operator_enum_vis fn pos(&self) -> PdfInputPosition {
|
||||
match *self {
|
||||
Self::$Unknown(ref operator) => operator.pos(),
|
||||
$(Self::$Variant(pos) => pos.0,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $PdfOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::$Unknown(operator) => PdfOperatorUnparsed::debug_with_name("Unknown", &operator.bytes, operator.pos.0, f),
|
||||
$(Self::$Variant(pos) => PdfOperatorUnparsed::debug_with_name(stringify!($Variant), $kw, pos.0, f),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$PdfOperator> for PdfOperatorUnparsed {
|
||||
fn from(v: $PdfOperator) -> PdfOperatorUnparsed {
|
||||
match v {
|
||||
$PdfOperator::$Unknown(operator) => operator,
|
||||
$($PdfOperator::$Variant(pos) => PdfOperatorUnparsed { pos, bytes: ArcOrRef::Ref($kw) },)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PdfOperatorUnparsed> for $PdfOperator {
|
||||
fn from(v: PdfOperatorUnparsed) -> $PdfOperator {
|
||||
match &**v.bytes() {
|
||||
$($kw => Self::$Variant(v.pos),)*
|
||||
_ => Self::$Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(#[derive(Clone)]
|
||||
$(#[$($variant_meta)*])*
|
||||
$enum_vis struct $VariantStruct {
|
||||
$enum_vis $pos: PdfInputPositionNoCompare,
|
||||
$(
|
||||
$(#[$($field_meta)*])*
|
||||
$enum_vis $field: $field_ty,
|
||||
)*
|
||||
}
|
||||
|
||||
impl fmt::Debug for $VariantStruct {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct(stringify!($VariantStruct)).field("pos", &self.pos)$(.field(stringify!($field), &self.$field))*.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for $VariantStruct {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$VariantStruct> for $PdfOperatorAndOperands {
|
||||
fn from(v: $VariantStruct) -> Self {
|
||||
Self::$Variant(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl $VariantStruct {
|
||||
$enum_vis fn operator_from_pos(pos: impl Into<PdfInputPositionNoCompare>) -> $PdfOperator {
|
||||
$PdfOperator::$Variant(pos.into())
|
||||
}
|
||||
$enum_vis fn operator(&self) -> $PdfOperator {
|
||||
$PdfOperator::$Variant(self.pos)
|
||||
}
|
||||
$enum_vis fn pos(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
make_pdf_operator_enum! {
|
||||
@impl_variant_parse
|
||||
$enum_vis enum;
|
||||
struct $VariantStruct {
|
||||
$pos: PdfInputPositionNoCompare,
|
||||
$(
|
||||
#[$field_parse($($parse_args)*)]
|
||||
$(#[$($field_meta)*])*
|
||||
$field: $field_ty,
|
||||
)*
|
||||
}
|
||||
})*
|
||||
|
||||
$(#[$($operator_and_operands_meta)*])*
|
||||
$enum_vis enum $PdfOperatorAndOperands {
|
||||
$(#[$($unknown_variant_meta)*])*
|
||||
$Unknown {
|
||||
$(#[$($unknown_operands_meta)*])*
|
||||
$unknown_operands: $unknown_operands_ty,
|
||||
$(#[$($unknown_operator_meta)*])*
|
||||
$unknown_operator: $unknown_operator_ty,
|
||||
},
|
||||
$(
|
||||
$(#[$($variant_meta)*])*
|
||||
$Variant($VariantStruct),
|
||||
)*
|
||||
}
|
||||
|
||||
impl $PdfOperatorAndOperands {
|
||||
$enum_vis fn operator(&self) -> $PdfOperator {
|
||||
match self {
|
||||
Self::Unknown { operator, .. } => $PdfOperator::Unknown(operator.clone()),
|
||||
$(Self::$Variant(v) => v.operator(),)*
|
||||
}
|
||||
}
|
||||
$enum_vis fn pos(&self) -> PdfInputPosition {
|
||||
match self {
|
||||
Self::$Unknown { operator, .. } => operator.pos(),
|
||||
$(Self::$Variant(v) => v.pos(),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $PdfOperatorAndOperands {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::$Unknown {
|
||||
operands,
|
||||
operator,
|
||||
} => f.debug_struct("Unknown").field("operator", operator).field("operands", operands).finish(),
|
||||
$(Self::$Variant($VariantStruct {
|
||||
$pos,
|
||||
$($field,)*
|
||||
}) => f.debug_struct(stringify!($Variant)).field("pos", $pos)$(.field(stringify!($field), $field))*.finish(),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
@impl_variant_parse
|
||||
$enum_vis:vis enum;
|
||||
struct $VariantStruct:ident {
|
||||
$pos:ident: PdfInputPositionNoCompare,
|
||||
$(
|
||||
#[$field_parse:ident($($parse_args:ident),* $(,)?)]
|
||||
$(#[$($field_meta:tt)*])*
|
||||
$field:ident: $field_ty:ty,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
impl $VariantStruct {
|
||||
$enum_vis fn parse(pos: impl Into<PdfInputPositionNoCompare>, operands: impl IntoIterator<Item = PdfObject>) -> Result<Self, PdfParseError> {
|
||||
let pos = pos.into();
|
||||
let mut operands = operands.into_iter();
|
||||
$($(let Some($parse_args) = operands.next() else {
|
||||
return Err(PdfParseError::OperatorHasTooFewOperands { operator: Self::operator_from_pos(pos) });
|
||||
};)*)*
|
||||
if operands.next().is_some() {
|
||||
return Err(PdfParseError::OperatorHasTooManyOperands { operator: Self::operator_from_pos(pos) });
|
||||
}
|
||||
Ok(Self {
|
||||
pos,
|
||||
$($field: <$field_ty>::$field_parse($($parse_args),*)?,)*
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
@impl_variant_parse
|
||||
$enum_vis:vis enum;
|
||||
struct $VariantStruct:ident {
|
||||
$pos:ident: PdfInputPositionNoCompare,
|
||||
#[$field_parse:ident(...)]
|
||||
$(#[$($field_meta:tt)*])*
|
||||
$field:ident: $field_ty:ty,
|
||||
}
|
||||
) => {
|
||||
impl $VariantStruct {
|
||||
$enum_vis fn parse(pos: impl Into<PdfInputPositionNoCompare>, operands: impl IntoIterator<Item = PdfObject>) -> Result<Self, PdfParseError> {
|
||||
let pos = pos.into();
|
||||
let operands = operands.into_iter();
|
||||
Ok(Self {
|
||||
pos,
|
||||
$field: <$field_ty>::$field_parse(operands)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_pdf_operator_enum! {
|
||||
#[derive(Clone)]
|
||||
pub enum PdfOperator;
|
||||
#[derive(Clone)]
|
||||
pub enum PdfOperatorAndOperands {
|
||||
Unknown {
|
||||
operands: Arc<[PdfObjectDirect]>,
|
||||
operator: PdfOperatorUnparsed,
|
||||
},
|
||||
#[kw = b"b"]
|
||||
CloseFillAndStrokePath(PdfOperatorCloseFillAndStrokePath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"B"]
|
||||
FillAndStrokePath(PdfOperatorFillAndStrokePath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"b*"]
|
||||
CloseFillAndStrokePathEvenOdd(PdfOperatorCloseFillAndStrokePathEvenOdd {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"B*"]
|
||||
FillAndStrokePathEvenOdd(PdfOperatorFillAndStrokePathEvenOdd {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"BDC"]
|
||||
BeginMarkedContentWithProperties(PdfOperatorBeginMarkedContentWithProperties {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(tag)]
|
||||
tag: PdfName,
|
||||
#[parse(properties)]
|
||||
properties: NameOr<PdfDictionary>,
|
||||
}),
|
||||
#[kw = b"BI"]
|
||||
BeginInlineImage(PdfOperatorBeginInlineImage {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"BMC"]
|
||||
BeginMarkedContent(PdfOperatorBeginMarkedContent {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(tag)]
|
||||
tag: PdfName,
|
||||
}),
|
||||
#[kw = b"BT"]
|
||||
BeginText(PdfOperatorBeginText {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"BX"]
|
||||
BeginCompatibilitySection(PdfOperatorBeginCompatibilitySection {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"c"]
|
||||
CurveTo(PdfOperatorCurveTo {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x1, y1)]
|
||||
p1: PdfVec2D,
|
||||
#[parse(x2, y2)]
|
||||
p2: PdfVec2D,
|
||||
#[parse(x3, y3)]
|
||||
p3: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"cm"]
|
||||
ConcatMatrix(PdfOperatorConcatMatrix {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_flat(a, b, c, d, e, f)]
|
||||
matrix: PdfMatrix,
|
||||
}),
|
||||
#[kw = b"CS"]
|
||||
SetStrokeColorSpace(PdfOperatorSetStrokeColorSpace {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(name)]
|
||||
name: PdfName,
|
||||
}),
|
||||
#[kw = b"cs"]
|
||||
SetNonStrokeColorSpace(PdfOperatorSetNonStrokeColorSpace {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(name)]
|
||||
name: PdfName,
|
||||
}),
|
||||
#[kw = b"d"]
|
||||
SetLineDashPattern(PdfOperatorSetLineDashPattern {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(dash_array)]
|
||||
dash_array: PdfObject, // TODO: actually parse
|
||||
#[parse(dash_phase)]
|
||||
dash_phase: PdfObject, // TODO: actually parse
|
||||
}),
|
||||
#[kw = b"d0"]
|
||||
FontType3SetWidth(PdfOperatorFontType3SetWidth {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
width: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"d1"]
|
||||
FontType3SetWidthAndBBox(PdfOperatorFontType3SetWidthAndBBox {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(width_x, width_y)]
|
||||
width: PdfVec2D,
|
||||
#[parse_flat(lower_left_x, lower_left_y, upper_right_x, upper_right_y)]
|
||||
bbox: PdfRectangle,
|
||||
}),
|
||||
#[kw = b"Do"]
|
||||
PaintXObject(PdfOperatorPaintXObject {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(name)]
|
||||
name: PdfName,
|
||||
}),
|
||||
#[kw = b"DP"]
|
||||
DesignateMarkedContentPointWithProperties(PdfOperatorDesignateMarkedContentPointWithProperties {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(tag)]
|
||||
tag: PdfName,
|
||||
#[parse(properties)]
|
||||
properties: NameOr<PdfDictionary>,
|
||||
}),
|
||||
#[kw = b"EI"]
|
||||
EndInlineImage(PdfOperatorEndInlineImage {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"EMC"]
|
||||
EndMarkedContent(PdfOperatorEndMarkedContent {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"ET"]
|
||||
EndText(PdfOperatorEndText {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"EX"]
|
||||
EndCompatibilitySection(PdfOperatorEndCompatibilitySection {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"f"]
|
||||
FillPath(PdfOperatorFillPath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"F"]
|
||||
FillPathObsolete(PdfOperatorFillPathObsolete {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"f*"]
|
||||
FillPathEvenOdd(PdfOperatorFillPathEvenOdd {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"G"]
|
||||
SetStrokeGray(PdfOperatorSetStrokeGray {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(gray)]
|
||||
gray: f32,
|
||||
}),
|
||||
#[kw = b"g"]
|
||||
SetNonStrokeGray(PdfOperatorSetNonStrokeGray {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(gray)]
|
||||
gray: f32,
|
||||
}),
|
||||
#[kw = b"gs"]
|
||||
SetGraphicsState(PdfOperatorSetGraphicsState {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(dictionary_name)]
|
||||
dictionary_name: PdfName,
|
||||
}),
|
||||
#[kw = b"h"]
|
||||
CloseSubpath(PdfOperatorCloseSubpath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"i"]
|
||||
SetFlatnessTolerance(PdfOperatorSetFlatnessTolerance {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(flatness)]
|
||||
flatness: f32,
|
||||
}),
|
||||
#[kw = b"ID"]
|
||||
BeginInlineImageData(PdfOperatorBeginInlineImageData {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"j"]
|
||||
SetLineJoinStyle(PdfOperatorSetLineJoinStyle {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(line_join_style)]
|
||||
line_join_style: u8, // TODO parse
|
||||
}),
|
||||
#[kw = b"J"]
|
||||
SetLineCapStyle(PdfOperatorSetLineCapStyle {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(line_cap_style)]
|
||||
line_cap_style: u8, // TODO parse
|
||||
}),
|
||||
#[kw = b"K"]
|
||||
SetStrokeCmyk(PdfOperatorSetStrokeCmyk {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(c)]
|
||||
c: f32,
|
||||
#[parse(m)]
|
||||
m: f32,
|
||||
#[parse(y)]
|
||||
y: f32,
|
||||
#[parse(k)]
|
||||
k: f32,
|
||||
}),
|
||||
#[kw = b"k"]
|
||||
SetNonStrokeCmyk(PdfOperatorSetNonStrokeCmyk {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(c)]
|
||||
c: f32,
|
||||
#[parse(m)]
|
||||
m: f32,
|
||||
#[parse(y)]
|
||||
y: f32,
|
||||
#[parse(k)]
|
||||
k: f32,
|
||||
}),
|
||||
#[kw = b"l"]
|
||||
LineTo(PdfOperatorLineTo {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
to: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"m"]
|
||||
MoveTo(PdfOperatorMoveTo {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
to: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"M"]
|
||||
SetMiterLimit(PdfOperatorSetMiterLimit {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(limit)]
|
||||
limit: f32,
|
||||
}),
|
||||
#[kw = b"MP"]
|
||||
DesignateMarkedContentPoint(PdfOperatorDesignateMarkedContentPoint {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(tag)]
|
||||
tag: PdfName,
|
||||
}),
|
||||
#[kw = b"n"]
|
||||
EndPath(PdfOperatorEndPath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"q"]
|
||||
SaveGraphicsState(PdfOperatorSaveGraphicsState {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"Q"]
|
||||
RestoreGraphicsState(PdfOperatorRestoreGraphicsState {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"re"]
|
||||
Rectangle(PdfOperatorRectangle {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
p: PdfVec2D,
|
||||
#[parse(width, height)]
|
||||
size: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"RG"]
|
||||
SetStrokeRgb(PdfOperatorSetStrokeRgb {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(r)]
|
||||
r: f32,
|
||||
#[parse(g)]
|
||||
g: f32,
|
||||
#[parse(b)]
|
||||
b: f32,
|
||||
}),
|
||||
#[kw = b"rg"]
|
||||
SetNonStrokeRgb(PdfOperatorSetNonStrokeRgb {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(r)]
|
||||
r: f32,
|
||||
#[parse(g)]
|
||||
g: f32,
|
||||
#[parse(b)]
|
||||
b: f32,
|
||||
}),
|
||||
#[kw = b"ri"]
|
||||
SetColorRenderingIntent(PdfOperatorSetColorRenderingIntent {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(intent)]
|
||||
intent: PdfName,
|
||||
}),
|
||||
#[kw = b"s"]
|
||||
CloseAndStrokePath(PdfOperatorCloseAndStrokePath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"S"]
|
||||
StrokePath(PdfOperatorStrokePath {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"SC"]
|
||||
SetStrokeColor(PdfOperatorSetStrokeColor {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_iter(...)]
|
||||
color: Arc<[f32]>,
|
||||
}),
|
||||
#[kw = b"sc"]
|
||||
SetNonStrokeColor(PdfOperatorSetNonStrokeColor {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_iter(...)]
|
||||
color: Arc<[f32]>,
|
||||
}),
|
||||
#[kw = b"SCN"]
|
||||
SetStrokeColorWithName(PdfOperatorSetStrokeColorWithName {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_iter(...)]
|
||||
color_and_name: Arc<[NameOr<f32>]>,
|
||||
}),
|
||||
#[kw = b"scn"]
|
||||
SetNonStrokeColorWithName(PdfOperatorSetNonStrokeColorWithName {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_iter(...)]
|
||||
color_and_name: Arc<[NameOr<f32>]>,
|
||||
}),
|
||||
#[kw = b"sh"]
|
||||
Shade(PdfOperatorShade {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"T*"]
|
||||
TextNextLine(PdfOperatorTextNextLine {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"Tc"]
|
||||
SetCharacterSpacing(PdfOperatorSetCharacterSpacing {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(char_space)]
|
||||
char_space: f32,
|
||||
}),
|
||||
#[kw = b"Td"]
|
||||
TextNextLineWithOffset(PdfOperatorTextNextLineWithOffset {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
offset: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"TD"]
|
||||
TextNextLineWithOffsetAndLeading(PdfOperatorTextNextLineWithOffsetAndLeading {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(x, y)]
|
||||
offset: PdfVec2D,
|
||||
}),
|
||||
#[kw = b"Tf"]
|
||||
SetFontAndSize(PdfOperatorSetFontAndSize {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(font)]
|
||||
font: PdfName,
|
||||
#[parse(size)]
|
||||
size: f32,
|
||||
}),
|
||||
#[kw = b"Tj"]
|
||||
ShowText(PdfOperatorShowText {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(text)]
|
||||
text: PdfString,
|
||||
}),
|
||||
#[kw = b"TJ"]
|
||||
ShowTextWithGlyphPositioning(PdfOperatorShowTextWithGlyphPositioning {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(text_and_positioning)]
|
||||
text_and_positioning: Arc<[PdfStringOrNumber]>,
|
||||
}),
|
||||
#[kw = b"TL"]
|
||||
SetTextLeading(PdfOperatorSetTextLeading {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(leading)]
|
||||
leading: f32,
|
||||
}),
|
||||
#[kw = b"Tm"]
|
||||
SetTextMatrix(PdfOperatorSetTextMatrix {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse_flat(a, b, c, d, e, f)]
|
||||
matrix: PdfMatrix,
|
||||
}),
|
||||
#[kw = b"Tr"]
|
||||
SetTextRenderingMode(PdfOperatorSetTextRenderingMode {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(rendering_mode)]
|
||||
rendering_mode: u8, // TODO: parse
|
||||
}),
|
||||
#[kw = b"Ts"]
|
||||
SetTextRise(PdfOperatorSetTextRise {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(rise)]
|
||||
rise: f32,
|
||||
}),
|
||||
#[kw = b"Tw"]
|
||||
SetWordSpacing(PdfOperatorSetWordSpacing {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(word_space)]
|
||||
word_space: f32,
|
||||
}),
|
||||
#[kw = b"Tz"]
|
||||
SetTextHorizontalScaling(PdfOperatorSetTextHorizontalScaling {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(scale_percent)]
|
||||
scale_percent: f32,
|
||||
}),
|
||||
#[kw = b"v"]
|
||||
CurveTo23(PdfOperatorCurveTo23 {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"w"]
|
||||
SetLineWidth(PdfOperatorSetLineWidth {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(line_width)]
|
||||
line_width: f32,
|
||||
}),
|
||||
#[kw = b"W"]
|
||||
Clip(PdfOperatorClip {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"W*"]
|
||||
ClipEvenOdd(PdfOperatorClipEvenOdd {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"y"]
|
||||
CurveTo13(PdfOperatorCurveTo13 {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
}),
|
||||
#[kw = b"'"]
|
||||
TextNextLineAndShow(PdfOperatorTextNextLineAndShow {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(text)]
|
||||
text: PdfString,
|
||||
}),
|
||||
#[kw = b"\""]
|
||||
SetSpacingThenTextNextLineAndShow(PdfOperatorSetSpacingThenTextNextLineAndShow {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
#[parse(word_space)]
|
||||
word_space: f32,
|
||||
#[parse(char_space)]
|
||||
char_space: f32,
|
||||
#[parse(text)]
|
||||
text: PdfString,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfOperator {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfOperatorAndOperands {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PdfContentStreamData {
|
||||
pub operators: Arc<[PdfOperatorAndOperands]>,
|
||||
}
|
||||
|
||||
impl PdfStreamContents for PdfContentStreamData {
|
||||
fn parse(
|
||||
data: &[u8],
|
||||
stream_pos: PdfInputPosition,
|
||||
objects: Arc<PdfObjects>,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
let mut parser = PdfParser {
|
||||
objects,
|
||||
tokenizer: PdfTokenizer::new(
|
||||
data,
|
||||
PdfInputPositionKnown {
|
||||
pos: 0,
|
||||
containing_streams_pos: stream_pos.get().map(|v| v.pos),
|
||||
},
|
||||
),
|
||||
};
|
||||
let mut operands = Vec::new();
|
||||
let mut operators = Vec::new();
|
||||
loop {
|
||||
parser.skip_comments_and_whitespace();
|
||||
if parser.tokenizer.peek().is_none() {
|
||||
break;
|
||||
}
|
||||
match parser.parse_object_or_operator()? {
|
||||
PdfObjectOrStreamDictionaryOrOperator::StreamDictionary {
|
||||
stream_kw_pos, ..
|
||||
} => return Err(PdfParseError::StreamNotAllowedHere { pos: stream_kw_pos }),
|
||||
PdfObjectOrStreamDictionaryOrOperator::Object(object) => operands.push(object),
|
||||
PdfObjectOrStreamDictionaryOrOperator::Operator(operator) => {
|
||||
operators.push(PdfOperator::from(operator).parse(operands.drain(..))?);
|
||||
}
|
||||
}
|
||||
}
|
||||
if operands.is_empty() {
|
||||
Ok(Self {
|
||||
operators: operators.into(),
|
||||
})
|
||||
} else {
|
||||
Err(PdfParseError::MissingOperator {
|
||||
pos: parser.tokenizer.pos(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type PdfContentStream = PdfStream<PdfDictionary, PdfContentStreamData>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue