Current section
Files
Jump to
Current section
Files
src/paddlefish.erl
-module(paddlefish).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/paddlefish.gleam").
-export([portrait/1, landscape/1, new_page/0, page_size/2, title/2, author/2, subject/2, keywords/2, creator/2, producer/2, created_at/2, modified_at/2, default_font/2, default_text_size/2, default_text_colour/2, default_page_size/2, add_page/2, text/3, font/2, text_size/2, text_colour/2, add_text/2, rectangle/4, rectangle_fill_colour/2, rectangle_stroke_colour/2, rectangle_line_width/2, add_rectangle/2, path/2, line/3, path_stroke_colour/2, path_line_width/2, add_path/2, shape/1, compound_shape/1, shape_fill_colour/2, shape_stroke_colour/2, shape_line_width/2, add_shape/2, image_position/3, image_width/2, image_height/2, add_image/2, image/1, new_document/0, render/1]).
-export_type([document/0, page/0, page_size/0, text/0, rectangle/0, path/0, shape/0, subpath/0, path_operation/0, image/0, image_error/0, content/0, info/0, object/0, value/0, assets/0, asset_indexes/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque document() :: {document,
info(),
list(page()),
binary(),
float(),
gleam_community@colour:colour(),
page_size()}.
-opaque page() :: {page, gleam@option:option(page_size()), list(content())}.
-type page_size() :: {page_size, float(), float()}.
-opaque text() :: {text,
binary(),
float(),
float(),
gleam@option:option(binary()),
gleam@option:option(float()),
gleam@option:option(gleam_community@colour:colour())}.
-opaque rectangle() :: {rectangle,
float(),
float(),
float(),
float(),
gleam@option:option(gleam_community@colour:colour()),
gleam@option:option(gleam_community@colour:colour()),
gleam@option:option(float())}.
-opaque path() :: {path,
float(),
float(),
list(path_operation()),
gleam@option:option(gleam_community@colour:colour()),
gleam@option:option(float())}.
-opaque shape() :: {shape,
list(subpath()),
gleam@option:option(gleam_community@colour:colour()),
gleam@option:option(gleam_community@colour:colour()),
gleam@option:option(float())}.
-type subpath() :: {subpath, float(), float(), list(path_operation())}.
-type path_operation() :: {line_to, float(), float()}.
-opaque image() :: {image,
bitstring(),
integer(),
integer(),
float(),
float(),
gleam@option:option(float()),
gleam@option:option(float())}.
-type image_error() :: {unsupported_image_format, binary()} |
unknown_image_format.
-type content() :: {content_text, text()} |
{content_rectangle, rectangle()} |
{content_path, path()} |
{content_shape, shape()} |
{content_jpeg_image, image()}.
-type info() :: {info,
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(gleam@time@timestamp:timestamp()),
gleam@option:option(gleam@time@timestamp:timestamp())}.
-type object() :: {object,
integer(),
gleam@option:option(bitstring()),
list({binary(), value()})}.
-type value() :: {reference, integer()} |
{name, binary()} |
{string, binary()} |
{float, float()} |
{int, integer()} |
{bool, boolean()} |
null |
{array, list(value())} |
{dictionary, list({binary(), value()})}.
-type assets() :: {assets,
gleam@set:set(binary()),
list(image()),
gleam@set:set(float())}.
-type asset_indexes() :: {asset_indexes,
gleam@dict:dict(binary(), integer()),
gleam@dict:dict(bitstring(), integer()),
gleam@dict:dict(float(), integer())}.
-file("src/paddlefish.gleam", 63).
?DOC(
" Convert a page size to portrait orientation.\n"
"\n"
" The smaller dimension becomes the width.\n"
).
-spec portrait(page_size()) -> page_size().
portrait(Size) ->
case erlang:element(2, Size) =< erlang:element(3, Size) of
true ->
Size;
false ->
{page_size, erlang:element(3, Size), erlang:element(2, Size)}
end.
-file("src/paddlefish.gleam", 74).
?DOC(
" Convert a page size to landscape orientation.\n"
"\n"
" The larger dimension becomes the width.\n"
).
-spec landscape(page_size()) -> page_size().
landscape(Size) ->
case erlang:element(2, Size) >= erlang:element(3, Size) of
true ->
Size;
false ->
{page_size, erlang:element(3, Size), erlang:element(2, Size)}
end.
-file("src/paddlefish.gleam", 186).
?DOC(" Create a new blank page.\n").
-spec new_page() -> page().
new_page() ->
{page, none, []}.
-file("src/paddlefish.gleam", 192).
?DOC(" Set the size of a page.\n").
-spec page_size(page(), page_size()) -> page().
page_size(Page, Size) ->
{page, {some, Size}, erlang:element(3, Page)}.
-file("src/paddlefish.gleam", 220).
?DOC(" Set the title of the document.\n").
-spec title(document(), binary()) -> document().
title(Document, Title) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
{some, Title},
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 226).
?DOC(" Set the name of the person who created the document content.\n").
-spec author(document(), binary()) -> document().
author(Document, Author) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
{some, Author},
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 232).
?DOC(" Set the subject of the document.\n").
-spec subject(document(), binary()) -> document().
subject(Document, Subject) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
{some, Subject},
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 238).
?DOC(" Set keywords associated with the document, typically comma-separated.\n").
-spec keywords(document(), binary()) -> document().
keywords(Document, Keywords) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
{some, Keywords},
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 244).
?DOC(" Set the name of the application that created the original content.\n").
-spec creator(document(), binary()) -> document().
creator(Document, Creator) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
{some, Creator},
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 250).
?DOC(" Set the name of the application that produced the PDF.\n").
-spec producer(document(), binary()) -> document().
producer(Document, Producer) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
{some, Producer},
erlang:element(8, _record),
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 256).
?DOC(" Set the date and time when the document was created.\n").
-spec created_at(document(), gleam@time@timestamp:timestamp()) -> document().
created_at(Document, Time) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
{some, Time},
erlang:element(9, _record)}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 262).
?DOC(" Set the date and time when the document was last modified.\n").
-spec modified_at(document(), gleam@time@timestamp:timestamp()) -> document().
modified_at(Document, Time) ->
{document,
begin
_record = erlang:element(2, Document),
{info,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
{some, Time}}
end,
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 273).
?DOC(
" Set the default font for text in the document.\n"
"\n"
" This font is used when text is added without specifying a font.\n"
).
-spec default_font(document(), binary()) -> document().
default_font(Document, Font) ->
{document,
erlang:element(2, Document),
erlang:element(3, Document),
Font,
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 281).
?DOC(
" Set the default text size for the document in points.\n"
"\n"
" This size is used when text is added without specifying a size.\n"
).
-spec default_text_size(document(), float()) -> document().
default_text_size(Document, Size) ->
{document,
erlang:element(2, Document),
erlang:element(3, Document),
erlang:element(4, Document),
Size,
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 289).
?DOC(
" Set the default text colour for the document.\n"
"\n"
" This colour is used when text is added without specifying a colour.\n"
).
-spec default_text_colour(document(), gleam_community@colour:colour()) -> document().
default_text_colour(Document, Colour) ->
{document,
erlang:element(2, Document),
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
Colour,
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 295).
?DOC(" Set the default page size for the document.\n").
-spec default_page_size(document(), page_size()) -> document().
default_page_size(Document, Size) ->
{document,
erlang:element(2, Document),
erlang:element(3, Document),
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
Size}.
-file("src/paddlefish.gleam", 308).
?DOC(
" Append a page to the document.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" new_document()\n"
" |> add_page(new_page())\n"
" ```\n"
).
-spec add_page(document(), page()) -> document().
add_page(Document, Page) ->
{document,
erlang:element(2, Document),
[Page | erlang:element(3, Document)],
erlang:element(4, Document),
erlang:element(5, Document),
erlang:element(6, Document),
erlang:element(7, Document)}.
-file("src/paddlefish.gleam", 324).
?DOC(
" Create a new text element at the given position.\n"
"\n"
" The position is specified in points from the bottom-left corner of the page.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" text(\"Hello, world!\", x: 72.0, y: 750.0)\n"
" |> font(\"Times-Roman\")\n"
" |> text_size(14.0)\n"
" ```\n"
).
-spec text(binary(), float(), float()) -> text().
text(Content, X, Y) ->
{text, Content, X, Y, none, none, none}.
-file("src/paddlefish.gleam", 347).
?DOC(
" Set the font for a text element.\n"
"\n"
" The font must be the name of one of the 14 standard PDF fonts.\n"
"\n"
" - Courier,\n"
" - Courier-Bold,\n"
" - Courier-Oblique,\n"
" - Courier-BoldOblique\n"
" - Helvetica,\n"
" - Helvetica-Bold,\n"
" - Helvetica-Oblique,\n"
" - Helvetica-BoldOblique\n"
" - Times-Roman,\n"
" - Times-Bold,\n"
" - Times-Italic,\n"
" - Times-BoldItalic\n"
" - Symbol\n"
" - ZapfDingbats\n"
).
-spec font(text(), binary()) -> text().
font(Text, Font) ->
{text,
erlang:element(2, Text),
erlang:element(3, Text),
erlang:element(4, Text),
{some, Font},
erlang:element(6, Text),
erlang:element(7, Text)}.
-file("src/paddlefish.gleam", 353).
?DOC(" Set the size for a text element in points.\n").
-spec text_size(text(), float()) -> text().
text_size(Text, Size) ->
{text,
erlang:element(2, Text),
erlang:element(3, Text),
erlang:element(4, Text),
erlang:element(5, Text),
{some, Size},
erlang:element(7, Text)}.
-file("src/paddlefish.gleam", 359).
?DOC(" Set the colour for a text element.\n").
-spec text_colour(text(), gleam_community@colour:colour()) -> text().
text_colour(Text, Colour) ->
{text,
erlang:element(2, Text),
erlang:element(3, Text),
erlang:element(4, Text),
erlang:element(5, Text),
erlang:element(6, Text),
{some, Colour}}.
-file("src/paddlefish.gleam", 372).
?DOC(
" Add a text element to the page.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" new_page()\n"
" |> add_text(text(\"Hello, world!\", x: 72.0, y: 750.0))\n"
" ```\n"
).
-spec add_text(page(), text()) -> page().
add_text(Page, Text) ->
{page,
erlang:element(2, Page),
[{content_text, Text} | erlang:element(3, Page)]}.
-file("src/paddlefish.gleam", 381).
?DOC(
" Create a new rectangle at the given position with the given dimensions.\n"
"\n"
" The position is specified in points from the bottom-left corner of the page.\n"
" The rectangle will be invisible until a fill or stroke colour is set.\n"
).
-spec rectangle(float(), float(), float(), float()) -> rectangle().
rectangle(X, Y, Width, Height) ->
{rectangle, X, Y, Width, Height, none, none, none}.
-file("src/paddlefish.gleam", 400).
?DOC(" Set the fill colour for a rectangle.\n").
-spec rectangle_fill_colour(rectangle(), gleam_community@colour:colour()) -> rectangle().
rectangle_fill_colour(Rectangle, Colour) ->
{rectangle,
erlang:element(2, Rectangle),
erlang:element(3, Rectangle),
erlang:element(4, Rectangle),
erlang:element(5, Rectangle),
{some, Colour},
erlang:element(7, Rectangle),
erlang:element(8, Rectangle)}.
-file("src/paddlefish.gleam", 406).
?DOC(" Set the stroke colour for a rectangle.\n").
-spec rectangle_stroke_colour(rectangle(), gleam_community@colour:colour()) -> rectangle().
rectangle_stroke_colour(Rectangle, Colour) ->
{rectangle,
erlang:element(2, Rectangle),
erlang:element(3, Rectangle),
erlang:element(4, Rectangle),
erlang:element(5, Rectangle),
erlang:element(6, Rectangle),
{some, Colour},
erlang:element(8, Rectangle)}.
-file("src/paddlefish.gleam", 415).
?DOC(" Set the line width for a rectangle's stroke in points.\n").
-spec rectangle_line_width(rectangle(), float()) -> rectangle().
rectangle_line_width(Rectangle, Width) ->
{rectangle,
erlang:element(2, Rectangle),
erlang:element(3, Rectangle),
erlang:element(4, Rectangle),
erlang:element(5, Rectangle),
erlang:element(6, Rectangle),
erlang:element(7, Rectangle),
{some, Width}}.
-file("src/paddlefish.gleam", 421).
?DOC(" Add a rectangle to the page.\n").
-spec add_rectangle(page(), rectangle()) -> page().
add_rectangle(Page, Rectangle) ->
{page,
erlang:element(2, Page),
[{content_rectangle, Rectangle} | erlang:element(3, Page)]}.
-file("src/paddlefish.gleam", 427).
?DOC(" Create a new path starting at the given point.\n").
-spec path(float(), float()) -> path().
path(X, Y) ->
{path, X, Y, [], none, none}.
-file("src/paddlefish.gleam", 439).
?DOC(" Add a line to the path.\n").
-spec line(path(), float(), float()) -> path().
line(Path, X, Y) ->
{path,
erlang:element(2, Path),
erlang:element(3, Path),
[{line_to, X, Y} | erlang:element(4, Path)],
erlang:element(5, Path),
erlang:element(6, Path)}.
-file("src/paddlefish.gleam", 445).
?DOC(" Set the stroke colour for a path.\n").
-spec path_stroke_colour(path(), gleam_community@colour:colour()) -> path().
path_stroke_colour(Path, Colour) ->
{path,
erlang:element(2, Path),
erlang:element(3, Path),
erlang:element(4, Path),
{some, Colour},
erlang:element(6, Path)}.
-file("src/paddlefish.gleam", 451).
?DOC(" Set the line width for a path in points.\n").
-spec path_line_width(path(), float()) -> path().
path_line_width(Path, Width) ->
{path,
erlang:element(2, Path),
erlang:element(3, Path),
erlang:element(4, Path),
erlang:element(5, Path),
{some, Width}}.
-file("src/paddlefish.gleam", 457).
?DOC(" Add a path to the page.\n").
-spec add_path(page(), path()) -> page().
add_path(Page, Path) ->
{page,
erlang:element(2, Page),
[{content_path, Path} | erlang:element(3, Page)]}.
-file("src/paddlefish.gleam", 466).
?DOC(
" Close a path to create a shape.\n"
"\n"
" The path's stroke colour and line width are not inherited. Use\n"
" `shape_stroke_colour` and `shape_line_width` to set them on the shape.\n"
).
-spec shape(path()) -> shape().
shape(Path) ->
Subpath = {subpath,
erlang:element(2, Path),
erlang:element(3, Path),
erlang:element(4, Path)},
{shape, [Subpath], none, none, none}.
-file("src/paddlefish.gleam", 481).
?DOC(
" Create a compound shape from multiple paths.\n"
"\n"
" The paths' stroke colours and line widths are not inherited. Use\n"
" `shape_stroke_colour` and `shape_line_width` to set them on the shape.\n"
).
-spec compound_shape(list(path())) -> shape().
compound_shape(Paths) ->
Subpaths = gleam@list:map(
Paths,
fun(P) ->
{subpath,
erlang:element(2, P),
erlang:element(3, P),
erlang:element(4, P)}
end
),
{shape, Subpaths, none, none, none}.
-file("src/paddlefish.gleam", 489).
?DOC(" Set the fill colour for a shape.\n").
-spec shape_fill_colour(shape(), gleam_community@colour:colour()) -> shape().
shape_fill_colour(Shape, Colour) ->
{shape,
erlang:element(2, Shape),
{some, Colour},
erlang:element(4, Shape),
erlang:element(5, Shape)}.
-file("src/paddlefish.gleam", 495).
?DOC(" Set the stroke colour for a shape.\n").
-spec shape_stroke_colour(shape(), gleam_community@colour:colour()) -> shape().
shape_stroke_colour(Shape, Colour) ->
{shape,
erlang:element(2, Shape),
erlang:element(3, Shape),
{some, Colour},
erlang:element(5, Shape)}.
-file("src/paddlefish.gleam", 501).
?DOC(" Set the line width for a shape in points.\n").
-spec shape_line_width(shape(), float()) -> shape().
shape_line_width(Shape, Width) ->
{shape,
erlang:element(2, Shape),
erlang:element(3, Shape),
erlang:element(4, Shape),
{some, Width}}.
-file("src/paddlefish.gleam", 507).
?DOC(" Add a shape to the page.\n").
-spec add_shape(page(), shape()) -> page().
add_shape(Page, Shape) ->
{page,
erlang:element(2, Page),
[{content_shape, Shape} | erlang:element(3, Page)]}.
-file("src/paddlefish.gleam", 536).
?DOC(
" Set the position of an image on the page.\n"
"\n"
" The position is from the bottom-left of the page.\n"
).
-spec image_position(image(), float(), float()) -> image().
image_position(Image, X, Y) ->
{image,
erlang:element(2, Image),
erlang:element(3, Image),
erlang:element(4, Image),
X,
Y,
erlang:element(7, Image),
erlang:element(8, Image)}.
-file("src/paddlefish.gleam", 545).
?DOC(
" Set the rendered width of an image.\n"
"\n"
" If only width is set, the height scales proportionally to preserve the\n"
" aspect ratio.\n"
).
-spec image_width(image(), float()) -> image().
image_width(Image, Width) ->
{image,
erlang:element(2, Image),
erlang:element(3, Image),
erlang:element(4, Image),
erlang:element(5, Image),
erlang:element(6, Image),
{some, Width},
erlang:element(8, Image)}.
-file("src/paddlefish.gleam", 554).
?DOC(
" Set the rendered height of an image.\n"
"\n"
" If only height is set, the width scales proportionally to preserve the\n"
" aspect ratio.\n"
).
-spec image_height(image(), float()) -> image().
image_height(Image, Height) ->
{image,
erlang:element(2, Image),
erlang:element(3, Image),
erlang:element(4, Image),
erlang:element(5, Image),
erlang:element(6, Image),
erlang:element(7, Image),
{some, Height}}.
-file("src/paddlefish.gleam", 560).
?DOC(" Add an image to the page.\n").
-spec add_image(page(), image()) -> page().
add_image(Page, Image) ->
{page,
erlang:element(2, Page),
[{content_jpeg_image, Image} | erlang:element(3, Page)]}.
-file("src/paddlefish.gleam", 830).
-spec collect_alpha(
gleam@set:set(float()),
gleam@option:option(gleam_community@colour:colour())
) -> gleam@set:set(float()).
collect_alpha(Alphas, Colour) ->
case Colour of
{some, C} ->
{_, _, _, Alpha} = gleam_community@colour:to_rgba(C),
case Alpha < 1.0 of
true ->
gleam@set:insert(Alphas, Alpha);
false ->
Alphas
end;
none ->
Alphas
end.
-file("src/paddlefish.gleam", 779).
-spec collect_assets(list(content()), binary(), gleam_community@colour:colour()) -> {list(binary()),
list(image()),
list(float())}.
collect_assets(Contents, Default_font, Default_colour) ->
Assets@1 = gleam@list:fold(
Contents,
{assets, gleam@set:new(), [], gleam@set:new()},
fun(Assets, Content) -> case Content of
{content_rectangle,
{rectangle, _, _, _, _, Fill_colour, Stroke_colour, _}} ->
Alphas = collect_alpha(
erlang:element(4, Assets),
Fill_colour
),
Alphas@1 = collect_alpha(Alphas, Stroke_colour),
{assets,
erlang:element(2, Assets),
erlang:element(3, Assets),
Alphas@1};
{content_path, {path, _, _, _, Stroke_colour@1, _}} ->
Alphas@2 = collect_alpha(
erlang:element(4, Assets),
Stroke_colour@1
),
{assets,
erlang:element(2, Assets),
erlang:element(3, Assets),
Alphas@2};
{content_shape, {shape, _, Fill_colour@1, Stroke_colour@2, _}} ->
Alphas@3 = collect_alpha(
erlang:element(4, Assets),
Fill_colour@1
),
Alphas@4 = collect_alpha(Alphas@3, Stroke_colour@2),
{assets,
erlang:element(2, Assets),
erlang:element(3, Assets),
Alphas@4};
{content_text, {text, _, _, _, Font, _, Colour}} ->
Font@1 = gleam@option:unwrap(Font, Default_font),
Fonts = gleam@set:insert(erlang:element(2, Assets), Font@1),
Colour@1 = gleam@option:unwrap(Colour, Default_colour),
{_, _, _, Alpha} = gleam_community@colour:to_rgba(Colour@1),
Alphas@5 = case Alpha < 1.0 of
true ->
gleam@set:insert(erlang:element(4, Assets), Alpha);
false ->
erlang:element(4, Assets)
end,
{assets, Fonts, erlang:element(3, Assets), Alphas@5};
{content_jpeg_image, Image} ->
Images = case gleam@list:find(
erlang:element(3, Assets),
fun(I) ->
erlang:element(2, I) =:= erlang:element(2, Image)
end
) of
{ok, _} ->
erlang:element(3, Assets);
{error, _} ->
[Image | erlang:element(3, Assets)]
end,
{assets,
erlang:element(2, Assets),
Images,
erlang:element(4, Assets)}
end end
),
Fonts@1 = begin
_pipe = erlang:element(2, Assets@1),
_pipe@1 = gleam@set:to_list(_pipe),
gleam@list:sort(_pipe@1, fun gleam@string:compare/2)
end,
Images@1 = lists:reverse(erlang:element(3, Assets@1)),
Alphas@6 = begin
_pipe@2 = erlang:element(4, Assets@1),
_pipe@3 = gleam@set:to_list(_pipe@2),
gleam@list:sort(_pipe@3, fun gleam@float:compare/2)
end,
{Fonts@1, Images@1, Alphas@6}.
-file("src/paddlefish.gleam", 846).
-spec set_alpha(bitstring(), float(), asset_indexes()) -> bitstring().
set_alpha(Stream, Alpha, Indexes) ->
case Alpha < 1.0 of
true ->
Gs_index = begin
_pipe = gleam_stdlib:map_get(erlang:element(4, Indexes), Alpha),
gleam@result:unwrap(_pipe, 0)
end,
Gs_key = <<"/GS"/utf8,
(erlang:integer_to_binary(Gs_index + 1))/binary>>,
<<Stream/bitstring, Gs_key/binary, " gs\n"/utf8>>;
false ->
Stream
end.
-file("src/paddlefish.gleam", 1288).
-spec render_float(float()) -> binary().
render_float(F) ->
Truncated = erlang:trunc(F),
case erlang:float(Truncated) =:= F of
true ->
erlang:integer_to_binary(Truncated);
false ->
gleam_stdlib:float_to_string(F)
end.
-file("src/paddlefish.gleam", 913).
-spec render_rectangle(bitstring(), rectangle(), asset_indexes()) -> bitstring().
render_rectangle(Stream, Rect, Indexes) ->
{rectangle, X, Y, Width, Height, Fill_colour, Stroke_colour, Line_width} = Rect,
Stream@1 = case Line_width of
{some, W} ->
<<Stream/bitstring, (render_float(W))/binary, " w\n"/utf8>>;
none ->
Stream
end,
Stream@3 = case Fill_colour of
{some, Colour} ->
{Red, Green, Blue, Alpha} = gleam_community@colour:to_rgba(Colour),
Stream@2 = set_alpha(Stream@1, Alpha, Indexes),
<<Stream@2/bitstring,
(render_float(Red))/binary,
" "/utf8,
(render_float(Green))/binary,
" "/utf8,
(render_float(Blue))/binary,
" rg\n"/utf8>>;
none ->
Stream@1
end,
Stream@5 = case Stroke_colour of
{some, Colour@1} ->
{Red@1, Green@1, Blue@1, Alpha@1} = gleam_community@colour:to_rgba(
Colour@1
),
Stream@4 = set_alpha(Stream@3, Alpha@1, Indexes),
<<Stream@4/bitstring,
(render_float(Red@1))/binary,
" "/utf8,
(render_float(Green@1))/binary,
" "/utf8,
(render_float(Blue@1))/binary,
" RG\n"/utf8>>;
none ->
Stream@3
end,
Stream@6 = <<Stream@5/bitstring,
(render_float(X))/binary,
" "/utf8,
(render_float(Y))/binary,
" "/utf8,
(render_float(Width))/binary,
" "/utf8,
(render_float(Height))/binary,
" re\n"/utf8>>,
case {Fill_colour, Stroke_colour} of
{{some, _}, {some, _}} ->
<<Stream@6/bitstring, "B\n"/utf8>>;
{{some, _}, none} ->
<<Stream@6/bitstring, "f\n"/utf8>>;
{none, {some, _}} ->
<<Stream@6/bitstring, "S\n"/utf8>>;
{none, none} ->
Stream@6
end.
-file("src/paddlefish.gleam", 992).
-spec render_path(bitstring(), path(), asset_indexes()) -> bitstring().
render_path(Stream, Path, Indexes) ->
{path, Start_x, Start_y, Operations, Stroke_colour, Line_width} = Path,
Stream@1 = case Line_width of
{some, W} ->
<<Stream/bitstring, (render_float(W))/binary, " w\n"/utf8>>;
none ->
Stream
end,
Stream@3 = case Stroke_colour of
{some, Colour} ->
{Red, Green, Blue, Alpha} = gleam_community@colour:to_rgba(Colour),
Stream@2 = set_alpha(Stream@1, Alpha, Indexes),
<<Stream@2/bitstring,
(render_float(Red))/binary,
" "/utf8,
(render_float(Green))/binary,
" "/utf8,
(render_float(Blue))/binary,
" RG\n"/utf8>>;
none ->
Stream@1
end,
Stream@4 = <<Stream@3/bitstring,
(render_float(Start_x))/binary,
" "/utf8,
(render_float(Start_y))/binary,
" m\n"/utf8>>,
Stream@6 = begin
_pipe = Operations,
_pipe@1 = lists:reverse(_pipe),
gleam@list:fold(_pipe@1, Stream@4, fun(Stream@5, Op) -> case Op of
{line_to, X, Y} ->
<<Stream@5/bitstring,
(render_float(X))/binary,
" "/utf8,
(render_float(Y))/binary,
" l\n"/utf8>>
end end)
end,
<<Stream@6/bitstring, "S\n"/utf8>>.
-file("src/paddlefish.gleam", 1048).
-spec render_shape(bitstring(), shape(), asset_indexes()) -> bitstring().
render_shape(Stream, Shape, Indexes) ->
{shape, Subpaths, Fill_colour, Stroke_colour, Line_width} = Shape,
Stream@1 = case Line_width of
{some, W} ->
<<Stream/bitstring, (render_float(W))/binary, " w\n"/utf8>>;
none ->
Stream
end,
Stream@3 = case Fill_colour of
{some, Colour} ->
{Red, Green, Blue, Alpha} = gleam_community@colour:to_rgba(Colour),
Stream@2 = set_alpha(Stream@1, Alpha, Indexes),
<<Stream@2/bitstring,
(render_float(Red))/binary,
" "/utf8,
(render_float(Green))/binary,
" "/utf8,
(render_float(Blue))/binary,
" rg\n"/utf8>>;
none ->
Stream@1
end,
Stream@5 = case Stroke_colour of
{some, Colour@1} ->
{Red@1, Green@1, Blue@1, Alpha@1} = gleam_community@colour:to_rgba(
Colour@1
),
Stream@4 = set_alpha(Stream@3, Alpha@1, Indexes),
<<Stream@4/bitstring,
(render_float(Red@1))/binary,
" "/utf8,
(render_float(Green@1))/binary,
" "/utf8,
(render_float(Blue@1))/binary,
" RG\n"/utf8>>;
none ->
Stream@3
end,
Stream@10 = begin
_pipe = Subpaths,
_pipe@1 = lists:reverse(_pipe),
gleam@list:fold(
_pipe@1,
Stream@5,
fun(Stream@6, Subpath) ->
{subpath, Start_x, Start_y, Operations} = Subpath,
Stream@7 = <<Stream@6/bitstring,
(render_float(Start_x))/binary,
" "/utf8,
(render_float(Start_y))/binary,
" m\n"/utf8>>,
Stream@9 = begin
_pipe@2 = Operations,
_pipe@3 = lists:reverse(_pipe@2),
gleam@list:fold(
_pipe@3,
Stream@7,
fun(Stream@8, Op) -> case Op of
{line_to, X, Y} ->
<<Stream@8/bitstring,
(render_float(X))/binary,
" "/utf8,
(render_float(Y))/binary,
" l\n"/utf8>>
end end
)
end,
<<Stream@9/bitstring, "h\n"/utf8>>
end
)
end,
case {Fill_colour, Stroke_colour} of
{{some, _}, {some, _}} ->
<<Stream@10/bitstring, "B*\n"/utf8>>;
{{some, _}, none} ->
<<Stream@10/bitstring, "f*\n"/utf8>>;
{none, {some, _}} ->
<<Stream@10/bitstring, "S\n"/utf8>>;
{none, none} ->
Stream@10
end.
-file("src/paddlefish.gleam", 1142).
-spec render_image(bitstring(), image(), asset_indexes()) -> bitstring().
render_image(Stream, Image, Indexes) ->
{image, Data, File_width, File_height, X, Y, Render_width, Render_height} = Image,
Image_index = begin
_pipe = gleam_stdlib:map_get(erlang:element(3, Indexes), Data),
gleam@result:unwrap(_pipe, 0)
end,
Image_key = <<"/Im"/utf8,
(erlang:integer_to_binary(Image_index + 1))/binary>>,
Aspect_ratio = case erlang:float(File_height) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(File_width) / Gleam@denominator
end,
{Width, Height} = case {Render_width, Render_height} of
{{some, W}, {some, H}} ->
{W, H};
{{some, W@1}, none} ->
{W@1, case Aspect_ratio of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> W@1 / Gleam@denominator@1
end};
{none, {some, H@1}} ->
{H@1 * Aspect_ratio, H@1};
{none, none} ->
{erlang:float(File_width), erlang:float(File_height)}
end,
<<Stream/bitstring,
"q\n"/utf8,
(render_float(Width))/binary,
" 0 0 "/utf8,
(render_float(Height))/binary,
" "/utf8,
(render_float(X))/binary,
" "/utf8,
(render_float(Y))/binary,
" cm\n"/utf8,
Image_key/binary,
" Do\nQ\n"/utf8>>.
-file("src/paddlefish.gleam", 1307).
?DOC(
" Convert UTF-8 text to WinAnsiEncoding for PDF standard fonts.\n"
"\n"
" PDF's 14 standard fonts (Helvetica, Times-Roman, Courier, Symbol, and\n"
" ZapfDingbats families) use WinAnsiEncoding, which is based on Windows-1252.\n"
" This encoding supports ASCII, Latin-1 Supplement (accented characters for\n"
" Western European languages), and some additional characters like curly\n"
" quotes, em-dashes, and the Euro sign.\n"
"\n"
" TODO: embed portions of fonts as needed in order to support more\n"
" characters.\n"
).
-spec encode_text(bitstring(), bitstring()) -> bitstring().
encode_text(In, Out) ->
case In of
<<>> ->
Out;
<<C, Rest/binary>> when C =< 127 ->
encode_text(Rest, <<Out/bitstring, C>>);
<<16#C2, C@1, Rest@1/binary>> when C@1 >= 16#A0 ->
encode_text(Rest@1, <<Out/bitstring, C@1>>);
<<16#C3, C@2, Rest@2/binary>> ->
encode_text(Rest@2, <<Out/bitstring, ((C@2 + 16#40))>>);
<<16#C5, 16#92, Rest@3/binary>> ->
encode_text(Rest@3, <<Out/bitstring, 16#8C>>);
<<16#C5, 16#93, Rest@4/binary>> ->
encode_text(Rest@4, <<Out/bitstring, 16#9C>>);
<<16#C5, 16#A0, Rest@5/binary>> ->
encode_text(Rest@5, <<Out/bitstring, 16#8A>>);
<<16#C5, 16#A1, Rest@6/binary>> ->
encode_text(Rest@6, <<Out/bitstring, 16#9A>>);
<<16#C5, 16#B8, Rest@7/binary>> ->
encode_text(Rest@7, <<Out/bitstring, 16#9F>>);
<<16#C5, 16#BD, Rest@8/binary>> ->
encode_text(Rest@8, <<Out/bitstring, 16#8E>>);
<<16#C5, 16#BE, Rest@9/binary>> ->
encode_text(Rest@9, <<Out/bitstring, 16#9E>>);
<<16#C6, 16#92, Rest@10/binary>> ->
encode_text(Rest@10, <<Out/bitstring, 16#83>>);
<<16#CB, 16#86, Rest@11/binary>> ->
encode_text(Rest@11, <<Out/bitstring, 16#88>>);
<<16#CB, 16#9C, Rest@12/binary>> ->
encode_text(Rest@12, <<Out/bitstring, 16#98>>);
<<16#E2, 16#80, 16#93, Rest@13/binary>> ->
encode_text(Rest@13, <<Out/bitstring, 16#96>>);
<<16#E2, 16#80, 16#94, Rest@14/binary>> ->
encode_text(Rest@14, <<Out/bitstring, 16#97>>);
<<16#E2, 16#80, 16#98, Rest@15/binary>> ->
encode_text(Rest@15, <<Out/bitstring, 16#91>>);
<<16#E2, 16#80, 16#99, Rest@16/binary>> ->
encode_text(Rest@16, <<Out/bitstring, 16#92>>);
<<16#E2, 16#80, 16#9A, Rest@17/binary>> ->
encode_text(Rest@17, <<Out/bitstring, 16#82>>);
<<16#E2, 16#80, 16#9C, Rest@18/binary>> ->
encode_text(Rest@18, <<Out/bitstring, 16#93>>);
<<16#E2, 16#80, 16#9D, Rest@19/binary>> ->
encode_text(Rest@19, <<Out/bitstring, 16#94>>);
<<16#E2, 16#80, 16#9E, Rest@20/binary>> ->
encode_text(Rest@20, <<Out/bitstring, 16#84>>);
<<16#E2, 16#80, 16#A0, Rest@21/binary>> ->
encode_text(Rest@21, <<Out/bitstring, 16#86>>);
<<16#E2, 16#80, 16#A1, Rest@22/binary>> ->
encode_text(Rest@22, <<Out/bitstring, 16#87>>);
<<16#E2, 16#80, 16#A2, Rest@23/binary>> ->
encode_text(Rest@23, <<Out/bitstring, 16#95>>);
<<16#E2, 16#80, 16#A6, Rest@24/binary>> ->
encode_text(Rest@24, <<Out/bitstring, 16#85>>);
<<16#E2, 16#80, 16#B0, Rest@25/binary>> ->
encode_text(Rest@25, <<Out/bitstring, 16#89>>);
<<16#E2, 16#80, 16#B9, Rest@26/binary>> ->
encode_text(Rest@26, <<Out/bitstring, 16#8B>>);
<<16#E2, 16#80, 16#BA, Rest@27/binary>> ->
encode_text(Rest@27, <<Out/bitstring, 16#9B>>);
<<16#E2, 16#82, 16#AC, Rest@28/binary>> ->
encode_text(Rest@28, <<Out/bitstring, 16#80>>);
<<16#E2, 16#84, 16#A2, Rest@29/binary>> ->
encode_text(Rest@29, <<Out/bitstring, 16#99>>);
<<C@3, Rest@30/binary>> ->
encode_text(Rest@30, <<Out/bitstring, C@3>>);
Rest@31 ->
<<Out/bitstring, Rest@31/bitstring>>
end.
-file("src/paddlefish.gleam", 873).
-spec render_text(bitstring(), text(), asset_indexes(), document()) -> bitstring().
render_text(Stream, Text, Indexes, Document) ->
{text, Content, X, Y, Font, Size, Colour} = Text,
Font@1 = gleam@option:unwrap(Font, erlang:element(4, Document)),
Size@1 = gleam@option:unwrap(Size, erlang:element(5, Document)),
Colour@1 = gleam@option:unwrap(Colour, erlang:element(6, Document)),
Font_index = begin
_pipe = gleam_stdlib:map_get(erlang:element(2, Indexes), Font@1),
gleam@result:unwrap(_pipe, 0)
end,
Font_key = <<"/F"/utf8, (erlang:integer_to_binary(Font_index + 1))/binary>>,
Stream@1 = <<Stream/bitstring, "BT\n"/utf8>>,
{Red, Green, Blue, Alpha} = gleam_community@colour:to_rgba(Colour@1),
Stream@2 = set_alpha(Stream@1, Alpha, Indexes),
Stream@3 = <<Stream@2/bitstring,
(render_float(Red))/binary,
" "/utf8,
(render_float(Green))/binary,
" "/utf8,
(render_float(Blue))/binary,
" rg\n"/utf8>>,
Encoded_content = encode_text(<<Content/binary>>, <<>>),
<<Stream@3/bitstring,
Font_key/binary,
" "/utf8,
(render_float(Size@1))/binary,
" Tf\n1 0 0 1 "/utf8,
(render_float(X))/binary,
" "/utf8,
(render_float(Y))/binary,
" Tm\n("/utf8,
Encoded_content/bitstring,
") Tj\nET\n"/utf8>>.
-file("src/paddlefish.gleam", 857).
-spec render_content_stream(list(content()), document(), asset_indexes()) -> bitstring().
render_content_stream(Contents, Document, Indexes) ->
gleam@list:fold(Contents, <<>>, fun(Stream, Content) -> case Content of
{content_text, Text} ->
render_text(Stream, Text, Indexes, Document);
{content_rectangle, Rect} ->
render_rectangle(Stream, Rect, Indexes);
{content_path, Path} ->
render_path(Stream, Path, Indexes);
{content_shape, Shape} ->
render_shape(Stream, Shape, Indexes);
{content_jpeg_image, Image} ->
render_image(Stream, Image, Indexes)
end end).
-file("src/paddlefish.gleam", 636).
-spec page_to_objects(page(), integer(), integer(), document()) -> {object(),
object(),
list(object()),
integer()}.
page_to_objects(Page, Page_id, Next_id, Document) ->
Contents = lists:reverse(erlang:element(3, Page)),
Content_id = Next_id,
{Fonts, Images, Alphas} = collect_assets(
Contents,
erlang:element(4, Document),
erlang:element(6, Document)
),
Font_start_id = Next_id + 1,
Size = gleam@option:unwrap(
erlang:element(2, Page),
erlang:element(7, Document)
),
{Font_dict, Font_objects, Next_id@1} = gleam@list:fold(
gleam@list:index_map(Fonts, fun(Font, I) -> {Font, I} end),
{[], [], Font_start_id},
fun(Acc, Pair) ->
{Dict, Objs, Object_id} = Acc,
{Font@1, Index} = Pair,
Font_key = <<"F"/utf8,
(erlang:integer_to_binary(Index + 1))/binary>>,
Font_object = {object,
Object_id,
none,
[{<<"Type"/utf8>>, {name, <<"Font"/utf8>>}},
{<<"Subtype"/utf8>>, {name, <<"Type1"/utf8>>}},
{<<"BaseFont"/utf8>>, {name, Font@1}},
{<<"Encoding"/utf8>>, {name, <<"WinAnsiEncoding"/utf8>>}}]},
{[{Font_key, {reference, Object_id}} | Dict],
[Font_object | Objs],
Object_id + 1}
end
),
{Image_dict, Image_objects, Next_id@2} = gleam@list:fold(
gleam@list:index_map(Images, fun(Image, I@1) -> {Image, I@1} end),
{[], [], Next_id@1},
fun(Acc@1, Pair@1) ->
{Dict@1, Objs@1, Object_id@1} = Acc@1,
{Image@1, Index@1} = Pair@1,
Image_key = <<"Im"/utf8,
(erlang:integer_to_binary(Index@1 + 1))/binary>>,
Image_object = {object,
Object_id@1,
{some, erlang:element(2, Image@1)},
[{<<"Type"/utf8>>, {name, <<"XObject"/utf8>>}},
{<<"Subtype"/utf8>>, {name, <<"Image"/utf8>>}},
{<<"Width"/utf8>>, {int, erlang:element(3, Image@1)}},
{<<"Height"/utf8>>, {int, erlang:element(4, Image@1)}},
{<<"ColorSpace"/utf8>>, {name, <<"DeviceRGB"/utf8>>}},
{<<"BitsPerComponent"/utf8>>, {int, 8}},
{<<"Filter"/utf8>>, {name, <<"DCTDecode"/utf8>>}}]},
{[{Image_key, {reference, Object_id@1}} | Dict@1],
[Image_object | Objs@1],
Object_id@1 + 1}
end
),
{Extgstate_dict, Extgstate_objects, Next_id@3} = gleam@list:fold(
gleam@list:index_map(Alphas, fun(Alpha, I@2) -> {Alpha, I@2} end),
{[], [], Next_id@2},
fun(Acc@2, Pair@2) ->
{Dict@2, Objs@2, Object_id@2} = Acc@2,
{Alpha@1, Index@2} = Pair@2,
Gs_key = <<"GS"/utf8,
(erlang:integer_to_binary(Index@2 + 1))/binary>>,
Gs_object = {object,
Object_id@2,
none,
[{<<"Type"/utf8>>, {name, <<"ExtGState"/utf8>>}},
{<<"ca"/utf8>>, {float, Alpha@1}},
{<<"CA"/utf8>>, {float, Alpha@1}}]},
{[{Gs_key, {reference, Object_id@2}} | Dict@2],
[Gs_object | Objs@2],
Object_id@2 + 1}
end
),
Indexes = {asset_indexes,
gleam@list:index_fold(Fonts, maps:new(), fun gleam@dict:insert/3),
gleam@list:index_fold(
Images,
maps:new(),
fun(Images@1, Image@2, Index@3) ->
gleam@dict:insert(Images@1, erlang:element(2, Image@2), Index@3)
end
),
gleam@list:index_fold(Alphas, maps:new(), fun gleam@dict:insert/3)},
Content_stream = render_content_stream(Contents, Document, Indexes),
Resources = [{<<"Font"/utf8>>, {dictionary, Font_dict}}],
Resources@1 = case Image_dict of
[] ->
Resources;
_ ->
[{<<"XObject"/utf8>>, {dictionary, Image_dict}} | Resources]
end,
Resources@2 = case Extgstate_dict of
[] ->
Resources@1;
_ ->
[{<<"ExtGState"/utf8>>, {dictionary, Extgstate_dict}} | Resources@1]
end,
Page_object = {object,
Page_id,
none,
[{<<"Type"/utf8>>, {name, <<"Page"/utf8>>}},
{<<"Parent"/utf8>>, {reference, 2}},
{<<"MediaBox"/utf8>>,
{array,
[{int, 0},
{int, 0},
{float, erlang:element(2, Size)},
{float, erlang:element(3, Size)}]}},
{<<"Resources"/utf8>>, {dictionary, Resources@2}},
{<<"Contents"/utf8>>, {reference, Content_id}}]},
Content_object = {object, Content_id, {some, Content_stream}, []},
Objects = lists:append(
[lists:reverse(Font_objects),
lists:reverse(Image_objects),
lists:reverse(Extgstate_objects)]
),
{Page_object, Content_object, Objects, Next_id@3}.
-file("src/paddlefish.gleam", 606).
-spec document_to_objects(document()) -> list(object()).
document_to_objects(Document) ->
Pages = lists:reverse(erlang:element(3, Document)),
Page_count = erlang:length(Pages),
Page_ids = gleam@list:range(3, (3 + Page_count) - 1),
Page_refs = gleam@list:map(
Page_ids,
fun(Field@0) -> {reference, Field@0} end
),
Catalog = {object,
1,
none,
[{<<"Type"/utf8>>, {name, <<"Catalog"/utf8>>}},
{<<"Pages"/utf8>>, {reference, 2}}]},
Pages_object = {object,
2,
none,
[{<<"Type"/utf8>>, {name, <<"Pages"/utf8>>}},
{<<"Kids"/utf8>>, {array, Page_refs}},
{<<"Count"/utf8>>, {int, Page_count}}]},
{Page_objects, _} = gleam@list:fold(
gleam@list:zip(Pages, Page_ids),
{[], 3 + Page_count},
fun(Acc, Pair) ->
{Objects, Next_id} = Acc,
{Page, Page_id} = Pair,
{Page_object, Content_object, Font_objects, Next_id@1} = page_to_objects(
Page,
Page_id,
Next_id,
Document
),
Objects@1 = lists:append(
[Objects, [Page_object, Content_object], Font_objects]
),
{Objects@1, Next_id@1}
end
),
[Catalog, Pages_object | Page_objects].
-file("src/paddlefish.gleam", 1402).
-spec parse_jpeg_dimensions(bitstring()) -> {ok, {integer(), integer()}} |
{error, image_error()}.
parse_jpeg_dimensions(Data) ->
case Data of
<<>> ->
{error, unknown_image_format};
<<_>> ->
{error, unknown_image_format};
<<16#FF, Marker, _:2/binary, _, Height:16/big, Width:16/big, _/binary>> when ((Marker >= 16#C0) andalso (Marker =< 16#CF)) andalso (Marker =/= 16#C4) ->
{ok, {Width, Height}};
<<16#FF, Marker@1, Length:16/big, Rest/binary>> when Marker@1 =/= 16#00 ->
Skip_count = Length - 2,
case Rest of
<<_:Skip_count/binary, Rest@1/binary>> ->
parse_jpeg_dimensions(Rest@1);
_ ->
{error, unknown_image_format}
end;
<<_, Rest@2/binary>> ->
parse_jpeg_dimensions(Rest@2);
_ ->
{error, unknown_image_format}
end.
-file("src/paddlefish.gleam", 1384).
-spec parse_image_dimensions(bitstring()) -> {ok, {integer(), integer()}} |
{error, image_error()}.
parse_image_dimensions(Data) ->
case Data of
<<16#FF, 16#D8, Rest/binary>> ->
parse_jpeg_dimensions(Rest);
<<16#89, 16#50, 16#4E, 16#47, 16#0D, 16#0A, 16#1A, 16#0A, _/binary>> ->
{error, {unsupported_image_format, <<"PNG"/utf8>>}};
<<16#47, 16#49, 16#46, 16#38, _/binary>> ->
{error, {unsupported_image_format, <<"GIF"/utf8>>}};
<<16#42, 16#4D, _/binary>> ->
{error, {unsupported_image_format, <<"BMP"/utf8>>}};
<<16#52,
16#49,
16#46,
16#46,
_,
_,
_,
_,
16#57,
16#45,
16#42,
16#50,
_/binary>> ->
{error, {unsupported_image_format, <<"WebP"/utf8>>}};
_ ->
{error, unknown_image_format}
end.
-file("src/paddlefish.gleam", 516).
?DOC(
" Create an image from JPEG data.\n"
"\n"
" Currently only JPEG images are supported. Returns an error if the data is\n"
" not valid JPEG.\n"
).
-spec image(bitstring()) -> {ok, image()} | {error, image_error()}.
image(Data) ->
case parse_image_dimensions(Data) of
{ok, {Width, Height}} ->
{ok, {image, Data, Width, Height, +0.0, +0.0, none, none}};
{error, E} ->
{error, E}
end.
-file("src/paddlefish.gleam", 1438).
-spec render_xref(bitstring(), list(integer())) -> bitstring().
render_xref(Pdf, Offsets) ->
Count = erlang:length(Offsets),
Pdf@1 = <<Pdf/bitstring,
"xref\n0 "/utf8,
(erlang:integer_to_binary(Count + 1))/binary,
"\n"/utf8,
"0000000000 65535 f \n"/utf8>>,
gleam@list:fold(
Offsets,
Pdf@1,
fun(Pdf@2, Offset) ->
Offset@1 = gleam@string:pad_start(
erlang:integer_to_binary(Offset),
10,
<<"0"/utf8>>
),
<<Pdf@2/bitstring, Offset@1/binary, " 00000 n \n"/utf8>>
end
).
-file("src/paddlefish.gleam", 1454).
-spec render_trailer(bitstring(), integer(), integer(), integer()) -> bitstring().
render_trailer(Pdf, Count, Xref_start, Info_id) ->
<<Pdf/bitstring,
"trailer\n"/utf8,
"<<\n"/utf8,
"/Size "/utf8,
(erlang:integer_to_binary(Count + 1))/binary,
"\n"/utf8,
"/Root 1 0 R\n"/utf8,
"/Info "/utf8,
(erlang:integer_to_binary(Info_id))/binary,
" 0 R\n"/utf8,
">>\n"/utf8,
"startxref\n"/utf8,
(erlang:integer_to_binary(Xref_start))/binary,
"\n%%EOF\n"/utf8>>.
-file("src/paddlefish.gleam", 1494).
-spec optional_property(
list({binary(), value()}),
binary(),
gleam@option:option(MYV),
fun((MYV) -> value())
) -> list({binary(), value()}).
optional_property(Dictionary, Key, Value, To_value) ->
case Value of
none ->
Dictionary;
{some, V} ->
[{Key, To_value(V)} | Dictionary]
end.
-file("src/paddlefish.gleam", 1506).
-spec format_pdf_date(gleam@time@timestamp:timestamp()) -> binary().
format_pdf_date(Time) ->
{Date, Time_of_day} = gleam@time@timestamp:to_calendar(
Time,
{duration, 0, 0}
),
<<<<<<<<<<<<<<"D:"/utf8,
(erlang:integer_to_binary(
erlang:element(2, Date)
))/binary>>/binary,
(gleam@string:pad_start(
erlang:integer_to_binary(
gleam@time@calendar:month_to_int(
erlang:element(3, Date)
)
),
2,
<<"0"/utf8>>
))/binary>>/binary,
(gleam@string:pad_start(
erlang:integer_to_binary(erlang:element(4, Date)),
2,
<<"0"/utf8>>
))/binary>>/binary,
(gleam@string:pad_start(
erlang:integer_to_binary(erlang:element(2, Time_of_day)),
2,
<<"0"/utf8>>
))/binary>>/binary,
(gleam@string:pad_start(
erlang:integer_to_binary(erlang:element(3, Time_of_day)),
2,
<<"0"/utf8>>
))/binary>>/binary,
(gleam@string:pad_start(
erlang:integer_to_binary(erlang:element(4, Time_of_day)),
2,
<<"0"/utf8>>
))/binary>>/binary,
"Z"/utf8>>.
-file("src/paddlefish.gleam", 1478).
-spec render_info_object(integer(), info()) -> object().
render_info_object(Id, Info) ->
Date_value = fun(Dt) -> {string, format_pdf_date(Dt)} end,
Dictionary = begin
_pipe = [],
_pipe@1 = optional_property(
_pipe,
<<"Title"/utf8>>,
erlang:element(2, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@2 = optional_property(
_pipe@1,
<<"Author"/utf8>>,
erlang:element(3, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@3 = optional_property(
_pipe@2,
<<"Subject"/utf8>>,
erlang:element(4, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@4 = optional_property(
_pipe@3,
<<"Keywords"/utf8>>,
erlang:element(5, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@5 = optional_property(
_pipe@4,
<<"Creator"/utf8>>,
erlang:element(6, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@6 = optional_property(
_pipe@5,
<<"Producer"/utf8>>,
erlang:element(7, Info),
fun(Field@0) -> {string, Field@0} end
),
_pipe@7 = optional_property(
_pipe@6,
<<"CreationDate"/utf8>>,
erlang:element(8, Info),
Date_value
),
optional_property(
_pipe@7,
<<"ModDate"/utf8>>,
erlang:element(9, Info),
Date_value
)
end,
{object, Id, none, Dictionary}.
-file("src/paddlefish.gleam", 198).
?DOC(" Create a new document.\n").
-spec new_document() -> document().
new_document() ->
{document,
{info, none, none, none, none, none, none, none, none},
[],
<<"Helvetica"/utf8>>,
12.0,
{rgba, +0.0, +0.0, +0.0, 1.0},
{page_size, 595.0, 842.0}}.
-file("src/paddlefish.gleam", 1273).
-spec render_value(bitstring(), value()) -> bitstring().
render_value(Pdf, Value) ->
case Value of
{reference, R} ->
<<Pdf/bitstring, (erlang:integer_to_binary(R))/binary, " 0 R"/utf8>>;
{name, N} ->
<<Pdf/bitstring, "/"/utf8, N/binary>>;
{string, S} ->
<<Pdf/bitstring, "("/utf8, S/binary, ")"/utf8>>;
{float, F} ->
<<Pdf/bitstring, (render_float(F))/binary>>;
{int, F@1} ->
<<Pdf/bitstring, (erlang:integer_to_binary(F@1))/binary>>;
{bool, true} ->
<<Pdf/bitstring, "true"/utf8>>;
{bool, false} ->
<<Pdf/bitstring, "false"/utf8>>;
null ->
<<Pdf/bitstring, "null"/utf8>>;
{array, Array} ->
render_array(Pdf, Array);
{dictionary, Pairs} ->
render_dictionary(Pdf, Pairs)
end.
-file("src/paddlefish.gleam", 1248).
-spec render_dictionary(bitstring(), list({binary(), value()})) -> bitstring().
render_dictionary(Pdf, Dictionary) ->
Pdf@1 = <<Pdf/bitstring, "<<"/utf8>>,
Pdf@5 = gleam@list:fold(
Dictionary,
Pdf@1,
fun(Pdf@2, Property) ->
Pdf@3 = <<Pdf@2/bitstring,
"/"/utf8,
(erlang:element(1, Property))/binary,
" "/utf8>>,
Pdf@4 = render_value(Pdf@3, erlang:element(2, Property)),
<<Pdf@4/bitstring, "\n"/utf8>>
end
),
Pdf@6 = <<Pdf@5/bitstring, ">>"/utf8>>,
Pdf@6.
-file("src/paddlefish.gleam", 1215).
-spec render_object(bitstring(), object(), list(integer())) -> {bitstring(),
list(integer())}.
render_object(Pdf, Object, Offsets) ->
{object, Id, Stream, Dictionary} = Object,
Offsets@1 = [erlang:byte_size(Pdf) | Offsets],
Pdf@1 = <<Pdf/bitstring,
(erlang:integer_to_binary(Id))/binary,
" 0 obj\n"/utf8>>,
Dictionary@1 = case Stream of
none ->
Dictionary;
{some, Stream@1} ->
[{<<"Length"/utf8>>, {int, erlang:byte_size(Stream@1)}} |
Dictionary]
end,
Pdf@2 = render_dictionary(Pdf@1, Dictionary@1),
Pdf@3 = <<Pdf@2/bitstring, "\n"/utf8>>,
Pdf@4 = case Stream of
{some, Bits} ->
<<Pdf@3/bitstring,
"stream\n"/utf8,
Bits/bitstring,
"\nendstream\n"/utf8>>;
none ->
Pdf@3
end,
Pdf@5 = <<Pdf@4/bitstring, "endobj\n"/utf8>>,
{Pdf@5, Offsets@1}.
-file("src/paddlefish.gleam", 1201).
-spec render_objects(bitstring(), list(object()), list(integer())) -> {bitstring(),
list(integer())}.
render_objects(Pdf, Objects, Offsets) ->
case Objects of
[] ->
{Pdf, Offsets};
[Object | Objects@1] ->
{Pdf@1, Offsets@1} = render_object(Pdf, Object, Offsets),
render_objects(Pdf@1, Objects@1, Offsets@1)
end.
-file("src/paddlefish.gleam", 1188).
-spec render_pdf(list(object()), info()) -> bitstring().
render_pdf(Objects, Info) ->
Pdf = <<"%PDF-1.4\n"/utf8>>,
Info_id = erlang:length(Objects) + 1,
{Pdf@1, Offsets} = render_objects(Pdf, Objects, []),
Info_object = render_info_object(Info_id, Info),
{Pdf@2, Offsets@1} = render_object(Pdf@1, Info_object, Offsets),
Offsets@2 = lists:reverse(Offsets@1),
Xref_start = erlang:byte_size(Pdf@2),
Pdf@3 = render_xref(Pdf@2, Offsets@2),
Pdf@4 = render_trailer(Pdf@3, Info_id, Xref_start, Info_id),
Pdf@4.
-file("src/paddlefish.gleam", 600).
?DOC(
" Render the document to a PDF file as a bit array.\n"
"\n"
" The resulting bytes can be written directly to a file.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" new_document()\n"
" |> title(\"My Document\")\n"
" |> add_page(\n"
" new_page()\n"
" |> add_text(text(\"Hello!\", x: 72.0, y: 750.0)),\n"
" )\n"
" |> render\n"
" ```\n"
).
-spec render(document()) -> bitstring().
render(Document) ->
_pipe = Document,
_pipe@1 = document_to_objects(_pipe),
render_pdf(_pipe@1, erlang:element(2, Document)).
-file("src/paddlefish.gleam", 1263).
-spec render_array(bitstring(), list(value())) -> bitstring().
render_array(Pdf, Array) ->
Pdf@1 = <<Pdf/bitstring, "["/utf8>>,
Pdf@3 = gleam@list:fold(
Array,
Pdf@1,
fun(Pdf@2, Value) ->
<<(render_value(Pdf@2, Value))/bitstring, " "/utf8>>
end
),
Pdf@4 = <<Pdf@3/bitstring, "]"/utf8>>,
Pdf@4.