tiny.pdf.Document
Defined in tiny.pdf.
API (15)
Actions
Public operations.
Fields and members
Public fields and members.
Source
Source: lib/pdf/src/document.zig:52
zig
pub const Document = struct { document_allocator: std.mem.Allocator, arena_state: alloc_arena.Arena, filter_storage: *filter.Storage, bytes: []const u8, table: xref.Table, containers: std.AutoHashMapUnmanaged(u32, Container), fonts: std.AutoHashMapUnmanaged(u32, *const font.Font), pub fn init( document_allocator: std.mem.Allocator, filter_storage: *filter.Storage, bytes: []const u8, ) DocumentError!Document { var arena_state = alloc_arena.Arena.init(document_allocator); errdefer arena_state.deinit(); var table = try xref.parse( document_allocator, arena_state.allocator(), filter_storage, bytes, ); errdefer table.deinit(document_allocator); return .{ .document_allocator = document_allocator, .arena_state = arena_state, .filter_storage = filter_storage, .bytes = bytes, .table = table, .containers = .empty, .fonts = .empty, }; } pub fn deinit(self: *Document) void { self.fonts.deinit(self.document_allocator); self.containers.deinit(self.document_allocator); self.table.deinit(self.document_allocator); self.arena_state.deinit(); } pub fn objectValue(self: *Document, reference: object.Reference) DocumentError!object.Value { return ObjectAccess.init(self).objectValue(reference); } pub fn objectStream(self: *Document, reference: object.Reference) DocumentError!Stream { return ObjectAccess.init(self).objectStream(reference); } pub fn resolve(self: *Document, value: object.Value) DocumentError!object.Value { return ObjectAccess.init(self).resolve(value); } pub fn decodeStream(self: *Document, stream: Stream) DocumentError![]u8 { return ObjectAccess.init(self).decodeStream(stream); } pub fn pagesAppend(self: *Document, list_allocator: std.mem.Allocator, pages: *std.ArrayList(Page)) DocumentError!void { const catalog = switch (try self.objectValue(self.table.root)) { .dict => |dict| dict, else => return error.NotADictionary, }; const pages_value = catalog.get("Pages") orelse return error.MissingPages; const pages_ref = switch (pages_value) { .reference => |reference| reference, else => return error.MissingPages, }; try self.walkPages(list_allocator, pages, pages_ref, null, 0); } fn walkPages(self: *Document, list_allocator: std.mem.Allocator, pages: *std.ArrayList(Page), reference: object.Reference, inherited: ?object.Dict, depth: usize) DocumentError!void { if (depth > 64) return error.ResolveDepth; const node = switch (try self.objectValue(reference)) { .dict => |dict| dict, else => return error.NotADictionary, }; const kind = node.get("Type") orelse return error.NotADictionary; const kind_name = switch (kind) { .name => |name| name, else => return error.NotADictionary, }; const resources: ?object.Dict = blk: { const value = node.get("Resources") orelse break :blk inherited; break :blk switch (try self.resolve(value)) { .dict => |dict| dict, else => inherited, }; }; if (std.mem.eql(u8, kind_name, "Pages")) { const kids = node.get("Kids") orelse return; const items = switch (try self.resolve(kids)) { .array => |array| array, else => return, }; for (items) |item| { switch (item) { .reference => |kid| try self.walkPages(list_allocator, pages, kid, resources, depth + 1), else => {}, } } return; } if (!std.mem.eql(u8, kind_name, "Page")) return; const arena = self.arena_state.allocator(); var refs: std.ArrayList(object.Reference) = .empty; if (node.get("Contents")) |contents| { switch (contents) { .reference => |stream_ref| refs.append(arena, stream_ref) catch return error.OutOfMemory, .array => |items| { for (items) |item| { switch (item) { .reference => |stream_ref| refs.append(arena, stream_ref) catch return error.OutOfMemory, else => {}, } } }, else => {}, } } const owned = refs.toOwnedSlice(arena) catch return error.OutOfMemory; pages.append(list_allocator, .{ .contents = owned, .resources = resources }) catch return error.OutOfMemory; } pub fn fontSetAlloc(self: *Document, resources: ?object.Dict) DocumentError!font.Set { const resources_dict = resources orelse return .{}; const fonts_value = resources_dict.get("Font") orelse return .{}; const fonts_dict = switch (try self.resolve(fonts_value)) { .dict => |dict| dict, else => return .{}, }; const arena = self.arena_state.allocator(); const entries = arena.alloc(font.Entry, fonts_dict.entries.len) catch return error.OutOfMemory; var count: usize = 0; for (fonts_dict.entries) |entry| { switch (entry.value) { .reference => |reference| { entries[count] = .{ .name = entry.key, .font = try self.loadFont(reference) }; count += 1; }, else => {}, } } return .{ .entries = entries[0..count] }; } fn loadFont(self: *Document, reference: object.Reference) DocumentError!*const font.Font { if (self.fonts.get(reference.number)) |cached| return cached; const arena = self.arena_state.allocator(); const created = arena.create(font.Font) catch return error.OutOfMemory; created.* = .{ .map = self.fontMapAlloc(reference) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => null, } }; self.fonts.put(self.document_allocator, reference.number, created) catch return error.OutOfMemory; return created; } fn fontMapAlloc(self: *Document, reference: object.Reference) DocumentError!?cmap.Map { const dict = switch (try self.objectValue(reference)) { .dict => |dict| dict, else => return null, }; const to_unicode = dict.get("ToUnicode") orelse return null; const stream_ref = switch (to_unicode) { .reference => |stream_ref| stream_ref, else => return null, }; const stream = try self.objectStream(stream_ref); const arena = self.arena_state.allocator(); const decoded = try self.decodeStream(stream); defer self.filter_storage.reset(); return cmap.parseAlloc(arena, decoded) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.BadCMap => null, }; }};Source: lib/pdf/src/root.zig:19
zig
pub const Document = @import("document.zig").Document;Audit
| Definitions | 9 |
|---|---|
| Public names | 9 |
| Members | 7 |
| Version | 26.7.0 |
| Revision | daab053ee433 |