Coloring text programmatically comes up more than you'd expect once you're generating or post-processing Word files from Java — flagging changed clauses in a contract, marking up review comments, or just making a generated report easier to skim. There's more than one way to do it, and which one you reach for depends on whether you're coloring a whole paragraph, a specific run of text, or every occurrence of a keyword across the document. Here's how each one works, and a couple of things that aren't obvious until you hit them.
Setup
The examples below use Spire.Doc for Java. With Maven, add the dependency to pom.xml:
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc</artifactId>
<version>13.5.3</version>
</dependency>
</dependencies>
If you're not on Maven, the jar can also be downloaded directly from the official website and added to the classpath.
Method 1: Coloring an entire paragraph via a style
If you want to recolor everything in a paragraph at once, the cleanest way is to define a ParagraphStyle with the color you want and apply it to the paragraph.
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.ParagraphStyle;
import java.awt.*;
public class ColorWholeParagraph {
public static void main(String[] args) {
Document document = new Document();
document.loadFromFile("report.docx");
Section section = document.getSections().get(0);
Paragraph paragraph = section.getParagraphs().get(0);
ParagraphStyle style = new ParagraphStyle(document);
style.setName("HighlightRed");
style.getCharacterFormat().setTextColor(new Color(178, 34, 34));
document.getStyles().add(style);
paragraph.applyStyle(style.getName());
document.saveToFile("output/colored.docx", FileFormat.Docx);
}
}
This is the right tool when the whole paragraph should look consistent and you're not fighting existing run-level formatting. Which brings up the first gotcha: applying a paragraph style doesn't override formatting that's already set directly on the runs inside it. Word (and Spire.Doc, following the same model) treats direct/run-level formatting as taking priority over whatever the paragraph's style says. So if some of the text in that paragraph already has an explicit color set — maybe from a previous edit, or because it was pasted in with its own formatting — applyStyle() alone won't touch it, and you'll end up with a paragraph that's only partially recolored. If you need to guarantee every character changes, Method 2 below is more reliable.
Method 2: Coloring runs directly
A paragraph's text is stored as a sequence of child objects, and the actual text lives in TextRange objects mixed in with other elements like line breaks or inline images. Looping through them and setting the color on each TextRange sidesteps the style-precedence issue entirely, since you're changing the direct formatting itself.
import com.spire.doc.Document;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.fields.TextRange;
import com.spire.doc.FileFormat;
import java.awt.*;
public class ColorParagraphRuns {
public static void main(String[] args) {
Document document = new Document();
document.loadFromFile("report.docx");
Section section = document.getSections().get(0);
Paragraph paragraph = section.getParagraphs().get(1);
for (int i = 0; i < paragraph.getChildObjects().getCount(); i++) {
if (paragraph.getChildObjects().get(i) instanceof TextRange) {
TextRange run = (TextRange) paragraph.getChildObjects().get(i);
run.getCharacterFormat().setTextColor(Color.blue);
}
}
document.saveToFile("output/coloredRuns.docx", FileFormat.Docx);
}
}
This is a bit more verbose than the style-based approach, but it's the one to reach for when you can't assume the paragraph is formatting-clean, which in practice is most of the time with documents that have already been edited by a human.
Method 3: Coloring every occurrence of a specific phrase
Sometimes the target isn't a paragraph at all — it's a word or phrase that might show up anywhere in the document. findAllString() returns every match as a TextSelection, and each one can be turned into a formattable range.
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.documents.TextSelection;
import com.spire.doc.fields.TextRange;
import java.awt.*;
public class ColorMatchedText {
public static void main(String[] args) {
Document document = new Document();
document.loadFromFile("report.docx");
TextSelection[] matches = document.findAllString("Confidential", false, true);
for (TextSelection match : matches) {
TextRange range = match.getAsOneRange();
range.getCharacterFormat().setTextColor(Color.red);
}
document.saveToFile("output/coloredMatches.docx", FileFormat.Docx);
}
}
The getAsOneRange() call matters more than it looks. A phrase that appears as one visible word or sentence in Word isn't guaranteed to be stored as a single TextRange internally — spell-check state, tracked changes, or just how the original document was authored can split it into several adjacent runs. getAsOneRange() merges whatever runs made up that particular match into a single range so you can format it as one unit, rather than ending up with only part of the phrase changing color because you only touched the first run.
A couple of general notes
Colors are plain java.awt.Color objects, so anything that works there — named constants like Color.red, or explicit RGB via new Color(r, g, b) — works here too. And findAllString() takes two boolean flags after the search string (case sensitivity and whole-word matching); worth double-checking those against your actual search term, since a whole-word match on something like "PDF" won't catch it inside "PDFs" or "PDF-2".
Between the three, style-based coloring is the fastest to write when you control how the document was built, direct run coloring is the one that actually works when you don't, and text search is for anything keyword-driven rather than position-driven. Picking the right one up front saves having to debug why only half a paragraph changed color.
Comments
Post a Comment