Skip to content
This repository was archived by the owner on Jun 29, 2025. It is now read-only.

Commit 63ce08b

Browse files
author
Javier Orfo
committed
output
1 parent 0c0adda commit 63ce08b

File tree

6 files changed

+225
-129
lines changed

6 files changed

+225
-129
lines changed

src/epub/Cover.zig

Lines changed: 0 additions & 59 deletions
This file was deleted.

src/epub/Epub.zig

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ const Section = @import("Section.zig");
44
const Body = @import("../util/body.zig").Body;
55
const output = @import("../util/output.zig");
66
const Stylesheet = @import("Stylesheet.zig");
7-
const Cover = @import("Cover.zig");
87
const Metadata = @import("Metadata.zig");
98
const testing = std.testing;
109

1110
allocator: std.mem.Allocator,
1211
metadata: Metadata,
1312
sections: ?std.ArrayList(Section) = null,
1413
stylesheet: ?Stylesheet = null,
15-
cover: ?Cover = null,
14+
cover: ?Section = null,
15+
cover_image: ?[]const u8 = null,
1616
images: ?[][]const u8 = null,
1717

1818
const Epub = @This();
@@ -29,10 +29,10 @@ pub fn deinit(self: *Epub) void {
2929
}
3030

3131
pub fn addSection(self: *Epub, title: []const u8, body: Body) *Epub {
32-
return self.addSectionWithReferenceType(title, Section.ReferenceType.Text, body);
32+
return self.addSectionType(title, body, Section.ReferenceType.Text);
3333
}
3434

35-
pub fn addSectionWithReferenceType(self: *Epub, title: []const u8, reference_type: Section.ReferenceType, body: Body) *Epub {
35+
pub fn addSectionType(self: *Epub, title: []const u8, body: Body, reference_type: Section.ReferenceType) *Epub {
3636
if (self.sections == null) self.sections = std.ArrayList(Section).init(self.allocator);
3737

3838
self.sections.?.append(Section.create(self.allocator, title, reference_type, body)) catch {
@@ -52,12 +52,12 @@ pub fn addImages(self: *Epub, paths: [][]const u8) *Epub {
5252
}
5353

5454
pub fn addCover(self: *Epub, body: Body) *Epub {
55-
self.cover = Cover.create(self.allocator, body, null);
55+
self.cover = Section.create(self.allocator, self.metadata.title, Section.ReferenceType.Cover, body);
5656
return self;
5757
}
5858

59-
pub fn addCoverWithImage(self: *Epub, body: Body, image_path: []const u8) *Epub {
60-
self.cover = Cover.create(self.allocator, body, image_path);
59+
pub fn addCoverImage(self: *Epub, cover_image_path: []const u8) *Epub {
60+
self.cover_image = cover_image_path;
6161
return self;
6262
}
6363

@@ -79,15 +79,16 @@ test "epub" {
7979
defer epub.deinit();
8080

8181
var mock_images_paths = [_][]const u8{
82-
"/path/to/img1.jpg",
83-
"/path/to/img2.jpg",
82+
"/home/javier/Downloads/cats.jpg",
83+
"/home/javier/Downloads/cats.jpg",
8484
};
8585

8686
try epub
8787
.addStylesheet(.{ .raw = "body { background: '#808080' }" })
88-
.addCoverWithImage(.{ .raw = "<h1>title</h1>" }, "/path/to/img.png")
88+
.addCoverImage("/home/javier/Downloads/cats.jpg")
8989
.addImages(&mock_images_paths)
90-
.addSectionWithReferenceType("Preface", .Preface, .{ .raw = "<p>preface</p>" })
90+
.addCover(.{ .raw = "<div class=\"cover\"><img src=\"images/cats.jpg\" alt=\"Cover Image\"/></div>" })
91+
.addSectionType("Preface", .{ .raw = "<p>preface</p>" }, .Preface)
9192
.addSection("Chapter 1", .{ .raw = "<p>test</p>" })
9293
.addSection("Chapter 2", .{ .raw = "<p>test</p>" })
9394
.generate("MyEpub");

src/epub/Metadata.zig

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
const std = @import("std");
22
const UUID = @import("../util/UUID.zig");
33

4-
const uuid_ident_template =
5-
\\<dc:identifier id="bookid">urn:uuid:{s}</dc:identifier>
6-
;
7-
const isbn_ident_template =
8-
\\<dc:identifier id="bookid">urn:isbn:{s}</dc:identifier>
9-
;
10-
114
title: []const u8,
125
creator: []const u8,
136
identifier: Identifier,
@@ -27,11 +20,6 @@ pub fn defaultIdentifier() Identifier {
2720
const Identifier = struct {
2821
value: []const u8,
2922
identifier_type: IdentifierType,
30-
31-
fn createIdentifierTag(self: Identifier) []const u8 {
32-
_ = self;
33-
return "";
34-
}
3523
};
3624

3725
const IdentifierType = enum(u2) {
@@ -85,7 +73,7 @@ const Language = enum(u8) {
8573
.Slovak => "sk",
8674
.Slovenian => "sl",
8775
.Spanish => "es",
88-
.Swedishw => "sv",
76+
.Swedish => "sv",
8977
.Turkish => "tr",
9078
};
9179
}

src/util/output.zig

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
const std = @import("std");
22
const Epub = @import("../epub/Epub.zig");
3+
const xhtml = @import("xhtml.zig");
34

45
const output_folder = "epub-files";
5-
const meta_inf_folder = output_folder ++ "/META-INF";
6-
const oebps_folder = output_folder ++ "/OEBPS";
6+
const meta_inf_folder = output_folder ++ "/META-INF/";
7+
const oebps_folder = output_folder ++ "/OEBPS/";
78
const mimetype = output_folder ++ "/mimetype";
89
const mimetype_content = "application/epub+zip";
9-
const images_folder = oebps_folder ++ "/images";
10-
const stylesheet = oebps_folder ++ "/stylesheet.css";
11-
const container = meta_inf_folder ++ "/container.xml";
10+
const images_folder = oebps_folder ++ "images/";
11+
const stylesheet = oebps_folder ++ "stylesheet.css";
12+
const container = meta_inf_folder ++ "container.xml";
13+
const content_opf = oebps_folder ++ "content.opf";
14+
1215
const container_content =
1316
\\<?xml version="1.0"?>
1417
\\<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
1518
\\ <rootfiles>
16-
\\ <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml" />
19+
\\ <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
1720
\\ </rootfiles>
1821
\\</container>
1922
;
2023

2124
pub fn createEpubFiles(epub: *Epub) !void {
25+
const cwd = std.fs.cwd();
26+
2227
try createOrOverrideDir(output_folder);
23-
try std.fs.cwd().makeDir(meta_inf_folder);
24-
try std.fs.cwd().makeDir(oebps_folder);
25-
try std.fs.cwd().makeDir(images_folder);
28+
try cwd.makeDir(meta_inf_folder);
29+
try cwd.makeDir(oebps_folder);
30+
try cwd.makeDir(images_folder);
2631
try createFileAndWrite(mimetype, mimetype_content);
2732
try createFileAndWrite(container, container_content);
2833

34+
try createContentOpf(epub);
35+
2936
std.log.debug("Generating stylesheet if set: {s}\n", .{stylesheet});
3037
if (epub.stylesheet) |ss| try ss.generate(stylesheet);
38+
39+
std.log.debug("Copying cover image if set: {any}\n", .{epub.cover_image});
40+
if (epub.cover_image) |path| {
41+
try saveToImageFolder(epub.allocator, path);
42+
}
43+
44+
std.log.debug("Copying images if set: {any}\n", .{epub.cover_image});
45+
if (epub.images) |images| {
46+
for (images) |img| try saveToImageFolder(epub.allocator, img);
47+
}
48+
}
49+
50+
fn saveToImageFolder(allocator: std.mem.Allocator, from: []const u8) !void {
51+
const cwd = std.fs.cwd();
52+
const epub_image_path = try std.mem.concat(allocator, u8, &.{ images_folder, std.fs.path.basename(from) });
53+
defer allocator.free(epub_image_path);
54+
try cwd.copyFile(from, cwd, epub_image_path, .{});
3155
}
3256

3357
fn createFileAndWrite(filename: []const u8, content: []const u8) !void {
@@ -38,13 +62,80 @@ fn createFileAndWrite(filename: []const u8, content: []const u8) !void {
3862
}
3963

4064
fn createOrOverrideDir(dirname: []const u8) !void {
41-
std.fs.cwd().makeDir(dirname) catch |err| {
65+
const cwd = std.fs.cwd();
66+
67+
cwd.makeDir(dirname) catch |err| {
4268
if (err == error.PathAlreadyExists) {
4369
std.log.debug("Deleting and creating existent dir: {s}\n", .{dirname});
44-
try std.fs.cwd().deleteTree(dirname);
45-
try std.fs.cwd().makeDir(dirname);
70+
try cwd.deleteTree(dirname);
71+
try cwd.makeDir(dirname);
4672
} else {
4773
return err;
4874
}
4975
};
5076
}
77+
78+
fn createContentOpf(epub: *Epub) !void {
79+
var file = try std.fs.cwd().createFile(content_opf, .{});
80+
defer file.close();
81+
try file.writeAll(xhtml.content_opf_package_metadata);
82+
83+
// METADATA
84+
const metadata = epub.metadata;
85+
86+
const title = try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_title, .{metadata.title});
87+
defer epub.allocator.free(title);
88+
try file.writeAll(title);
89+
90+
const creator = try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_creator, .{metadata.creator});
91+
defer epub.allocator.free(creator);
92+
try file.writeAll(creator);
93+
94+
const identifier = switch (metadata.identifier.identifier_type) {
95+
.ISBN => try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_identifier_isbn, .{metadata.identifier.value}),
96+
.UUID => try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_identifier_uuid, .{metadata.identifier.value}),
97+
};
98+
defer epub.allocator.free(identifier);
99+
try file.writeAll(identifier);
100+
101+
const language = try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_language, .{metadata.language.toString()});
102+
defer epub.allocator.free(language);
103+
try file.writeAll(language);
104+
105+
if (metadata.date) |d| {
106+
const date = try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_date, .{d});
107+
defer epub.allocator.free(date);
108+
try file.writeAll(date);
109+
}
110+
111+
if (metadata.publisher) |p| {
112+
const publisher = try std.fmt.allocPrint(epub.allocator, xhtml.content_opt_metadata_publisher, .{p});
113+
defer epub.allocator.free(publisher);
114+
try file.writeAll(publisher);
115+
}
116+
117+
if (epub.cover_image) |_| try file.writeAll(xhtml.content_opt_metadata_cover_image);
118+
119+
try file.writeAll(xhtml.content_opf_metadata_manifest);
120+
121+
// MANIFEST
122+
if (epub.stylesheet) |_| try file.writeAll(xhtml.content_opf_manifest_css);
123+
124+
if (epub.sections) |sections| {
125+
for (sections.items) |section| {
126+
const id = try std.mem.replaceOwned(u8, epub.allocator, section.title, " ", "");
127+
defer epub.allocator.free(id);
128+
const html = try std.fmt.allocPrint(epub.allocator, xhtml.content_opf_manifest_xhtml, .{ id, id });
129+
defer epub.allocator.free(html);
130+
try file.writeAll(html);
131+
}
132+
}
133+
134+
if (epub.cover) |_| {
135+
const html = try std.fmt.allocPrint(epub.allocator, xhtml.content_opf_manifest_xhtml, .{ "cover", "cover" });
136+
defer epub.allocator.free(html);
137+
try file.writeAll(html);
138+
}
139+
140+
// cover_img
141+
}

0 commit comments

Comments
 (0)