4

Is it possible to bold out specific letters within a word in itext?

Consider this sentence, "this is a word". Could i make all the "i" withing that sentence bold? So the output would be like this: "this is a word"

So to get the first word right (this), do i really have to create three chunks for one word and than add all the chunks together? Or is there another approach?

With three chunks i mean something like this (i know its not working code but made it like this for readability):

Chunk chunk1 = new Chunk("th");
Chunk chunk2 = new Chunk("i", bold);
Chunk chunk3 = new Chunk("s");

Paragraph p = new Paragraph(); 
p.add(chunk1); p.add(chunk2); p.add(chunk3)

There has to be a better way. Some "strings" i want colorized as well, like each letter in the string will have a different color, do i have to create chunks for each letter than combine them?

With a EditText box in android to change each letter color i could use SpannableString. But its different with itext since it doesnt have the char. I hope you guys understand what i mean, i will post two methods on how i solved in android in an editText box. Now i just want a similar method for writing a colorized and bold text to a pdf.

    public SpannableString colorizeText(String text) {
        SpannableString spannableColor = new SpannableString(text);
        int x = 1;
        for(char letter : text.toCharArray()){
            spannableColor.setSpan(new ForegroundColorSpan(returnCorrectColor(letter)), x-1, x, 0);
            x++;
        }
        return spannableColor;
    }

    private int returnCorrectColor(char letter) {
        String theLetter = Character.toString(letter);
        if (theLetter.contains("a")){
            return Color.BLUE;
        }
        else if(theLetter.contains("o")){
            return Color.GREEN;
        }
        return Color.RED;
    }
user3711421
  • 1,658
  • 3
  • 20
  • 37

2 Answers2

3

Why do you say you code sample isn't working? I've combined your iText and Android example into a new example: ColoredLetters

I've written a method similar to yours:

private Chunk returnCorrectColor(char letter) {
    if (letter == 'b'){
        return B;
    }
    else if(letter == 'g'){
        return G;
    }
    return new Chunk(String.valueOf(letter), RED_NORMAL);
}

Note that I used some constants:

public static final Font RED_NORMAL = new Font(FontFamily.HELVETICA, 12, Font.NORMAL, BaseColor.RED);
public static final Font BLUE_BOLD = new Font(FontFamily.HELVETICA, 12, Font.BOLD, BaseColor.BLUE);
public static final Font GREEN_ITALIC = new Font(FontFamily.HELVETICA, 12, Font.ITALIC, BaseColor.GREEN);
public static final Chunk B = new Chunk("b", BLUE_BOLD);
public static final Chunk G = new Chunk("g", GREEN_ITALIC);

Now I can construct a Paragraph like this:

Paragraph p = new Paragraph();
String s = "all text is written in red, except the letters b and g; they are written in blue and green.";
for (int i = 0; i < s.length(); i++) {
    p.add(returnCorrectColor(s.charAt(i)));
}

The result looks like this: colored_letters.pdf

enter image description here

An alternative would be to use different fonts, where fontB only contains the letter b and fontG only contains the letter g. You could then declare these fonts to the FontSelector object, along with a normal font. You could then process the font. For an example using this alternative, please read my answer to the following question: iText changing the font color and size when using fontselector

Updates based on additional questions in the comments

Could i specify the color as a HEX. for example something like BaseColor(#ffcd03); I understand that you can specify it like new BaseColor(0, 0, 255), however HEX would be more useful.

Actually, I like the HEX notation more myself, because it is easier for me to recognize certain colors when they are expressed in HEX notation. That's why I often use the HEX notation for integers in Java like this: new BaseColor(0xFF, 0xCD, 0x03);

Additionally, there is a decodeColor() method in the HtmlUtilities class that can be used like this:

BaseColor color = HtmlUtilities.decodeColor("#ffcd03");

is there a way to just define the color and leave the font to the default. Something like this: public static final Font RED_NORMAL = new Font(BaseColor.RED);

You could create the font like this:

new Font(FontFamily.UNDEFINED, 12, Font.UNDEFINED, BaseColor.RED);

Now when you add a Chunk with such a font to a Paragraph, it should take the font defined at the level of the Paragraph (that's how I intended it when I first wrote iText. I should check if this is still true).

My goal is to write a program that colorizes existing PDF files without changing the structure of the PDF. Do you think this approach will work for this purpose (performance etc)?

No, this will not work. If you read the introduction of chapter 6 of the second edition of iText in Action, you'll understand that PDF is not a format that was created for editing. The internal syntax for the sentence shown in the screen shot looks like this:

BT
36 806 Td
0 -16 Td
/F1 12 Tf
1 0 0 rg
(all text is written in red, except the letters ) Tj
0 g
/F2 12 Tf
0 0 1 rg
(b) Tj
0 g
/F1 12 Tf
1 0 0 rg
( and ) Tj
0 g
/F3 12 Tf
0 1 0 rg
(g) Tj
0 g
/F1 12 Tf
1 0 0 rg
(; they are written in ) Tj
0 g
/F2 12 Tf
0 0 1 rg
(b) Tj
0 g
/F1 12 Tf
1 0 0 rg
(lue and ) Tj
0 g
/F3 12 Tf
0 1 0 rg
(g) Tj
0 g
/F1 12 Tf
1 0 0 rg
(reen.) Tj
0 g
0 0 Td
ET

As you can see, the Tf operator changes the font:

  • /F1 is the regular font,
  • /F2 is the bold font,
  • /F3 is the italic font.

These names refer to fonts in the /Resources dictionary of the page, where you'll find the references to the actual font descriptors.

The rg operator changes the color. As we use red, green and blue, you recognize the operande 1 0 0, 0 1 0 and 0 0 1.

This looks fairly simple, because we used WINANSI encoding. One could parse the content stream, look for all the PDF string (between ( and ) or between < and >), and introduce Tf and rg operators.

However: the content stream won't always be as trivial as here. Custom encodings can be used, Unicode can be used,... Take a look at the second screen shot in my answer to the following question: Can't get Czech characters while generating a PDF. You'll understand that your plan to change colors in an existing PDF is a non-trivial task. We have done such a project in the past for one of our customers. It was a project that took several weeks.

Community
  • 1
  • 1
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Answered by Bruno himself, i feel honored :). Spent the whole day reading your book and watching you on youtube. I wrote that it wouldnt work because i hadnt defined the font "bold". You understood exactly what i meant, and it works for my project. My goal is to write a program that colorizes existing PDF files without changing the structure of the PDF. Do you think this approach will work for this purpose (performance etc)? I want to colorize each and every letter. Great that you used constants, i guess that will improve performance not having to instantiate a font in the loop. – user3711421 Nov 22 '14 at 19:58
  • Oh, is there a way to just define the color and leave the font to the default. Something like this: public static final Font RED_NORMAL = new Font(BaseColor.RED); – user3711421 Nov 22 '14 at 20:00
  • And while im at it, hehe. Could i specify the color as a HEX. for example something like BaseColor(#ffcd03); I understand that you can specify it like new BaseColor(0, 0, 255), however HEX would be more useful. – user3711421 Nov 22 '14 at 20:18
  • Thanks for your thorough answer, and the tricks on how to use HEX and UNDEFINED. "No, this will not work..." too bad, i guess i knew that although i didn't want to accept it.. But you also mentioned that you have done it, this means that it is not impossible at least. Right now my app can take in a PDF, extract the text, colorize it, than create a pdf from that colorized text. So now my next step is to write a method that finds headers/titles in that extracted text, hehe. Thanks for warning me that this process could take a while, but none the least is achievable. – user3711421 Nov 23 '14 at 15:35
  • Watch http://m.youtube.com/watch?v=lZnbhnU4m3Y for some info about the project we did. Some sample code is available in the SVN repository on sourceforge. Look for the java one examples in the sandbox under trunk. (I'm answering from my phone. It's not that practical for me to find the correct link right now.) – Bruno Lowagie Nov 23 '14 at 17:55
  • Okej, i will make sure to watch that however i cannot find the SVN repository, i found something on github but is uncertain if that is what you mean: (https://github.com/itext/itextpdf/tree/master/sandbox/src). Please provide a link whenever comfortable :). I was thinking about my problem with the formatting. Right now i extract text from PDF to a string which i colorize and creates a new PDF with. I understod correct that there was no way to keep the original texts' style when extracting the text to my string? I mean, the PDF.getText().toString() deletes the texts' style? – user3711421 Nov 24 '14 at 17:18
2

If anyone looking for few word in bold and few normal then this how you do,

NAME : Ullas

  Paragraph NameField = new Paragraph(); 
        NameField.add(new Chunk("   NAME : ", new Font(base, 11f, Font.BOLD)));
        NameField.add(new Chunk("   Ullas Kularni", new Font(base, 11f, Font.NORMAL)));
        NameField.setAlignment(Element.ALIGN_CENTER);
        doc.add(NameField);
ULLAS K
  • 881
  • 2
  • 11
  • 24