<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Coding with Files]]></title><description><![CDATA[Coding with Files]]></description><link>https://codingwithfiles.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 23 Sep 2026 07:51:16 GMT</lastBuildDate><atom:link href="https://codingwithfiles.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Add Data Validation to Excel in Java]]></title><description><![CDATA[Excel data validation is useful when a worksheet is meant to be filled in by other people. Instead of accepting any value, a cell can be limited to a number range, a date period, a certain text length]]></description><link>https://codingwithfiles.hashnode.dev/how-to-add-data-validation-to-excel-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-add-data-validation-to-excel-in-java</guid><category><![CDATA[Java]]></category><category><![CDATA[excel]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Tue, 15 Sep 2026 08:56:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/51e625f5-303d-4a6b-8157-e78c7115fdf3.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Excel data validation is useful when a worksheet is meant to be filled in by other people. Instead of accepting any value, a cell can be limited to a number range, a date period, a certain text length, or a predefined list of choices.</p>
<p>This is especially helpful for forms and reusable templates, where inconsistent input can create extra cleanup work later.</p>
<p>In this tutorial, we’ll add several common validation rules to an Excel worksheet with Java, including whole number, date, text length, list, and time validation.</p>
<h2>Common Excel Data Validation Types</h2>
<p>Excel supports several validation types for different kinds of input:</p>
<table>
<thead>
<tr>
<th>Validation Type</th>
<th>Typical Use</th>
</tr>
</thead>
<tbody><tr>
<td>Whole number</td>
<td>Quantities, counts, IDs</td>
</tr>
<tr>
<td>Decimal</td>
<td>Prices, percentages, measurements</td>
</tr>
<tr>
<td>List</td>
<td>Status, department, category</td>
</tr>
<tr>
<td>Date</td>
<td>Deadlines, submission dates, schedules</td>
</tr>
<tr>
<td>Time</td>
<td>Appointments, shifts, working hours</td>
</tr>
<tr>
<td>Text length</td>
<td>Codes, abbreviations, identifiers</td>
</tr>
</tbody></table>
<p>Most rules are built from three parts: the allowed data type, a comparison operator, and one or two limits.</p>
<p>For example, a quantity field may accept only whole numbers from 1 to 100, while a date field may allow only dates within a given year.</p>
<h2>Environment Setup</h2>
<p>Add the required Excel processing dependency to your Java project.</p>
<p>For Maven, add the following to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.xls&lt;/artifactId&gt;
        &lt;version&gt;16.8.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>Import the required classes:</p>
<pre><code class="language-java">import com.spire.xls.*;
</code></pre>
<h2>Step 1: Create a Workbook and Access the Worksheet</h2>
<p>Create a workbook and get the first worksheet:</p>
<pre><code class="language-java">Workbook workbook = new Workbook();

Worksheet sheet = workbook.getWorksheets().get(0);
</code></pre>
<p>To make the sample worksheet easier to test, add a label for each validation type:</p>
<pre><code class="language-java">sheet.getCellRange("B2").setText("Whole Number Validation:");
sheet.getCellRange("B4").setText("Date Validation:");
sheet.getCellRange("B6").setText("Text Length Validation:");
sheet.getCellRange("B8").setText("List Validation:");
sheet.getCellRange("B10").setText("Time Validation:");
</code></pre>
<p>The corresponding input cells will be placed in column C.</p>
<h2>Step 2: Apply Data Validation</h2>
<h3>Whole Number Validation</h3>
<p>Suppose C2 is used for a quantity and should accept only whole numbers from 1 to 100:</p>
<pre><code class="language-java">CellRange rangeNumber = sheet.getCellRange("C2");

// Allow whole numbers only
rangeNumber.getDataValidation()
        .setAllowType(CellDataType.Integer);

// Restrict the value to a range
rangeNumber.getDataValidation()
        .setCompareOperator(
                ValidationComparisonOperator.Between
        );

// Set the minimum and maximum values
rangeNumber.getDataValidation().setFormula1("1");
rangeNumber.getDataValidation().setFormula2("100");

// Show an input prompt
rangeNumber.getDataValidation()
        .setInputMessage("Enter a whole number between 1 and 100");

// Highlight the input cell
rangeNumber.getCellStyle()
        .setKnownColor(ExcelColors.Gray25Percent);
</code></pre>
<p>This kind of rule works well for quantities, headcounts, inventory levels, and similar fields where decimal values should not be accepted.</p>
<h3>Date Validation</h3>
<p>For C4, limit the input to dates within 2026:</p>
<pre><code class="language-java">CellRange rangeDate = sheet.getCellRange("C4");

// Allow dates only
rangeDate.getDataValidation()
        .setAllowType(CellDataType.Date);

// Restrict the date to a specific range
rangeDate.getDataValidation()
        .setCompareOperator(
                ValidationComparisonOperator.Between
        );

// Set the start and end dates
rangeDate.getDataValidation()
        .setFormula1("1/1/2026");

rangeDate.getDataValidation()
        .setFormula2("12/31/2026");

// Show an input prompt
rangeDate.getDataValidation()
        .setInputMessage(
                "Enter a date between 1/1/2026 and 12/31/2026"
        );

rangeDate.getCellStyle()
        .setKnownColor(ExcelColors.Gray25Percent);
</code></pre>
<p>The comparison does not have to use <code>Between</code>. For a deadline field, for example, you could allow only dates on or after a certain day.</p>
<h3>Text Length Validation</h3>
<p>Text length validation is useful for fields such as internal codes, abbreviations, or short identifiers.</p>
<p>Here, C6 is limited to 10 characters:</p>
<pre><code class="language-java">CellRange rangeTextLength =
        sheet.getCellRange("C6");

// Validate the length of the entered text
rangeTextLength.getDataValidation()
        .setAllowType(CellDataType.TextLength);

// Limit the text to 10 characters
rangeTextLength.getDataValidation()
        .setCompareOperator(
                ValidationComparisonOperator.LessOrEqual
        );

rangeTextLength.getDataValidation()
        .setFormula1("10");

// Show an input prompt
rangeTextLength.getDataValidation()
        .setInputMessage(
                "Enter no more than 10 characters"
        );

rangeTextLength.getCellStyle()
        .setKnownColor(ExcelColors.Gray25Percent);
</code></pre>
<p>If a field must contain an exact number of characters, the comparison operator can be changed accordingly.</p>
<h3>List Validation</h3>
<p>For fields with a fixed set of values, a drop-down list helps avoid variations in spelling and wording.</p>
<p>The code below adds a department list to C8:</p>
<pre><code class="language-java">CellRange rangeList =
        sheet.getCellRange("C8");

// Define the available choices
rangeList.getDataValidation().setValues(
        new String[]{
                "Development",
                "Testing",
                "Marketing",
                "Finance"
        }
);

// Show the drop-down arrow
rangeList.getDataValidation()
        .isSuppressDropDownArrow(false);

// Show an input prompt
rangeList.getDataValidation()
        .setInputMessage("Select a department from the list");

rangeList.getCellStyle()
        .setKnownColor(ExcelColors.Gray25Percent);
</code></pre>
<p>For a short, stable list, defining the values directly in code is usually sufficient.</p>
<p>If the list changes frequently, it is better to keep the values in a worksheet range and use that range as the validation source.</p>
<h3>Time Validation</h3>
<p>C10 can be restricted to times between 9:00 and 18:00:</p>
<pre><code class="language-java">CellRange rangeTime =
        sheet.getCellRange("C10");

// Allow time values only
rangeTime.getDataValidation()
        .setAllowType(CellDataType.Time);

// Restrict the value to a time range
rangeTime.getDataValidation()
        .setCompareOperator(
                ValidationComparisonOperator.Between
        );

rangeTime.getDataValidation()
        .setFormula1("9:00");

rangeTime.getDataValidation()
        .setFormula2("18:00");

// Show an input prompt
rangeTime.getDataValidation()
        .setInputMessage(
                "Enter a time between 9:00 and 18:00"
        );

rangeTime.getCellStyle()
        .setKnownColor(ExcelColors.Gray25Percent);
</code></pre>
<p>This can be useful for appointment times, work shifts, or any field that should stay within defined working hours.</p>
<h2>Step 3: Adjust the Worksheet Layout</h2>
<p>A little formatting makes the generated sheet easier to use:</p>
<pre><code class="language-java">// Auto-fit column B
sheet.autoFitColumn(2);

// Set the width of column C
sheet.setColumnWidth(3, 20);
</code></pre>
<h2>Step 4: Save the Workbook</h2>
<p>Save the finished workbook:</p>
<pre><code class="language-java">workbook.saveToFile(
        "DataValidation.xlsx",
        ExcelVersion.Version2016
);

workbook.dispose();
</code></pre>
<p>The generated worksheet now contains five different validation rules:</p>
<ul>
<li><p>C2 accepts whole numbers from 1 to 100.</p>
</li>
<li><p>C4 accepts dates within 2026.</p>
</li>
<li><p>C6 accepts up to 10 characters.</p>
</li>
<li><p>C8 provides a department drop-down list.</p>
</li>
<li><p>C10 accepts times between 9:00 and 18:00.</p>
</li>
</ul>
<p>These rules stay with the workbook, so the same input restrictions apply whenever the file is reused as a template.</p>
]]></content:encoded></item><item><title><![CDATA[How to Extract Tables from Word Documents with Python]]></title><description><![CDATA[Word documents often use tables to store structured information such as inventory lists, inspection records, project data, and reports. Extracting one table manually is simple enough, but it quickly b]]></description><link>https://codingwithfiles.hashnode.dev/how-to-extract-tables-from-word-documents-with-python</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-extract-tables-from-word-documents-with-python</guid><category><![CDATA[Python]]></category><category><![CDATA[word]]></category><category><![CDATA[table]]></category><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Tue, 15 Sep 2026 03:29:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/6dbf3b44-c9d8-4460-902c-62455d1bb276.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Word documents often use tables to store structured information such as inventory lists, inspection records, project data, and reports. Extracting one table manually is simple enough, but it quickly becomes tedious when a document contains several tables or when many Word files need to be processed.</p>
<p>With Python, you can read the rows and cells of a Word table and convert the content into a structure that is easier to reuse or export.</p>
<p>This guide covers how to read a table from a Word document, extract all tables to CSV files, and process multiple Word files in a folder.</p>
<h2>Environment Setup</h2>
<p>To run the examples below, install the required Python module for Word processing:</p>
<pre><code class="language-bash">pip install Spire.Doc
</code></pre>
<h2>Read a Table from a Word Document</h2>
<p>A Word table can be accessed through its section and then read row by row.</p>
<p>The example below reads the first table in the first section and stores its content in a two-dimensional Python list:</p>
<pre><code class="language-python">from spire.doc import *
from spire.doc.common import *

input_file = "input.docx"

document = Document()
document.LoadFromFile(input_file)

section = document.Sections.get_Item(0)
table = section.Tables.get_Item(0)

table_data = []

for r in range(table.Rows.Count):
    row = table.Rows.get_Item(r)
    row_data = []

    for c in range(row.Cells.Count):
        cell = row.Cells.get_Item(c)

        paragraphs = []

        for p in range(cell.Paragraphs.Count):
            text = cell.Paragraphs.get_Item(p).Text.strip()

            if text:
                paragraphs.append(text)

        row_data.append(" ".join(paragraphs))

    table_data.append(row_data)

for row in table_data:
    print(row)

document.Close()
</code></pre>
<p>A table cell may contain more than one paragraph, so the code reads all paragraphs in the cell instead of assuming that only one exists.</p>
<p>The extracted data may look like this:</p>
<pre><code class="language-python">[
    ["Name", "Department", "Position"],
    ["John Smith", "Development", "Software Engineer"],
    ["Emma Lee", "Testing", "QA Engineer"]
]
</code></pre>
<p>If the original paragraph breaks need to be preserved, replace:</p>
<pre><code class="language-python">" ".join(paragraphs)
</code></pre>
<p>with:</p>
<pre><code class="language-python">"\n".join(paragraphs)
</code></pre>
<h2>Extract All Tables from Word to CSV</h2>
<p>A Word document may contain tables in more than one section. To extract all of them, iterate through every section and its <code>Tables</code> collection.</p>
<p>The following code saves each table as a separate CSV file:</p>
<pre><code class="language-python">import csv
import os
from spire.doc import *
from spire.doc.common import *

input_file = "input.docx"
output_folder = "ExtractedTables"

os.makedirs(output_folder, exist_ok=True)

document = Document()
document.LoadFromFile(input_file)

table_number = 0

for s in range(document.Sections.Count):
    section = document.Sections.get_Item(s)

    for t in range(section.Tables.Count):
        table = section.Tables.get_Item(t)
        table_number += 1

        output_file = os.path.join(
            output_folder,
            f"table_{table_number}.csv"
        )

        with open(
            output_file,
            "w",
            newline="",
            encoding="utf-8-sig"
        ) as csv_file:

            writer = csv.writer(csv_file)

            for r in range(table.Rows.Count):
                row = table.Rows.get_Item(r)
                row_data = []

                for c in range(row.Cells.Count):
                    cell = row.Cells.get_Item(c)

                    paragraphs = []

                    for p in range(cell.Paragraphs.Count):
                        text = cell.Paragraphs.get_Item(p).Text.strip()

                        if text:
                            paragraphs.append(text)

                    row_data.append(" ".join(paragraphs))

                writer.writerow(row_data)

document.Close()

print(f"Extracted {table_number} tables.")
</code></pre>
<p>If the document contains three tables, the output folder will look like this:</p>
<pre><code class="language-text">ExtractedTables/
├── table_1.csv
├── table_2.csv
└── table_3.csv
</code></pre>
<p>The CSV files use <code>utf-8-sig</code>, which helps avoid encoding problems when text containing non-ASCII characters is opened directly in spreadsheet applications such as Excel.</p>
<h2>Batch Extract Tables from Multiple Word Files</h2>
<p>For multiple documents, it is cleaner to move the extraction logic into a reusable function instead of repeating the same code for every file.</p>
<pre><code class="language-python">import csv
import os
from spire.doc import *
from spire.doc.common import *


def extract_tables(word_file, output_folder):
    os.makedirs(output_folder, exist_ok=True)

    document = Document()
    document.LoadFromFile(word_file)

    table_number = 0

    for s in range(document.Sections.Count):
        section = document.Sections.get_Item(s)

        for t in range(section.Tables.Count):
            table = section.Tables.get_Item(t)
            table_number += 1

            output_file = os.path.join(
                output_folder,
                f"table_{table_number}.csv"
            )

            with open(
                output_file,
                "w",
                newline="",
                encoding="utf-8-sig"
            ) as csv_file:

                writer = csv.writer(csv_file)

                for r in range(table.Rows.Count):
                    row = table.Rows.get_Item(r)
                    row_data = []

                    for c in range(row.Cells.Count):
                        cell = row.Cells.get_Item(c)

                        text = " ".join(
                            cell.Paragraphs.get_Item(p).Text.strip()
                            for p in range(cell.Paragraphs.Count)
                            if cell.Paragraphs.get_Item(p).Text.strip()
                        )

                        row_data.append(text)

                    writer.writerow(row_data)

    document.Close()

    return table_number


input_folder = "WordFiles"
output_folder = "ExtractedTables"

for file_name in os.listdir(input_folder):

    if not file_name.lower().endswith((".doc", ".docx")):
        continue

    input_file = os.path.join(input_folder, file_name)

    document_name = os.path.splitext(file_name)[0]

    document_output = os.path.join(
        output_folder,
        document_name
    )

    count = extract_tables(
        input_file,
        document_output
    )

    print(f"{file_name}: extracted {count} tables")
</code></pre>
<p>Each document gets its own output folder, so tables from different files do not overwrite one another:</p>
<pre><code class="language-text">ExtractedTables/
├── report/
│   ├── table_1.csv
│   └── table_2.csv
├── inventory/
│   └── table_1.csv
└── records/
    ├── table_1.csv
    └── table_2.csv
</code></pre>
<h2>A Note on Merged Cells</h2>
<p>Merged cells need extra attention when exporting Word tables to CSV.</p>
<p>Word supports both horizontal and vertical cell merging, while CSV only stores rows and columns and has no concept of merged cells. As a result, a complex Word table may not map cleanly to a flat CSV structure.</p>
<p>If the extracted data will be imported into a database or used for analysis, it is worth checking tables with merged headers or grouped rows and normalizing them as needed after extraction.</p>
<h2>Conclusion</h2>
<p>Extracting Word tables with Python mainly involves reading the document structure from sections to tables, rows, and cells.</p>
<p>For a single table, you can access it directly and convert the content into a Python list. For documents with multiple tables, iterating through each section makes it straightforward to export every table to its own CSV file. The same logic can also be reused for batch processing when multiple Word documents need to be handled.</p>
]]></content:encoded></item><item><title><![CDATA[Compress PDF Files with Python: Images, Fonts & Document Content]]></title><description><![CDATA[Large PDF files are not always caused by a high page count. High-resolution images, scanned pages, embedded fonts, and insufficiently compressed document content can all increase file size significant]]></description><link>https://codingwithfiles.hashnode.dev/compress-pdf-files-with-python-images-fonts-document-content</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/compress-pdf-files-with-python-images-fonts-document-content</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 11 Sep 2026 09:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/810c14c9-1804-48f5-a1b5-7e44fee8c216.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Large PDF files are not always caused by a high page count. High-resolution images, scanned pages, embedded fonts, and insufficiently compressed document content can all increase file size significantly.</p>
<p>When PDFs need to be sent by email, uploaded to a website, or stored in bulk, the best compression method depends on what the file contains. For example, scanned PDFs usually benefit most from image compression, while text-heavy documents may be reduced by compressing fonts and document content.</p>
<p>This article shows how to compress images, fonts, and document content in PDF files with Python, as well as how to process multiple PDFs in a folder.</p>
<h2>Environment Setup</h2>
<p>To run the code examples below, first install the required Python module for PDF processing:</p>
<pre><code class="language-bash">pip install Spire.PDF
</code></pre>
<h2>Compress Images in a PDF with Python</h2>
<p>For scanned documents, product manuals, screenshots, and similar PDFs, images often account for most of the file size.</p>
<p>You can reduce the size of these files by compressing the images and adjusting their quality:</p>
<pre><code class="language-python">from spire.pdf import *

input_file = "input.pdf"
output_file = "compressed_images.pdf"

# Load the PDF file
compressor = PdfCompressor(input_file)

# Get compression options
options = compressor.OptimizationOptions

# Enable image resizing
options.SetResizeImages(True)

# Enable image compression
options.SetIsCompressImage(True)

# Set image quality
options.SetImageQuality(ImageQuality.Medium)

# Save the compressed PDF
compressor.CompressToFile(output_file)
</code></pre>
<p><code>SetIsCompressImage(True)</code> enables image compression, while <code>SetResizeImages(True)</code> allows image dimensions to be adjusted during compression.</p>
<p>Image quality can be set to low, medium, or high. For PDFs mainly intended for on-screen viewing, <code>Medium</code> is a reasonable starting point.</p>
<p>For engineering drawings, contract scans, or documents that need to remain readable when zoomed in, avoid starting with a low image quality setting. Excessive compression may make text, lines, or other fine details difficult to read.</p>
<h2>Compress Embedded Fonts in a PDF</h2>
<p>PDF files often embed fonts so that text is displayed consistently across different devices.</p>
<p>If a document uses several fonts, or if the embedded font files are relatively large, font data can also contribute to the overall file size.</p>
<p>The following example compresses embedded fonts:</p>
<pre><code class="language-python">from spire.pdf import *

input_file = "input.pdf"
output_file = "compressed_fonts.pdf"

# Load the PDF file
compressor = PdfCompressor(input_file)

# Get compression options
options = compressor.OptimizationOptions

# Compress embedded fonts
options.SetIsCompressFonts(True)

# Save the compressed PDF
compressor.CompressToFile(output_file)
</code></pre>
<p>If you need to reduce the file size further, embedded fonts can also be removed:</p>
<pre><code class="language-python">options.SetIsUnembedFonts(True)
</code></pre>
<p>This option should be used with caution.</p>
<p>If the system opening the PDF does not have the required font installed, the PDF viewer may substitute another font. This can affect text appearance and, in some cases, page layout.</p>
<p>For PDFs that need to be shared across different devices, printed, or archived, it is usually safer to keep fonts embedded and only compress the font data.</p>
<h2>Compress PDF Document Content</h2>
<p>In addition to images and fonts, the PDF document itself can also be compressed.</p>
<p>The following example disables incremental updates and sets the document compression level to the highest level:</p>
<pre><code class="language-python">from spire.pdf import *

input_file = "input.pdf"
output_file = "compressed.pdf"

# Load the PDF file
pdf = PdfDocument()
pdf.LoadFromFile(input_file)

# Disable incremental updates
pdf.FileInfo.IncrementalUpdate = False

# Set the document compression level
pdf.CompressionLevel = PdfCompressionLevel.Best

# Save the compressed PDF
pdf.SaveToFile(output_file)

pdf.Close()
</code></pre>
<p>The <code>IncrementalUpdate</code> setting is worth noting.</p>
<p>When a PDF is edited and saved, incremental updates can append new changes to the end of the existing file instead of rewriting the entire document.</p>
<p>This preserves previous data, but after repeated edits and saves, the file may contain additional data that is no longer needed, causing the file size to grow.</p>
<p>Setting:</p>
<pre><code class="language-python">pdf.FileInfo.IncrementalUpdate = False
</code></pre>
<p>forces the document to be rewritten when saved instead of continuing to append incremental changes.</p>
<p>This approach is more useful for PDFs that mainly contain text, vector graphics, and other document content. If the file consists mostly of scanned images, document compression alone may not make a noticeable difference, and image compression should also be applied.</p>
<h2>Compress Images and Fonts Together</h2>
<p>For PDFs that contain both images and embedded fonts, you can enable both compression options in the same operation:</p>
<pre><code class="language-python">from spire.pdf import *

input_file = "input.pdf"
output_file = "compressed.pdf"

# Load the PDF file
compressor = PdfCompressor(input_file)

# Get compression options
options = compressor.OptimizationOptions

# Compress images
options.SetResizeImages(True)
options.SetIsCompressImage(True)
options.SetImageQuality(ImageQuality.Medium)

# Compress fonts
options.SetIsCompressFonts(True)

# Save the compressed PDF
compressor.CompressToFile(output_file)
</code></pre>
<p>This approach keeps fonts embedded while reducing both image and font data, making it suitable for many general-purpose documents.</p>
<p>For image-heavy PDFs, you can test different image quality levels and compare the resulting file size and visual quality before deciding which setting is appropriate.</p>
<h2>Batch Compress Multiple PDF Files</h2>
<p>If you need to process multiple PDFs, you can loop through a folder and apply the same compression settings to each file:</p>
<pre><code class="language-python">import os
from spire.pdf import *

input_folder = "PDFs"
output_folder = "Compressed"

os.makedirs(output_folder, exist_ok=True)

for file_name in os.listdir(input_folder):

    if not file_name.lower().endswith(".pdf"):
        continue

    input_file = os.path.join(input_folder, file_name)
    output_file = os.path.join(output_folder, file_name)

    # Load the PDF file
    compressor = PdfCompressor(input_file)

    # Get compression options
    options = compressor.OptimizationOptions

    # Compress images
    options.SetResizeImages(True)
    options.SetIsCompressImage(True)
    options.SetImageQuality(ImageQuality.Medium)

    # Compress fonts
    options.SetIsCompressFonts(True)

    # Save the compressed PDF
    compressor.CompressToFile(output_file)

    print(f"Compressed: {file_name}")
</code></pre>
<p>This approach is useful for processing archived documents, preparing files before upload, or compressing PDFs as part of a batch workflow.</p>
<h2>Why Does PDF Compression Sometimes Make Little Difference?</h2>
<p>The result depends heavily on the original PDF content.</p>
<p>For example, if the images in a PDF are already heavily compressed, recompressing them may save very little additional space.</p>
<p>Similarly, if a PDF mainly contains simple text and its fonts, images, and content streams have already been optimized, the file size may not change much after another compression pass.</p>
<p>The following table provides a simple guide:</p>
<table>
<thead>
<tr>
<th>PDF Type</th>
<th>Recommended Approach</th>
</tr>
</thead>
<tbody><tr>
<td>Scanned PDF</td>
<td>Image compression</td>
</tr>
<tr>
<td>PDF with many screenshots or photos</td>
<td>Image compression and resizing</td>
</tr>
<tr>
<td>Text-heavy report</td>
<td>Document and font compression</td>
</tr>
<tr>
<td>PDF with many embedded fonts</td>
<td>Font compression</td>
</tr>
<tr>
<td>PDF edited and saved many times</td>
<td>Disable incremental updates and resave</td>
</tr>
<tr>
<td>PDF with mixed text, images, and fonts</td>
<td>Combine multiple compression methods</td>
</tr>
</tbody></table>
<p>After compression, do not compare file sizes alone. Open the output PDF and check the text, images, and page layout as well.</p>
<p>This is especially important when lowering image quality or removing embedded fonts.</p>
<h2>Conclusion</h2>
<p>For scanned and image-heavy documents, image compression and resizing are usually the most effective. For text-heavy PDFs, compressing fonts and document content may be more useful. If a PDF has been edited and saved repeatedly, disabling incremental updates before resaving may also help reduce unnecessary file data.</p>
<p>In practice, it is better to start with moderate compression settings and then adjust them based on the resulting file size and document quality.</p>
]]></content:encoded></item><item><title><![CDATA[How to Convert XLS to XLSX and XLSX to XLS Using Python]]></title><description><![CDATA[Excel files can be saved in different formats depending on the version of Microsoft Excel and the application that generates them. Among these formats, .xls and .xlsx are the two most commonly used.
T]]></description><link>https://codingwithfiles.hashnode.dev/how-to-convert-xls-to-xlsx-and-xlsx-to-xls-using-python</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-convert-xls-to-xlsx-and-xlsx-to-xls-using-python</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Wed, 09 Sep 2026 10:40:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/8a2cf6fa-b035-4a93-8b77-7587adf012e1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Excel files can be saved in different formats depending on the version of Microsoft Excel and the application that generates them. Among these formats, <code>.xls</code> and <code>.xlsx</code> are the two most commonly used.</p>
<p>The <code>.xls</code> format was used by older versions of Excel, while <code>.xlsx</code> became the default format after Excel 2007. Although <code>.xlsx</code> is now widely used, <code>.xls</code> files can still be found in many existing systems and applications.</p>
<p>When working with Excel files in Python, converting between these two formats is sometimes necessary, especially when dealing with legacy files or applications with specific format requirements.</p>
<p>This article shows how to convert <code>.xls</code> files to <code>.xlsx</code> and <code>.xlsx</code> files to <code>.xls</code> using Python.</p>
<h2>Why Convert between XLS and XLSX?</h2>
<p>The <code>.xlsx</code> format provides several improvements over the older <code>.xls</code> format:</p>
<ul>
<li><p><strong>Higher capacity</strong>: <code>.xlsx</code> supports more rows and columns than <code>.xls</code>.</p>
</li>
<li><p><strong>Better compatibility</strong>: It works better with newer versions of Excel and other spreadsheet applications.</p>
</li>
<li><p><strong>Smaller file sizes</strong>: <code>.xlsx</code> uses ZIP compression, which can reduce file size.</p>
</li>
<li><p><strong>More features</strong>: Newer Excel functions, formulas, and formatting options are better supported.</p>
</li>
</ul>
<p>However, <code>.xls</code> files are still required in some cases, especially when working with older software or systems. For these scenarios, converting <code>.xlsx</code> files back to <code>.xls</code> can also be useful.</p>
<h2>Install the Required Library</h2>
<p>Before converting Excel files, ensure you have Python 3.7 or later installed, then install the required package using pip:</p>
<pre><code class="language-shell">pip install spire.xls
</code></pre>
<h2>Convert XLS to XLSX Using Python</h2>
<p>To convert an <code>.xls</code> file to <code>.xlsx</code>, load the workbook and save it with the target Excel format.</p>
<p>Example:</p>
<pre><code class="language-python">from spire.xls import *

# Create a workbook object
workbook = Workbook()

# Load the XLS file
workbook.LoadFromFile("input.xls")

# Save as XLSX format
workbook.SaveToFile("output.xlsx", ExcelVersion.Version2013)

# Release resources
workbook.Dispose()
</code></pre>
<p>The <code>LoadFromFile()</code> method loads the existing Excel file, and <code>SaveToFile()</code> saves the workbook in the specified format.</p>
<p>The <code>ExcelVersion.Version2013</code> parameter indicates that the output file should be saved as an <code>.xlsx</code> file.</p>
<h2>Convert XLSX to XLS Using Python</h2>
<p>The conversion from <code>.xlsx</code> to <code>.xls</code> follows the same process. The only difference is the Excel version used when saving the file.</p>
<p>Example:</p>
<pre><code class="language-python">from spire.xls import *

# Create a workbook object
workbook = Workbook()

# Load the XLSX file
workbook.LoadFromFile("input.xlsx")

# Save as XLS format
workbook.SaveToFile("output.xls", ExcelVersion.Version97To2003)

# Release resources
workbook.Dispose()
</code></pre>
<p>Here, <code>ExcelVersion.Version97To2003</code> specifies the older <code>.xls</code> format.</p>
<h2>Important Notes</h2>
<ul>
<li><p><strong>XLS format limitations</strong>: The <code>.xls</code> format has several restrictions compared with <code>.xlsx</code>:</p>
<ul>
<li><p>Maximum of 65,536 rows.</p>
</li>
<li><p>Maximum of 256 columns.</p>
</li>
<li><p>Limited support for newer Excel features.</p>
</li>
</ul>
<p>Because of these limitations, converting a large <code>.xlsx</code> file into <code>.xls</code> should be done carefully. Some data or features may not be preserved after conversion.</p>
</li>
<li><p><strong>Formatting compatibility</strong>: When converting between .xls and .xlsx, some Excel features may not be fully supported by both formats. After conversion, check the workbook to ensure that formulas, formatting, and other features are preserved as expected.</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Converting between <code>.xls</code> and <code>.xlsx</code> formats is a common task when processing Excel files in Python. By loading an existing workbook and saving it with the required Excel version, developers can convert files between the two formats with a small amount of code.</p>
]]></content:encoded></item><item><title><![CDATA[How to Extract Images from Word Documents with Python]]></title><description><![CDATA[Word files may contain screenshots, product photos, diagrams, logos, and other embedded images. When these images need to be reused separately, saving them one by one from Microsoft Word is inefficien]]></description><link>https://codingwithfiles.hashnode.dev/how-to-extract-images-from-word-documents-with-python</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-extract-images-from-word-documents-with-python</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 04 Sep 2026 12:02:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/4ea8aeb7-a53b-4455-8d1a-c89239d42629.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Word files may contain screenshots, product photos, diagrams, logos, and other embedded images. When these images need to be reused separately, saving them one by one from Microsoft Word is inefficient, especially when a document contains dozens of pictures.</p>
<p>This article shows how to <strong>extract images from Word documents with Python</strong> and save them as separate image files.</p>
<h2>Prerequisites</h2>
<p>Make sure Python is installed on your computer, then install the required package:</p>
<pre><code class="language-bash">pip install Spire.Doc
</code></pre>
<h2>Step 1: Load the Word Document in Python</h2>
<p>First, import the required modules and load the document with the <code>LoadFromFile</code> method:</p>
<pre><code class="language-python">import queue
from spire.doc import *
from spire.doc.common import *

doc = Document()
doc.LoadFromFile("Sample.docx")
</code></pre>
<p>The document is now available for traversing its internal objects.</p>
<h2>Step 2: Find Images in the Word Document</h2>
<p>Images in a Word document are represented as <code>DocPicture</code> objects.</p>
<p>Because pictures may appear inside different document objects, you can use a queue to traverse the document structure and identify objects whose type is <code>DocumentObjectType.Picture</code>.</p>
<pre><code class="language-python">nodes = queue.Queue()
nodes.put(doc)

images = []

while not nodes.empty():
    node = nodes.get()

    for i in range(node.ChildObjects.Count):
        child = node.ChildObjects.get_Item(i)

        if child.DocumentObjectType == DocumentObjectType.Picture:
            picture = child if isinstance(child, DocPicture) else None

            if picture is not None:
                images.append(picture.ImageBytes)

        elif isinstance(child, ICompositeObject):
            nodes.put(child)
</code></pre>
<p>When a picture is found, its binary image data is retrieved through the <code>ImageBytes</code> property and stored in the <code>images</code> list.</p>
<h2>Step 3: Save the Extracted Word Images</h2>
<p>After collecting the image data, write each image to a separate file:</p>
<pre><code class="language-python">import os

output_folder = "ExtractedImages"
os.makedirs(output_folder, exist_ok=True)

for i, image_data in enumerate(images, start=1):
    output_path = os.path.join(
        output_folder,
        f"Image-{i}.png"
    )

    with open(output_path, "wb") as image_file:
        image_file.write(image_data)
</code></pre>
<p>For a document containing three pictures, the output folder will look like this:</p>
<pre><code class="language-text">ExtractedImages/
├── Image-1.png
├── Image-2.png
└── Image-3.png
</code></pre>
<h2>Full Python Code to Extract Images from Word</h2>
<p>Here is the complete example:</p>
<pre><code class="language-python">import os
import queue
from spire.doc import *
from spire.doc.common import *

input_file = "Sample.docx"
output_folder = "ExtractedImages"

os.makedirs(output_folder, exist_ok=True)

# Load the Word document
doc = Document()
doc.LoadFromFile(input_file)

# Traverse the document objects
nodes = queue.Queue()
nodes.put(doc)

images = []

while not nodes.empty():
    node = nodes.get()

    for i in range(node.ChildObjects.Count):
        child = node.ChildObjects.get_Item(i)

        # Get embedded pictures
        if child.DocumentObjectType == DocumentObjectType.Picture:
            picture = child if isinstance(child, DocPicture) else None

            if picture is not None:
                images.append(picture.ImageBytes)

        # Continue traversing nested objects
        elif isinstance(child, ICompositeObject):
            nodes.put(child)

# Save the extracted images
for i, image_data in enumerate(images, start=1):
    output_path = os.path.join(
        output_folder,
        f"Image-{i}.png"
    )

    with open(output_path, "wb") as image_file:
        image_file.write(image_data)

doc.Close()
</code></pre>
<p>The script scans the document, collects embedded pictures, and saves them to the <code>ExtractedImages</code> folder.</p>
<h2>Extract Images from Multiple Word Documents with Python</h2>
<p>If you have multiple Word files, the same extraction logic can be placed inside a function and applied to every <code>.docx</code> file in a folder.</p>
<p>For example:</p>
<pre><code class="language-python">for filename in os.listdir("WordFiles"):
    if filename.lower().endswith(".docx"):
        input_path = os.path.join("WordFiles", filename)

        # Run the image extraction logic for each document
</code></pre>
<p>For batch processing, it is usually better to create a separate output folder for each source document so images with the same file names do not overwrite one another.</p>
<h2>Things to Know When Extracting Images from Word</h2>
<ul>
<li><p>The example extracts objects represented as <code>DocPicture</code>.</p>
</li>
<li><p>Charts, SmartArt, shapes, OLE objects, and other graphical elements may use different Word object types and are not necessarily extracted by this code.</p>
</li>
<li><p>The example saves the extracted image data with <code>.png</code> file names. If preserving the original image format is important, the source image format should be identified before assigning the output extension.</p>
</li>
<li><p>Always call <code>Close()</code> after processing the document to release its resources.</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Extracting images from Word with Python is useful when documents contain many embedded pictures that need to be reused, archived, or processed separately.</p>
<p>By traversing the Word document objects, identifying <code>DocPicture</code> instances, and retrieving their image data, you can automate the extraction instead of saving each image manually.</p>
]]></content:encoded></item><item><title><![CDATA[How to Attach Files to a PDF with Python]]></title><description><![CDATA[A PDF does not always have to contain everything directly on its pages.
A project report, for example, may need the original Excel data used to generate its charts. An invoice may need supporting docu]]></description><link>https://codingwithfiles.hashnode.dev/how-to-attach-files-to-a-pdf-with-python</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-attach-files-to-a-pdf-with-python</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Thu, 03 Sep 2026 09:54:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/ff07acf8-9a98-44fe-9edb-d8acb68f4a1e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A PDF does not always have to contain everything directly on its pages.</p>
<p>A project report, for example, may need the original Excel data used to generate its charts. An invoice may need supporting documents, while a technical report may need to include configuration files, logs, or other reference material.</p>
<p>Instead of sending these files separately, they can be embedded directly in the PDF.</p>
<p>There are two useful ways to do this. A file can be attached to the PDF as a whole, or it can be placed at a specific location on a page as an attachment annotation.</p>
<p>This article shows how to handle both cases with Python.</p>
<h2>Document Attachments vs. Attachment Annotations</h2>
<p>Before adding a file, it helps to understand the difference between the two approaches.</p>
<p>A <strong>document-level attachment</strong> belongs to the PDF itself. It does not appear in the visible page content. Users typically access it through the Attachments panel in a PDF reader.</p>
<p>An <strong>attachment annotation</strong>, on the other hand, is placed on a particular page. It appears as a clickable attachment icon, which makes it useful when the attached file relates to a specific paragraph, chart, figure, or section.</p>
<p>For example:</p>
<ul>
<li><p>Attach an Excel workbook to a financial report as a document-level attachment.</p>
</li>
<li><p>Place a source-data file next to a chart as an attachment annotation.</p>
</li>
<li><p>Include supporting Word documents with a submitted PDF package.</p>
</li>
<li><p>Attach a CSV or JSON file to a technical report while keeping the report itself easy to read.</p>
</li>
</ul>
<p>The main question is whether the attachment needs a visible location within the document.</p>
<h2>Environment Setup</h2>
<p>To run the following code examples, install the required module for PDF processing:</p>
<pre><code class="language-bash">pip install Spire.PDF
</code></pre>
<h2>Add a File as a Document-Level Attachment</h2>
<p>Suppose we have a PDF report named <code>report.pdf</code> and an Excel workbook named <code>source-data.xlsx</code>.</p>
<p>If the spreadsheet contains supplementary data for the entire report, attaching it at the document level is usually the cleaner option.</p>
<pre><code class="language-python">from spire.pdf import *

# Load the PDF
pdf = PdfDocument()
pdf.LoadFromFile("report.pdf")

# Create an attachment from an external file
attachment = PdfAttachment("source-data.xlsx")

# Add the attachment to the PDF
pdf.Attachments.Add(attachment)

# Save the result
pdf.SaveToFile("report-with-attachment.pdf")
</code></pre>
<p>The attachment itself is created with <code>PdfAttachment</code>:</p>
<pre><code class="language-python">attachment = PdfAttachment("source-data.xlsx")
</code></pre>
<p>It is then added to the document's attachment collection:</p>
<pre><code class="language-python">pdf.Attachments.Add(attachment)
</code></pre>
<p>Nothing is added to the visible PDF pages. In a PDF reader that supports embedded attachments, the spreadsheet can be accessed through the document's Attachments panel.</p>
<p>This makes document-level attachments particularly useful for supplementary material that belongs to the document as a whole.</p>
<h2>Attach Multiple Files to a PDF</h2>
<p>A PDF can also contain more than one document-level attachment.</p>
<p>For example, a project report could include its source spreadsheet, meeting notes, and an original diagram:</p>
<pre><code class="language-python">attachment1 = PdfAttachment("source-data.xlsx")
attachment2 = PdfAttachment("notes.docx")
attachment3 = PdfAttachment("diagram.png")

pdf.Attachments.Add(attachment1)
pdf.Attachments.Add(attachment2)
pdf.Attachments.Add(attachment3)
</code></pre>
<p>This can be useful when a PDF is intended to serve as a self-contained document package rather than being distributed together with several loose files.</p>
<h2>Add an Attachment to a Specific PDF Page</h2>
<p>Sometimes an attachment makes more sense when it is associated with a particular location in the document.</p>
<p>Consider a PDF report containing a chart generated from an Excel workbook. Instead of placing the workbook in the general attachment list, we can put an attachment icon next to the chart so readers immediately understand what the file relates to.</p>
<p>This is done with an attachment annotation.</p>
<pre><code class="language-python">from spire.pdf import *

# Load the PDF
pdf = PdfDocument()
pdf.LoadFromFile("report.pdf")

# Get the first page
page = pdf.Pages.get_Item(0)

# Read the file to be attached
data = Stream("source-data.xlsx")

# Define the position and size of the attachment icon
bounds = RectangleF(50.0, 100.0, 16.0, 16.0)

# Create the attachment annotation
annotation = PdfAttachmentAnnotation(
    bounds,
    "source-data.xlsx",
    data
)

# Set the appearance and tooltip text
annotation.Color = PdfRGBColor(Color.get_Blue())
annotation.Flags = PdfAnnotationFlags.Default
annotation.Icon = PdfAttachmentIcon.Graph
annotation.Text = "Open the source data"

# Add the annotation to the page
page.AnnotationsWidget.Add(annotation)

# Save the result
pdf.SaveToFile("report-with-page-attachment.pdf")
</code></pre>
<p>Here, <code>RectangleF</code> determines where the attachment icon appears:</p>
<pre><code class="language-python">bounds = RectangleF(50.0, 100.0, 16.0, 16.0)
</code></pre>
<p>The four values represent the X coordinate, Y coordinate, width, and height.</p>
<p>The file is then used to create a <code>PdfAttachmentAnnotation</code>:</p>
<pre><code class="language-python">annotation = PdfAttachmentAnnotation(
    bounds,
    "source-data.xlsx",
    data
)
</code></pre>
<p>Finally, the annotation is added to the page:</p>
<pre><code class="language-python">page.AnnotationsWidget.Add(annotation)
</code></pre>
<p>Unlike a document-level attachment, this file now has a visible entry point on the PDF page.</p>
<h2>Add a Label Next to the Attachment</h2>
<p>An attachment icon by itself may not always make its purpose obvious.</p>
<p>If the PDF will be shared with other users, adding a short label such as <strong>Source Data</strong>, <strong>Supporting File</strong>, or <strong>Download Spreadsheet</strong> can make the attachment easier to understand.</p>
<p>For example:</p>
<pre><code class="language-python">text = "Source data:"
font = PdfTrueTypeFont(
    "Arial",
    12.0,
    PdfFontStyle.Regular,
    True
)

x = 50.0
y = 100.0

page.Canvas.DrawString(
    text,
    font,
    PdfBrushes.get_Black(),
    x,
    y
)

text_size = font.MeasureString(text)

bounds = RectangleF(
    x + text_size.Width + 5.0,
    y,
    16.0,
    16.0
)
</code></pre>
<p>The width of the label is measured first, and the attachment icon is positioned a few points after the text.</p>
<p>The resulting layout can look something like this:</p>
<pre><code class="language-text">Source data: [attachment icon]
</code></pre>
<p>This is particularly useful when attachments are part of the document's normal reading flow rather than simply supplementary files stored with the PDF.</p>
<h2>Which Type of PDF Attachment Should You Use?</h2>
<p>Use a <strong>document-level attachment</strong> when the file relates to the PDF as a whole.</p>
<p>Typical examples include:</p>
<ul>
<li><p>Raw datasets</p>
</li>
<li><p>Source spreadsheets</p>
</li>
<li><p>Supporting documents</p>
</li>
<li><p>Original images</p>
</li>
<li><p>Appendices</p>
</li>
<li><p>Configuration files</p>
</li>
<li><p>Other supplementary material</p>
</li>
</ul>
<p>Use an <strong>attachment annotation</strong> when the file is directly related to something visible on a particular page.</p>
<p>For example:</p>
<ul>
<li><p>Source data for a chart</p>
</li>
<li><p>An original image associated with a figure</p>
</li>
<li><p>Supporting evidence for a paragraph</p>
</li>
<li><p>A downloadable template referenced in the text</p>
</li>
<li><p>A file associated with a specific section of a report</p>
</li>
</ul>
<p>For general document packages, document-level attachments are usually simpler because they do not affect the page layout.</p>
<p>Attachment annotations are more useful when the position of the file provides additional context to the reader.</p>
<h2>A Note About PDF Viewers</h2>
<p>Embedded attachments are part of the PDF, but how users access them can vary between PDF viewers.</p>
<p>Desktop PDF applications generally provide an Attachments panel and support attachment annotations. Browser-based PDF viewers may expose these features differently or support only part of the functionality.</p>
<p>If attachments are an important part of a document workflow, it is worth opening the finished PDF in the same viewer your recipients are likely to use.</p>
<h2>Final Thoughts</h2>
<p>Embedding supporting files can be cleaner than distributing a PDF together with a collection of separate documents.</p>
<p>For files that apply to the entire PDF, document-level attachments keep the page layout untouched while storing the supporting material inside the same file.</p>
<p>When an attachment belongs to a particular chart, paragraph, or section, an attachment annotation gives readers a visible and more contextual way to access it.</p>
<p>The coding difference between the two approaches is small, but choosing the right attachment type can make the finished PDF much easier to navigate.</p>
]]></content:encoded></item><item><title><![CDATA[How to Restrict Editing in Word and Allow Specific Editable Ranges in Java]]></title><description><![CDATA[In contracts, application forms, report templates, and other Word documents, you may need to prevent users from changing certain content while still leaving selected areas editable.
For example, a doc]]></description><link>https://codingwithfiles.hashnode.dev/how-to-restrict-editing-in-word-and-allow-specific-editable-ranges-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-restrict-editing-in-word-and-allow-specific-editable-ranges-in-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 28 Aug 2026 11:41:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/b56ad306-1595-49a2-ad0a-b542e7c70b9d.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In contracts, application forms, report templates, and other Word documents, you may need to prevent users from changing certain content while still leaving selected areas editable.</p>
<p>For example, a document can be made read-only, restricted to tracked changes or comments, or configured so that only form fields can be filled in. You can also protect most of the document while leaving specific ranges open for editing.</p>
<p>These restrictions are different from a document open password. An open password controls whether someone can access the file at all, while editing restrictions control what users can do after the document has been opened.</p>
<p>This article shows how to apply editing restrictions to Word documents in Java and how to define editable exceptions inside a protected document.</p>
<h2>Add the Dependency</h2>
<p>The examples below use Spire.Doc for Java to work with Word documents. For Maven projects, add its repository and dependency to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.doc&lt;/artifactId&gt;
        &lt;version&gt;14.7.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h2>Restrict Editing in a Word Document</h2>
<p>Use <code>Document.protect()</code> to apply editing restrictions and <code>ProtectionType</code> to specify what users are still allowed to do.</p>
<p>Common protection types include:</p>
<table>
<thead>
<tr>
<th>ProtectionType</th>
<th>Allowed Action</th>
</tr>
</thead>
<tbody><tr>
<td><code>Allow_Only_Reading</code></td>
<td>View the document without editing it</td>
</tr>
<tr>
<td><code>Allow_Only_Revisions</code></td>
<td>Edit the document with changes recorded as revisions</td>
</tr>
<tr>
<td><code>Allow_Only_Comments</code></td>
<td>Add or modify comments only</td>
</tr>
<tr>
<td><code>Allow_Only_Form_Fields</code></td>
<td>Fill in form fields only</td>
</tr>
<tr>
<td><code>No_Protection</code></td>
<td>No editing restriction</td>
</tr>
</tbody></table>
<p>The following example makes a Word document read-only:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.ProtectionType;

public class RestrictWordEditing {
    public static void main(String[] args) {

        // Load the Word document
        Document doc = new Document();
        doc.loadFromFile("Contract.docx");

        // Make the document read-only and set a password
        // for removing the restriction
        doc.protect(
                ProtectionType.Allow_Only_Reading,
                "123456"
        );

        // Save the document
        doc.saveToFile(
                "Contract_Protected.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}
</code></pre>
<p>To use another restriction mode, change the <code>ProtectionType</code>.</p>
<p>For example, to allow comments only:</p>
<pre><code class="language-java">doc.protect(
        ProtectionType.Allow_Only_Comments,
        "123456"
);
</code></pre>
<p>For documents that go through review, <code>Allow_Only_Revisions</code> is often more useful. Users can still edit the content, but their changes are recorded as revisions that can later be accepted or rejected.</p>
<p>For templates containing text form fields, check boxes, or similar controls, <code>Allow_Only_Form_Fields</code> can be used to limit editing to those fields.</p>
<p>The password passed to <code>protect()</code> is used to remove the editing restriction. It is not a password for opening the document. If the file itself should require a password before it can be opened, document encryption must be configured separately.</p>
<h2>Allow a Specific Range to Remain Editable</h2>
<p>Making the entire document read-only is not always enough. A common requirement is to lock standard contract clauses or instructions while leaving selected content editable.</p>
<p>Spire.Doc provides <code>PermissionStart</code> and <code>PermissionEnd</code> to mark a range that remains editable inside a protected document.</p>
<p>The following example protects the document while allowing the first six paragraphs to remain editable:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.PermissionEnd;
import com.spire.doc.PermissionStart;
import com.spire.doc.ProtectionType;
import com.spire.doc.Section;

public class AllowEditingInSpecifiedRange {
    public static void main(String[] args) {

        // Load the Word document
        Document doc = new Document();
        doc.loadFromFile("ContractTemplate.docx");

        // Create a pair of permission markers
        PermissionStart start =
                new PermissionStart(doc, "EditableRange1");
        PermissionEnd end =
                new PermissionEnd(doc, "EditableRange1");

        // Get the target section
        Section section = doc.getSections().get(0);

        // Insert the start marker at the beginning
        // of the first paragraph
        section.getParagraphs()
                .get(0)
                .getChildObjects()
                .insert(0, start);

        // Insert the end marker at the end
        // of the sixth paragraph
        section.getParagraphs()
                .get(5)
                .getChildObjects()
                .add(end);

        // Make the rest of the document read-only
        doc.protect(
                ProtectionType.Allow_Only_Reading,
                "123456"
        );

        // Save the result
        doc.saveToFile(
                "ContractTemplate_Protected.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}
</code></pre>
<p><code>PermissionStart</code> and <code>PermissionEnd</code> must use the same permission ID:</p>
<pre><code class="language-java">new PermissionStart(doc, "EditableRange1");
new PermissionEnd(doc, "EditableRange1");
</code></pre>
<p>Word uses this matching ID to identify the content between the two markers as one editable range.</p>
<p>In the example above, the start marker is inserted before the first child object of the first paragraph, while the end marker is appended to the sixth paragraph. Everything between those markers remains editable.</p>
<p>If only part of a paragraph should be editable, the markers can be inserted around specific <code>TextRange</code> objects instead of using entire paragraphs as boundaries.</p>
<p>For templates that change regularly, it is usually better to locate the target content through bookmarks, placeholder text, or another stable marker rather than relying on fixed paragraph indexes.</p>
<h2>Use Unique IDs for Multiple Editable Ranges</h2>
<p>A document can contain several editable areas, for example:</p>
<pre><code class="language-text">CustomerInfo
ContractAmount
Remarks
</code></pre>
<p>Each range should use its own permission ID, and every <code>PermissionStart</code> must have a matching <code>PermissionEnd</code>.</p>
<p>If the IDs do not match, or if a start marker is inserted without the correct end marker, the editable range may not behave as expected.</p>
<p>When editable ranges are created dynamically from business configuration, use clear and unique IDs instead of reusing the same hard-coded value for every range.</p>
<h2>Remove Editing Restrictions from a Word Document</h2>
<p>To restore normal editing, set the protection type to <code>No_Protection</code>:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.ProtectionType;

public class RemoveEditingRestriction {
    public static void main(String[] args) {

        // Load the protected Word document
        Document doc = new Document();
        doc.loadFromFile("Contract_Protected.docx");

        // Remove the editing restriction
        doc.protect(ProtectionType.No_Protection);

        // Save the result
        doc.saveToFile(
                "Contract_Unprotected.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}
</code></pre>
<p>If the document only uses document-level protection, this is usually enough.</p>
<p>However, if <code>PermissionStart</code> and <code>PermissionEnd</code> were added to define editable exceptions, those markers remain part of the document structure.</p>
<p>If the output should be a fully cleaned document with no remaining permission markers, remove them as well:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.DocumentObject;
import com.spire.doc.FileFormat;
import com.spire.doc.PermissionEnd;
import com.spire.doc.PermissionStart;
import com.spire.doc.ProtectionType;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;

public class RemoveEditingRestrictionAndPermissions {
    public static void main(String[] args) {

        Document doc = new Document();
        doc.loadFromFile("ContractTemplate_Protected.docx");

        // Remove document protection
        doc.protect(ProtectionType.No_Protection);

        // Remove permission markers
        for (int s = 0; s &lt; doc.getSections().getCount(); s++) {
            Section section = doc.getSections().get(s);

            for (int p = 0; p &lt; section.getParagraphs().getCount(); p++) {
                Paragraph paragraph = section.getParagraphs().get(p);

                for (int i = 0;
                     i &lt; paragraph.getChildObjects().getCount();) {

                    DocumentObject obj =
                            paragraph.getChildObjects().get(i);

                    if (obj instanceof PermissionStart
                            || obj instanceof PermissionEnd) {

                        paragraph.getChildObjects().remove(obj);
                    } else {
                        i++;
                    }
                }
            }
        }

        doc.saveToFile(
                "ContractTemplate_Unprotected.docx",
                FileFormat.Docx_2019
        );

        doc.close();
    }
}
</code></pre>
<p>Notice that <code>i</code> is not incremented after an object is removed. Once the current item is deleted, the next object shifts into the same index. Incrementing immediately would skip that object, which matters if two permission markers appear next to each other.</p>
<h2>Editing Restrictions Are Not the Same as Document Encryption</h2>
<p>Editing restrictions control what users can do after the document is opened:</p>
<pre><code class="language-java">doc.protect(
        ProtectionType.Allow_Only_Reading,
        "123456"
);
</code></pre>
<p>Encryption controls whether the document can be opened without a password.</p>
<p>So "users can open the file but cannot edit it" and "users cannot open the file without a password" are separate requirements. A document can use both, but <code>protect()</code> should not be treated as file-access control.</p>
<p>Editing restrictions are also intended to control normal Word editing behavior rather than provide strong data security. If the content itself must be protected from unauthorized access, encryption or another access-control mechanism should be used.</p>
<h2>Practical Considerations</h2>
<p>For fixed templates, editable ranges can be defined directly around paragraphs, table cells, or other document objects.</p>
<p>For templates that change often, hard-coded indexes such as:</p>
<pre><code class="language-java">section.getParagraphs().get(5)
</code></pre>
<p>can become fragile. Adding a title or instruction paragraph may shift the target content and place the editable range in the wrong location.</p>
<p>Bookmarks, placeholder text, or other stable document markers usually make better anchors for editable ranges.</p>
<p>It is also worth checking whether the document already contains editing restrictions or permission markers before applying new ones. Reprocessing the same template without checking its existing structure can result in duplicate or overlapping permission ranges.</p>
<h2>Conclusion</h2>
<p>For Word templates that need to be maintained over time, the most important part is not the paragraph number used in the code, but how reliably the application can locate the content that should remain editable.</p>
<p>Stable anchors such as bookmarks or placeholders make the protection logic much less dependent on layout changes and help keep the code working when the template evolves.</p>
]]></content:encoded></item><item><title><![CDATA[How to Make PDF Form Fields Read-Only or Flatten Them in Java]]></title><description><![CDATA[Once a PDF form has been completed, you may want to prevent further edits without losing the form structure, or remove the interactive fields entirely and produce a final version for delivery or archi]]></description><link>https://codingwithfiles.hashnode.dev/how-to-make-pdf-form-fields-read-only-or-flatten-them-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-make-pdf-form-fields-read-only-or-flatten-them-in-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 28 Aug 2026 11:20:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/7f9b9f05-0931-4918-abb4-26238e2d9729.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Once a PDF form has been completed, you may want to prevent further edits without losing the form structure, or remove the interactive fields entirely and produce a final version for delivery or archiving.</p>
<p>These two requirements are usually handled differently. A read-only field remains part of the PDF form and can still be accessed programmatically, while a flattened field is converted into static page content.</p>
<p>This article shows how to make an entire PDF form or an individual field read-only, how to flatten all or selected fields, and when each approach is more appropriate.</p>
<h2>Add the Dependency</h2>
<p>The examples below use Spire.PDF for Java to work with PDF forms. For Maven projects, add the following repository and dependency to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.8.6&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h2>Make an Entire PDF Form Read-Only</h2>
<p>If the field values still need to be available to later code but users should no longer be able to change them, keep the form structure and mark the form as read-only.</p>
<p>Use <code>PdfFormWidget.setReadOnly()</code> to apply the setting to all fields:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.widget.PdfFormWidget;

public class SetFormReadOnly {
    public static void main(String[] args) {

        // Load the PDF form
        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile("ApplicationForm.pdf");

        // Make all form fields read-only
        PdfFormWidget form = (PdfFormWidget) pdf.getForm();
        form.setReadOnly(true);

        // Save the result
        pdf.saveToFile("ApplicationForm_ReadOnly.pdf");
        pdf.close();
    }
}
</code></pre>
<p>The fields remain in the PDF after this operation, so the application can still retrieve their names and values or perform other form-related processing later.</p>
<h2>Make a Specific PDF Form Field Read-Only</h2>
<p>To lock only one field, retrieve the corresponding <code>PdfField</code> and call <code>setReadOnly()</code> on it:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.fields.PdfField;
import com.spire.pdf.widget.PdfFormWidget;

public class SetFieldReadOnly {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile("ApplicationForm.pdf");

        PdfFormWidget form = (PdfFormWidget) pdf.getForm();

        // Get the field by its internal name
        PdfField field = form.getFieldsWidget().get("RequestAmount");

        if (field != null) {
            field.setReadOnly(true);
        }

        pdf.saveToFile("ApplicationForm_PartiallyReadOnly.pdf");
        pdf.close();
    }
}
</code></pre>
<p>One detail that matters in real projects is that the name used in code is the field's internal PDF name, not necessarily the label visible on the page.</p>
<p>A field displayed as <code>Request Amount</code>, for example, may internally be named:</p>
<pre><code class="language-text">RequestAmount
amount
TextField12
</code></pre>
<p>If the template comes from another team or an external source, inspect the available field names first:</p>
<pre><code class="language-java">PdfFormWidget form = (PdfFormWidget) pdf.getForm();

for (int i = 0; i &lt; form.getFieldsWidget().getCount(); i++) {
    PdfField field = form.getFieldsWidget().get(i);
    System.out.println(field.getName());
}
</code></pre>
<p>For templates that change over time, field names are also safer than hard-coded indexes. Once fields are added or reordered, an index may point to a different field without making the problem immediately obvious.</p>
<h2>Flatten All PDF Form Fields</h2>
<p>When the PDF no longer needs to behave as an interactive form, the fields can be flattened.</p>
<p>Use <code>isFlatten(true)</code> to flatten the entire form:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;

public class FlattenForm {
    public static void main(String[] args) {

        // Load the completed PDF form
        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile("ApprovedForm.pdf");

        // Flatten all form fields
        pdf.getForm().isFlatten(true);

        // Save the result
        pdf.saveToFile("ApprovedForm_Flattened.pdf");
        pdf.close();
    }
}
</code></pre>
<p>The current appearance of each field is preserved on the page, but text boxes, check boxes, drop-down lists, and other interactive controls are no longer available as fillable fields.</p>
<p>Any logic that still depends on the form structure should therefore run before flattening. This includes reading values, assigning data, validating fields, and exporting form data.</p>
<h2>Flatten a Specific PDF Form Field</h2>
<p>You can also flatten a single field while leaving the rest of the form interactive.</p>
<p>Retrieve the target <code>PdfField</code> and call <code>setFlatten(true)</code>:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.fields.PdfField;
import com.spire.pdf.widget.PdfFormWidget;

public class FlattenField {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile("ApplicationForm.pdf");

        PdfFormWidget form = (PdfFormWidget) pdf.getForm();

        // Get the target field
        PdfField field = form.getFieldsWidget().get("RequestAmount");

        if (field != null) {
            field.setFlatten(true);
        }

        pdf.saveToFile("ApplicationForm_PartiallyFlattened.pdf");
        pdf.close();
    }
}
</code></pre>
<p>This is useful when one part of a form is final but other fields still need to remain editable.</p>
<p>Checking for <code>null</code> is worth keeping in production code. PDF templates are often updated independently of the application, and a renamed or removed field can otherwise turn a simple template change into a <code>NullPointerException</code>.</p>
<h2>Read-Only vs. Flattened Form Fields</h2>
<p>Both approaches can stop normal user input, but they leave the PDF in very different states.</p>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Read-Only</th>
<th>Flattened</th>
</tr>
</thead>
<tbody><tr>
<td>Interactive field structure preserved</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>User can edit the field normally</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Field can still be accessed by name</td>
<td>Yes</td>
<td>No longer appropriate</td>
</tr>
<tr>
<td>Field properties can be changed later</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Suitable for ongoing form processing</td>
<td>Yes</td>
<td>Usually not</td>
</tr>
<tr>
<td>Suitable for final delivery or archiving</td>
<td>Yes</td>
<td>Usually better</td>
</tr>
</tbody></table>
<p>Use read-only fields when the PDF is still part of a larger workflow and your code may need to inspect or process the form later.</p>
<p>Flatten the fields when the form itself is no longer needed and only the final rendered content matters.</p>
<p>Neither option should be treated as a PDF security feature. Setting a field to read-only or flattening it does not prevent the whole document from being edited, copied, or printed. Those requirements belong to PDF permission settings, while tamper detection is better handled with digital signatures.</p>
<h2>Practical Considerations</h2>
<p>For fixed templates, field names are generally more reliable than field indexes. If templates are maintained outside the development team, it is useful to inspect the internal field names during integration and keep those names in configuration or constants rather than scattering them throughout the codebase.</p>
<p>Flattening should also be one of the last steps in the processing pipeline. Once a final flattened file has been produced, later code should not assume that the original form structure is still available.</p>
<p>The rendered result deserves a quick check as well, especially when the form contains CJK text, custom fonts, symbols, check boxes, or drop-down fields. A server may not have the same fonts as a developer workstation, and that difference can affect how field content appears after flattening.</p>
<h2>Conclusion</h2>
<p>For production systems, keep the editable source form separate from the generated read-only or flattened output. That small separation makes template updates, data corrections, and troubleshooting much easier than trying to recover structure from a file that has already been finalized.</p>
]]></content:encoded></item><item><title><![CDATA[Convert Markdown to PDF in Java (with Advanced Settings)]]></title><description><![CDATA[Markdown is widely used for writing technical documentation, project notes, README files, and online content. Its lightweight syntax makes documents easy to create, update, and manage.
However, Markdo]]></description><link>https://codingwithfiles.hashnode.dev/convert-markdown-to-pdf-in-java-with-advanced-settings</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/convert-markdown-to-pdf-in-java-with-advanced-settings</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 21 Aug 2026 11:07:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/da350ad8-d72c-4582-9c2b-4fec0f1d83dd.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Markdown is widely used for writing technical documentation, project notes, README files, and online content. Its lightweight syntax makes documents easy to create, update, and manage.</p>
<p>However, Markdown is not always the best format for sharing. When a document needs to be printed, archived, or distributed to users who do not use Markdown tools, PDF is usually a better choice because it provides a fixed layout and consistent appearance.</p>
<p>In Java applications, automating Markdown-to-PDF conversion can be useful for documentation platforms, report generation systems, and publishing workflows.</p>
<p>This article explains how to convert Markdown files to PDF in Java and how to customize the page settings of the generated PDF document.</p>
<h2>Why Convert Markdown to PDF?</h2>
<p>Markdown and PDF serve different purposes.</p>
<p>Markdown is convenient during content creation because:</p>
<ul>
<li><p>It is simple and readable.</p>
</li>
<li><p>It works well with version control systems.</p>
</li>
<li><p>It separates content from formatting.</p>
</li>
<li><p>It is easy to maintain.</p>
</li>
</ul>
<p>PDF is more suitable for final distribution because:</p>
<ul>
<li><p>The layout remains consistent across platforms.</p>
</li>
<li><p>The document can be printed directly.</p>
</li>
<li><p>It is easier to archive and share.</p>
</li>
<li><p>Users do not need Markdown editing tools.</p>
</li>
</ul>
<p>Common use cases include:</p>
<ul>
<li><p>Converting technical documentation into PDF manuals.</p>
</li>
<li><p>Generating reports from Markdown templates.</p>
</li>
<li><p>Creating downloadable documents automatically.</p>
</li>
<li><p>Publishing articles or internal knowledge-base content.</p>
</li>
</ul>
<h2>Prerequisites</h2>
<p>Before converting Markdown files, prepare:</p>
<ul>
<li><p>Java Development Kit (JDK).</p>
</li>
<li><p>A Java document processing library that supports Markdown loading and PDF export.</p>
</li>
</ul>
<p>In this example, we will use <strong>Spire.Doc for Java</strong> to handle the document conversion.</p>
<h2>Add the Required Dependency</h2>
<p>For Maven projects, add the following dependency to your <code>pom.xml</code> file:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.doc&lt;/artifactId&gt;
        &lt;version&gt;14.7.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h2>Convert Markdown to PDF in Java</h2>
<p>After adding the dependency, you can load a Markdown file and save it as PDF.</p>
<p>The conversion process only requires a few steps:</p>
<ul>
<li><p>Create a <code>Document</code> object.</p>
</li>
<li><p>Load the Markdown file.</p>
</li>
<li><p>Save the document using the PDF format.</p>
</li>
</ul>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;

public class MarkdownToPDF {

    public static void main(String[] args) {

        Document doc = new Document();

        // Load Markdown file
        doc.loadFromFile("Sample.md");

        // Save as PDF
        doc.saveToFile(
                "output/MarkdownToPDF.pdf",
                FileFormat.PDF
        );

        doc.dispose();
    }
}
</code></pre>
<p>After running the code, the Markdown content will be converted into a PDF document.</p>
<h2>Customize PDF Page Settings</h2>
<p>For many documents, the default page layout may not be enough. Reports, manuals, and printed documents often require specific page settings, such as:</p>
<ul>
<li><p>Page size.</p>
</li>
<li><p>Page orientation.</p>
</li>
<li><p>Page margins.</p>
</li>
</ul>
<p>Before exporting the PDF, you can configure these settings through the document's <code>PageSetup</code> object.</p>
<p>The following example sets the page size, orientation, and margins before conversion:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.PageSetup;
import com.spire.doc.Section;
import com.spire.doc.documents.MarginsF;
import com.spire.doc.documents.PageOrientation;
import com.spire.doc.documents.PageSize;

public class MarkdownPageSettings {

    public static void main(String[] args) {

        Document doc = new Document();

        // Load Markdown file
        doc.loadFromFile("Sample.md");

        // Get the document section
        Section section = doc.getSections().get(0);

        // Configure page settings
        PageSetup pageSetup = section.getPageSetup();

        pageSetup.setPageSize(PageSize.A4);

        pageSetup.setOrientation(
                PageOrientation.Portrait
        );

        pageSetup.setMargins(
                new MarginsF(72, 72, 72, 72)
        );

        // Save as PDF
        doc.saveToFile(
                "output/MarkdownToPDF_Custom.pdf",
                FileFormat.PDF
        );

        doc.dispose();
    }
}
</code></pre>
<p>With these settings, the generated PDF will use the specified page layout instead of the default configuration.</p>
<h2>Additional Tips</h2>
<ul>
<li><p><strong>Test complex Markdown content:</strong> Documents containing tables, images, or advanced formatting should be checked after conversion.</p>
</li>
<li><p><strong>Configure page settings based on usage:</strong> A4 portrait may work well for articles, while landscape mode may be better for wide tables.</p>
</li>
<li><p><strong>Keep the original Markdown files:</strong> Markdown is easy to update, so keeping the source files makes future modifications easier.</p>
</li>
<li><p><strong>Release resources properly:</strong> When converting multiple files, dispose of document objects after each operation to avoid unnecessary resource usage.</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Markdown is an efficient format for creating and maintaining structured content, while PDF is often preferred for final delivery and distribution.</p>
<p>By combining Markdown loading with PDF export capabilities, Java developers can automate the conversion process and integrate it into documentation systems, report generators, and publishing workflows.</p>
<p>Customizing page settings before export also provides more control over the final document layout, making the generated PDFs better suited for different business and publishing scenarios.</p>
]]></content:encoded></item><item><title><![CDATA[Add & Remove Watermarks in Word Using Java: A Step-by-Step Guide]]></title><description><![CDATA[Watermarks are commonly used in Word documents to indicate document status, ownership, or confidentiality. For example, a report may need a “DRAFT” watermark during review, internal documents may requ]]></description><link>https://codingwithfiles.hashnode.dev/add-remove-watermarks-in-word-using-java-a-step-by-step-guide</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/add-remove-watermarks-in-word-using-java-a-step-by-step-guide</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 21 Aug 2026 10:44:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/7799dc08-6219-42df-ad3f-c311564ee7f2.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Watermarks are commonly used in Word documents to indicate document status, ownership, or confidentiality. For example, a report may need a “DRAFT” watermark during review, internal documents may require a “CONFIDENTIAL” label, and business templates may include a company logo watermark.</p>
<p>Adding or removing watermarks manually is simple for individual documents. However, it becomes inefficient when documents are generated automatically, processed in batches, or managed by enterprise document systems. In these scenarios, programmatic watermark management allows developers to apply consistent formatting across multiple Word files.</p>
<p>In this guide, we will show how to use Java to:</p>
<ul>
<li><p>Add text watermarks to Word documents.</p>
</li>
<li><p>Add image watermarks to Word documents.</p>
</li>
<li><p>Remove existing watermarks from Word documents.</p>
</li>
</ul>
<h2>Why Manage Word Watermarks Programmatically?</h2>
<p>Automated watermark processing is useful in many scenarios:</p>
<ol>
<li><p><strong>Document review workflows:</strong> Add a “DRAFT” watermark during review and remove it after approval.</p>
</li>
<li><p><strong>Confidential document management:</strong> Mark sensitive files with labels such as “CONFIDENTIAL” or “INTERNAL USE ONLY”.</p>
</li>
<li><p><strong>Automated report generation:</strong> Apply consistent watermarks when generating reports, contracts, or business documents.</p>
</li>
<li><p><strong>Batch document processing:</strong> Update multiple Word files without manually opening each document.</p>
</li>
</ol>
<h2>Prerequisites</h2>
<p>Before getting started, you need:</p>
<ul>
<li><p><strong>Java Development Kit (JDK):</strong> A Java development environment for building and running Java applications.</p>
</li>
<li><p><strong>Spire.Doc for Java:</strong> A Java library for creating, reading, and modifying Word documents programmatically.</p>
</li>
</ul>
<p>You can add the library to your project using Maven.</p>
<h2>Maven Dependency</h2>
<p>Add the following configuration to your <code>pom.xml</code> file:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.doc&lt;/artifactId&gt;
        &lt;version&gt;14.7.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h1>Part 1: Add a Text Watermark to a Word Document</h1>
<p>Text watermarks are the most common type of watermark. They are usually used to display document status, such as “DRAFT”, “CONFIDENTIAL”, or “APPROVED”.</p>
<h2>Step 1: Load a Word Document</h2>
<p>First, create a <code>Document</code> object and load the Word file that you want to modify.</p>
<pre><code class="language-java">Document document = new Document();

document.loadFromFile("input.docx");
</code></pre>
<p>The <code>loadFromFile()</code> method loads the Word document into memory, allowing you to modify its content.</p>
<h2>Step 2: Create a Text Watermark</h2>
<p>Use the <code>TextWatermark</code> class to create a text watermark and configure its content, font, and color.</p>
<pre><code class="language-java">import java.awt.*;

TextWatermark watermark = new TextWatermark(
        "CONFIDENTIAL",
        new Font("Arial", Font.PLAIN, 45),
        Color.GRAY
);
</code></pre>
<p>The parameters control the appearance of the watermark:</p>
<ul>
<li><p>The first parameter defines the watermark text.</p>
</li>
<li><p>The second parameter specifies the font style and size.</p>
</li>
<li><p>The third parameter sets the watermark color.</p>
</li>
</ul>
<p>You can replace <code>"CONFIDENTIAL"</code> with other labels depending on your requirements:</p>
<pre><code class="language-text">DRAFT
INTERNAL USE ONLY
APPROVED
</code></pre>
<h2>Step 3: Configure the Text Watermark Layout</h2>
<p>You can control how the watermark appears by setting its layout.</p>
<p>For example, create a diagonal watermark:</p>
<pre><code class="language-java">watermark.setLayout(WatermarkLayout.Diagonal);
</code></pre>
<p>A diagonal watermark is commonly used for document status labels because it is noticeable without covering the main content.</p>
<p>For a horizontal watermark, use:</p>
<pre><code class="language-java">watermark.setLayout(WatermarkLayout.Horizontal);
</code></pre>
<h2>Step 4: Apply and Save the Text Watermark</h2>
<p>After configuring the watermark, apply it to the document and save the result.</p>
<pre><code class="language-java">document.setWatermark(watermark);

document.saveToFile(
        "text-watermarked.docx",
        FileFormat.Docx
);
</code></pre>
<h2>Full Code Example: Add a Text Watermark</h2>
<p>The following example adds a diagonal “CONFIDENTIAL” watermark to a Word document.</p>
<pre><code class="language-java">import com.spire.doc.*;
import com.spire.doc.documents.*;
import java.awt.*;

public class AddTextWatermark {

    public static void main(String[] args) {

        Document document = new Document();

        // Load a Word document
        document.loadFromFile("input.docx");

        // Create a text watermark
        TextWatermark watermark = new TextWatermark(
                "CONFIDENTIAL",
                new Font("Arial", Font.PLAIN, 45),
                Color.GRAY
        );

        // Set watermark layout
        watermark.setLayout(WatermarkLayout.Diagonal);

        // Add watermark
        document.setWatermark(watermark);

        // Save the document
        document.saveToFile(
                "text-watermarked.docx",
                FileFormat.Docx
        );

        document.dispose();

        System.out.println("Text watermark added successfully!");
    }
}
</code></pre>
<h1>Part 2: Add an Image Watermark to a Word Document</h1>
<p>Besides text watermarks, Word documents often use image watermarks such as company logos, brand marks, or copyright images.</p>
<p>Image watermarks are useful when a visual identifier is needed, such as in company templates or official documents.</p>
<h2>Step 1: Load a Word Document</h2>
<p>First, load the Word document where you want to add the image watermark.</p>
<pre><code class="language-java">Document document = new Document();

document.loadFromFile("input.docx");
</code></pre>
<h2>Step 2: Create an Image Watermark</h2>
<p>Use the <code>PictureWatermark</code> class to create an image watermark.</p>
<pre><code class="language-java">PictureWatermark watermark = new PictureWatermark();

watermark.setPicture("logo.png");
</code></pre>
<p>The <code>logo.png</code> file is the image that will be displayed as the document watermark.</p>
<h2>Step 3: Adjust the Image Watermark Appearance</h2>
<p>You can customize the image watermark according to your needs.</p>
<p>For example, reduce the image intensity:</p>
<pre><code class="language-java">watermark.setWashout(true);
</code></pre>
<p>Adjust the image scale:</p>
<pre><code class="language-java">watermark.setScaling(100);
</code></pre>
<p>These settings help the image work better as a background element without affecting document readability.</p>
<h2>Step 4: Apply and Save the Image Watermark</h2>
<p>After configuring the image watermark, apply it to the document and save the result.</p>
<pre><code class="language-java">document.setWatermark(watermark);

document.saveToFile(
        "image-watermarked.docx",
        FileFormat.Docx
);
</code></pre>
<h2>Full Code Example: Add an Image Watermark</h2>
<p>The following example adds a logo image as a watermark to a Word document.</p>
<pre><code class="language-java">import com.spire.doc.*;

public class AddImageWatermark {

    public static void main(String[] args) {

        Document document = new Document();

        // Load a Word document
        document.loadFromFile("input.docx");

        // Create an image watermark
        PictureWatermark watermark = new PictureWatermark();

        watermark.setPicture("logo.png");

        // Configure watermark appearance
        watermark.setWashout(true);
        watermark.setScaling(100);

        // Add image watermark
        document.setWatermark(watermark);

        // Save the document
        document.saveToFile(
                "image-watermarked.docx",
                FileFormat.Docx
        );

        document.dispose();

        System.out.println("Image watermark added successfully!");
    }
}
</code></pre>
<h1>Part 3: Remove a Watermark from a Word Document</h1>
<p>After a document has been reviewed or approved, you may need to remove the watermark before publishing or sharing it.</p>
<h2>Step 1: Load the Watermarked Document</h2>
<p>First, load the Word document that contains the watermark.</p>
<pre><code class="language-java">Document document = new Document();

document.loadFromFile("watermarked.docx");
</code></pre>
<h2>Step 2: Remove the Watermark</h2>
<p>Use the <code>removeWatermark()</code> method to remove the existing watermark:</p>
<pre><code class="language-java">document.removeWatermark();
</code></pre>
<p>This removes the watermark previously applied to the document.</p>
<h2>Step 3: Save the Document Without the Watermark</h2>
<p>Finally, save the updated document:</p>
<pre><code class="language-java">document.saveToFile(
        "without-watermark.docx",
        FileFormat.Docx
);
</code></pre>
<h2>Full Code Example: Remove a Watermark</h2>
<p>The following example removes a watermark from an existing Word document.</p>
<pre><code class="language-java">import com.spire.doc.*;

public class RemoveWatermark {

    public static void main(String[] args) {

        Document document = new Document();

        // Load a watermarked document
        document.loadFromFile("watermarked.docx");

        // Remove watermark
        document.removeWatermark();

        // Save the document
        document.saveToFile(
                "without-watermark.docx",
                FileFormat.Docx
        );

        document.dispose();

        System.out.println("Watermark removed successfully!");
    }
}
</code></pre>
<h1>Run the Program</h1>
<p>Compile and run the Java programs:</p>
<ul>
<li><p>The text watermark example generates a Word document with a text label.</p>
</li>
<li><p>The image watermark example adds a logo or image background.</p>
</li>
<li><p>The removal example creates a new document without the watermark.</p>
</li>
</ul>
<p>You can open the generated <code>.docx</code> files in Microsoft Word to verify the results.</p>
<h1>Additional Tips</h1>
<ul>
<li><p><strong>Choose appropriate watermark settings:</strong> Use lighter colors and suitable font sizes so the watermark does not affect document readability.</p>
</li>
<li><p><strong>Keep the original document:</strong> Adding or removing watermarks modifies the document, so keep a backup copy when processing important files.</p>
</li>
<li><p><strong>Process multiple documents:</strong> For batch operations, place the document loading, modification, and saving logic inside a loop.</p>
</li>
<li><p><strong>Test complex documents:</strong> Documents with multiple sections, images, or advanced formatting should be tested before large-scale processing.</p>
</li>
</ul>
<h1>Conclusion</h1>
<p>Watermarks are widely used in Word document management to indicate document status, protect sensitive information, and maintain consistent branding.</p>
<p>While manual editing is sufficient for individual files, automated watermark management is more efficient for document generation systems and batch processing workflows.</p>
<p>With Spire.Doc for Java, developers can add text watermarks, add image watermarks, and remove existing watermarks from Word documents through simple API calls. This makes watermark handling easier to integrate into reporting systems, document management platforms, and enterprise applications.</p>
]]></content:encoded></item><item><title><![CDATA[How to Add, Read, and Remove Speaker Notes in PowerPoint Using Java]]></title><description><![CDATA[Speaker notes are useful when the content shown on a PowerPoint slide is not enough for the presenter. They can contain talking points, explanations, reminders, references, or instructions that should]]></description><link>https://codingwithfiles.hashnode.dev/how-to-add-read-and-remove-speaker-notes-in-powerpoint-using-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-add-read-and-remove-speaker-notes-in-powerpoint-using-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 14 Aug 2026 11:29:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/c6b8b66e-7163-4082-9b06-4242c16aa319.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Speaker notes are useful when the content shown on a PowerPoint slide is not enough for the presenter. They can contain talking points, explanations, reminders, references, or instructions that should not appear directly on the slide.</p>
<p>For presentations created or maintained by an application, these notes may also need to be generated automatically. For example, a training system can build slides from a template and insert instructor notes at the same time, while a document-processing workflow may need to extract existing notes for review, archiving, or migration.</p>
<p>This article shows how to use Java to add speaker notes to PowerPoint slides, read existing notes, remove them when they are no longer needed, and process notes across multiple slides.</p>
<h2>Install the Java PowerPoint Library</h2>
<p>This example uses <strong>Spire.Presentation for Java</strong>. If you use Maven, add the dependency to your <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.presentation&lt;/artifactId&gt;
        &lt;version&gt;11.7.2&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>You can also download the JAR package and add the required files to the project manually if Maven is not used.</p>
<h2>Add Speaker Notes to a PowerPoint Slide</h2>
<p>In PowerPoint, speaker notes are associated with individual slides. A slide can therefore have its own notes content without displaying that text during the normal slide show.</p>
<p>With Spire.Presentation for Java, you can access a slide through the presentation's slide collection, create its notes slide, and then append one or more paragraphs to the notes text frame.</p>
<p>The following example adds several speaker notes to the first slide:</p>
<pre><code class="language-java">import com.spire.presentation.*;

public class AddSpeakerNotes {

    public static void main(String[] args) throws Exception {

        // Load the PowerPoint presentation
        Presentation presentation = new Presentation();
        presentation.loadFromFile("input.pptx");

        // Get the first slide
        ISlide slide = presentation.getSlides().get(0);

        // Create a notes slide for the selected slide
        NotesSlide notesSlide = slide.addNotesSlide();

        // Add the first note paragraph
        ParagraphEx paragraph = new ParagraphEx();
        paragraph.setText("Key message:");
        notesSlide.getNotesTextFrame().getParagraphs().append(paragraph);

        // Add another note paragraph
        paragraph = new ParagraphEx();
        paragraph.setText(
                "Explain that the increase was mainly driven by enterprise customers."
        );
        notesSlide.getNotesTextFrame().getParagraphs().append(paragraph);

        // Add another note paragraph
        paragraph = new ParagraphEx();
        paragraph.setText(
                "Mention the regional breakdown before moving to the next slide."
        );
        notesSlide.getNotesTextFrame().getParagraphs().append(paragraph);

        // Save the result
        presentation.saveToFile(
                "PresentationWithNotes.pptx",
                FileFormat.PPTX_2013
        );

        presentation.dispose();
    }
}
</code></pre>
<p>The key step is creating a notes slide for the target slide:</p>
<pre><code class="language-java">NotesSlide notesSlide = slide.addNotesSlide();
</code></pre>
<p>Once the notes slide is available, its text frame can contain one or more paragraphs.</p>
<p>For example:</p>
<pre><code class="language-java">ParagraphEx paragraph = new ParagraphEx();
paragraph.setText("Key message:");

notesSlide.getNotesTextFrame()
        .getParagraphs()
        .append(paragraph);
</code></pre>
<p>Using separate paragraphs is useful when the notes contain several distinct talking points rather than one long block of text. It also makes the notes easier to update or remove individually later.</p>
<p>This approach works well for presentations generated from structured data. A reporting system, for example, might create a chart on the slide while storing the explanation of the chart in the corresponding notes section.</p>
<h2>Read Speaker Notes from PowerPoint</h2>
<p>Speaker notes are not always created by your own application. You may need to inspect a presentation uploaded by a user, collect presenter instructions from an existing slide deck, or export notes into another format.</p>
<p>To read the notes associated with a slide, first obtain its <code>NotesSlide</code> object:</p>
<pre><code class="language-java">NotesSlide notesSlide = slide.getNotesSlide();
</code></pre>
<p>Then retrieve the text from its notes text frame.</p>
<p>The following example loops through the entire presentation and prints the notes for each slide:</p>
<pre><code class="language-java">import com.spire.presentation.*;

public class ReadSpeakerNotes {

    public static void main(String[] args) throws Exception {

        // Load the PowerPoint presentation
        Presentation presentation = new Presentation();
        presentation.loadFromFile("PresentationWithNotes.pptx");

        // Loop through all slides
        for (int i = 0; i &lt; presentation.getSlides().getCount(); i++) {

            ISlide slide = presentation.getSlides().get(i);
            NotesSlide notesSlide = slide.getNotesSlide();

            // Some slides may not contain speaker notes
            if (notesSlide != null) {

                String notes = notesSlide
                        .getNotesTextFrame()
                        .getText();

                System.out.println(
                        "Slide " + (i + 1) + ":\n" + notes
                );
            }
        }

        presentation.dispose();
    }
}
</code></pre>
<p>One detail worth keeping is the null check:</p>
<pre><code class="language-java">if (notesSlide != null) {
    // Read the notes
}
</code></pre>
<p>Not every slide in a presentation necessarily has speaker notes. When processing PowerPoint files from unknown sources, assuming that a notes slide always exists can cause the program to fail when it reaches a slide without notes.</p>
<p>For a presentation containing notes on only some slides, the output might look like this:</p>
<pre><code class="language-text">Slide 1:
Key message:
Explain that the increase was mainly driven by enterprise customers.
Mention the regional breakdown before moving to the next slide.

Slide 3:
Remind the audience that these figures are preliminary.
</code></pre>
<p>After extraction, the notes can be written to a text file, stored in a database, indexed for search, or passed to another part of the application.</p>
<p>This can be useful for reviewing large presentation libraries because the presenter instructions can be collected without opening every slide deck manually.</p>
<h2>Remove Speaker Notes from PowerPoint</h2>
<p>There are also situations where speaker notes should be removed before a presentation is distributed.</p>
<p>An internal presentation, for example, may contain reminders such as:</p>
<pre><code class="language-text">Do not discuss pricing unless the customer asks.
</code></pre>
<p>or:</p>
<pre><code class="language-text">Mention that these figures have not been approved yet.
</code></pre>
<p>Those notes may be useful during internal meetings but inappropriate in a presentation that will be shared with customers or external partners.</p>
<p>To remove all note paragraphs from a slide, clear the paragraph collection in the notes text frame:</p>
<pre><code class="language-java">notesSlide.getNotesTextFrame()
        .getParagraphs()
        .clear();
</code></pre>
<p>The following example removes speaker-note text from every slide in the presentation:</p>
<pre><code class="language-java">import com.spire.presentation.*;

public class RemoveSpeakerNotes {

    public static void main(String[] args) throws Exception {

        // Load the presentation
        Presentation presentation = new Presentation();
        presentation.loadFromFile("PresentationWithNotes.pptx");

        // Process all slides
        for (int i = 0; i &lt; presentation.getSlides().getCount(); i++) {

            ISlide slide = presentation.getSlides().get(i);
            NotesSlide notesSlide = slide.getNotesSlide();

            if (notesSlide != null) {

                // Remove all note paragraphs
                notesSlide.getNotesTextFrame()
                        .getParagraphs()
                        .clear();
            }
        }

        // Save the cleaned presentation
        presentation.saveToFile(
                "PresentationWithoutNotes.pptx",
                FileFormat.PPTX_2013
        );

        presentation.dispose();
    }
}
</code></pre>
<p>If you only want to remove a specific paragraph rather than clearing all notes, use <code>removeAt()</code>:</p>
<pre><code class="language-java">notesSlide.getNotesTextFrame()
        .getParagraphs()
        .removeAt(1);
</code></pre>
<p>The paragraph collection uses a zero-based index, so <code>removeAt(1)</code> removes the second paragraph.</p>
<p>This gives you more control when the notes contain multiple pieces of information and only part of them should be deleted.</p>
<h2>Add Notes to Multiple Slides</h2>
<p>When presentations are generated automatically, speaker notes often come from the same data source as the visible slide content.</p>
<p>Suppose each slide has a corresponding presenter instruction stored in an array:</p>
<pre><code class="language-java">String[] speakerNotes = {
        "Introduce the overall project status.",
        "Explain the reason for the schedule change.",
        "Review the three main risks with the audience."
};
</code></pre>
<p>You can loop through the slides and insert the corresponding note:</p>
<pre><code class="language-java">for (int i = 0;
     i &lt; presentation.getSlides().getCount()
             &amp;&amp; i &lt; speakerNotes.length;
     i++) {

    ISlide slide = presentation.getSlides().get(i);

    NotesSlide notesSlide = slide.getNotesSlide();

    if (notesSlide == null) {
        notesSlide = slide.addNotesSlide();
    }

    ParagraphEx paragraph = new ParagraphEx();
    paragraph.setText(speakerNotes[i]);

    notesSlide.getNotesTextFrame()
            .getParagraphs()
            .append(paragraph);
}
</code></pre>
<p>Here, the code checks whether the slide already has a notes slide before creating one:</p>
<pre><code class="language-java">if (notesSlide == null) {
    notesSlide = slide.addNotesSlide();
}
</code></pre>
<p>This is useful when modifying existing presentations because some slides may already contain notes while others do not.</p>
<p>It also prevents the program from assuming that every presentation starts from a completely blank notes state.</p>
<p>In a real application, the notes do not have to come from an array. They could come from JSON data, a database, an Excel file, an API response, or the same template data used to generate the slide itself.</p>
<p>For example, a training platform might store:</p>
<pre><code class="language-text">Slide title
Slide content
Instructor note
</code></pre>
<p>as separate fields for each training section. The visible content can then be written to the slide while the instructor note is stored as speaker notes.</p>
<h2>Speaker Notes vs. Comments</h2>
<p>Speaker notes and PowerPoint comments may both contain information that is not part of the visible slide content, but they serve different purposes.</p>
<p>Speaker notes are generally intended for the person presenting the slide deck. They often contain:</p>
<ul>
<li><p>Talking points</p>
</li>
<li><p>Additional explanations</p>
</li>
<li><p>Reminders</p>
</li>
<li><p>Supporting facts</p>
</li>
<li><p>Transition cues</p>
</li>
<li><p>Instructions for demonstrations</p>
</li>
</ul>
<p>Comments are mainly used during editing and review. They are more appropriate for feedback such as:</p>
<pre><code class="language-text">Replace this chart with the latest version.
</code></pre>
<p>or:</p>
<pre><code class="language-text">Please verify the Q3 revenue figure.
</code></pre>
<p>So if the information describes <strong>what the presenter should say</strong>, speaker notes are usually the better place for it.</p>
<p>If the information describes <strong>what another editor should change</strong>, a comment is generally more appropriate.</p>
<p>Keeping the two types of information separate also helps when presentations are processed automatically. An application can extract presenter instructions without mixing them with review comments.</p>
<h2>Things to Consider When Processing Existing Presentations</h2>
<p>When working with PowerPoint files created by other users, there are a few practical details worth considering.</p>
<p>First, not every slide has a notes slide. Always check whether <code>getNotesSlide()</code> returns <code>null</code> before attempting to read or modify the notes.</p>
<p>Second, existing notes may contain multiple paragraphs. Calling <code>clear()</code> removes all of them, so use <code>removeAt()</code> instead if only a specific paragraph should be deleted.</p>
<p>Finally, speaker notes may contain information that is not visible during a normal slide show but is still stored in the presentation file. If a presentation is being prepared for external distribution, checking the notes before sharing the file can help prevent internal instructions or unfinished remarks from being included accidentally.</p>
]]></content:encoded></item><item><title><![CDATA[How to Add Page Numbers to PDF in Java (Step-by-Step)]]></title><description><![CDATA[Page numbers are a small detail, but they become important in reports, contracts, manuals, and other multi-page PDFs. They make printed documents easier to navigate and give reviewers a simple way to ]]></description><link>https://codingwithfiles.hashnode.dev/how-to-add-page-numbers-to-pdf-in-java-step-by-step</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-add-page-numbers-to-pdf-in-java-step-by-step</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 14 Aug 2026 10:57:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/0e41890d-5d7f-4590-af7a-ad09b5503e1e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Page numbers are a small detail, but they become important in reports, contracts, manuals, and other multi-page PDFs. They make printed documents easier to navigate and give reviewers a simple way to refer to a specific page.</p>
<p>When PDFs are generated or processed in a Java application, adding page numbers manually is not practical. A better approach is to add them programmatically after the document has been created or assembled.</p>
<p>In this article, we'll use <strong>Spire.PDF for Java</strong> to add dynamic page numbers in the format <strong>Page 1 of 10</strong> to an existing PDF.</p>
<h2>Install Spire.PDF for Java</h2>
<p>If you use Maven, add the repository and Spire.PDF dependency to your <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.8.1&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h2>Add "Page X of Y" to a PDF in Java</h2>
<p>Spire.PDF for Java provides three useful classes for dynamic page numbering:</p>
<ul>
<li><p><code>PdfPageNumberField</code> represents the current page number.</p>
</li>
<li><p><code>PdfPageCountField</code> represents the total number of pages.</p>
</li>
<li><p><code>PdfCompositeField</code> combines these values into text such as <code>Page 2 of 10</code>.</p>
</li>
</ul>
<p>This means you don't need to create a different page-number string for every page manually.</p>
<p>The following example adds a centered page number near the bottom of every page:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.automaticfields.PdfCompositeField;
import com.spire.pdf.automaticfields.PdfPageCountField;
import com.spire.pdf.automaticfields.PdfPageNumberField;
import com.spire.pdf.graphics.PdfBrush;
import com.spire.pdf.graphics.PdfBrushes;
import com.spire.pdf.graphics.PdfTrueTypeFont;

import java.awt.Font;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;

public class AddPageNumbers {

    public static void main(String[] args) {

        // Load the PDF document
        PdfDocument document = new PdfDocument();
        document.loadFromFile("input.pdf");

        // Set the font and color of the page number
        PdfTrueTypeFont font = new PdfTrueTypeFont(
                new Font("Arial", Font.PLAIN, 10), true);
        PdfBrush brush = PdfBrushes.getBlack();

        // Create fields for the current page number and total page count
        PdfPageNumberField pageNumberField = new PdfPageNumberField();
        PdfPageCountField pageCountField = new PdfPageCountField();

        // Combine the fields into "Page X of Y"
        PdfCompositeField pageNumber = new PdfCompositeField(
                font,
                brush,
                "Page {0} of {1}",
                pageNumberField,
                pageCountField
        );

        // Add the page number to each page
        for (int i = 0; i &lt; document.getPages().getCount(); i++) {

            PdfPageBase page = document.getPages().get(i);
            Dimension2D pageSize = page.getSize();

            // Measure the displayed text so it can be centered
            String text = String.format(
                    "Page %d of %d",
                    i + 1,
                    document.getPages().getCount()
            );

            Dimension2D textSize = font.measureString(text);

            // Calculate the position at the bottom center of the page
            double x = (pageSize.getWidth() - textSize.getWidth()) / 2;
            double y = pageSize.getHeight() - 30;

            // Draw the page number
            pageNumber.setLocation(
                    new Point2D.Float((float) x, (float) y)
            );
            pageNumber.draw(page.getCanvas());
        }

        // Save the result
        document.saveToFile("output.pdf");
        document.dispose();
    }
}
</code></pre>
<p>The implementation is fairly short, but there are a few details worth understanding.</p>
<h2>Step 1: Load the Existing PDF</h2>
<p>Start by creating a <code>PdfDocument</code> object and loading the source PDF:</p>
<pre><code class="language-java">PdfDocument document = new PdfDocument();
document.loadFromFile("input.pdf");
</code></pre>
<p>This approach works for an existing PDF as well as a document generated earlier in the same application. The page-numbering code only needs to run before the final PDF is saved.</p>
<h2>Step 2: Define the Page Number Appearance</h2>
<p>Next, create a font and brush:</p>
<pre><code class="language-java">PdfTrueTypeFont font = new PdfTrueTypeFont(
        new Font("Arial", Font.PLAIN, 10), true);

PdfBrush brush = PdfBrushes.getBlack();
</code></pre>
<p>These settings control the font, size, style, and color of the page number.</p>
<p>For most reports, a relatively small font works well in the footer. You can change the font and size to match the rest of the document.</p>
<p>If the application runs on Linux or a server, make sure the font specified in the code is available in that environment. Otherwise, use a font that is installed on the target system.</p>
<h2>Step 3: Create Dynamic Page Number Fields</h2>
<p>Instead of calculating the page number and total page count yourself, create two automatic fields:</p>
<pre><code class="language-java">PdfPageNumberField pageNumberField = new PdfPageNumberField();
PdfPageCountField pageCountField = new PdfPageCountField();
</code></pre>
<p><code>PdfPageNumberField</code> supplies the current page number, while <code>PdfPageCountField</code> supplies the total number of pages. Spire.PDF provides these fields specifically for dynamic information added to PDF pages.</p>
<p>They can then be combined with <code>PdfCompositeField</code>:</p>
<pre><code class="language-java">PdfCompositeField pageNumber = new PdfCompositeField(
        font,
        brush,
        "Page {0} of {1}",
        pageNumberField,
        pageCountField
);
</code></pre>
<p>Here, <code>{0}</code> is replaced by the current page number and <code>{1}</code> by the total page count.</p>
<p>For an eight-page PDF, the result will look like:</p>
<pre><code class="language-text">Page 1 of 8
Page 2 of 8
Page 3 of 8
...
Page 8 of 8
</code></pre>
<p>This is more convenient than preparing a separate string for every page, especially when the final page count is not known in advance.</p>
<h2>Step 4: Process Each Page Separately</h2>
<p>Next, iterate through the PDF:</p>
<pre><code class="language-java">for (int i = 0; i &lt; document.getPages().getCount(); i++) {

    PdfPageBase page = document.getPages().get(i);
    Dimension2D pageSize = page.getSize();

    // ...
}
</code></pre>
<p>The page size is read inside the loop instead of assuming that every page has identical dimensions.</p>
<p>That matters when a PDF contains a mix of portrait and landscape pages or pages with different sizes. Each page can then have its page-number position calculated independently.</p>
<h2>Step 5: Center the Page Number at the Bottom</h2>
<p>To center the page number properly, first measure the text that will appear on the current page:</p>
<pre><code class="language-java">String text = String.format(
        "Page %d of %d",
        i + 1,
        document.getPages().getCount()
);

Dimension2D textSize = font.measureString(text);
</code></pre>
<p>Then calculate its coordinates:</p>
<pre><code class="language-java">double x = (pageSize.getWidth() - textSize.getWidth()) / 2;
double y = pageSize.getHeight() - 30;
</code></pre>
<p>The X coordinate centers the text horizontally, while the Y coordinate places it near the bottom of the page.</p>
<p>For existing PDFs, Spire.PDF uses a coordinate system whose origin is at the top-left corner. X increases to the right and Y increases downward, which is why a value close to the page height places the page number near the footer.</p>
<p>Finally, set the position and draw the field:</p>
<pre><code class="language-java">pageNumber.setLocation(
        new Point2D.Float((float) x, (float) y)
);

pageNumber.draw(page.getCanvas());
</code></pre>
<p>Because the position is calculated for each page, the page number remains centered even when page dimensions vary.</p>
<h2>Change the Page Number Format</h2>
<p>The displayed format is controlled by the format string passed to <code>PdfCompositeField</code>.</p>
<p>For example:</p>
<pre><code class="language-java">"Page {0}"
</code></pre>
<p>produces:</p>
<pre><code class="language-text">Page 1
Page 2
Page 3
</code></pre>
<p>For a shorter style, use:</p>
<pre><code class="language-java">"{0} / {1}"
</code></pre>
<p>which produces:</p>
<pre><code class="language-text">1 / 10
</code></pre>
<p>You can also combine page numbers with fixed footer text:</p>
<pre><code class="language-java">"Project Report | Page {0} of {1}"
</code></pre>
<p>The dynamic fields remain the same, so changing the format does not require changing the rest of the page-numbering logic.</p>
<h2>Make Sure the Footer Has Enough Space</h2>
<p>When adding page numbers to an existing PDF, check whether the bottom of the page already contains text, tables, signatures, or other content.</p>
<p>Drawing a page number does <strong>not</strong> automatically create extra footer space. If the original content already extends close to the bottom edge, the page number may overlap it.</p>
<p>In that case, adjust the Y coordinate:</p>
<pre><code class="language-java">double y = pageSize.getHeight() - 30;
</code></pre>
<p>to place the page number in a clearer area.</p>
<p>If you also control how the PDF is originally generated, reserving some footer space from the beginning is usually a better solution.</p>
<h2>Conclusion</h2>
<p>Adding page numbers programmatically is useful when reports, contracts, manuals, or other PDFs are generated in batches or assembled dynamically.</p>
<p>With Spire.PDF for Java, <code>PdfPageNumberField</code> and <code>PdfPageCountField</code> provide the current page number and total page count, while <code>PdfCompositeField</code> combines them into formats such as <strong>Page X of Y</strong>.</p>
<p>By calculating the position for each page, the same approach also works with PDFs that contain different page sizes or orientations. From there, the footer can be further customized with different formats, fonts, positions, or additional text.</p>
]]></content:encoded></item><item><title><![CDATA[How to Add, Edit, and Remove PDF Bookmarks in Java]]></title><description><![CDATA[In long PDF documents such as project reports, product manuals, technical specifications, or contract collections, navigating page by page can quickly become inconvenient.
Bookmarks provide a simple w]]></description><link>https://codingwithfiles.hashnode.dev/how-to-add-edit-and-remove-pdf-bookmarks-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-add-edit-and-remove-pdf-bookmarks-in-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 07 Aug 2026 11:31:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/76fcbc59-2710-4eba-99bf-fd683ee7da67.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In long PDF documents such as project reports, product manuals, technical specifications, or contract collections, navigating page by page can quickly become inconvenient.</p>
<p>Bookmarks provide a simple way to organize the document structure and let readers jump directly to important sections from the navigation panel. Existing PDFs may also need bookmark maintenance when chapter names change, sections are removed, or the original bookmark structure is no longer accurate.</p>
<p>This article shows how to manage PDF bookmarks in Java, including how to:</p>
<ul>
<li><p>Add bookmarks to a PDF</p>
</li>
<li><p>Create multi-level bookmarks</p>
</li>
<li><p>Edit existing bookmarks</p>
</li>
<li><p>Remove individual or all bookmarks</p>
</li>
</ul>
<h2>Install the Required PDF Library</h2>
<p>This article uses <strong>Spire.PDF for Java</strong> to read and modify PDF files. It provides APIs for creating top-level and child bookmarks, changing bookmark properties, and removing existing bookmarks.</p>
<p>If you are using Maven, add the repository and dependency to your <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.6.1&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>You can replace the version number with the current version used in your project.</p>
<p>After installing the library, load an existing PDF with <code>PdfDocument</code> and work with its bookmark collection.</p>
<h2>Add Bookmarks to a PDF</h2>
<p>Suppose a project report contains the following major sections:</p>
<ul>
<li><p>Project Overview</p>
</li>
<li><p>Implementation Plan</p>
</li>
<li><p>Data Analysis</p>
</li>
<li><p>Recommendations</p>
</li>
</ul>
<p>You can create one top-level bookmark for each section and link it to the corresponding page.</p>
<p>The following example adds bookmarks for the first four pages of a PDF.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.actions.PdfGoToAction;
import com.spire.pdf.bookmarks.PdfBookmark;
import com.spire.pdf.bookmarks.PdfTextStyle;
import com.spire.pdf.general.PdfDestination;
import com.spire.pdf.graphics.PdfRGBColor;

import java.awt.Color;
import java.awt.geom.Point2D;

public class AddPdfBookmarks {
    public static void main(String[] args) {

        // Create a PdfDocument object
        PdfDocument pdf = new PdfDocument();

        // Load the source PDF
        pdf.loadFromFile("ProjectReport.pdf");

        // Define bookmark titles
        String[] bookmarkTitles = {
                "Project Overview",
                "Implementation Plan",
                "Data Analysis",
                "Recommendations"
        };

        // Add bookmarks for the first four pages
        for (int i = 0; i &lt; bookmarkTitles.length; i++) {

            PdfPageBase page = pdf.getPages().get(i);

            // Add a bookmark
            PdfBookmark bookmark =
                    pdf.getBookmarks().add(bookmarkTitles[i]);

            // Set the bookmark destination
            PdfDestination destination =
                    new PdfDestination(
                            page,
                            new Point2D.Float(0, 0)
                    );

            bookmark.setAction(
                    new PdfGoToAction(destination)
            );

            // Set the bookmark color
            bookmark.setColor(
                    new PdfRGBColor(
                            new Color(47, 84, 150)
                    )
            );

            // Display the bookmark in bold
            bookmark.setDisplayStyle(
                    PdfTextStyle.Bold
            );
        }

        // Save the result
        pdf.saveToFile("ProjectReportWithBookmarks.pdf");

        pdf.close();
    }
}
</code></pre>
<p>The process consists of three main parts.</p>
<p>First, create a bookmark in the document bookmark collection:</p>
<pre><code class="language-java">pdf.getBookmarks().add("Project Overview");
</code></pre>
<p>Next, create a <code>PdfDestination</code> that identifies the target page and position:</p>
<pre><code class="language-java">PdfDestination destination =
        new PdfDestination(
                page,
                new Point2D.Float(0, 0)
        );
</code></pre>
<p>Finally, connect the bookmark to that destination:</p>
<pre><code class="language-java">bookmark.setAction(
        new PdfGoToAction(destination)
);
</code></pre>
<p>One detail worth noting is that PDF page indexes start from <strong>0</strong>.</p>
<p>For example:</p>
<pre><code class="language-text">get(0) → Page 1
get(1) → Page 2
get(2) → Page 3
</code></pre>
<p>If the actual chapter starts on another page, adjust the page index accordingly.</p>
<h2>Create Multi-Level PDF Bookmarks</h2>
<p>A single level of bookmarks may not be enough for a document with multiple sections and subsections.</p>
<p>For example:</p>
<pre><code class="language-text">Implementation Plan
├── Project Schedule
├── Team Assignment
└── Risk Management
</code></pre>
<p>In this case, child bookmarks can be added under a parent bookmark.</p>
<p>The following example creates one top-level bookmark and three child bookmarks.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.actions.PdfGoToAction;
import com.spire.pdf.bookmarks.PdfBookmark;
import com.spire.pdf.general.PdfDestination;

import java.awt.geom.Point2D;

public class AddChildBookmarks {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile("ProjectReport.pdf");

        // Create the parent bookmark
        PdfBookmark parentBookmark =
                pdf.getBookmarks().add("Implementation Plan");

        // Link the parent bookmark to page 2
        PdfPageBase parentPage =
                pdf.getPages().get(1);

        PdfDestination parentDestination =
                new PdfDestination(
                        parentPage,
                        new Point2D.Float(0, 0)
                );

        parentBookmark.setAction(
                new PdfGoToAction(parentDestination)
        );

        // Add child bookmark: Project Schedule
        PdfBookmark scheduleBookmark =
                parentBookmark.add("Project Schedule");

        PdfDestination scheduleDestination =
                new PdfDestination(
                        pdf.getPages().get(1),
                        new Point2D.Float(0, 120)
                );

        scheduleBookmark.setAction(
                new PdfGoToAction(scheduleDestination)
        );

        // Add child bookmark: Team Assignment
        PdfBookmark teamBookmark =
                parentBookmark.add("Team Assignment");

        PdfDestination teamDestination =
                new PdfDestination(
                        pdf.getPages().get(2),
                        new Point2D.Float(0, 0)
                );

        teamBookmark.setAction(
                new PdfGoToAction(teamDestination)
        );

        // Add child bookmark: Risk Management
        PdfBookmark riskBookmark =
                parentBookmark.add("Risk Management");

        PdfDestination riskDestination =
                new PdfDestination(
                        pdf.getPages().get(3),
                        new Point2D.Float(0, 0)
                );

        riskBookmark.setAction(
                new PdfGoToAction(riskDestination)
        );

        pdf.saveToFile("ProjectReportWithNestedBookmarks.pdf");

        pdf.close();
    }
}
</code></pre>
<p>The important difference is that child bookmarks are added to the parent bookmark:</p>
<pre><code class="language-java">parentBookmark.add("Project Schedule");
</code></pre>
<p>rather than directly to:</p>
<pre><code class="language-java">pdf.getBookmarks()
</code></pre>
<p>This creates a real hierarchical bookmark structure.</p>
<p>For reports and manuals that already follow a chapter-and-section structure, multi-level bookmarks are usually easier to navigate than a long flat list.</p>
<h2>Edit Existing PDF Bookmarks</h2>
<p>PDF content often changes over time.</p>
<p>For example, a section originally named:</p>
<pre><code class="language-text">Project Plan
</code></pre>
<p>may later be renamed to:</p>
<pre><code class="language-text">Project Implementation Plan
</code></pre>
<p>If the PDF pages have already been updated, the bookmark can be edited directly instead of rebuilding the entire file.</p>
<p>The following example changes the title, color, and display style of the first bookmark.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.bookmarks.PdfBookmark;
import com.spire.pdf.bookmarks.PdfTextStyle;
import com.spire.pdf.graphics.PdfRGBColor;

import java.awt.Color;

public class EditPdfBookmark {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();

        // Load a PDF that already contains bookmarks
        pdf.loadFromFile("ProjectReport.pdf");

        // Get the first bookmark
        PdfBookmark bookmark =
                pdf.getBookmarks().get(0);

        // Change the bookmark title
        bookmark.setTitle("Project Implementation Plan");

        // Change the bookmark color
        bookmark.setColor(
                new PdfRGBColor(
                        new Color(31, 78, 121)
                )
        );

        // Display it in bold
        bookmark.setDisplayStyle(
                PdfTextStyle.Bold
        );

        // Save the result
        pdf.saveToFile("ProjectReportWithUpdatedBookmark.pdf");

        pdf.close();
    }
}
</code></pre>
<p>If only the title needs to change, the essential code is simply:</p>
<pre><code class="language-java">bookmark.setTitle("New Section Title");
</code></pre>
<p>Changing the color or text style is optional and depends on how the bookmark panel should be presented.</p>
<h2>Remove a Specific PDF Bookmark</h2>
<p>If a section has been removed from the document, its bookmark should usually be removed as well.</p>
<p>Otherwise, the bookmark may still point to a page that no longer represents the expected content.</p>
<p>A top-level bookmark can be removed with:</p>
<pre><code class="language-java">pdf.getBookmarks().removeAt(0);
</code></pre>
<p>For example:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;

public class DeletePdfBookmark {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();

        pdf.loadFromFile("ProjectReport.pdf");

        // Remove the first top-level bookmark
        pdf.getBookmarks().removeAt(0);

        pdf.saveToFile("ProjectReportAfterBookmarkRemoval.pdf");

        pdf.close();
    }
}
</code></pre>
<p>The index also starts from <code>0</code>, so <code>removeAt(0)</code> removes the first top-level bookmark.</p>
<p>If that bookmark contains child bookmarks, removing the parent also removes the bookmarks under it.</p>
<h2>Remove a Child Bookmark</h2>
<p>Sometimes only one subsection needs to be removed while the parent bookmark should remain.</p>
<p>In that case, get the parent bookmark first and remove the required child bookmark from it.</p>
<pre><code class="language-java">PdfBookmark parentBookmark =
        pdf.getBookmarks().get(0);

// Remove the first child bookmark
parentBookmark.removeAt(0);
</code></pre>
<p>This changes a structure such as:</p>
<pre><code class="language-text">Implementation Plan
├── Project Schedule   ← removed
├── Team Assignment
└── Risk Management
</code></pre>
<p>without deleting the entire <code>Implementation Plan</code> bookmark.</p>
<p>This is useful when only part of the document structure changes.</p>
<h2>Remove All Bookmarks from a PDF</h2>
<p>If the existing bookmark structure is completely outdated, it may be simpler to remove all bookmarks and rebuild them from scratch.</p>
<p>Use:</p>
<pre><code class="language-java">pdf.getBookmarks().clear();
</code></pre>
<p>A complete example looks like this:</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;

public class DeleteAllPdfBookmarks {
    public static void main(String[] args) {

        PdfDocument pdf = new PdfDocument();

        pdf.loadFromFile("ProjectReport.pdf");

        // Remove all bookmarks
        pdf.getBookmarks().clear();

        pdf.saveToFile("ProjectReportWithoutBookmarks.pdf");

        pdf.close();
    }
}
</code></pre>
<p>This approach is useful when:</p>
<ul>
<li><p>The existing bookmark structure is no longer valid</p>
</li>
<li><p>The document has been reorganized significantly</p>
</li>
<li><p>Bookmarks need to be regenerated from a new table of contents</p>
</li>
<li><p>PDFs from different sources contain inconsistent bookmark structures</p>
</li>
</ul>
<h2>Practical Considerations</h2>
<h3>1. Remember That Page Indexes Start from 0</h3>
<p>This is one of the easiest mistakes to make when assigning bookmark destinations.</p>
<p>If a business rule says that a bookmark should point to page 5, the corresponding code is:</p>
<pre><code class="language-java">pdf.getPages().get(4);
</code></pre>
<p>If page numbers are stored externally as normal one-based numbers, convert them before accessing the PDF page collection:</p>
<pre><code class="language-java">int pageIndex = pageNumber - 1;
</code></pre>
<p>This is particularly important when generating many bookmarks automatically.</p>
<h3>2. Validate the Target Page Before Creating a Bookmark</h3>
<p>If bookmark definitions come from a database, configuration file, or another external source, do not assume that every page number is valid.</p>
<p>For example:</p>
<pre><code class="language-java">int pageIndex = 10;

if (pageIndex &gt;= 0 &amp;&amp;
        pageIndex &lt; pdf.getPages().getCount()) {

    PdfPageBase page =
            pdf.getPages().get(pageIndex);

    // Create the bookmark here
}
</code></pre>
<p>This avoids failures caused by invalid page references.</p>
<h3>3. Keep Bookmark Titles Consistent with the Document Structure</h3>
<p>If a visible section heading is:</p>
<pre><code class="language-text">3. Project Implementation Plan
</code></pre>
<p>but the bookmark is simply:</p>
<pre><code class="language-text">Plan
</code></pre>
<p>the bookmark technically works, but the navigation structure becomes less clear.</p>
<p>For automatically generated reports, it is usually better to reuse the same chapter titles for both the document body and the bookmarks.</p>
<p>For example:</p>
<pre><code class="language-java">String[] chapterNames = {
        "1. Project Overview",
        "2. Implementation Plan",
        "3. Data Analysis",
        "4. Recommendations"
};
</code></pre>
<p>This makes the document body, table of contents, and bookmark panel easier to keep consistent.</p>
<h3>4. Avoid Excessively Deep Bookmark Hierarchies</h3>
<p>PDF bookmarks support nested levels, but a very deep structure can become difficult to use.</p>
<p>For many reports and manuals, a structure such as:</p>
<pre><code class="language-text">Chapter
└── Section
</code></pre>
<p>or:</p>
<pre><code class="language-text">Chapter
└── Section
    └── Subsection
</code></pre>
<p>is usually enough.</p>
<p>If the source data contains six or seven hierarchical levels, consider exposing only the most useful levels as PDF bookmarks rather than reproducing the full internal structure.</p>
<h2>Conclusion</h2>
<p>Bookmarks provide a practical navigation layer for long PDF documents such as reports, manuals, specifications, and contract collections.</p>
<p>This article covered how to use Java to:</p>
<ul>
<li><p>Add top-level bookmarks to a PDF</p>
</li>
<li><p>Create parent-child bookmark structures</p>
</li>
<li><p>Edit bookmark titles and styles</p>
</li>
<li><p>Remove individual top-level or child bookmarks</p>
</li>
<li><p>Remove all bookmarks from a PDF</p>
</li>
</ul>
<p>For automatically generated PDFs, bookmarks can be created from the same chapter names and page information used to build the document. For existing PDFs, outdated bookmark structures can be edited or rebuilt without recreating the entire file.</p>
<p>Keeping the bookmark structure aligned with the actual document makes long PDFs easier to navigate and easier to maintain.</p>
]]></content:encoded></item><item><title><![CDATA[How to Create Drop-Down Lists in Excel with C#]]></title><description><![CDATA[In employee records, order forms, project trackers, and other Excel templates, some fields should only contain predefined values, such as departments, task statuses, approval results, or product categ]]></description><link>https://codingwithfiles.hashnode.dev/how-to-create-drop-down-lists-in-excel-with-c</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-create-drop-down-lists-in-excel-with-c</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 07 Aug 2026 11:23:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/ed13b1d0-6f9e-4305-affc-761217edf8e8.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In employee records, order forms, project trackers, and other Excel templates, some fields should only contain predefined values, such as departments, task statuses, approval results, or product categories.</p>
<p>If users enter these values manually, the same option can easily appear in different forms. For example, a task status might be entered as <code>In Progress</code>, <code>In progress</code>, or an abbreviated variation. This creates extra cleanup work later when the workbook is filtered, summarized, or imported into another system.</p>
<p>Adding drop-down lists to these cells gives users a controlled set of choices and helps reduce inconsistent data at the point of entry.</p>
<p>This article shows how to create Excel drop-down lists in C# in three common scenarios:</p>
<ul>
<li><p>Use fixed values as drop-down options</p>
</li>
<li><p>Use a cell range in the current worksheet as the data source</p>
</li>
<li><p>Use data from another worksheet as the drop-down source</p>
</li>
</ul>
<h2>Install the Required Excel Library</h2>
<p>This article uses <strong>Spire.XLS for .NET</strong> to create and modify Excel files. It supports Excel data validation, including list-based drop-downs, and does not require Microsoft Excel to be installed on the machine running the code.</p>
<p>You can install it through NuGet Package Manager Console:</p>
<pre><code class="language-powershell">Install-Package Spire.XLS
</code></pre>
<p>Then import the required namespace:</p>
<pre><code class="language-csharp">using Spire.Xls;
</code></pre>
<p>The implementation depends mainly on where the drop-down values come from.</p>
<h2>Create an Excel Drop-Down List from Fixed Values</h2>
<p>If the available options are limited and unlikely to change often, the simplest approach is to define them directly in a string array.</p>
<p>For example, a task management sheet may restrict the task status to:</p>
<ul>
<li><p>Not Started</p>
</li>
<li><p>In Progress</p>
</li>
<li><p>Completed</p>
</li>
<li><p>On Hold</p>
</li>
</ul>
<p>The following example creates a simple task table and adds a status drop-down list to cell <code>D2</code>.</p>
<pre><code class="language-csharp">using Spire.Xls;

namespace CreateExcelDropdown
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a Workbook object
            Workbook workbook = new Workbook();

            // Get the first worksheet
            Worksheet sheet = workbook.Worksheets[0];
            sheet.Name = "Task Management";

            // Add headers
            sheet.Range["A1"].Text = "Task ID";
            sheet.Range["B1"].Text = "Task Name";
            sheet.Range["C1"].Text = "Owner";
            sheet.Range["D1"].Text = "Status";

            // Add sample data
            sheet.Range["A2"].Text = "T001";
            sheet.Range["B2"].Text = "Prepare Project Plan";
            sheet.Range["C2"].Text = "Alice Johnson";

            // Define drop-down options
            string[] statusValues =
            {
                "Not Started",
                "In Progress",
                "Completed",
                "On Hold"
            };

            // Apply the drop-down list to D2
            sheet.Range["D2"].DataValidation.Values = statusValues;

            // Auto-fit columns
            sheet.AllocatedRange.AutoFitColumns();

            // Save the workbook
            workbook.SaveToFile(
                "TaskStatusDropdown.xlsx",
                ExcelVersion.Version2016);

            workbook.Dispose();
        }
    }
}
</code></pre>
<p>The key line is:</p>
<pre><code class="language-csharp">sheet.Range["D2"].DataValidation.Values = statusValues;
</code></pre>
<p><code>DataValidation.Values</code> accepts a string array and uses the array items as the available list values.</p>
<p>This approach works well for fixed choices such as:</p>
<ul>
<li><p>Status</p>
</li>
<li><p>Priority</p>
</li>
<li><p>Enabled / Disabled</p>
</li>
<li><p>Approval result</p>
</li>
<li><p>Fixed categories</p>
</li>
</ul>
<p>If the options are numerous or change frequently, hard-coding them in the application is less convenient. In that case, storing the values in worksheet cells is usually easier to maintain.</p>
<h2>Create a Drop-Down List from a Cell Range</h2>
<p>Sometimes the available options already exist inside the workbook.</p>
<p>For example, an employee worksheet may contain a department list in <code>F2:F5</code>:</p>
<table>
<thead>
<tr>
<th>Cell</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>F2</td>
<td>Sales</td>
</tr>
<tr>
<td>F3</td>
<td>Finance</td>
</tr>
<tr>
<td>F4</td>
<td>IT</td>
</tr>
<tr>
<td>F5</td>
<td>Human Resources</td>
</tr>
</tbody></table>
<p>The Department field can then use that range as its drop-down source.</p>
<pre><code class="language-csharp">using Spire.Xls;

namespace CreateDropdownFromRange
{
    class Program
    {
        static void Main(string[] args)
        {
            Workbook workbook = new Workbook();

            Worksheet sheet = workbook.Worksheets[0];
            sheet.Name = "Employees";

            // Create the employee table
            sheet.Range["A1"].Text = "Employee ID";
            sheet.Range["B1"].Text = "Employee Name";
            sheet.Range["C1"].Text = "Department";

            sheet.Range["A2"].Text = "E001";
            sheet.Range["B2"].Text = "John Smith";

            // Create the department source list
            sheet.Range["F1"].Text = "Department List";
            sheet.Range["F2"].Text = "Sales";
            sheet.Range["F3"].Text = "Finance";
            sheet.Range["F4"].Text = "IT";
            sheet.Range["F5"].Text = "Human Resources";

            // Get the source range
            CellRange departmentRange = sheet.Range["F2:F5"];

            // Use the range as the drop-down source
            sheet.Range["C2"].DataValidation.DataRange =
                departmentRange;

            sheet.AllocatedRange.AutoFitColumns();

            workbook.SaveToFile(
                "DepartmentDropdown.xlsx",
                ExcelVersion.Version2016);

            workbook.Dispose();
        }
    }
}
</code></pre>
<p>The main difference here is:</p>
<pre><code class="language-csharp">sheet.Range["C2"].DataValidation.DataRange = departmentRange;
</code></pre>
<p>Using a worksheet range as the data source makes the list easier to maintain.</p>
<p>For example, if another department is added later, the source data can be updated in the workbook rather than duplicated as a long list of hard-coded values in C#.</p>
<p>This approach is useful when the source values already belong to the same worksheet.</p>
<p>In larger business templates, however, storing helper values beside the main data can make the sheet look cluttered. A more common design is to keep these values on a separate worksheet.</p>
<h2>Create a Drop-Down List from Another Worksheet</h2>
<p>In real-world templates, business data and lookup values are often stored separately.</p>
<p>For example, a workbook might contain:</p>
<ul>
<li><p><code>Employees</code>: stores employee information</p>
</li>
<li><p><code>Options</code>: stores departments, job titles, statuses, and other lookup values</p>
</li>
</ul>
<p>This keeps the main worksheet cleaner and makes the source values easier to manage.</p>
<p>The following example creates a drop-down list whose values come from another worksheet.</p>
<pre><code class="language-csharp">using Spire.Xls;

namespace CreateCrossSheetDropdown
{
    class Program
    {
        static void Main(string[] args)
        {
            Workbook workbook = new Workbook();

            // Get the employee worksheet
            Worksheet employeeSheet = workbook.Worksheets[0];
            employeeSheet.Name = "Employees";

            // Add the options worksheet
            Worksheet optionsSheet =
                workbook.Worksheets.Add("Options");

            // -------------------------
            // Employees worksheet
            // -------------------------

            employeeSheet.Range["A1"].Text = "Employee ID";
            employeeSheet.Range["B1"].Text = "Employee Name";
            employeeSheet.Range["C1"].Text = "Department";

            employeeSheet.Range["A2"].Text = "E001";
            employeeSheet.Range["B2"].Text = "John Smith";

            // -------------------------
            // Options worksheet
            // -------------------------

            optionsSheet.Range["A1"].Text = "Department List";
            optionsSheet.Range["A2"].Text = "Sales";
            optionsSheet.Range["A3"].Text = "Finance";
            optionsSheet.Range["A4"].Text = "IT";
            optionsSheet.Range["A5"].Text = "Human Resources";

            // Allow data validation to reference another worksheet
            workbook.Allow3DRangesInDataValidation = true;

            // Get the department source range
            CellRange departmentRange =
                optionsSheet.Range["A2:A5"];

            // Apply the source range to the Department field
            employeeSheet.Range["C2"]
                .DataValidation.DataRange = departmentRange;

            employeeSheet.AllocatedRange.AutoFitColumns();
            optionsSheet.AllocatedRange.AutoFitColumns();

            workbook.SaveToFile(
                "CrossSheetDropdown.xlsx",
                ExcelVersion.Version2016);

            workbook.Dispose();
        }
    }
}
</code></pre>
<p>One setting is easy to overlook when the validation source is on another worksheet:</p>
<pre><code class="language-csharp">workbook.Allow3DRangesInDataValidation = true;
</code></pre>
<p>This allows the data validation rule to reference a range outside the current worksheet.</p>
<p>After enabling it, you can set the source range normally:</p>
<pre><code class="language-csharp">employeeSheet.Range["C2"].DataValidation.DataRange =
    optionsSheet.Range["A2:A5"];
</code></pre>
<p>This layout works well for business templates that need centrally maintained lookup values.</p>
<p>A workbook might be organized like this:</p>
<pre><code class="language-text">Workbook
│
├── Employees
│   ├── Employee ID
│   ├── Employee Name
│   └── Department ▼
│
└── Options
    ├── Sales
    ├── Finance
    ├── IT
    └── Human Resources
</code></pre>
<p>If end users do not need to see the helper data, the <code>Options</code> worksheet can also be hidden.</p>
<h2>Apply the Same Drop-Down List to Multiple Cells</h2>
<p>The previous examples apply data validation to a single cell, but real templates usually need the same list across many rows.</p>
<p>For example, to apply the department list to <code>C2:C100</code>:</p>
<pre><code class="language-csharp">employeeSheet.Range["C2:C100"]
    .DataValidation.DataRange = departmentRange;
</code></pre>
<p>The same approach works with fixed values:</p>
<pre><code class="language-csharp">string[] statusValues =
{
    "Not Started",
    "In Progress",
    "Completed",
    "On Hold"
};

sheet.Range["D2:D100"].DataValidation.Values =
    statusValues;
</code></pre>
<p>Applying validation to a range is simpler than looping through cells one by one and is usually a better fit for generated Excel templates.</p>
<h2>Which Approach Should You Use?</h2>
<p>The main difference between the three approaches is where the drop-down values are stored.</p>
<table>
<thead>
<tr>
<th>Data Source</th>
<th>Implementation</th>
<th>Best For</th>
</tr>
</thead>
<tbody><tr>
<td>Fixed strings</td>
<td><code>DataValidation.Values</code></td>
<td>Status, priority, approval results, and other fixed options</td>
</tr>
<tr>
<td>Current worksheet range</td>
<td><code>DataValidation.DataRange</code></td>
<td>Simple templates with a small amount of helper data</td>
</tr>
<tr>
<td>Another worksheet</td>
<td><code>DataValidation.DataRange</code> + <code>Allow3DRangesInDataValidation</code></td>
<td>Business templates with centrally managed lookup values</td>
</tr>
</tbody></table>
<p>For a small fixed set such as <code>Yes / No</code> or <code>Enabled / Disabled</code>, a string array is usually the simplest choice.</p>
<p>If the values change regularly or come from business data, using a cell range is easier to maintain.</p>
<p>For long-lived templates such as employee forms, order forms, or project tracking workbooks, keeping lookup values on a dedicated worksheet is often the cleaner approach.</p>
<h2>Practical Considerations</h2>
<h3>1. Avoid Hard-Coding Frequently Changing Options</h3>
<p>Suppose a department list originally contains:</p>
<pre><code class="language-text">Sales
Finance
IT
</code></pre>
<p>and later needs:</p>
<pre><code class="language-text">Customer Service
</code></pre>
<p>If the entire list is hard-coded in C#, the application must be updated and redeployed.</p>
<p>If the values come from a database, configuration source, or admin system, a more maintainable workflow is:</p>
<ol>
<li><p>Read the latest values from the business system</p>
</li>
<li><p>Write them to an <code>Options</code> worksheet</p>
</li>
<li><p>Point the data validation rule to that range</p>
</li>
</ol>
<p>This keeps the generated workbook aligned with the current business data.</p>
<h3>2. Keep the Source Range in Sync</h3>
<p>If the drop-down list points to:</p>
<pre><code class="language-text">A2:A5
</code></pre>
<p>but the actual list later grows to <code>A8</code>, the new values will not appear unless the validation source range is updated.</p>
<p>For dynamic data, calculate the final row when generating the workbook.</p>
<p>For example:</p>
<pre><code class="language-csharp">int lastRow = 8;

employeeSheet.Range["C2:C100"]
    .DataValidation.DataRange =
    optionsSheet.Range["A2:A" + lastRow];
</code></pre>
<p>This makes the source range follow the actual number of available options.</p>
<h3>3. Excel Drop-Down Lists Do Not Replace Server-Side Validation</h3>
<p>Excel data validation helps reduce user input errors, but it should not be treated as the only validation layer if the data will later be imported into a database or business system.</p>
<p>For example, even if the Department field uses a drop-down list, the import process can still verify that the selected department is currently valid.</p>
<p>This is important because Excel validation can sometimes be bypassed through copy and paste, external editing tools, or direct file manipulation.</p>
<h3>4. Dependent Drop-Down Lists Require Additional Logic</h3>
<p>Some lists depend on a previous selection, for example:</p>
<pre><code class="language-text">Country → City
Product Category → Product
Department → Job Title
</code></pre>
<p>A simple fixed list is not enough in these cases.</p>
<p>Dependent drop-downs usually require a combination of:</p>
<ul>
<li><p>Named ranges</p>
</li>
<li><p>Data validation formulas</p>
</li>
<li><p>Excel functions such as <code>INDIRECT</code></p>
</li>
</ul>
<p>It is therefore worth deciding whether the options are independent or hierarchical before designing the workbook template.</p>
<h2>Conclusion</h2>
<p>Drop-down lists are a practical way to improve data consistency in Excel templates generated with C#.</p>
<p>This article covered three common approaches:</p>
<ul>
<li><p>Creating a drop-down list from fixed string values</p>
</li>
<li><p>Using a cell range in the current worksheet as the data source</p>
</li>
<li><p>Referencing values stored on another worksheet</p>
</li>
</ul>
<p>For small and stable option sets, a string array is usually sufficient. For values that need regular maintenance or come from business systems, storing the options in worksheet cells and using them as the validation source is generally more flexible.</p>
<p>Choosing the data source based on how the options are maintained makes the resulting Excel file easier to use and easier to keep in sync with the rest of the application.</p>
]]></content:encoded></item><item><title><![CDATA[How to Create and Update a Table of Contents in Word Using Java]]></title><description><![CDATA[Project reports, product manuals, technical documents, and other long-form Word files often contain multiple chapters and sections. As the content changes, section titles, chapter order, and page numb]]></description><link>https://codingwithfiles.hashnode.dev/how-to-create-and-update-a-table-of-contents-in-word-using-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-create-and-update-a-table-of-contents-in-word-using-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 31 Jul 2026 12:56:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/c69bf9dd-5517-4a1a-8a38-45ffa368b681.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Project reports, product manuals, technical documents, and other long-form Word files often contain multiple chapters and sections. As the content changes, section titles, chapter order, and page numbers may also change.</p>
<p>Maintaining the table of contents manually is repetitive and can easily result in missing headings or incorrect page numbers.</p>
<p>A Word table of contents is a field generated from the heading styles used in the document. As long as the document uses Heading 1, Heading 2, Heading 3, and other built-in heading styles correctly, the table of contents can be inserted programmatically and updated after the document changes.</p>
<p>This article demonstrates how to use Java to:</p>
<ul>
<li><p>Create a Word document with multilevel headings</p>
</li>
<li><p>Generate a table of contents from Heading 1 through Heading 3</p>
</li>
<li><p>Insert a table of contents into an existing Word document</p>
</li>
<li><p>Update heading text and page numbers in an existing table of contents</p>
</li>
<li><p>Control which heading levels appear in the table of contents</p>
</li>
</ul>
<h2>How Word Identifies Headings for a Table of Contents</h2>
<p>A Word table of contents normally uses paragraph styles to determine the heading hierarchy.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>Document Content</th>
<th>Word Style</th>
<th>TOC Level</th>
</tr>
</thead>
<tbody><tr>
<td>1. Project Overview</td>
<td>Heading 1</td>
<td>Level 1</td>
</tr>
<tr>
<td>1.1 Project Background</td>
<td>Heading 2</td>
<td>Level 2</td>
</tr>
<tr>
<td>1.1.1 Project Goals</td>
<td>Heading 3</td>
<td>Level 3</td>
</tr>
</tbody></table>
<p>Making text bold or increasing its font size does not automatically make it a heading. The paragraph must use an actual Word heading style.</p>
<p>In Java, the following built-in styles can be applied:</p>
<pre><code class="language-java">BuiltinStyle.Heading_1
BuiltinStyle.Heading_2
BuiltinStyle.Heading_3
</code></pre>
<p>The <code>appendTOC()</code> method specifies the heading levels included in the table of contents, while <code>updateTableOfContents()</code> recalculates the entries and page numbers based on the current document structure.</p>
<h2>Install the Word Library</h2>
<p>The examples below use Spire.Doc for Java to create and edit Word documents.</p>
<p>Add the following repository and dependency to the <code>pom.xml</code> file of a Maven project:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;
            https://repo.e-iceblue.com/nexus/content/groups/public/
        &lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.doc&lt;/artifactId&gt;
        &lt;version&gt;14.6.0&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>The version number can be changed to the version currently used in your project.</p>
<p>Import the required classes:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.Section;
import com.spire.doc.documents.BreakType;
import com.spire.doc.documents.BuiltinStyle;
import com.spire.doc.documents.HorizontalAlignment;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.fields.TextRange;
</code></pre>
<h2>Create a Word Document with a Table of Contents in Java</h2>
<p>The following example creates a Word document from scratch and inserts a table of contents containing Heading 1 through Heading 3.</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.Section;
import com.spire.doc.documents.BreakType;
import com.spire.doc.documents.BuiltinStyle;
import com.spire.doc.documents.HorizontalAlignment;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.fields.TextRange;

public class CreateWordWithToc {

    public static void main(String[] args) {

        // Create a Word document
        Document document = new Document();

        try {
            // Add a section
            Section section = document.addSection();

            // Add the table of contents title
            Paragraph tocTitle = section.addParagraph();
            TextRange titleText = tocTitle.appendText(
                    "Table of Contents"
            );

            titleText.getCharacterFormat().setBold(true);
            titleText.getCharacterFormat().setFontSize(18);

            tocTitle.getFormat().setHorizontalAlignment(
                    HorizontalAlignment.Center
            );

            // Insert a table of contents containing
            // Heading 1 through Heading 3
            Paragraph tocParagraph = section.addParagraph();
            tocParagraph.appendTOC(1, 3);

            // Insert a page break after the table of contents
            tocParagraph.appendBreak(BreakType.Page_Break);

            // Add a level-one heading
            addHeading(
                    section,
                    "1. Project Overview",
                    BuiltinStyle.Heading_1
            );

            addBodyText(
                    section,
                    "This chapter introduces the project background, "
                            + "main objectives, and implementation scope."
            );

            // Add level-two headings
            addHeading(
                    section,
                    "1.1 Project Background",
                    BuiltinStyle.Heading_2
            );

            addBodyText(
                    section,
                    "As the scale of the business grows, the existing "
                            + "management approach is no longer sufficient "
                            + "for centralized operations."
            );

            addHeading(
                    section,
                    "1.2 Project Objectives",
                    BuiltinStyle.Heading_2
            );

            addBodyText(
                    section,
                    "The project will establish a unified platform for "
                            + "data management and business collaboration."
            );

            // Add level-three headings
            addHeading(
                    section,
                    "1.2.1 Business Objectives",
                    BuiltinStyle.Heading_3
            );

            addBodyText(
                    section,
                    "Standardize business processes and improve "
                            + "cross-department collaboration."
            );

            addHeading(
                    section,
                    "1.2.2 Technical Objectives",
                    BuiltinStyle.Heading_3
            );

            addBodyText(
                    section,
                    "Create a scalable and maintainable system architecture."
            );

            // Add another level-one heading
            addHeading(
                    section,
                    "2. Implementation Plan",
                    BuiltinStyle.Heading_1
            );

            addBodyText(
                    section,
                    "This chapter describes the implementation stages "
                            + "and major project tasks."
            );

            addHeading(
                    section,
                    "2.1 Implementation Stages",
                    BuiltinStyle.Heading_2
            );

            addBodyText(
                    section,
                    "The project includes requirements analysis, "
                            + "system design, development, testing, "
                            + "and deployment."
            );

            // Update the table of contents based on
            // the current headings and pagination
            document.updateTableOfContents();

            // Save the document
            document.saveToFile(
                    "WordDocumentWithTOC.docx",
                    FileFormat.Docx_2019
            );

        } finally {
            document.dispose();
        }
    }

    /**
     * Add a heading paragraph.
     */
    private static void addHeading(
            Section section,
            String text,
            BuiltinStyle style
    ) {
        Paragraph paragraph = section.addParagraph();
        paragraph.appendText(text);
        paragraph.applyStyle(style);
    }

    /**
     * Add a body paragraph.
     */
    private static void addBodyText(
            Section section,
            String text
    ) {
        Paragraph paragraph = section.addParagraph();
        paragraph.appendText(text);
        paragraph.getFormat().setAfterSpacing(10);
    }
}
</code></pre>
<p>After the code runs, it creates:</p>
<pre><code class="language-text">WordDocumentWithTOC.docx
</code></pre>
<p>The first page contains the table of contents, while the main document starts on the next page. The table of contents includes level-one, level-two, and level-three headings together with their page numbers.</p>
<h2>Understanding the appendTOC() Parameters</h2>
<p>The following code creates a table of contents containing Heading 1 through Heading 3:</p>
<pre><code class="language-java">tocParagraph.appendTOC(1, 3);
</code></pre>
<p>The two parameters represent:</p>
<pre><code class="language-text">Starting heading level
Ending heading level
</code></pre>
<p>For example, to include only Heading 1 and Heading 2:</p>
<pre><code class="language-java">tocParagraph.appendTOC(1, 2);
</code></pre>
<p>To include only Heading 1:</p>
<pre><code class="language-java">tocParagraph.appendTOC(1, 1);
</code></pre>
<p>For most project reports and technical documents, three heading levels are usually sufficient. Including too many levels may make the table of contents difficult to scan and unnecessarily long.</p>
<h2>Insert a Table of Contents into an Existing Word Document</h2>
<p>In many cases, the Word document already contains the main content and only needs a table of contents added at the beginning.</p>
<p>The following example loads an existing Word file and inserts the table of contents at the beginning of the first section.</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.Section;
import com.spire.doc.documents.BreakType;
import com.spire.doc.documents.HorizontalAlignment;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.fields.TextRange;

public class AddTocToExistingDocument {

    public static void main(String[] args) {

        Document document = new Document();

        try {
            // Load an existing Word document
            document.loadFromFile("ProjectReport.docx");

            // Get the first section
            Section firstSection =
                    document.getSections().get(0);

            // Create the table of contents title
            Paragraph tocTitle = new Paragraph(document);
            TextRange titleText = tocTitle.appendText(
                    "Table of Contents"
            );

            titleText.getCharacterFormat().setBold(true);
            titleText.getCharacterFormat().setFontSize(18);

            tocTitle.getFormat().setHorizontalAlignment(
                    HorizontalAlignment.Center
            );

            // Create the table of contents paragraph
            Paragraph tocParagraph = new Paragraph(document);
            tocParagraph.appendTOC(1, 3);

            // Insert a page break after the table of contents
            tocParagraph.appendBreak(BreakType.Page_Break);

            // Insert the title and table of contents
            // at the beginning of the first section
            firstSection.getParagraphs().insert(
                    0,
                    tocTitle
            );

            firstSection.getParagraphs().insert(
                    1,
                    tocParagraph
            );

            // Update the table of contents
            document.updateTableOfContents();

            // Save the result as a new file
            document.saveToFile(
                    "ProjectReportWithTOC.docx",
                    FileFormat.Docx_2019
            );

        } finally {
            document.dispose();
        }
    }
}
</code></pre>
<p>The result is saved as a new file instead of overwriting the source document:</p>
<pre><code class="language-text">ProjectReport.docx
ProjectReportWithTOC.docx
</code></pre>
<p>The headings in the original document must already use styles such as Heading 1, Heading 2, and Heading 3. Otherwise, the table of contents field may be inserted successfully but contain few or no entries.</p>
<h2>Apply Heading Styles to Ordinary Paragraphs</h2>
<p>If the section titles in an existing document are ordinary paragraphs, heading styles can be applied before generating the table of contents.</p>
<p>For example, suppose the third paragraph in the first section is a level-one heading and the fifth paragraph is a level-two heading:</p>
<pre><code class="language-java">Section section = document.getSections().get(0);

section.getParagraphs()
        .get(2)
        .applyStyle(BuiltinStyle.Heading_1);

section.getParagraphs()
        .get(4)
        .applyStyle(BuiltinStyle.Heading_2);
</code></pre>
<p>After applying the styles, insert and update the table of contents:</p>
<pre><code class="language-java">Paragraph tocParagraph = new Paragraph(document);
tocParagraph.appendTOC(1, 3);

section.getParagraphs().insert(
        0,
        tocParagraph
);

document.updateTableOfContents();
</code></pre>
<p>This approach works well with documents that follow a fixed template.</p>
<p>For documents with an unpredictable structure, relying entirely on paragraph indexes is risky. Adding or removing a paragraph changes the indexes of all subsequent paragraphs.</p>
<p>A more reliable approach is to identify headings by their text, existing styles, bookmarks, or other document markers.</p>
<h2>Update an Existing Word Table of Contents</h2>
<p>When section titles, chapter order, or document length changes, the table of contents should be updated.</p>
<p>The following example changes a heading and then refreshes the table of contents:</p>
<pre><code class="language-java">import com.spire.doc.Document;
import com.spire.doc.FileFormat;

public class UpdateWordToc {

    public static void main(String[] args) {

        Document document = new Document();

        try {
            // Load a Word document containing a table of contents
            document.loadFromFile(
                    "WordDocumentWithTOC.docx"
            );

            // Change a heading
            document.replace(
                    "2. Implementation Plan",
                    "2. Project Implementation Plan",
                    false,
                    true
            );

            // Update the TOC entries and page numbers
            document.updateTableOfContents();

            // Save the updated document
            document.saveToFile(
                    "UpdatedWordTOC.docx",
                    FileFormat.Docx_2019
            );

        } finally {
            document.dispose();
        }
    }
}
</code></pre>
<p>After the update, the table of contents entry:</p>
<pre><code class="language-text">2. Implementation Plan
</code></pre>
<p>becomes:</p>
<pre><code class="language-text">2. Project Implementation Plan
</code></pre>
<p>If the document changes cause a heading to move to another page, the corresponding page number is recalculated as well.</p>
<h2>Prevent the TOC Title from Appearing in the Table of Contents</h2>
<p>The table of contents page often includes a title such as “Table of Contents.”</p>
<p>That title should not use the Heading 1 style unless it is intended to appear as an entry inside the table of contents.</p>
<p>Instead, format it manually:</p>
<pre><code class="language-java">Paragraph tocTitle = section.addParagraph();

TextRange textRange =
        tocTitle.appendText("Table of Contents");

textRange.getCharacterFormat().setBold(true);
textRange.getCharacterFormat().setFontSize(18);

tocTitle.getFormat().setHorizontalAlignment(
        HorizontalAlignment.Center
);
</code></pre>
<p>Avoid applying a heading style like this:</p>
<pre><code class="language-java">tocTitle.applyStyle(BuiltinStyle.Heading_1);
</code></pre>
<p>Otherwise, “Table of Contents” may appear as a level-one entry inside the table itself.</p>
<h2>Common Problems When Updating a Table of Contents</h2>
<h3>The Table of Contents Is Empty</h3>
<p>This usually means the section headings do not use formal Word heading styles.</p>
<p>Bold text, larger font sizes, or different colors do not make a paragraph part of the heading hierarchy.</p>
<p>Apply an actual heading style:</p>
<pre><code class="language-java">paragraph.applyStyle(BuiltinStyle.Heading_1);
</code></pre>
<p>The same applies to Heading 2, Heading 3, and other levels.</p>
<h3>Level-Three Headings Are Missing</h3>
<p>Check the ending level passed to <code>appendTOC()</code>.</p>
<p>The following code includes only Heading 1 and Heading 2:</p>
<pre><code class="language-java">tocParagraph.appendTOC(1, 2);
</code></pre>
<p>To include Heading 3 as well, use:</p>
<pre><code class="language-java">tocParagraph.appendTOC(1, 3);
</code></pre>
<h3>Page Numbers Have Not Changed</h3>
<p>After modifying the document content, call:</p>
<pre><code class="language-java">document.updateTableOfContents();
</code></pre>
<p>If the document is saved without updating the table of contents, it may continue to display outdated entries or page numbers.</p>
<h3>The Table of Contents Appears Before the Cover Page</h3>
<p>If the document contains a cover page, place the table of contents in a separate section after the cover instead of inserting it at the first paragraph of the document.</p>
<p>A suitable document structure is:</p>
<pre><code class="language-text">Section 1: Cover page
Section 2: Table of contents
Section 3: Main content
</code></pre>
<p>This approach is more appropriate for formal reports, proposals, and product manuals.</p>
<h3>Heading Numbers Are Duplicated</h3>
<p>Heading styles define the hierarchy but do not automatically guarantee that manually entered chapter numbers are correct.</p>
<p>For example:</p>
<pre><code class="language-text">1. Project Overview
1.1 Project Background
</code></pre>
<p>If the numbers are written directly in the heading text, the program must ensure that they match the actual heading hierarchy.</p>
<p>When Word multilevel lists are used for automatic numbering, both the list formatting and heading styles need to be maintained.</p>
<h2>Practical Considerations</h2>
<h3>Use a Consistent Heading Structure</h3>
<p>A reliable table of contents depends on a consistent document hierarchy.</p>
<p>For example:</p>
<pre><code class="language-text">Heading 1: Main chapters
Heading 2: Sections
Heading 3: Subsections
</code></pre>
<p>Avoid using the same heading level for unrelated structural purposes.</p>
<h3>Save the Output as a New File</h3>
<p>When adding or updating a table of contents in an existing document, save the result as a new file:</p>
<pre><code class="language-text">ProjectReport.docx
ProjectReportWithTOC.docx
</code></pre>
<p>This keeps the source document available in case the heading styles, pagination, or table of contents layout need to be adjusted.</p>
<h3>Keep the Number of TOC Levels Reasonable</h3>
<p>Although Word supports several heading levels, including too many levels may reduce readability.</p>
<p>For most business and technical documents, one to three levels are enough.</p>
<h3>Check the Result in Word</h3>
<p>Automatic generation can handle the heading entries and page numbers, but the result should still be reviewed in Word.</p>
<p>Pay particular attention to:</p>
<ul>
<li><p>Long heading text</p>
</li>
<li><p>Page breaks</p>
</li>
<li><p>Section breaks</p>
</li>
<li><p>Headers and footers</p>
</li>
<li><p>Landscape pages</p>
</li>
<li><p>Tables that affect pagination</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Java can be used to automate common Word table of contents operations, including:</p>
<ul>
<li><p>Creating Heading 1 through Heading 3 paragraphs</p>
</li>
<li><p>Generating a table of contents from heading styles</p>
</li>
<li><p>Inserting a table of contents into an existing Word document</p>
</li>
<li><p>Updating heading text and page numbers</p>
</li>
<li><p>Controlling which heading levels appear</p>
</li>
<li><p>Placing the table of contents between the cover page and main content</p>
</li>
</ul>
<p>The most important part of the process is not the table of contents field itself, but the document’s heading structure.</p>
<p>When headings use the correct Word styles, <code>updateTableOfContents()</code> can regenerate the entries and page numbers after the document changes, reducing the need for manual maintenance.</p>
]]></content:encoded></item><item><title><![CDATA[How to Add Sparklines to Excel in Python]]></title><description><![CDATA[Sales reports, inventory sheets, and operational dashboards often contain data that changes over time. Although the values can be compared directly, it may still be difficult to identify growth, decli]]></description><link>https://codingwithfiles.hashnode.dev/how-to-add-sparklines-to-excel-in-python</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-add-sparklines-to-excel-in-python</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 31 Jul 2026 12:53:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/627f96ee-a87e-4db1-930e-767a2e20790f.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sales reports, inventory sheets, and operational dashboards often contain data that changes over time. Although the values can be compared directly, it may still be difficult to identify growth, decline, or unusual fluctuations across many rows.</p>
<p>A standard Excel chart can make trends easier to understand, but creating a separate chart for every product, department, or project would take up too much space.</p>
<p>Excel sparklines provide a more compact alternative. A sparkline is a small chart displayed inside a single cell, allowing readers to view the trend of a data series without changing the overall worksheet layout.</p>
<p>This article demonstrates how to use Python to:</p>
<ul>
<li><p>Create an Excel workbook containing monthly sales data</p>
</li>
<li><p>Add line sparklines to multiple rows</p>
</li>
<li><p>Change sparklines to column or win/loss types</p>
</li>
<li><p>Configure sparkline and high-point colors</p>
</li>
<li><p>Add sparklines to an existing Excel workbook</p>
</li>
</ul>
<h2>What Are Excel Sparklines?</h2>
<p>Unlike standard Excel charts, a sparkline is usually displayed inside one cell.</p>
<p>For example, consider the following monthly sales data:</p>
<table>
<thead>
<tr>
<th>Product</th>
<th>Jan</th>
<th>Feb</th>
<th>Mar</th>
<th>Apr</th>
<th>Trend</th>
</tr>
</thead>
<tbody><tr>
<td>Product A</td>
<td>120</td>
<td>135</td>
<td>128</td>
<td>160</td>
<td>Sparkline</td>
</tr>
<tr>
<td>Product B</td>
<td>95</td>
<td>110</td>
<td>108</td>
<td>126</td>
<td>Sparkline</td>
</tr>
</tbody></table>
<p>A sparkline can be placed in the cell next to each row, allowing readers to quickly identify whether the values are increasing, decreasing, or fluctuating.</p>
<p>Excel supports three common sparkline types:</p>
<ul>
<li><p><strong>Line sparklines</strong> show continuous changes over time, such as sales, website visits, or revenue.</p>
</li>
<li><p><strong>Column sparklines</strong> make it easier to compare the relative size of individual values.</p>
</li>
<li><p><strong>Win/loss sparklines</strong> emphasize positive and negative results rather than exact values.</p>
</li>
</ul>
<h2>Install the Excel Library</h2>
<p>The examples below use Spire.XLS for Python to create and edit Excel workbooks.</p>
<p>Install the package with pip:</p>
<pre><code class="language-bash">pip install Spire.XLS
</code></pre>
<p>Then import the required modules:</p>
<pre><code class="language-python">from spire.xls import *
from spire.xls.common import *
</code></pre>
<h2>Create Sample Excel Data in Python</h2>
<p>The following example creates a worksheet containing monthly sales data for four products.</p>
<p>The data is stored in the range <code>A1:N5</code>:</p>
<ul>
<li><p>Column A contains product names</p>
</li>
<li><p>Columns B through M contain sales data from January to December</p>
</li>
<li><p>Column N is reserved for sparklines</p>
</li>
</ul>
<pre><code class="language-python">from spire.xls import *
from spire.xls.common import *

# Create a workbook
workbook = Workbook()

# Get the first worksheet
sheet = workbook.Worksheets[0]
sheet.Name = "Monthly Sales"

# Define the headers
headers = [
    "Product",
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "Trend"
]

# Define monthly sales data
sales_data = [
    ["Product A", 120, 135, 128, 160, 172, 168, 190, 205, 198, 220, 235, 248],
    ["Product B", 95, 108, 115, 110, 126, 140, 138, 150, 163, 158, 172, 185],
    ["Product C", 180, 172, 165, 170, 158, 150, 162, 155, 148, 142, 150, 138],
    ["Product D", 75, 92, 88, 105, 98, 115, 121, 118, 132, 140, 137, 152]
]

# Write the headers
for column_index, header in enumerate(headers, start=1):
    sheet.Range[1, column_index].Text = header

# Write the product names and sales values
for row_index, row_data in enumerate(sales_data, start=2):
    sheet.Range[row_index, 1].Text = row_data[0]

    for column_index, value in enumerate(row_data[1:], start=2):
        sheet.Range[row_index, column_index].NumberValue = value

# Make the header row bold
sheet.Range["A1:N1"].Style.Font.IsBold = True

# Automatically adjust the column widths
sheet.Range["A1:N5"].AutoFitColumns()
</code></pre>
<p>At this stage, the worksheet contains the complete sales data, but no sparklines have been added yet.</p>
<h2>Add Line Sparklines to Excel in Python</h2>
<p>To add sparklines, first create a sparkline group and specify its chart type.</p>
<p>The following code adds line sparklines to cells <code>N2:N5</code>. Each sparkline uses the 12 monthly values from the corresponding row.</p>
<pre><code class="language-python"># Create a sparkline group
sparkline_group = sheet.SparklineGroups.AddGroup()

# Set the sparkline type to line
sparkline_group.SparklineType = SparklineType.Line

# Set the sparkline color
sparkline_group.SparklineColor = Color.get_DarkBlue()

# Set the color of the highest point
sparkline_group.HighPointColor = Color.get_Red()

# Create a sparkline collection
sparklines = sparkline_group.Add()

# Add one sparkline for each product row
for row in range(2, 6):
    data_range = sheet.Range[f"B{row}:M{row}"]
    location = sheet.Range[f"N{row}"]

    sparklines.Add(data_range, location)
</code></pre>
<p>The main operations are:</p>
<ul>
<li><p><code>AddGroup()</code> creates a new sparkline group.</p>
</li>
<li><p><code>SparklineType.Line</code> specifies a line sparkline.</p>
</li>
<li><p><code>SparklineColor</code> sets the main sparkline color.</p>
</li>
<li><p><code>HighPointColor</code> sets the color of the highest value.</p>
</li>
<li><p><code>sparklines.Add()</code> defines the source data and destination cell.</p>
</li>
</ul>
<p>Keeping similar sparklines in one group makes it easier to apply the same type and formatting to all of them.</p>
<h2>Save the Excel Workbook</h2>
<p>After adding the sparklines, save the workbook as an XLSX file:</p>
<pre><code class="language-python"># Save the workbook
workbook.SaveToFile(
    "sales_trends_with_sparklines.xlsx",
    ExcelVersion.Version2016
)

# Release resources
workbook.Dispose()
</code></pre>
<p>The output file is:</p>
<pre><code class="language-text">sales_trends_with_sparklines.xlsx
</code></pre>
<p>When the file is opened in Excel, column N displays a monthly trend sparkline for each product.</p>
<h2>Complete Code Example</h2>
<p>The following code combines workbook creation, data entry, sparkline generation, and file saving.</p>
<pre><code class="language-python">from spire.xls import *
from spire.xls.common import *

# Create a workbook
workbook = Workbook()

# Get the first worksheet
sheet = workbook.Worksheets[0]
sheet.Name = "Monthly Sales"

# Define the headers
headers = [
    "Product",
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "Trend"
]

# Define monthly sales data
sales_data = [
    ["Product A", 120, 135, 128, 160, 172, 168, 190, 205, 198, 220, 235, 248],
    ["Product B", 95, 108, 115, 110, 126, 140, 138, 150, 163, 158, 172, 185],
    ["Product C", 180, 172, 165, 170, 158, 150, 162, 155, 148, 142, 150, 138],
    ["Product D", 75, 92, 88, 105, 98, 115, 121, 118, 132, 140, 137, 152]
]

# Write the headers
for column_index, header in enumerate(headers, start=1):
    sheet.Range[1, column_index].Text = header

# Write the data
for row_index, row_data in enumerate(sales_data, start=2):
    # Write the product name
    sheet.Range[row_index, 1].Text = row_data[0]

    # Write the monthly sales values
    for column_index, value in enumerate(row_data[1:], start=2):
        sheet.Range[row_index, column_index].NumberValue = value

# Format the header row
sheet.Range["A1:N1"].Style.Font.IsBold = True

# Create a line sparkline group
sparkline_group = sheet.SparklineGroups.AddGroup()
sparkline_group.SparklineType = SparklineType.Line

# Configure sparkline colors
sparkline_group.SparklineColor = Color.get_DarkBlue()
sparkline_group.HighPointColor = Color.get_Red()

# Create a sparkline collection
sparklines = sparkline_group.Add()

# Add sparklines to cells N2:N5
for row in range(2, 6):
    sparklines.Add(
        sheet.Range[f"B{row}:M{row}"],
        sheet.Range[f"N{row}"]
    )

# Automatically adjust the column widths
sheet.Range["A1:N5"].AutoFitColumns()

# Save the result
workbook.SaveToFile(
    "sales_trends_with_sparklines.xlsx",
    ExcelVersion.Version2016
)

# Release resources
workbook.Dispose()
</code></pre>
<h2>Add Column Sparklines</h2>
<p>Column sparklines are useful when comparing the relative size of individual values is more important than showing a continuous trend.</p>
<p>Change this line:</p>
<pre><code class="language-python">sparkline_group.SparklineType = SparklineType.Line
</code></pre>
<p>to:</p>
<pre><code class="language-python">sparkline_group.SparklineType = SparklineType.Column
</code></pre>
<p>The rest of the code can remain unchanged.</p>
<p>Column sparklines work well for data such as:</p>
<ul>
<li><p>Monthly order volumes</p>
</li>
<li><p>Inventory levels</p>
</li>
<li><p>Department expenses</p>
</li>
<li><p>Completion counts by stage</p>
</li>
</ul>
<h2>Add Win/Loss Sparklines</h2>
<p>A win/loss sparkline is useful when the data represents positive and negative outcomes.</p>
<p>Set the sparkline type as follows:</p>
<pre><code class="language-python">sparkline_group.SparklineType = SparklineType.Stacked
</code></pre>
<p>For example, the following values may represent the difference between actual results and monthly targets:</p>
<pre><code class="language-python">performance_data = [
    12, -5, 8, 15, -3, -10,
    6, 9, -4, 11, 7, -2
]
</code></pre>
<p>In a win/loss sparkline, positive and negative values are shown in opposite directions. The chart emphasizes whether a result is above or below zero rather than the exact difference between values.</p>
<p>Typical use cases include:</p>
<ul>
<li><p>Monthly profit and loss</p>
</li>
<li><p>Results above or below a target</p>
</li>
<li><p>Month-over-month growth and decline</p>
</li>
<li><p>Win and loss records</p>
</li>
</ul>
<h2>Add Sparklines to an Existing Excel Workbook</h2>
<p>When the source data already exists in an Excel file, there is no need to recreate the worksheet. Load the workbook, locate the data range, and add the sparklines directly.</p>
<pre><code class="language-python">from spire.xls import *
from spire.xls.common import *

workbook = Workbook()

# Load an existing Excel workbook
workbook.LoadFromFile("monthly_sales.xlsx")

# Get the first worksheet
sheet = workbook.Worksheets[0]

# Create a line sparkline group
sparkline_group = sheet.SparklineGroups.AddGroup()
sparkline_group.SparklineType = SparklineType.Line
sparkline_group.SparklineColor = Color.get_DarkBlue()

# Create a sparkline collection
sparklines = sparkline_group.Add()

# Add sparklines
for row in range(2, 6):
    sparklines.Add(
        sheet.Range[f"B{row}:M{row}"],
        sheet.Range[f"N{row}"]
    )

# Save the result as a new file
workbook.SaveToFile(
    "monthly_sales_with_sparklines.xlsx",
    ExcelVersion.Version2016
)

workbook.Dispose()
</code></pre>
<p>Saving the result as a new file is generally safer than overwriting the original workbook.</p>
<h2>Practical Considerations</h2>
<h3>Match Each Data Range to the Correct Destination Cell</h3>
<p>Every sparkline uses two ranges:</p>
<ul>
<li><p>A source data range, such as <code>B2:M2</code></p>
</li>
<li><p>A destination cell, such as <code>N2</code></p>
</li>
</ul>
<p>If the row references do not match, the sparkline may display data for a different product or record.</p>
<h3>Sparklines in the Same Group Share Their Type and Formatting</h3>
<p>All sparklines in one group generally use the same chart type and formatting.</p>
<p>If one section requires line sparklines and another section requires column sparklines, create separate sparkline groups.</p>
<h3>Win/Loss Sparklines Focus on Positive and Negative Results</h3>
<p>Win/loss sparklines do not emphasize the exact size of each value. They are designed to show whether values are positive or negative.</p>
<p>Use line or column sparklines when the magnitude and progression of the data matter.</p>
<h3>Sparklines Do Not Replace Full Excel Charts</h3>
<p>Sparklines are useful for compact trend visualization, but they usually do not include:</p>
<ul>
<li><p>Axis titles</p>
</li>
<li><p>Data labels</p>
</li>
<li><p>Legends</p>
</li>
<li><p>Detailed scales</p>
</li>
</ul>
<p>A standard Excel chart is more appropriate when a report needs precise values, several data series, or more complex comparisons.</p>
<h2>Conclusion</h2>
<p>Excel sparklines provide a compact way to display trends without taking up large areas of a worksheet.</p>
<p>With Python, you can:</p>
<ul>
<li><p>Create an Excel workbook containing business data</p>
</li>
<li><p>Add sparklines to multiple rows</p>
</li>
<li><p>Create line, column, and win/loss sparklines</p>
</li>
<li><p>Configure sparkline colors</p>
</li>
<li><p>Add a trend column to an existing Excel report</p>
</li>
</ul>
<p>For monthly sales, inventory, cost, and operational data, sparklines make it easier to identify growth, decline, and unusual changes while preserving the original table layout.</p>
]]></content:encoded></item><item><title><![CDATA[How to Fill PDF Form Fields in Java: Text Box, Checkbox, Combo Box & List Box]]></title><description><![CDATA[PDF forms are widely used for registration forms, applications, surveys, contract confirmations, and business approval processes. Unlike ordinary PDF documents, interactive PDF forms contain fields su]]></description><link>https://codingwithfiles.hashnode.dev/how-to-fill-pdf-form-fields-in-java-text-box-checkbox-combo-box-list-box</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-fill-pdf-form-fields-in-java-text-box-checkbox-combo-box-list-box</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 24 Jul 2026 11:51:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/28009e02-91dd-412a-bedd-80f7f1390888.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PDF forms are widely used for registration forms, applications, surveys, contract confirmations, and business approval processes. Unlike ordinary PDF documents, interactive PDF forms contain fields such as text boxes, checkboxes, radio buttons, combo boxes, and list boxes that can be filled programmatically.</p>
<p>When generating large numbers of application forms, importing customer data, or exporting completed forms from a business system, filling each form manually is inefficient. With Java, form fields can be read and populated automatically as part of a backend service, desktop application, or batch-processing workflow.</p>
<p>This article explains how to:</p>
<ul>
<li><p>Read form fields from a PDF</p>
</li>
<li><p>Fill text boxes</p>
</li>
<li><p>Select radio button options</p>
</li>
<li><p>Check or clear checkboxes</p>
</li>
<li><p>Select items in list boxes and combo boxes</p>
</li>
<li><p>Populate fields based on their names</p>
</li>
<li><p>Save the completed PDF document</p>
</li>
</ul>
<blockquote>
<p>This method applies to PDF files that contain interactive form fields. It does not work directly with scanned PDFs, image-based forms, ordinary page content, or forms that have already been flattened.</p>
</blockquote>
<h2>1. Install the Required Java Library</h2>
<p>The Java standard library does not provide built-in APIs for reading and filling PDF forms, so a third-party PDF library is required.</p>
<p>The examples in this article use <strong>Spire.PDF for Java</strong> to access and populate interactive form fields.</p>
<h3>Option 1: Add the JAR File Manually</h3>
<p>Download the library from:</p>
<ul>
<li><a href="https://www.e-iceblue.com/Download/pdf-for-java.html">Download Spire.PDF for Java</a></li>
</ul>
<p>After extracting the downloaded package, add <code>Spire.Pdf.jar</code> to the project build path.</p>
<p>In IntelliJ IDEA, open:</p>
<p><strong>File &gt; Project Structure &gt; Modules &gt; Dependencies</strong></p>
<p>Then add the JAR file.</p>
<p>In Eclipse, right-click the project and select:</p>
<p><strong>Build Path &gt; Configure Build Path &gt; Libraries</strong></p>
<p>Then add the JAR file.</p>
<h3>Option 2: Add the Maven Dependency</h3>
<p>For Maven projects, add the following repository and dependency settings to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.6.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h2>2. Common PDF Form Field Types</h2>
<p>A PDF form may contain several types of interactive controls. The program must first determine the field type before assigning a value.</p>
<table>
<thead>
<tr>
<th>Form field</th>
<th>Corresponding class</th>
<th>Common method</th>
</tr>
</thead>
<tbody><tr>
<td>Text box</td>
<td><code>PdfTextBoxFieldWidget</code></td>
<td><code>setText()</code></td>
</tr>
<tr>
<td>Radio button group</td>
<td><code>PdfRadioButtonListFieldWidget</code></td>
<td><code>setSelectedIndex()</code></td>
</tr>
<tr>
<td>List box</td>
<td><code>PdfListBoxWidgetFieldWidget</code></td>
<td><code>setSelectedIndex()</code></td>
</tr>
<tr>
<td>Checkbox</td>
<td><code>PdfCheckBoxWidgetFieldWidget</code></td>
<td><code>setChecked()</code></td>
</tr>
<tr>
<td>Combo box</td>
<td><code>PdfComboBoxWidgetFieldWidget</code></td>
<td><code>setSelectedIndex()</code></td>
</tr>
</tbody></table>
<p>Radio buttons, list boxes, and combo boxes are usually selected by index.</p>
<p>Indexes start at <code>0</code>:</p>
<ul>
<li><p>Index <code>0</code> selects the first option</p>
</li>
<li><p>Index <code>1</code> selects the second option</p>
</li>
<li><p>Index <code>2</code> selects the third option</p>
</li>
</ul>
<h2>3. Fill All Form Fields in a PDF</h2>
<p>The following example reads every form field in a PDF and assigns a value according to the field type.</p>
<h3>Implementation Steps</h3>
<ol>
<li><p>Create a <code>PdfDocument</code> object.</p>
</li>
<li><p>Load the PDF form with <code>loadFromFile()</code>.</p>
</li>
<li><p>Retrieve the form through <code>getForm()</code>.</p>
</li>
<li><p>Get the form field collection.</p>
</li>
<li><p>Iterate through the fields and determine each field type.</p>
</li>
<li><p>Assign an appropriate value to each field.</p>
</li>
<li><p>Save the completed PDF.</p>
</li>
<li><p>Close the document and release resources.</p>
</li>
</ol>
<h3>Complete Code Example</h3>
<pre><code class="language-java">import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.fields.PdfField;
import com.spire.pdf.widget.PdfCheckBoxWidgetFieldWidget;
import com.spire.pdf.widget.PdfComboBoxWidgetFieldWidget;
import com.spire.pdf.widget.PdfFormFieldWidgetCollection;
import com.spire.pdf.widget.PdfFormWidget;
import com.spire.pdf.widget.PdfListBoxWidgetFieldWidget;
import com.spire.pdf.widget.PdfRadioButtonListFieldWidget;
import com.spire.pdf.widget.PdfTextBoxFieldWidget;

public class FillFormFields {

    public static void main(String[] args) {

        String inputPath = "Forms.pdf";
        String outputPath = "FillFormFields.pdf";

        // Create a PdfDocument object
        PdfDocument document = new PdfDocument();

        try {
            // Load the PDF containing form fields
            document.loadFromFile(inputPath);

            // Retrieve the PDF form
            PdfFormWidget form =
                (PdfFormWidget) document.getForm();

            // Retrieve the form field collection
            PdfFormFieldWidgetCollection fields =
                form.getFieldsWidget();

            // Iterate through and fill all form fields
            for (int i = 0; i &lt; fields.getCount(); i++) {

                PdfField field = fields.get(i);

                // Fill a text box
                if (field instanceof PdfTextBoxFieldWidget) {
                    PdfTextBoxFieldWidget textBox =
                        (PdfTextBoxFieldWidget) field;

                    textBox.setText("Kaila Smith");
                }

                // Select the second radio button option
                else if (
                    field instanceof PdfRadioButtonListFieldWidget
                ) {
                    PdfRadioButtonListFieldWidget radioButton =
                        (PdfRadioButtonListFieldWidget) field;

                    radioButton.setSelectedIndex(1);
                }

                // Select the first item in a list box
                else if (
                    field instanceof PdfListBoxWidgetFieldWidget
                ) {
                    PdfListBoxWidgetFieldWidget listBox =
                        (PdfListBoxWidgetFieldWidget) field;

                    listBox.setSelectedIndex(0);
                }

                // Check specific checkboxes by field name
                else if (
                    field instanceof PdfCheckBoxWidgetFieldWidget
                ) {
                    PdfCheckBoxWidgetFieldWidget checkBox =
                        (PdfCheckBoxWidgetFieldWidget) field;

                    switch (checkBox.getName()) {
                        case "checkbox1":
                        case "checkbox2":
                            checkBox.setChecked(true);
                            break;

                        default:
                            break;
                    }
                }

                // Select the second item in a combo box
                else if (
                    field instanceof PdfComboBoxWidgetFieldWidget
                ) {
                    PdfComboBoxWidgetFieldWidget comboBox =
                        (PdfComboBoxWidgetFieldWidget) field;

                    comboBox.setSelectedIndex(1);
                }
            }

            // Save the completed PDF
            document.saveToFile(
                outputPath,
                FileFormat.PDF
            );

            System.out.println(
                "The PDF form was filled successfully: "
                + outputPath
            );
        } finally {
            // Close the document and release resources
            document.close();
        }
    }
}
</code></pre>
<h2>4. Code Explanation</h2>
<h3>Load the PDF Form</h3>
<pre><code class="language-java">PdfDocument document = new PdfDocument();
document.loadFromFile("Forms.pdf");
</code></pre>
<p><code>PdfDocument</code> represents and processes the PDF file. The <code>loadFromFile()</code> method loads the source document from the specified path.</p>
<h3>Retrieve the PDF Form Object</h3>
<pre><code class="language-java">PdfFormWidget form =
    (PdfFormWidget) document.getForm();
</code></pre>
<p>The <code>getForm()</code> method retrieves the form object contained in the PDF.</p>
<p>The returned object is cast to <code>PdfFormWidget</code> so that the interactive field collection can be accessed.</p>
<h3>Retrieve All Form Fields</h3>
<pre><code class="language-java">PdfFormFieldWidgetCollection fields =
    form.getFieldsWidget();
</code></pre>
<p>The <code>getFieldsWidget()</code> method returns all interactive form fields in the PDF.</p>
<p>Use the following method to retrieve the number of fields:</p>
<pre><code class="language-java">int fieldCount = fields.getCount();
</code></pre>
<p>A field can then be accessed by index:</p>
<pre><code class="language-java">PdfField field = fields.get(i);
</code></pre>
<h3>Determine the Field Type</h3>
<p>Each field is represented as a <code>PdfField</code>, but its actual type may differ. Use <code>instanceof</code> to identify the concrete field type.</p>
<p>For example:</p>
<pre><code class="language-java">if (field instanceof PdfTextBoxFieldWidget) {
    PdfTextBoxFieldWidget textBox =
        (PdfTextBoxFieldWidget) field;

    textBox.setText("Kaila Smith");
}
</code></pre>
<p>After identifying the type, cast the field to the corresponding widget class and call the appropriate setter method.</p>
<h3>Save the Completed PDF</h3>
<pre><code class="language-java">document.saveToFile(
    "FillFormFields.pdf",
    FileFormat.PDF
);
</code></pre>
<p>Save the result to a new file so that the original PDF form remains unchanged.</p>
<h2>5. Fill Different Values Based on Field Names</h2>
<p>The previous example fills every text box with the same value:</p>
<pre><code class="language-java">textBox.setText("Kaila Smith");
</code></pre>
<p>In a real application, different text boxes typically represent different values, such as a name, email address, phone number, or postal address.</p>
<p>In that case, assign values based on the field name.</p>
<h3>Example</h3>
<pre><code class="language-java">if (field instanceof PdfTextBoxFieldWidget) {

    PdfTextBoxFieldWidget textBox =
        (PdfTextBoxFieldWidget) field;

    String fieldName = textBox.getName();

    switch (fieldName) {
        case "name":
            textBox.setText("Kaila Smith");
            break;

        case "email":
            textBox.setText("kaila@example.com");
            break;

        case "phone":
            textBox.setText("13800000000");
            break;

        case "address":
            textBox.setText(
                "No. 100, Example Road"
            );
            break;

        default:
            break;
    }
}
</code></pre>
<p>This is more reliable than filling fields by index.</p>
<p>If the form design changes, the order of the fields may also change. As long as the field names remain the same, name-based matching can still locate the correct fields.</p>
<h2>6. List All PDF Form Field Names and Types</h2>
<p>Before writing the field-filling logic, it is often useful to inspect the form and determine which fields it contains.</p>
<p>The following code prints the name and type of every field:</p>
<pre><code class="language-java">PdfFormWidget form =
    (PdfFormWidget) document.getForm();

PdfFormFieldWidgetCollection fields =
    form.getFieldsWidget();

for (int i = 0; i &lt; fields.getCount(); i++) {

    PdfField field = fields.get(i);

    System.out.println(
        "Field index: " + i
    );

    System.out.println(
        "Field name: " + field.getName()
    );

    System.out.println(
        "Field type: "
        + field.getClass().getSimpleName()
    );

    System.out.println("--------------------");
}
</code></pre>
<p>Example output:</p>
<pre><code class="language-text">Field index: 0
Field name: name
Field type: PdfTextBoxFieldWidget
--------------------
Field index: 1
Field name: gender
Field type: PdfRadioButtonListFieldWidget
--------------------
Field index: 2
Field name: checkbox1
Field type: PdfCheckBoxWidgetFieldWidget
--------------------
</code></pre>
<p>This information can then be used to create accurate field-mapping rules.</p>
<h2>7. Fill Individual PDF Form Field Types</h2>
<h3>Fill a Text Box</h3>
<pre><code class="language-java">PdfTextBoxFieldWidget textBox =
    (PdfTextBoxFieldWidget) field;

textBox.setText("Kaila Smith");
</code></pre>
<p>Text boxes are commonly used for:</p>
<ul>
<li><p>Names</p>
</li>
<li><p>Addresses</p>
</li>
<li><p>Phone numbers</p>
</li>
<li><p>Email addresses</p>
</li>
<li><p>Notes</p>
</li>
<li><p>Application details</p>
</li>
</ul>
<h3>Select a Radio Button</h3>
<pre><code class="language-java">PdfRadioButtonListFieldWidget radioButton =
    (PdfRadioButtonListFieldWidget) field;

radioButton.setSelectedIndex(1);
</code></pre>
<p>A radio button group allows only one option to be selected.</p>
<p>An index of <code>1</code> selects the second option.</p>
<h3>Check or Clear a Checkbox</h3>
<pre><code class="language-java">PdfCheckBoxWidgetFieldWidget checkBox =
    (PdfCheckBoxWidgetFieldWidget) field;

checkBox.setChecked(true);
</code></pre>
<p>To clear the checkbox, pass <code>false</code>:</p>
<pre><code class="language-java">checkBox.setChecked(false);
</code></pre>
<h3>Select an Item in a List Box</h3>
<pre><code class="language-java">PdfListBoxWidgetFieldWidget listBox =
    (PdfListBoxWidgetFieldWidget) field;

listBox.setSelectedIndex(0);
</code></pre>
<p>Index <code>0</code> selects the first item in the list.</p>
<h3>Select an Item in a Combo Box</h3>
<pre><code class="language-java">PdfComboBoxWidgetFieldWidget comboBox =
    (PdfComboBoxWidgetFieldWidget) field;

comboBox.setSelectedIndex(1);
</code></pre>
<p>Index <code>1</code> selects the second item in the combo box.</p>
<h2>8. Practical Considerations</h2>
<h3>Confirm That the PDF Contains Interactive Form Fields</h3>
<p>Not every PDF that looks like a form actually contains interactive fields.</p>
<p>The following files usually cannot be filled directly through form field APIs:</p>
<ul>
<li><p>Scanned PDFs</p>
</li>
<li><p>Image-based application forms</p>
</li>
<li><p>Tables made from ordinary text and lines</p>
</li>
<li><p>Flattened PDF forms</p>
</li>
</ul>
<p>You can check the number of detected fields first:</p>
<pre><code class="language-java">PdfFormWidget form =
    (PdfFormWidget) document.getForm();

PdfFormFieldWidgetCollection fields =
    form.getFieldsWidget();

if (fields.getCount() == 0) {
    System.out.println(
        "No interactive form fields were found in the PDF."
    );
}
</code></pre>
<h3>Do Not Assume That Field Indexes Are Fixed</h3>
<p>The following code depends on field order:</p>
<pre><code class="language-java">PdfField field = fields.get(0);
</code></pre>
<p>If the form is modified, its field order may change.</p>
<p>For production applications, prefer matching fields by name:</p>
<pre><code class="language-java">if ("email".equals(field.getName())) {
    // Fill the email field
}
</code></pre>
<h3>Validate Option Indexes</h3>
<p>Radio buttons, list boxes, and combo boxes are selected by index. An invalid index may cause an exception or fail to select the intended option.</p>
<p>Before setting an index, confirm:</p>
<ul>
<li><p>How many options the field contains</p>
</li>
<li><p>Which index corresponds to the required option</p>
</li>
<li><p>Whether indexing starts at <code>0</code></p>
</li>
</ul>
<h3>Save the Result as a New File</h3>
<p>Avoid overwriting the original template:</p>
<pre><code class="language-java">document.saveToFile(
    "Forms_Filled.pdf",
    FileFormat.PDF
);
</code></pre>
<p>Keeping the original blank form makes it easier to reuse the template.</p>
<h3>Release Resources Properly</h3>
<p>Always close the <code>PdfDocument</code>, regardless of whether the operation succeeds:</p>
<pre><code class="language-java">PdfDocument document =
    new PdfDocument();

try {
    document.loadFromFile("Forms.pdf");

    // Fill and save the form
} finally {
    document.close();
}
</code></pre>
<p>This is especially important when processing many files in a batch.</p>
<h2>9. Frequently Asked Questions</h2>
<h3>Why Does the Program Find No Form Fields?</h3>
<p>Possible reasons include:</p>
<ul>
<li><p>The PDF is a scanned image</p>
</li>
<li><p>The visible input areas are only drawn rectangles</p>
</li>
<li><p>The form has already been flattened</p>
</li>
<li><p>The file uses a special form structure</p>
</li>
<li><p>The PDF does not contain interactive fields</p>
</li>
</ul>
<p>Print <code>fields.getCount()</code> to check how many fields were detected.</p>
<h3>Why Are All Text Boxes Filled with the Same Value?</h3>
<p>The example applies the same instruction to every <code>PdfTextBoxFieldWidget</code>:</p>
<pre><code class="language-java">textBox.setText("Kaila Smith");
</code></pre>
<p>In a real application, assign values according to each field name.</p>
<h3>How Can I Fill Only One Field?</h3>
<p>Check the field name before assigning a value:</p>
<pre><code class="language-java">if (
    field instanceof PdfTextBoxFieldWidget
    &amp;&amp; "name".equals(field.getName())
) {
    PdfTextBoxFieldWidget textBox =
        (PdfTextBoxFieldWidget) field;

    textBox.setText("Kaila Smith");
}
</code></pre>
<h3>Why Is the Wrong Combo Box Item Selected?</h3>
<p><code>setSelectedIndex()</code> uses zero-based indexing.</p>
<p>For example:</p>
<pre><code class="language-java">comboBox.setSelectedIndex(0);
</code></pre>
<p>selects the first item, not the second.</p>
<h3>How Can I Clear a Checkbox?</h3>
<p>Pass <code>false</code> to <code>setChecked()</code>:</p>
<pre><code class="language-java">checkBox.setChecked(false);
</code></pre>
<h3>Can Multiple PDF Forms Be Filled in a Batch?</h3>
<p>Yes. Iterate through the PDF files in a folder, create a separate <code>PdfDocument</code> for each file, fill the fields, and save each result separately.</p>
<p>When processing files in a batch:</p>
<ul>
<li><p>Close each document after processing</p>
</li>
<li><p>Generate a unique output file name</p>
</li>
<li><p>Log files that fail</p>
</li>
<li><p>Avoid overwriting the original templates</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Java can be used to automatically read and populate interactive PDF form fields.</p>
<p>For production use, first inspect the available field names and types, then populate each field by name. This is more reliable than depending on field indexes, especially when the PDF form template may change.</p>
<p>Also confirm that the source PDF contains interactive form fields. Scanned documents, ordinary page content, and flattened forms require a different approach.</p>
]]></content:encoded></item><item><title><![CDATA[How to Convert PDF to PowerPoint (PPTX) in Java]]></title><description><![CDATA[Converting PDF files to PowerPoint presentations is useful for meeting presentations, classroom materials, business reports, and content reuse.
Automating the conversion with Java eliminates the need ]]></description><link>https://codingwithfiles.hashnode.dev/how-to-convert-pdf-to-powerpoint-pptx-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/how-to-convert-pdf-to-powerpoint-pptx-in-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 24 Jul 2026 11:23:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/0f679951-c69f-4589-8c14-f63cc82279bb.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Converting PDF files to PowerPoint presentations is useful for meeting presentations, classroom materials, business reports, and content reuse.</p>
<p>Automating the conversion with Java eliminates the need to copy content page by page and makes it easier to integrate PDF-to-PowerPoint conversion into document management systems, batch-processing programs, or backend services. In most cases, each PDF page is converted into a corresponding PowerPoint slide.</p>
<p>This article covers how to:</p>
<ul>
<li><p>Install the required PDF processing library in a Java project</p>
</li>
<li><p>Convert an entire PDF document to PPTX</p>
</li>
<li><p>Convert selected PDF pages to PowerPoint</p>
</li>
<li><p>Select pages by range, odd-numbered pages, or even-numbered pages</p>
</li>
<li><p>Convert multiple PDF files in a folder</p>
</li>
<li><p>Validate page indexes and release document resources correctly</p>
</li>
</ul>
<p>PDF and PowerPoint use different page and object models. For PDFs containing complex fonts, graphics, transparency effects, or advanced layouts, review the generated slides to confirm that fonts, images, and element positions are displayed as expected.</p>
<h2>1. Install the Required Java Library</h2>
<p>The standard Java library does not provide built-in PDF-to-PowerPoint conversion, so a third-party PDF processing library is required.</p>
<p>The examples in this article use <strong>Spire.PDF for Java</strong> to load PDF files, extract pages, and export documents to PPTX. The library works without Microsoft PowerPoint installed.</p>
<h3>Option 1: Add the JAR File Manually</h3>
<p>Download the required JAR file from the following page:</p>
<ul>
<li><a href="https://www.e-iceblue.com/Download/pdf-for-java.html">Download Spire.PDF for Java</a></li>
</ul>
<p>After downloading and extracting the package, add <code>Spire.Pdf.jar</code> to the project build path.</p>
<p>In IntelliJ IDEA, open:</p>
<p><strong>File &gt; Project Structure &gt; Modules &gt; Dependencies</strong></p>
<p>Then add the JAR file.</p>
<p>In Eclipse, right-click the project and select:</p>
<p><strong>Build Path &gt; Configure Build Path &gt; Libraries</strong></p>
<p>Then add the JAR file.</p>
<h3>Option 2: Add the Maven Dependency</h3>
<p>For Maven projects, add the repository and dependency configuration to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.6.4&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h3>Environment Requirements</h3>
<ul>
<li><p>JDK 1.8 or later</p>
</li>
<li><p>IntelliJ IDEA, Eclipse, or another Java development environment</p>
</li>
</ul>
<h2>2. Convert an Entire PDF to PowerPoint</h2>
<p>To convert a complete PDF document, load the source file with <code>loadFromFile()</code> and save it as PPTX with <code>saveToFile()</code>.</p>
<p>Each page in the PDF is converted into a corresponding PowerPoint slide.</p>
<h3>Implementation Steps</h3>
<ol>
<li><p>Create a <code>PdfDocument</code> object.</p>
</li>
<li><p>Load the source PDF with <code>loadFromFile()</code>.</p>
</li>
<li><p>Call <code>saveToFile()</code>.</p>
</li>
<li><p>Set the target format to <code>FileFormat.PPTX</code>.</p>
</li>
<li><p>Close the document after conversion.</p>
</li>
</ol>
<h3>Complete Code Example</h3>
<pre><code class="language-java">import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;

public class PDFtoPowerPoint {
    public static void main(String[] args) {

        PdfDocument pdfDocument = new PdfDocument();

        try {
            // Load the PDF document
            pdfDocument.loadFromFile("sample.pdf");

            // Save the entire PDF as a PPTX file
            pdfDocument.saveToFile(
                "PDFtoPowerPoint.pptx",
                FileFormat.PPTX
            );

            System.out.println(
                "The PDF was successfully converted to PowerPoint."
            );
        } finally {
            // Close the document and release resources
            pdfDocument.close();
        }
    }
}
</code></pre>
<h3>Code Explanation</h3>
<table>
<thead>
<tr>
<th>Class or method</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>PdfDocument</code></td>
<td>Represents the loaded PDF and provides access to document processing and conversion features</td>
</tr>
<tr>
<td><code>loadFromFile("sample.pdf")</code></td>
<td>Loads the source PDF from the specified path</td>
</tr>
<tr>
<td><code>saveToFile(..., FileFormat.PPTX)</code></td>
<td>Converts the current PDF to PPTX and saves it</td>
</tr>
<tr>
<td><code>FileFormat.PPTX</code></td>
<td>Specifies PowerPoint PPTX as the output format</td>
</tr>
<tr>
<td><code>close()</code></td>
<td>Closes the document and releases associated resources</td>
</tr>
</tbody></table>
<p>After the code runs, each page in <code>sample.pdf</code> becomes a slide in <code>PDFtoPowerPoint.pptx</code>.</p>
<h2>3. Convert Selected PDF Pages to PowerPoint</h2>
<p>In some workflows, only certain pages need to be converted rather than the complete PDF.</p>
<p>One approach is to create a new PDF document, add the required pages to it, and then save the new document as PPTX.</p>
<p>This is useful when you need to:</p>
<ul>
<li><p>Extract key sections from a long PDF</p>
</li>
<li><p>Convert selected report pages</p>
</li>
<li><p>Select pages according to business rules</p>
</li>
<li><p>Rearrange pages before generating the presentation</p>
</li>
</ul>
<h3>Implementation Steps</h3>
<ol>
<li><p>Load the source PDF.</p>
</li>
<li><p>Create a new empty <code>PdfDocument</code>.</p>
</li>
<li><p>Retrieve the required pages by index.</p>
</li>
<li><p>Add the selected pages to the new document.</p>
</li>
<li><p>Save the new document as PPTX.</p>
</li>
<li><p>Close both the source and destination documents.</p>
</li>
</ol>
<blockquote>
<p><strong>Note:</strong> Page indexes start at <code>0</code>. For example, index <code>0</code> refers to page 1, while index <code>2</code> refers to page 3.</p>
</blockquote>
<h3>Complete Code Example</h3>
<pre><code class="language-java">import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;

public class PDFSpecificPagesToPPTX {
    public static void main(String[] args) {

        PdfDocument sourcePdf = new PdfDocument();
        PdfDocument newPdf = new PdfDocument();

        try {
            // Load the source PDF
            sourcePdf.loadFromFile("sample.pdf");

            // Specify the page indexes to extract
            // This example extracts pages 1, 3, and 5
            int[] pagesToExtract = {0, 2, 4};

            for (int pageIndex : pagesToExtract) {
                // Retrieve the selected page
                PdfPageBase page =
                    sourcePdf.getPages().get(pageIndex);

                // Add the page to the new document
                newPdf.getPages().add(page);
            }

            // Convert the selected pages to PPTX
            newPdf.saveToFile(
                "SelectedPagesToPPTX.pptx",
                FileFormat.PPTX
            );

            System.out.println(
                "The selected pages were converted successfully. "
                + pagesToExtract.length
                + " pages were processed."
            );
        } finally {
            sourcePdf.close();
            newPdf.close();
        }
    }
}
</code></pre>
<h3>Key Methods</h3>
<table>
<thead>
<tr>
<th>Method</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>sourcePdf.getPages().get(pageIndex)</code></td>
<td>Retrieves a page from the source PDF by index</td>
</tr>
<tr>
<td><code>newPdf.getPages().add(page)</code></td>
<td>Adds the retrieved page to the new PDF document</td>
</tr>
<tr>
<td><code>newPdf.saveToFile(..., FileFormat.PPTX)</code></td>
<td>Saves the document containing the selected pages as PPTX</td>
</tr>
</tbody></table>
<h2>4. Convert Pages by Range, Odd Numbers, or Even Numbers</h2>
<p>Instead of listing page indexes individually, a loop can be used to select a continuous range, all pages, odd-numbered pages, or even-numbered pages.</p>
<h3>Convert a Continuous Page Range</h3>
<p>The following example converts pages 2 through 5:</p>
<pre><code class="language-java">int startPage = 1;  // Page 2
int endPage = 4;    // Page 5

for (int i = startPage; i &lt;= endPage; i++) {
    PdfPageBase page =
        sourcePdf.getPages().get(i);

    newPdf.getPages().add(page);
}
</code></pre>
<p>In production code, validate the page range first to avoid accessing an index outside the document:</p>
<pre><code class="language-java">int pageCount =
    sourcePdf.getPages().getCount();

if (
    startPage &lt; 0
    || endPage &gt;= pageCount
    || startPage &gt; endPage
) {
    throw new IllegalArgumentException(
        "The specified page range is invalid."
    );
}
</code></pre>
<h3>Convert Odd-Numbered Pages</h3>
<p>Pages 1, 3, and 5 correspond to indexes <code>0</code>, <code>2</code>, and <code>4</code>:</p>
<pre><code class="language-java">for (
    int i = 0;
    i &lt; sourcePdf.getPages().getCount();
    i += 2
) {
    PdfPageBase page =
        sourcePdf.getPages().get(i);

    newPdf.getPages().add(page);
}
</code></pre>
<h3>Convert Even-Numbered Pages</h3>
<p>Pages 2, 4, and 6 correspond to indexes <code>1</code>, <code>3</code>, and <code>5</code>:</p>
<pre><code class="language-java">for (
    int i = 1;
    i &lt; sourcePdf.getPages().getCount();
    i += 2
) {
    PdfPageBase page =
        sourcePdf.getPages().get(i);

    newPdf.getPages().add(page);
}
</code></pre>
<h2>5. Practical Considerations</h2>
<h3>Validate Page Indexes</h3>
<p>Before retrieving selected pages, confirm that every index is within the document page count. Otherwise, the program may stop with an index-out-of-range error.</p>
<pre><code class="language-java">int pageCount =
    sourcePdf.getPages().getCount();

for (int pageIndex : pagesToExtract) {
    if (
        pageIndex &lt; 0
        || pageIndex &gt;= pageCount
    ) {
        throw new IllegalArgumentException(
            "Invalid page index: " + pageIndex
        );
    }
}
</code></pre>
<p>To skip invalid indexes rather than stop the entire conversion, log the issue and continue:</p>
<pre><code class="language-java">for (int pageIndex : pagesToExtract) {
    if (
        pageIndex &lt; 0
        || pageIndex &gt;= pageCount
    ) {
        System.out.println(
            "Skipped invalid page index: "
            + pageIndex
        );
        continue;
    }

    PdfPageBase page =
        sourcePdf.getPages().get(pageIndex);

    newPdf.getPages().add(page);
}
</code></pre>
<h3>Save the Result with a New File Name</h3>
<p>Save the converted presentation under a new file name to avoid overwriting an existing output file.</p>
<pre><code class="language-java">String outputPath =
    "output/PDFtoPowerPoint.pptx";
</code></pre>
<p>Before saving, confirm that the output directory exists:</p>
<pre><code class="language-java">import java.io.File;

File outputDirectory =
    new File("output");

if (!outputDirectory.exists()) {
    outputDirectory.mkdirs();
}
</code></pre>
<h3>Release Document Resources</h3>
<p>For batch-conversion tasks, close each document object after processing to prevent unnecessary memory usage.</p>
<p>A <code>try-finally</code> block ensures that <code>close()</code> is called even if loading or conversion fails.</p>
<pre><code class="language-java">PdfDocument document =
    new PdfDocument();

try {
    document.loadFromFile("sample.pdf");

    document.saveToFile(
        "output.pptx",
        FileFormat.PPTX
    );
} finally {
    document.close();
}
</code></pre>
<h3>Verify the Conversion Result</h3>
<p>PDF and PowerPoint use different document models. After conversion, review the output for:</p>
<ul>
<li><p>Correct font rendering</p>
</li>
<li><p>Complete images and graphics</p>
</li>
<li><p>Expected slide dimensions</p>
</li>
<li><p>Correct positioning of text, tables, and other elements</p>
</li>
<li><p>Accurate reproduction of complex layouts</p>
</li>
<li><p>Correct page order</p>
</li>
</ul>
<p>PDFs containing embedded fonts, transparent objects, complex vector graphics, or special layers may produce different results depending on the source document and runtime environment.</p>
<h3>Convert Multiple PDF Files in a Folder</h3>
<p>To process an entire folder, enumerate the PDF files and create a separate <code>PdfDocument</code> instance for each file.</p>
<pre><code class="language-java">import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;

import java.io.File;

public class BatchPDFtoPowerPoint {
    public static void main(String[] args) {

        File inputFolder =
            new File("C:/InputPDF");

        File outputFolder =
            new File("C:/OutputPPTX");

        if (!inputFolder.exists()) {
            System.out.println(
                "The input folder does not exist."
            );
            return;
        }

        if (!outputFolder.exists()
            &amp;&amp; !outputFolder.mkdirs()) {
            System.out.println(
                "The output folder could not be created."
            );
            return;
        }

        File[] files =
            inputFolder.listFiles(
                (dir, name) -&gt;
                    name.toLowerCase()
                        .endsWith(".pdf")
            );

        if (files == null
            || files.length == 0) {
            System.out.println(
                "No PDF files were found."
            );
            return;
        }

        for (File file : files) {
            PdfDocument document =
                new PdfDocument();

            try {
                document.loadFromFile(
                    file.getAbsolutePath()
                );

                String outputName =
                    file.getName().replaceAll(
                        "(?i)\\.pdf$",
                        ".pptx"
                    );

                File outputFile =
                    new File(
                        outputFolder,
                        outputName
                    );

                document.saveToFile(
                    outputFile.getAbsolutePath(),
                    FileFormat.PPTX
                );

                System.out.println(
                    "Converted: " + file.getName()
                );
            } catch (Exception ex) {
                System.out.println(
                    "Failed to convert "
                    + file.getName()
                    + ": "
                    + ex.getMessage()
                );
            } finally {
                document.close();
            }
        }
    }
}
</code></pre>
<h2>6. Frequently Asked Questions</h2>
<h3>Can the Converted PowerPoint File Be Edited?</h3>
<p>The output is a PPTX file and can be opened in Microsoft PowerPoint or another compatible application.</p>
<p>However, whether each element can be edited like a native PowerPoint object depends on the structure of the source PDF and the conversion result. Some content may be represented as images, text boxes, or grouped objects.</p>
<h3>Why Do Fonts Change After Conversion?</h3>
<p>If the source PDF uses a font that is not installed in the runtime environment or on the computer opening the PPTX file, the system may substitute another font.</p>
<p>Install the required fonts where possible and review the text layout after conversion.</p>
<h3>How Many Slides Are Generated from One PDF Page?</h3>
<p>In most cases, one PDF page is converted into one PowerPoint slide.</p>
<h3>How Can I Convert Only the First Page?</h3>
<p>Retrieve the page at index <code>0</code> and add it to a new PDF document:</p>
<pre><code class="language-java">PdfPageBase page =
    sourcePdf.getPages().get(0);

newPdf.getPages().add(page);
</code></pre>
<p>Then save the new document as PPTX:</p>
<pre><code class="language-java">newPdf.saveToFile(
    "FirstPage.pptx",
    FileFormat.PPTX
);
</code></pre>
<h3>How Can I Check Whether a PDF Contains Any Pages?</h3>
<p>Check the page count after loading the document:</p>
<pre><code class="language-java">int pageCount =
    sourcePdf.getPages().getCount();

if (pageCount == 0) {
    System.out.println(
        "The PDF does not contain any pages to convert."
    );
    return;
}
</code></pre>
<h3>Is Microsoft PowerPoint Required?</h3>
<p>No. The code shown in this article does not depend on Microsoft PowerPoint and can run in an environment where PowerPoint is not installed.</p>
<h2>Conclusion</h2>
<p>Java can be used to automate PDF-to-PowerPoint conversion for both complete documents and selected pages.</p>
<p>For a complete PDF, call <code>saveToFile()</code> and specify <code>FileFormat.PPTX</code>. When only certain pages are required, add those pages to a new document and convert the resulting document instead.</p>
<p>The same API also supports converting PDF documents to Word, Excel, HTML, images, and other formats.</p>
]]></content:encoded></item><item><title><![CDATA[Set Font Color in Word Documents with Java: 3 Ways]]></title><description><![CDATA[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 j]]></description><link>https://codingwithfiles.hashnode.dev/set-font-color-in-word-documents-with-java-3-ways</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/set-font-color-in-word-documents-with-java-3-ways</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 17 Jul 2026 11:55:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/78b25cc9-e320-4abb-84c4-310322922ab1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h2>Setup</h2>
<p>The examples below use Spire.Doc for Java. With Maven, add the dependency to <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.doc&lt;/artifactId&gt;
        &lt;version&gt;13.5.3&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>If you're not on Maven, the jar can also be downloaded directly from the official website and added to the classpath.</p>
<h2>Method 1: Coloring an entire paragraph via a style</h2>
<p>If you want to recolor everything in a paragraph at once, the cleanest way is to define a <code>ParagraphStyle</code> with the color you want and apply it to the paragraph.</p>
<pre><code class="language-java">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);
    }
}
</code></pre>
<p>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: <strong>applying a paragraph style doesn't override formatting that's already set directly on the runs inside it.</strong> 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 — <code>applyStyle()</code> 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.</p>
<h2>Method 2: Coloring runs directly</h2>
<p>A paragraph's text is stored as a sequence of child objects, and the actual text lives in <code>TextRange</code> objects mixed in with other elements like line breaks or inline images. Looping through them and setting the color on each <code>TextRange</code> sidesteps the style-precedence issue entirely, since you're changing the direct formatting itself.</p>
<pre><code class="language-java">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 &lt; 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);
    }
}
</code></pre>
<p>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.</p>
<h2>Method 3: Coloring every occurrence of a specific phrase</h2>
<p>Sometimes the target isn't a paragraph at all — it's a word or phrase that might show up anywhere in the document. <code>findAllString()</code> returns every match as a <code>TextSelection</code>, and each one can be turned into a formattable range.</p>
<pre><code class="language-java">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);
    }
}
</code></pre>
<p>The <code>getAsOneRange()</code> 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 <code>TextRange</code> internally — spell-check state, tracked changes, or just how the original document was authored can split it into several adjacent runs. <code>getAsOneRange()</code> 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.</p>
<h2>A couple of general notes</h2>
<p>Colors are plain <code>java.awt.Color</code> objects, so anything that works there — named constants like <code>Color.red</code>, or explicit RGB via <code>new Color(r, g, b)</code> — works here too. And <code>findAllString()</code> 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".</p>
<p>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.</p>
]]></content:encoded></item><item><title><![CDATA[Delete, Reorder, Rotate, and Crop PDF Pages in Java]]></title><description><![CDATA[Page-level PDF editing — removing extra pages, reordering pages, fixing pages with the wrong orientation, or cropping out unwanted margins — comes up pretty often in day-to-day development. It sounds ]]></description><link>https://codingwithfiles.hashnode.dev/delete-reorder-rotate-and-crop-pdf-pages-in-java</link><guid isPermaLink="true">https://codingwithfiles.hashnode.dev/delete-reorder-rotate-and-crop-pdf-pages-in-java</guid><dc:creator><![CDATA[James Brown]]></dc:creator><pubDate>Fri, 17 Jul 2026 11:32:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/693bf242bb23a7bfd17e7369/1aa67121-dfd3-4508-aeb0-0160c4b33de3.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Page-level PDF editing — removing extra pages, reordering pages, fixing pages with the wrong orientation, or cropping out unwanted margins — comes up pretty often in day-to-day development. It sounds simple, but once you actually write the code, index shifting and coordinate system direction are the kind of details that trip people up. This post walks through the implementation for each of these operations with Java code examples.</p>
<h2>Setup</h2>
<p>The library used here is Spire.PDF for Java. If you're using Maven, add the following to your <code>pom.xml</code>:</p>
<pre><code class="language-xml">&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;com.e-iceblue&lt;/id&gt;
        &lt;name&gt;e-iceblue&lt;/name&gt;
        &lt;url&gt;https://repo.e-iceblue.com/nexus/content/groups/public/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;e-iceblue&lt;/groupId&gt;
        &lt;artifactId&gt;spire.pdf&lt;/artifactId&gt;
        &lt;version&gt;12.7.0&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>If you're not using Maven, you can also download the jar directly from the vendor's site and add it to your project manually.</p>
<p>Once the dependency is in place, pretty much everything page-related revolves around the <code>PdfDocument</code> class and its <code>getPages()</code> collection. Let's go through each operation.</p>
<h2>1. Deleting Pages</h2>
<p>Deleting a page is the most common operation. Use <code>PdfDocument.getPages().removeAt(int index)</code>, passing in the zero-based index of the page you want to remove.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;

public class DeletePage {
    public static void main(String[] args) {
        // Create a PdfDocument instance
        PdfDocument pdf = new PdfDocument();
        // Load the PDF document
        pdf.loadFromFile("sample.pdf");
        // Remove the second page (index is zero-based, so 1 means the second page)
        pdf.getPages().removeAt(1);
        // Save the result
        pdf.saveToFile("output/deletePage.pdf");
        pdf.close();
    }
}
</code></pre>
<p>Page indices start at 0, which is easy to mix up with the "page 1 = first page" convention people usually think in — worth double-checking the index before you run this. The deletion is also irreversible, so back up the original file first.</p>
<p>If you need to delete multiple pages at once, delete from the highest index to the lowest. Say you want to remove pages 2, 4, and 6: if you iterate forward and delete as you go, once page 2 is gone, the old page 4 shifts into page 3's slot, and continuing with the original indices ends up deleting the wrong pages.</p>
<pre><code class="language-java">int[] pagesToDelete = {1, 3, 5}; // corresponds to pages 2, 4, 6
Arrays.sort(pagesToDelete);
for (int i = pagesToDelete.length - 1; i &gt;= 0; i--) {
    pdf.getPages().removeAt(pagesToDelete[i]);
}
</code></pre>
<h2>2. Reordering Pages</h2>
<p>When page order is scrambled, use <code>PdfDocument.getPages().reArrange()</code> to fix it in one shot. It takes an <code>int[]</code> array where each element is the original page index, and the array's order becomes the new page order.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;

public class RearrangePages {
    public static void main(String[] args) {
        // Create a PdfDocument instance
        PdfDocument doc = new PdfDocument();
        // Load the PDF document
        doc.loadFromFile("input.pdf");
        // Reorder pages: original page 1, 3, 2, 4
        doc.getPages().reArrange(new int[]{0, 2, 1, 3});
        // Save the result
        doc.saveToFile("output/rearranged.pdf");
        doc.close();
    }
}
</code></pre>
<h2>3. Rotating Pages</h2>
<p>Scanned PDFs frequently end up with the wrong orientation. Rotation works in 90-degree increments — 0°, 90°, 180°, or 270° — set via <code>PdfPageBase.setRotation()</code>.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.PdfPageRotateAngle;

public class RotatePdfPage {
    public static void main(String[] args) {
        // Create a PdfDocument instance
        PdfDocument pdf = new PdfDocument();
        // Load the PDF document
        pdf.loadFromFile("sample.pdf");
        // Get the first page
        PdfPageBase page = pdf.getPages().get(0);
        // Get the current rotation angle
        int rotation = page.getRotation().getValue();
        // Rotate 180 degrees on top of the existing angle
        rotation += PdfPageRotateAngle.Rotate_Angle_180.getValue();
        page.setRotation(PdfPageRotateAngle.fromValue(rotation));
        // Save the result
        pdf.saveToFile("output/rotated.pdf");
        pdf.close();
    }
}
</code></pre>
<p>Note that this adds to the existing rotation angle rather than overwriting it. Scanned files often already carry a rotation value of their own (PDFs generated from phone photos default to 270 degrees quite often), so if you skip reading the original angle and just assign a new one directly, the displayed result won't match what you expect.</p>
<p>To rotate every page, just loop through the <code>pdf.getPages()</code> collection and apply the same logic to each one:</p>
<pre><code class="language-java">for (int i = 0; i &lt; pdf.getPages().getCount(); i++) {
    PdfPageBase page = pdf.getPages().get(i);
    int rotation = page.getRotation().getValue();
    rotation += PdfPageRotateAngle.Rotate_Angle_90.getValue();
    page.setRotation(PdfPageRotateAngle.fromValue(rotation));
}
</code></pre>
<h2>4. Cropping Pages</h2>
<p>Cropping works by modifying the page's CropBox, which defines the visible area of the page — anything outside it simply won't render. Use <code>PdfPageBase.setCropBox(Rectangle2D rect)</code> to set it.</p>
<pre><code class="language-java">import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import java.awt.geom.Rectangle2D;

public class CropPdfPage {
    public static void main(String[] args) {
        // Create a PdfDocument instance
        PdfDocument pdf = new PdfDocument();
        // Load the PDF document
        pdf.loadFromFile("example.pdf");
        // Get the first page
        PdfPageBase page = pdf.getPages().get(0);
        // Define the crop area: x, y, width, height
        Rectangle2D rect = new Rectangle2D.Float(0, 0, 550, 822);
        // Apply the crop box
        page.setCropBox(rect);
        // Save the result
        pdf.saveToFile("output/cropped.pdf");
        pdf.close();
    }
}
</code></pre>
<p>All four <code>Rectangle2D.Float</code> parameters are in points. There's one gotcha worth calling out on its own: Spire.PDF's coordinate system is not the same as the native PDF spec. The PDF spec places the origin at the bottom-left of the page with the y-axis pointing up. Spire.PDF, to make top-down positioning more intuitive for programmers, remaps that to an origin at the top-left with the y-axis pointing down. <code>setCropBox</code> follows this same remapped system: <code>x</code> and <code>y</code> are the offset of the crop area's top-left corner from the page's top-left corner, and <code>width</code>/<code>height</code> extend right and downward from there.</p>
<p>So to crop out a black margin at the top of the page, you just set <code>y</code> to the margin height directly — no need to work backward from the total page height. For a 20pt margin at the top, that's <code>new Rectangle2D.Float(0, 20, width, height - 20)</code> — starting 20pt down from the top and extending down to the bottom of the page skips right past that margin. Assuming the origin is bottom-left, the way the raw PDF spec defines it, gets the direction backwards — you'll typically end up with either the margin still sitting there or a chunk of your content cut off.</p>
<p>One more thing worth noting: <code>setCropBox</code> only changes the visible region — the original content is still fully intact in the file, just not rendered outside the crop box. That means it's not a real deletion. If you're trying to redact sensitive information from a page, cropping isn't the right tool for that.</p>
<h2>Summary</h2>
<p>This article showed how to remove, reorder, rotate and crop pages in PDF. Use <code>removeAt()</code> for deleting pages, <code>reArrange()</code> for reordering, <code>setRotation()</code> for rotating, and <code>setCropBox()</code> for cropping. A few things worth keeping in mind: delete pages from the end backward when removing multiple at once; rotation angles accumulate rather than get overwritten; and the crop coordinate system is Spire.PDF's own remapped one — origin at the top-left, y-axis pointing down — which is the opposite of what the native PDF spec defines, even though it happens to be what you'd normally expect from a graphics API. Keeping these in mind up front saves a fair bit of debugging time later.</p>
]]></content:encoded></item></channel></rss>