Skip to content

Commit

Permalink
karm-print: Simple PDF generator.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Jul 31, 2024
1 parent 560286b commit 436bff8
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 200 deletions.
2 changes: 1 addition & 1 deletion src/libs/karm-base/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ struct Map {
}

auto iter() {
return mutIter(_els);
return ::iter(_els);
}

auto iter() const {
Expand Down
8 changes: 2 additions & 6 deletions src/libs/karm-base/union.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,7 @@ struct Union {
return false;
}

std::partial_ordering operator<=>(Union const &other) const
requires(Meta::Comparable<Ts> && ...)
{
std::partial_ordering operator<=>(Union const &other) const {
if (_index == other._index)
return visit(
[&]<typename T>(T const &ptr)
Expand All @@ -194,9 +192,7 @@ struct Union {
return std::partial_ordering::unordered;
}

bool operator==(Union const &other) const
requires(Meta::Equatable<Ts> && ...)
{
bool operator==(Union const &other) const {
if (_index == other._index)
return visit(
[&]<typename T>(T const &ptr) {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/karm-io/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ struct Emit : public Io::TextWriterBase<> {
Res<usize> flush() override {
try$(_error);
if (_newline)
_tryWrapper(_writer.writeRune('\n'));
try$(_insertNewline());
return Ok(_total);
}
};
Expand Down
89 changes: 89 additions & 0 deletions src/libs/karm-print/pdf/cli/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,95 @@
#include <karm-sys/entry.h>
#include <karm-sys/file.h>

#include "../objects.h"

Async::Task<> entryPointAsync(Sys::Context &) {
Pdf::Ref ref;

Pdf::File file;

file.header = "PDF-1.7"s;

auto catalogRef = ref.alloc();
auto pagesRef = ref.alloc();
auto pageRef = ref.alloc();
auto fontRef = ref.alloc();
auto contentRef = ref.alloc();

// Catalog

Pdf::Dict catalog;
catalog.put("Type"s, Pdf::Name{"Catalog"s});
catalog.put("Pages"s, pagesRef);

file.add(catalogRef, std::move(catalog));

// Pages

Pdf::Dict pages;
pages.put("Type"s, Pdf::Name{"Pages"s});

Pdf::Array mediaBox;
mediaBox.pushBack(isize{0});
mediaBox.pushBack(isize{0});
mediaBox.pushBack(isize{200});
mediaBox.pushBack(isize{200});

pages.put("MediaBox"s, mediaBox);
pages.put("Count"s, isize{1});
pages.put("Kids"s, Pdf::Array{pageRef});

file.add(pagesRef, std::move(pages));

// Page

Pdf::Dict page;
page.put("Type"s, Pdf::Name{"Page"s});
page.put("Parent"s, pagesRef);

Pdf::Dict resources;
Pdf::Dict fonts = {};
fonts.put("F1"s, fontRef);
resources.put("Font"s, fonts);
page.put("Resources"s, resources);

page.put("Contents"s, contentRef);

file.add(pageRef, std::move(page));

// Font

Pdf::Dict font;
font.put("Type"s, Pdf::Name{"Font"s});
font.put("Subtype"s, Pdf::Name{"Type1"s});
font.put("BaseFont"s, Pdf::Name{"Times-Roman"s});

file.add(fontRef, std::move(font));

// Content

Io::BufferWriter pageStream;
Io::BEmit pageEmit{pageStream};
pageEmit.writeStr(
R"(BT
70 50 TD
/F1 12 Tf
(Hello, world!) Tj
ET)"s
);

Pdf::Stream content;
content.dict.put("Length"s, (isize)pageStream.bytes().len());
content.data = pageStream.take();

file.add(contentRef, std::move(content));

file.trailer.put("Root"s, catalogRef);
file.trailer.put("Size"s, (isize)file.body.len() + 1);

Io::Emit out{Sys::out()};
Pdf::write(out, file);
co_try$(Sys::out().flush());

co_return Ok();
}
172 changes: 172 additions & 0 deletions src/libs/karm-print/pdf/graphic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#include "graphic.h"

namespace Pdf {

// Graphics state operators

void Graphic::save() {
e("q");
}
void Graphic::restore() {
e("Q");
}
void Graphic::transform(Math::Trans2f t) {
e(t.xx);
e(' ');
e(t.xy);
e(' ');
e(t.yx);
e(' ');
e(t.yy);
e(' ');
e(t.ox);
e(' ');
e(t.oy);
e(" cm");
}
void Graphic::lineWidth(f64 w) {
e("{} w", w);
}
void Graphic::lineCap(LineCap cap) {
e("{} J", toUnderlyingType(cap));
}
void Graphic::lineJoin(LineJoin join) {
e("{} j", toUnderlyingType(join));
}
void Graphic::miterLimit(f64 m) {
e("{} M", m);
}
void Graphic::dash(Slice<f64> const &d, f64 o) {
e("[");
for (usize i = 0; i < d.len(); ++i) {
if (i > 0) {
e(' ');
}
e(d[i]);
}
e("] ");
e(o);
e(" d");
}

// Path construction operators

void Graphic::moveTo(Math::Vec2f p) {
e("{} {} m", p.x, p.y);
}

void Graphic::lineTo(Math::Vec2f p) {
e("{} {} l", p.x, p.y);
}

void Graphic::curveTo(Math::Vec2f c1, Math::Vec2f c2, Math::Vec2f p) {
e("{} {} {} {} {} {} c", c1.x, c1.y, c2.x, c2.y, p.x, p.y);
}

void Graphic::closePath() {
e("h");
}

void Graphic::rectangle(Math::Rectf r) {
e("{} {} {} {} re", r.x, r.y, r.width, r.height);
}

// Path painting operators

void Graphic::stroke() {
e("S");
}

void Graphic::closeStroke() {
e("s");
}

void Graphic::fill(FillRule rule) {
if (rule == FillRule::NONZERO) {
e("f");
} else {
e("f*");
}
}

void Graphic::fillStroke(FillRule rule) {
if (rule == FillRule::NONZERO) {
e("B");
} else {
e("B*");
}
}

void Graphic::closeFillStroke(FillRule rule) {
if (rule == FillRule::NONZERO) {
e("b");
} else {
e("b*");
}
}

void Graphic::endPath() {
e("n");
}

// Clipping path operators

void Graphic::clip(FillRule rule) {
if (rule == FillRule::NONZERO) {
e("W");
} else {
e("W*");
}
}

// Text object operators

void Graphic::beginText() {
e("BT");
}

void Graphic::endText() {
e("ET");
}

// Text state operators

void Graphic::charSpacing(f64 s) {
e("{} Tc", s);
}

void Graphic::wordSpacing(f64 s) {
e("{} Tw", s);
}

void Graphic::horizScaling(f64 s) {
e("{} Tz", s);
}

void Graphic::textLeading(f64 l) {
e("{} TL", l);
}

void Graphic::fontSize(Name const &font, f64 size) {
e("/{} {} Tf", font.str(), size);
}

void Graphic::textRenderMode(TextRenderMode mode) {
e("{} Tr", toUnderlyingType(mode));
}

void Graphic::rise(f64 r) {
e("{} Ts", r);
}

void Graphic::moveText(Math::Vec2f p) {
e("{} {} Td", p.x, p.y);
}

void Graphic::moveTextSet(Math::Vec2f p) {
e("{} {} Tm", p.x, p.y);
}

// Text-positioning operators

} // namespace Pdf
Loading

0 comments on commit 436bff8

Please sign in to comment.