2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License,
22 * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23 * (or with modified versions of the above that use the same license as the above),
24 * and distribute linked combinations including the two. You must obey the
25 * GNU General Public License in all respects for all of the code used other than
26 * the above mentioned libraries. If you modify this file, you may extend this
27 * exception to your version of the file, but you are not obligated to do so.
28 * If you do not wish to do so, delete this exception statement from your version.
30 package mircoders.pdf;
33 import gnu.regexp.REException;
34 import gnu.regexp.REMatch;
35 import gnu.regexp.REMatchEnumeration;
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.net.MalformedURLException;
42 import mir.config.MirPropertiesConfiguration;
43 import mir.entity.EntityBrowser;
44 import mir.entity.adapter.EntityAdapter;
45 import mir.log.LoggerWrapper;
46 import mir.misc.StringUtil;
47 import mir.util.DateTimeRoutines;
48 import mir.util.HTMLRoutines;
49 import mir.util.ParameterExpander;
50 import mir.generator.GeneratorHelper;
51 import mir.generator.GeneratorExc;
52 import mircoders.entity.EntityContent;
53 import mircoders.entity.EntityImages;
54 import mircoders.storage.DatabaseImages;
55 import mircoders.global.MirGlobal;
56 import mircoders.localizer.MirLocalizerExc;
58 import com.lowagie.text.BadElementException;
59 import com.lowagie.text.Document;
60 import com.lowagie.text.DocumentException;
61 import com.lowagie.text.Element;
62 import com.lowagie.text.Font;
63 import com.lowagie.text.Image;
64 import com.lowagie.text.PageSize;
65 import com.lowagie.text.Paragraph;
66 import com.lowagie.text.Phrase;
67 import com.lowagie.text.pdf.BaseFont;
68 import com.lowagie.text.pdf.ColumnText;
69 import com.lowagie.text.pdf.PdfContentByte;
70 import com.lowagie.text.pdf.PdfTemplate;
71 import com.lowagie.text.pdf.PdfWriter;
72 import multex.Failure;
74 public class PDFGenerator {
75 public Document document;
76 public PdfWriter writer;
77 public PdfContentByte cb;
78 public String localImageDir;
79 public float currentYPosition;
80 public int currentPage;
81 public float pageWidth;
82 public float pageHeight;
83 public float verticalMargin;
84 public float horizontalMargin;
86 public float bottomEdge;
87 public float rightEdge;
88 public float leftEdge;
90 public int maxImageHeight;
91 public int maxImageWidth;
92 protected LoggerWrapper logger;
94 public int indexFontSize;
95 public int indexLineHeight;
96 public int indexFontFamily;
98 public float footerHeight;
99 public String footerText;
100 public int footerFontSize;
101 public int footerFontFamily;
103 public int metaHeight;
104 public int metaFontSize;
105 public int metaFontFamily;
107 public int descriptionLineHeight;
108 public int descriptionFontSize;
109 public int descriptionFontFamily;
111 public int contentLineHeight;
112 public int contentFontSize;
113 public int contentFontFamily;
115 public int sourceLineHeight;
116 public int sourceFontSize;
117 public int sourceFontFamily;
119 public int bigImageCaptionFontSize;
120 public int bigImageCaptionFontFamily;
122 protected MirPropertiesConfiguration configuration;
125 public PDFGenerator(ByteArrayOutputStream out) {
126 logger = new LoggerWrapper("PDFGenerator");
127 configuration = MirPropertiesConfiguration.instance();
128 localImageDir = configuration.getString("Producer.Image.Path");
131 indexFontSize = Integer.parseInt(configuration.getString("PDF.Index.FontSize"));
132 indexLineHeight = Integer.parseInt(configuration.getString("PDF.Index.LineHeight"));
133 indexFontFamily = getFontByName(configuration.getString("PDF.Index.FontFamily"));
135 footerText = configuration.getString("PDF.Footer.String");
136 footerFontSize = Integer.parseInt(configuration.getString("PDF.Footer.FontSize"));
137 footerFontFamily = getFontByName(configuration.getString("PDF.Footer.FontFamily"));
138 footerHeight = Integer.parseInt(configuration.getString("PDF.Footer.Height"));
140 metaFontSize = Integer.parseInt(configuration.getString("PDF.Meta.FontSize"));
141 metaFontFamily = getFontByName(configuration.getString("PDF.Meta.FontFamily"));
142 metaHeight = Integer.parseInt(configuration.getString("PDF.Meta.Height"));
144 descriptionFontSize = Integer.parseInt(configuration.getString("PDF.Description.FontSize"));
145 descriptionLineHeight = Integer.parseInt(configuration.getString("PDF.Description.LineHeight"));
146 descriptionFontFamily = getFontByName(configuration.getString("PDF.Description.FontFamily"));
148 contentFontSize = Integer.parseInt(configuration.getString("PDF.Content.FontSize"));
149 contentLineHeight = Integer.parseInt(configuration.getString("PDF.Content.LineHeight"));
150 contentFontFamily = getFontByName(configuration.getString("PDF.Content.FontFamily"));
152 sourceFontSize = Integer.parseInt(configuration.getString("PDF.Source.FontSize"));
153 sourceLineHeight = Integer.parseInt(configuration.getString("PDF.Source.LineHeight"));
154 sourceFontFamily = getFontByName(configuration.getString("PDF.Source.FontFamily"));
156 bigImageCaptionFontSize = Integer.parseInt(configuration.getString("PDF.BigImageCaption.FontSize"));
157 bigImageCaptionFontFamily = getFontByName(configuration.getString("PDF.BigImageCaption.FontFamily"));
160 catch (NumberFormatException e) {
161 throw new Failure(e.getMessage(), e);
164 // step 1: make a document
166 String pageSize = configuration.getString("PDF.Pagesize");
168 if (pageSize.equals("LETTER")) {
169 document = new Document(PageSize.LETTER);
173 document = new Document(PageSize.A4);
178 maxImageHeight = 250;
183 horizontalMargin = 20;
186 topEdge = pageHeight - verticalMargin;
187 bottomEdge = verticalMargin;
188 rightEdge = pageWidth - horizontalMargin;
189 leftEdge = horizontalMargin;
191 currentYPosition = topEdge;
194 String headerText = configuration.getString("PDF.Title.String");
197 writer = PdfWriter.getInstance(document, out);
198 cb = writer.getDirectContent();
201 addHeader(headerText);
203 catch (DocumentException de) {
204 logger.error(de.getMessage());
213 public void addHeader(String headerText) {
214 int titleFontSize = Integer.parseInt(configuration.getString("PDF.Title.FontSize"));
215 int titleLineHeight = Integer.parseInt(configuration.getString("PDF.Title.LineHeight"));
216 String titleFontFamily = configuration.getString("PDF.Title.FontFamily");
217 String headerImage = configuration.getString("PDF.Header.Image");
218 int headerImageHeight = Integer.parseInt(configuration.getString("PDF.Header.ImageHeight"));
221 if ((! headerImage.equals("")) && headerImageHeight != 0) {
222 PdfTemplate template = cb.createTemplate(rightEdge - horizontalMargin, headerImageHeight);
224 float toYPosition = currentYPosition - headerImageHeight;
225 Image theImage = Image.getInstance(headerImage);
226 theImage.setAbsolutePosition(0, 0);
227 // theImage.scaleAbsolute(img_width,img_height);
228 template.addImage(theImage);
231 cb.addTemplate(template, leftEdge, toYPosition);
232 currentYPosition = toYPosition;
234 if (! headerText.equals("")) {
235 ColumnText ct = new ColumnText(cb);
237 ct.addText(new Phrase(headerText, new Font(getFontByName(titleFontFamily), titleFontSize, Font.BOLD)));
238 float[] rightCol = {rightEdge, currentYPosition, rightEdge, currentYPosition - titleLineHeight};
239 float[] leftCol = {leftEdge, currentYPosition, leftEdge, currentYPosition - titleLineHeight};
240 ct.setColumns(leftCol, rightCol);
241 ct.setYLine(currentYPosition);
242 ct.setAlignment(Element.ALIGN_CENTER);
245 currentYPosition = currentYPosition - titleLineHeight;
248 catch (DocumentException de) {
249 logger.error(de.getMessage());
251 catch (MalformedURLException de) {
252 logger.error(de.getMessage());
254 catch (IOException de) {
255 logger.error(de.getMessage());
259 public void addIndexItem(EntityContent entityContent) {
262 ColumnText ict = new ColumnText(cb);
263 String theTitle = entityContent.getFieldValue("title");
264 String theCreator = entityContent.getFieldValue("creator");
265 Phrase titleP = new Phrase(" - " + theTitle, new Font(indexFontFamily, indexFontSize, Font.BOLD));
266 Phrase creatorP = new Phrase(" :: " + theCreator, new Font(indexFontFamily, indexFontSize));
267 float toYPosition = currentYPosition - indexLineHeight;
268 float[] leftIndexCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
269 float[] rightIndexCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
271 ict.addText(creatorP);
272 ict.setColumns(leftIndexCols, rightIndexCols);
273 ict.setYLine(currentYPosition);
274 ict.setAlignment(Element.ALIGN_LEFT);
276 currentYPosition = toYPosition;
278 catch (DocumentException de) {
279 logger.error(de.getMessage());
285 private int addTextLine(ColumnText ct, int lineHeight, int alignment, float left, float right) {
286 logger.debug("adding a line of text");
287 if (! enoughY(lineHeight)) {
290 float toYPosition = currentYPosition - lineHeight;
291 float[] leftContentCols = {left, currentYPosition, left, toYPosition};
292 float[] rightContentCols = {right, currentYPosition, right, toYPosition};
293 ct.setColumns(leftContentCols, rightContentCols);
294 ct.setYLine(currentYPosition);
295 ct.setAlignment(alignment);
297 int status = ct.go();
298 currentYPosition = toYPosition;
301 catch (DocumentException de) {
302 logger.error(de.getMessage());
307 public void addLine() {
309 cb.moveTo(rightEdge, currentYPosition - 5);
310 cb.lineTo(leftEdge, currentYPosition - 5);
312 currentYPosition = currentYPosition - 10;
316 public void addFooter() {
318 ColumnText fct = new ColumnText(cb);
320 cb.moveTo(rightEdge, bottomEdge + footerHeight - 5);
321 cb.lineTo(leftEdge, bottomEdge + footerHeight - 5);
323 float[] leftFooterCols = {leftEdge, bottomEdge + footerHeight - 1, leftEdge, bottomEdge};
324 float[] rightFooterCols = {rightEdge, bottomEdge + footerHeight - 1, rightEdge, bottomEdge};
326 Paragraph footerP = new Paragraph(footerText, new Font(footerFontFamily, footerFontSize));
327 fct.addText(footerP);
329 fct.setColumns(leftFooterCols, rightFooterCols);
330 fct.setYLine(bottomEdge + footerHeight - 1);
331 fct.setAlignment(Element.ALIGN_JUSTIFIED);
334 Paragraph numberP = new Paragraph((new Integer(currentPage)).toString(), new Font(footerFontFamily, footerFontSize, Font.BOLD));
335 fct.addText(numberP);
336 fct.setAlignment(Element.ALIGN_RIGHT);
340 catch (DocumentException de) {
341 logger.error(de.getMessage());
347 public void newPage() {
353 currentYPosition = topEdge;
355 catch (DocumentException de) {
356 logger.error(de.getMessage());
360 public void addArticleSeparator() {
366 cb.moveTo(rightEdge, currentYPosition - 5);
367 cb.lineTo(leftEdge, currentYPosition - 5);
369 currentYPosition = currentYPosition - 10;
372 public void addArticleMetaInfo(ColumnText ct, String theTitle, String theCreator, String theDate) {
373 //see if we have room for the author and title
375 if (! enoughY(metaHeight)) {
379 Paragraph titleP = new Paragraph(theTitle + "\n", new Font(metaFontFamily, metaFontSize, Font.BOLD));
380 Paragraph whowhenP = new Paragraph(theCreator + " " + theDate, new Font(metaFontFamily, metaFontSize));
382 ct.addText(whowhenP);
384 ct.setYLine(currentYPosition);
385 ct.setAlignment(Element.ALIGN_LEFT);
387 float toYPosition = currentYPosition - metaHeight;
388 float[] leftHeadCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
389 float[] rightHeadCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
391 ct.setColumns(leftHeadCols, rightHeadCols);
394 currentYPosition = toYPosition;
396 catch (DocumentException de) {
397 logger.error(de.getMessage());
402 public void addArticleDescription(ColumnText ct, String theDescription) {
403 // Now we add the description, one line at a time, the ct should be empty at this point
406 Paragraph descP = new Paragraph(theDescription, new Font(descriptionFontFamily, descriptionFontSize, Font.BOLD));
409 // every article has a description, so we can assume that:
410 int status = ColumnText.NO_MORE_COLUMN;
413 while ((status & ColumnText.NO_MORE_TEXT) == 0 && brake > 0) {
414 //there is still text left in the description.
415 status = addTextLine(ct, descriptionLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
419 logger.error("runaway description...try increasing the line height or decreasing the font size");
422 public void addArticleContent(ColumnText ct, String theContent, Iterator images) {
423 //let's go ahead and add in all the body text
424 Paragraph contentP = new Paragraph(theContent, new Font(contentFontFamily, contentFontSize));
425 ct.addText(contentP);
427 int contentLinesBeforeImages = 3;
428 //and assume we have at least one line of text in the content
429 int status = ColumnText.NO_MORE_COLUMN;
431 // let's add a little bit of text, like a couple of lines
433 while (((status & ColumnText.NO_MORE_TEXT) == 0) && x < contentLinesBeforeImages) {
434 status = addTextLine(ct, contentLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
438 boolean addImageOnLeft = true; //we will alternate within articles
439 while (images.hasNext()) {
441 EntityImages currentImage = (EntityImages) images.next();
442 float img_width = (new Float(currentImage.getFieldValue("img_width"))).floatValue();
443 float img_height = (new Float(currentImage.getFieldValue("img_height"))).floatValue();
444 if (img_height > maxImageHeight) {
445 img_width = (new Float((new Float(img_width * (maxImageHeight / img_height))).intValue())).floatValue();
446 img_height = maxImageHeight;
448 if (img_width > maxImageWidth) {
449 img_height = (new Float((new Float(img_height * (maxImageWidth / img_width))).intValue())).floatValue();
450 img_width = maxImageWidth;
453 String img_title = currentImage.getFieldValue("title");
454 String img_path = currentImage.getFieldValue("publish_path");
456 if ((status & ColumnText.NO_MORE_TEXT) == 0) {
457 // there is still text, so add an image which will have text wrapped around it, then add the text which
458 // will be on the left or the right of the image
460 float templateMinimumHeight = img_height + 20;
461 float templateWidth = img_width + 10;
462 float templateHeight = templateMinimumHeight + contentLineHeight - (templateMinimumHeight % contentLineHeight);
464 PdfTemplate template = cb.createTemplate(templateWidth, templateHeight);
466 //here we need a page check
467 if (! enoughY((new Float(templateHeight)).intValue())) {
468 //ok, well just fill text to the bottom then
469 float toYPosition = bottomEdge + footerHeight;
470 float[] leftBottomCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
471 float[] rightBottomCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
472 ct.setColumns(leftBottomCols, rightBottomCols);
473 ct.setYLine(currentYPosition);
474 ct.setAlignment(Element.ALIGN_JUSTIFIED);
478 catch (DocumentException de) {
479 logger.error(de.getMessage());
484 float toYPosition = currentYPosition - templateHeight;
487 Image theImage = Image.getInstance(localImageDir + img_path);
488 theImage.scaleAbsolute(img_width, img_height);
489 theImage.setAbsolutePosition(5, 13);
491 template.addImage(theImage);
492 template.beginText();
493 BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
494 template.setFontAndSize(bf, 8);
495 template.setTextMatrix(5, 3);
496 template.showText(img_title);
499 catch (BadElementException de) {
500 logger.error(de.getMessage());
502 catch (DocumentException de) {
503 logger.error(de.getMessage());
505 catch (MalformedURLException de) {
506 logger.error(de.getMessage());
508 catch (IOException de) {
509 logger.error(de.getMessage());
513 float leftImageTextEdge = leftEdge;
514 float rightImageTextEdge = rightEdge;
517 if (addImageOnLeft) {
518 cb.addTemplate(template, leftEdge, toYPosition);
519 leftImageTextEdge = leftEdge + templateWidth + 5;
520 addImageOnLeft = false;
522 cb.addTemplate(template, rightEdge - templateWidth, toYPosition);
523 rightImageTextEdge = rightEdge - templateWidth - 5;
524 addImageOnLeft = true;
527 logger.debug("adding template at " + leftEdge + "," + toYPosition);
529 //and fill some text while we are at it
531 float[] leftBottomCols = {leftImageTextEdge, currentYPosition, leftImageTextEdge, toYPosition};
532 float[] rightBottomCols = {rightImageTextEdge, currentYPosition, rightImageTextEdge, toYPosition};
533 ct.setColumns(leftBottomCols, rightBottomCols);
534 ct.setYLine(currentYPosition);
535 ct.setAlignment(Element.ALIGN_JUSTIFIED);
538 currentYPosition = toYPosition;
540 catch (DocumentException de) {
541 logger.error(de.getMessage());
546 //add an image on the left with a big caption to the right
547 currentYPosition = currentYPosition - 10;
548 float templateMinimumHeight = img_height;
549 float templateWidth = img_width;
550 float templateHeight = templateMinimumHeight + contentLineHeight - (templateMinimumHeight % contentLineHeight);
551 PdfTemplate template = cb.createTemplate(templateWidth, templateHeight);
552 if (! enoughY((new Float(templateHeight)).intValue())) {
555 float toYPosition = currentYPosition - templateHeight;
557 Image theImage = Image.getInstance(localImageDir + img_path);
558 theImage.setAbsolutePosition(0, 13);
559 theImage.scaleAbsolute(img_width, img_height);
560 template.addImage(theImage);
562 catch (BadElementException de) {
563 logger.error(de.getMessage());
565 catch (DocumentException de) {
566 logger.error(de.getMessage());
568 catch (MalformedURLException de) {
569 logger.error(de.getMessage());
571 catch (IOException de) {
572 logger.error(de.getMessage());
575 cb.addTemplate(template, leftEdge, toYPosition);
578 ColumnText cct = new ColumnText(cb);
579 float[] leftCaptionCols = {leftEdge + templateWidth + 5, currentYPosition - 5, leftEdge + templateWidth + 5, toYPosition};
580 float[] rightCaptionCols = {rightEdge, currentYPosition - 5, rightEdge, toYPosition};
582 Paragraph captionP = new Paragraph(img_title, new Font(bigImageCaptionFontFamily, bigImageCaptionFontSize, Font.BOLD));
583 cct.addText(captionP);
584 cct.setColumns(leftCaptionCols, rightCaptionCols);
585 cct.setYLine(currentYPosition - 5);
586 cct.setAlignment(Element.ALIGN_LEFT);
589 currentYPosition = toYPosition;
591 catch (DocumentException de) {
592 logger.error(de.getMessage());
597 //add the rest of the text which might be left
599 while ((status & ColumnText.NO_MORE_TEXT) == 0 && brake > 0) {
600 status = addTextLine(ct, contentLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
604 logger.error("runaway content....try decreasing font size or increasing line height");
607 private void addArticleSource(ColumnText ct, String theSource) {
608 Paragraph sourceP = new Paragraph(theSource, new Font(sourceFontFamily, sourceFontSize, Font.BOLD));
610 addTextLine(ct, sourceLineHeight, Element.ALIGN_RIGHT, leftEdge, rightEdge);
614 private boolean enoughY(int heightOfBlockToAdd) {
615 if ((currentYPosition - heightOfBlockToAdd - footerHeight) < bottomEdge)
621 public void add(EntityContent anArticle, Locale aLocale) throws GeneratorExc, MirLocalizerExc, Exception {
622 logger.debug("adding a content Entity");
632 * --image without text
636 List extraTables = new ArrayList();
637 extraTables.add("content_x_media cxm");
638 Iterator images = new EntityBrowser(
639 DatabaseImages.getInstance(), "i", extraTables,
640 "cxm.content_id=" + anArticle.getId() + "and cxm.media_id=i.id",
641 "i.id desc", 30, -1, 0);
643 String isHTML = anArticle.getFieldValue("is_html");
644 String theTitle = anArticle.getFieldValue("title");
645 String theCreator = anArticle.getFieldValue("creator");
646 String theDate = DateTimeRoutines.advancedDateFormat(
647 configuration.getString("RDF.Meta.DateFormat"),
648 StringUtil.convertMirInternalDateToDate(anArticle.getFieldValue("webdb_create")),
649 configuration.getString("Mir.DefaultTimezone"));
652 String theDescriptionRaw = anArticle.getFieldValue("description");
653 String theContentRaw = anArticle.getFieldValue("content_data");
655 MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
656 Map variables = GeneratorHelper.makeBasicGenerationData(new Locale[] {
657 aLocale ,new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "")},
658 "bundles.open","bundles.open");
660 EntityAdapter article =
661 MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", anArticle);
662 variables.put("article", article);
663 String source = ParameterExpander.expandExpression(
665 configuration.getString("PDF.Source")
667 String theContent = "";
668 String theDescription = "";
670 if (isHTML.equals("1")) {
674 RE nobackslashr = new RE("\r");
675 theContent = nobackslashr.substituteAll(theContentRaw, "");
676 theDescription = nobackslashr.substituteAll(theDescriptionRaw, "");
678 RE HxTag = new RE("</?h[1-6][^>]*>", RE.REG_ICASE);
679 theContent = HxTag.substituteAll(theContent, "\n\n");
680 theDescription = HxTag.substituteAll(theDescription, "\n\n");
682 RE ListItemTag = new RE("<li[^>]*>", RE.REG_ICASE);
683 theContent = ListItemTag.substituteAll(theContent, "\n * ");
684 theDescription = ListItemTag.substituteAll(theDescription, "\n * ");
686 RE ListTag = new RE("<(u|o)l[^>]*>", RE.REG_ICASE);
687 theContent = ListTag.substituteAll(theContent, "\n");
688 theDescription = ListTag.substituteAll(theDescription, "\n");
690 RE DivTag = new RE("</?div[^>]*>", RE.REG_ICASE);
691 theContent = DivTag.substituteAll(theContent, "\n");
692 theDescription = DivTag.substituteAll(theDescription, "\n");
694 RE PTag = new RE("<(p|P)([:space:]+[^>]*)?>");
695 theContent = PTag.substituteAll(theContent, "\n ");
696 theDescription = PTag.substituteAll(theDescription, "\n ");
698 RE PTagClose = new RE("</(p|P)([:space:]+[^>]*)?>");
699 theContent = PTagClose.substituteAll(theContent, "\n");
700 theDescription = PTagClose.substituteAll(theDescription, "\n");
702 RE BRTag = new RE("<(br|BR)([:space:]+[^>]*)?>");
703 theContent = BRTag.substituteAll(theContent, "\n");
704 theDescription = BRTag.substituteAll(theDescription, "\n");
706 RE ATagAll = new RE("<a[^>]*href=(?:\"|\')([^#\"\'][^\'\"]+)(?:\"|\')[^>]*>(.*?)</a>", RE.REG_ICASE);
707 REMatchEnumeration atags = ATagAll.getMatchEnumeration(theContent);
708 String theContentCopy = theContent;
709 while (atags.hasMoreMatches()) {
710 REMatch atag = atags.nextMatch();
711 String atagString = atag.toString();
712 String atagStringHref = atag.toString(1);
713 String atagStringText = atag.toString(2);
714 int begin = theContentCopy.indexOf(atagString);
715 theContentCopy = theContentCopy.substring(0, begin) + atagStringText + " [" + atagStringHref + "] " + theContentCopy.substring(begin + atagString.length());
717 theContent = theContentCopy;
719 REMatchEnumeration atags2 = ATagAll.getMatchEnumeration(theDescription);
720 String theDescriptionCopy = theDescription;
721 while (atags2.hasMoreMatches()) {
722 REMatch atag = atags2.nextMatch();
723 String atagString = atag.toString();
724 String atagStringHref = atag.toString(1);
725 String atagStringText = atag.toString(2);
726 int begin = theDescriptionCopy.indexOf(atagString);
727 theDescriptionCopy = theDescriptionCopy.substring(0, begin) + atagStringText + " [" + atagStringHref + "] " + theDescriptionCopy.substring(begin + atagString.length());
729 theDescription = theDescriptionCopy;
732 RE noTags = new RE("<[^>]*>");
733 theContent = noTags.substituteAll(theContent, " ");
734 theDescription = noTags.substituteAll(theDescription, " ");
736 theContent = HTMLRoutines.resolveHTMLEntites(theContent);
737 theDescription = HTMLRoutines.resolveHTMLEntites(theDescription);
739 RE re1 = new RE("\r?\n\r?\n");
740 String theDescription1 = re1.substituteAll(theDescription, "BREAKHERE");
742 RE re2 = new RE("\r?\n");
743 String theDescription2 = re2.substituteAll(theDescription1, " ");
745 RE re3 = new RE("BREAKHERE");
746 theDescription = re3.substituteAll(theDescription2, "\n ");
750 catch (REException ree) {
751 logger.error(ree.getMessage());
755 RE re1 = new RE("\r?\n\r?\n");
756 String theContent1 = re1.substituteAll(theContentRaw, "BREAKHERE");
757 String theDescription1 = re1.substituteAll(theDescriptionRaw, "BREAKHERE");
759 RE re2 = new RE("\r?\n");
760 String theContent2 = re2.substituteAll(theContent1, " ");
761 String theDescription2 = re2.substituteAll(theDescription1, " ");
763 RE re3 = new RE("BREAKHERE");
764 theContent = " " + re3.substituteAll(theContent2, "\n ");
765 theDescription = re3.substituteAll(theDescription2, "\n ");
768 catch (REException ree) {
769 logger.error(ree.getMessage());
773 addArticleSeparator();
775 ColumnText ct = new ColumnText(cb);
777 addArticleMetaInfo(ct, theTitle, theCreator, theDate);
778 addArticleDescription(ct, theDescription);
779 addArticleContent(ct, theContent, images);
780 addArticleSource(ct, source);
783 public int getFontByName(String fontName) {
785 if ("helvetica".equalsIgnoreCase(fontName)) {
786 theFont = Font.HELVETICA;
788 else if ("courier".equalsIgnoreCase(fontName)) {
789 theFont = Font.COURIER;
791 else if ("times".equalsIgnoreCase(fontName)) {
792 theFont = Font.TIMES_ROMAN;
795 logger.error("using helvetica because I can't get font for name: " + fontName);
796 theFont = Font.HELVETICA;