Fix some CBZ cover/fake cover issues
[fanfix.git] / src / be / nikiroo / fanfix / output / Html.java
CommitLineData
2206ef66
NR
1package be.nikiroo.fanfix.output;
2
3d247bc3 3import java.io.BufferedWriter;
a6395bef 4import java.io.File;
3d247bc3 5import java.io.FileOutputStream;
a6395bef 6import java.io.IOException;
333f0e7b 7import java.io.InputStream;
3d247bc3 8import java.io.OutputStreamWriter;
333f0e7b
NR
9
10import javax.imageio.ImageIO;
2206ef66 11
a6395bef 12import be.nikiroo.fanfix.Instance;
333f0e7b 13import be.nikiroo.fanfix.bundles.Config;
a6395bef 14import be.nikiroo.fanfix.data.Chapter;
333f0e7b 15import be.nikiroo.fanfix.data.MetaData;
a6395bef
NR
16import be.nikiroo.fanfix.data.Paragraph;
17import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
18import be.nikiroo.fanfix.data.Story;
333f0e7b 19import be.nikiroo.utils.IOUtils;
a6395bef
NR
20import be.nikiroo.utils.StringUtils;
21
22class Html extends BasicOutput {
333f0e7b 23 private File dir;
3d247bc3 24 protected BufferedWriter writer;
a6395bef
NR
25 private boolean inDialogue = false;
26 private boolean inNormal = false;
27
28 @Override
29 public File process(Story story, File targetDir, String targetName)
30 throws IOException {
333f0e7b
NR
31 String targetNameOrig = targetName;
32
a6395bef
NR
33 File target = new File(targetDir, targetName);
34 target.mkdir();
333f0e7b 35 dir = target;
a6395bef 36
373da363
NR
37 // write a copy of the originals inside
38 InfoCover.writeInfo(dir, targetName, story.getMeta());
39 InfoCover.writeCover(dir, targetName, story.getMeta());
925298fd
NR
40 BasicOutput.getOutput(OutputType.TEXT, isWriteInfo(), isWriteCover())
41 .process(story, dir, targetNameOrig);
373da363 42
10d558d2 43 target = new File(targetDir, targetName + getDefaultExtension(true));
373da363 44
3d247bc3
NR
45 writer = new BufferedWriter(new OutputStreamWriter(
46 new FileOutputStream(target), "UTF-8"));
a6395bef
NR
47 try {
48 super.process(story, targetDir, targetNameOrig);
49 } finally {
50 writer.close();
51 writer = null;
52 }
53
333f0e7b
NR
54 String format = Instance.getConfig()
55 .getString(Config.IMAGE_FORMAT_COVER).toLowerCase();
56 if (story.getMeta().getCover() != null) {
57 ImageIO.write(story.getMeta().getCover(), format, new File(dir,
58 "cover." + format));
59 }
60
a6395bef
NR
61 return target;
62 }
63
64 @Override
10d558d2
NR
65 public String getDefaultExtension(boolean readerTarget) {
66 if (readerTarget) {
67 return File.separator + "index.html";
10d558d2 68 }
211f7ddb
NR
69
70 return "";
a6395bef
NR
71 }
72
73 @Override
74 protected void writeStoryHeader(Story story) throws IOException {
75 String title = "";
333f0e7b
NR
76 String tags = "";
77 String author = "";
78 Chapter resume = null;
a6395bef 79 if (story.getMeta() != null) {
333f0e7b
NR
80 MetaData meta = story.getMeta();
81 title = meta.getTitle();
82 resume = meta.getResume();
83 if (meta.getTags() != null) {
84 for (String tag : meta.getTags()) {
85 if (!tags.isEmpty()) {
86 tags += ", ";
87 }
88 tags += tag;
89 }
90
91 if (!tags.isEmpty()) {
92 tags = "(" + tags + ")";
93 }
94 }
95 author = meta.getAuthor();
96 }
97
98 String format = Instance.getConfig()
99 .getString(Config.IMAGE_FORMAT_COVER).toLowerCase();
100
101 InputStream inStyle = getClass().getResourceAsStream("html.style.css");
102 if (inStyle == null) {
103 throw new IOException("Cannot find style.css resource");
104 }
105 try {
106 IOUtils.write(inStyle, new File(dir, "style.css"));
107 } finally {
108 inStyle.close();
a6395bef
NR
109 }
110
111 writer.write("<!DOCTYPE html>");
112 writer.write("\n<html>");
113 writer.write("\n<head>");
114 writer.write("\n <meta http-equiv='content-type' content='text/html; charset=utf-8'>");
115 writer.write("\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>");
333f0e7b 116 writer.write("\n <link rel='stylesheet' type='text/css' href='style.css'>");
a6395bef
NR
117 writer.write("\n <title>" + StringUtils.xmlEscape(title) + "</title>");
118 writer.write("\n</head>");
119 writer.write("\n<body>\n");
120
333f0e7b
NR
121 writer.write("\n <div class=\"titlepage\">");
122 writer.write("\n <h1>" + StringUtils.xmlEscape(title) + "</h1>");
123 writer.write("\n <div class=\"type\">" + StringUtils.xmlEscape(tags)
124 + "</div>");
125 writer.write("\n <div class=\"cover\">");
126 writer.write("\n <img src=\"cover." + format + "\"></img>");
127 writer.write("\n </div>");
128 writer.write("\n <div class=\"author\">"
129 + StringUtils.xmlEscape(author) + "</div>");
130 writer.write("\n </div>");
131
132 writer.write("\n <hr/><br/>");
133
134 if (resume != null) {
135 for (Paragraph para : resume) {
136 writeParagraph(para);
137 }
138 if (inDialogue) {
139 writer.write(" </div>\n");
140 inDialogue = false;
141 }
142 if (inNormal) {
143 writer.write(" </div>\n");
144 inNormal = false;
145 }
146 }
147
148 writer.write("\n <br/>");
a6395bef
NR
149 }
150
151 @Override
152 protected void writeStoryFooter(Story story) throws IOException {
153 writer.write("</body>\n");
154 }
155
156 @Override
157 protected void writeChapterHeader(Chapter chap) throws IOException {
333f0e7b 158 String nameOrNumber;
a6395bef 159 if (chap.getName() != null && !chap.getName().isEmpty()) {
333f0e7b 160 nameOrNumber = chap.getName();
a6395bef 161 } else {
333f0e7b 162 nameOrNumber = Integer.toString(chap.getNumber());
a6395bef
NR
163 }
164
333f0e7b
NR
165 writer.write("\n <h2>");
166 writer.write("\n <span class='chap'>Chapter <span class='chapnumber'>"
167 + chap.getNumber() + "</span>:</span> ");
168 writer.write("\n <span class='chaptitle'>"
169 + StringUtils.xmlEscape(nameOrNumber) + "</span>");
170 writer.write("\n </h2>");
171 writer.write("\n ");
172 writer.write("\n <div class='chapter_content'>\n");
a6395bef
NR
173
174 inDialogue = false;
175 inNormal = false;
176 }
177
333f0e7b
NR
178 @Override
179 protected void writeChapterFooter(Chapter chap) throws IOException {
180 if (inDialogue) {
181 writer.write(" </div>\n");
182 inDialogue = false;
183 }
184 if (inNormal) {
185 writer.write(" </div>\n");
186 inNormal = false;
187 }
188
189 writer.write("\n </div>");
190 }
191
a6395bef
NR
192 @Override
193 protected void writeParagraphHeader(Paragraph para) throws IOException {
194 if (para.getType() == ParagraphType.QUOTE && !inDialogue) {
195 writer.write(" <div class='dialogues'>\n");
196 inDialogue = true;
197 } else if (para.getType() != ParagraphType.QUOTE && inDialogue) {
198 writer.write(" </div>\n");
199 inDialogue = false;
200 }
201
202 if (para.getType() == ParagraphType.NORMAL && !inNormal) {
203 writer.write(" <div class='normals'>\n");
204 inNormal = true;
205 } else if (para.getType() != ParagraphType.NORMAL && inNormal) {
206 writer.write(" </div>\n");
207 inNormal = false;
208 }
209
210 switch (para.getType()) {
211 case BLANK:
212 writer.write(" <div class='blank'></div>");
213 break;
214 case BREAK:
f977d05b 215 writer.write(" <hr class='break'/>");
a6395bef
NR
216 break;
217 case NORMAL:
218 writer.write(" <span class='normal'>");
219 break;
220 case QUOTE:
221 writer.write(" <div class='dialogue'>&mdash; ");
222 break;
223 case IMAGE:
224 // TODO
225 writer.write("<a href='"
226 + StringUtils.xmlEscapeQuote(para.getContent()) + "'>"
227 + StringUtils.xmlEscape(para.getContent()) + "</a>");
228 break;
229 }
230 }
231
232 @Override
233 protected void writeParagraphFooter(Paragraph para) throws IOException {
234 switch (para.getType()) {
235 case NORMAL:
236 writer.write("</span>\n");
237 break;
238 case QUOTE:
239 writer.write("</div>\n");
240 break;
241 default:
242 writer.write("\n");
243 break;
244 }
245 }
246
247 @Override
248 protected void writeTextLine(ParagraphType type, String line)
249 throws IOException {
250 switch (type) {
251 case QUOTE:
252 case NORMAL:
253 writer.write(decorateText(StringUtils.xmlEscape(line)));
254 break;
255 default:
256 break;
257 }
258 }
259
260 @Override
261 protected String enbold(String word) {
262 return "<strong>" + word + "</strong>";
263 }
264
265 @Override
266 protected String italize(String word) {
267 return "<emph>" + word + "</emph>";
268 }
2206ef66 269}