Converting Excel to OFD Format

Introduction

OFD (Open Fixed-layout Document) is a Chinese national standard (GB/T 33190-2016) for representing digital documents in a fixed, page-based layout. It serves a role similar to PDF for use cases where the visual appearance of the source document must be preserved exactly as authored. OFD is widely adopted for government submissions, regulatory filings, electronic invoices, and long-term archival in the People’s Republic of China.

Converting Excel workbooks to OFD is a common requirement in scenarios where spreadsheet content must be distributed as a read-only, layout-locked artifact rather than as an editable spreadsheet. Examples include shipping a finalized invoice to a customer, archiving a quarterly financial report, or submitting a budget spreadsheet to a regulatory authority. Aspose.Cells addresses this requirement through the SaveFormat.Ofd enumeration value, which writes the workbook directly to OFD without requiring an intermediate conversion step. The OFD output preserves cell values, merged ranges, fonts, colors, borders, number formats, and page setup options configured on the workbook.

Creating an Excel Workbook and Saving as OFD

Aspose.Cells allows you to build a workbook programmatically, populate it with data, and then save it directly to OFD format using the SaveFormat.Ofd enumeration. The following example creates an invoice from scratch. It adds a company logo, header information, a bill-to section, line items, and calculated totals, then exports the workbook to an OFD document.

The example constructs an invoice worksheet by inserting a logo image into the top-left area, populating the company name and contact details, adding an “INVOICE” title across merged cells, recording the invoice number and date, listing the bill-to client, building a line items table with description, quantity, unit price, and total columns, and computing the subtotal, tax, and grand total using cell formulas. Formatting such as bold headers, currency format for prices, borders, and column widths is applied using Style and Font objects. Finally, the workbook is saved with the .ofd extension using SaveFormat.Ofd.

from datetime import datetime

data_dir = "C:\\Temp\\"

# Create a new Workbook
workbook = ac.Workbook()

# Obtain the first worksheet
worksheet = workbook.worksheets[0]

# Set column widths
worksheet.cells.set_column_width(0, 5)
worksheet.cells.set_column_width(1, 35)
worksheet.cells.set_column_width(2, 12)
worksheet.cells.set_column_width(3, 15)
worksheet.cells.set_column_width(4, 15)
worksheet.cells.set_column_width(5, 5)

# Insert company logo
worksheet.pictures.add(1, 1, data_dir + "logo.png")

# Company name and contact details
worksheet.cells["B3"].put_value("Acme Corporation")
worksheet.cells["B4"].put_value("123 Business Street")
worksheet.cells["B5"].put_value("City, State 12345")
worksheet.cells["B6"].put_value("Phone: (555) 123-4567")

# INVOICE title - merge cells
worksheet.cells.merge(7, 1, 2, 4)
title_cell = worksheet.cells["B8"]
title_cell.put_value("INVOICE")

title_style = workbook.create_style()
title_style.font.is_bold = True
title_style.font.size = 20
title_style.horizontal_alignment = ac.TextAlignmentType.CENTER
title_cell.set_style(title_style)

# Invoice number and date
worksheet.cells["B11"].put_value("Invoice Number:")
worksheet.cells["C11"].put_value("INV-2024-001")
worksheet.cells["B12"].put_value("Date:")
worksheet.cells["C12"].put_value(datetime.now().strftime("%Y-%m-%d"))

# Bill-to section
worksheet.cells["B14"].put_value("Bill To:")
worksheet.cells["B15"].put_value("Client Name")
worksheet.cells["B16"].put_value("Client Address")
worksheet.cells["B17"].put_value("Client City, State")

# Line items header
header_desc = worksheet.cells["B19"]
header_qty = worksheet.cells["C19"]
header_price = worksheet.cells["D19"]
header_total = worksheet.cells["E19"]

header_desc.put_value("Description")
header_qty.put_value("Quantity")
header_price.put_value("Unit Price")
header_total.put_value("Total")

header_style = workbook.create_style()
header_style.font.is_bold = True
header_style.font.color = drawing.Color.white
header_style.background_color = drawing.Color.navy
header_style.horizontal_alignment = ac.TextAlignmentType.CENTER
header_style.borders[ac.BorderType.TOP_BORDER].line_style = ac.CellBorderType.THIN
header_style.borders[ac.BorderType.BOTTOM_BORDER].line_style = ac.CellBorderType.THIN
header_style.borders[ac.BorderType.LEFT_BORDER].line_style = ac.CellBorderType.THIN
header_style.borders[ac.BorderType.RIGHT_BORDER].line_style = ac.CellBorderType.THIN

header_desc.set_style(header_style)
header_qty.set_style(header_style)
header_price.set_style(header_style)
header_total.set_style(header_style)

# Currency style with borders
currency_style = workbook.create_style()
currency_style.custom = "\"$\"#,##0.00"
currency_style.borders[ac.BorderType.TOP_BORDER].line_style = ac.CellBorderType.THIN
currency_style.borders[ac.BorderType.BOTTOM_BORDER].line_style = ac.CellBorderType.THIN
currency_style.borders[ac.BorderType.LEFT_BORDER].line_style = ac.CellBorderType.THIN
currency_style.borders[ac.BorderType.RIGHT_BORDER].line_style = ac.CellBorderType.THIN

# Plain border style for description/quantity cells
border_style = workbook.create_style()
border_style.borders[ac.BorderType.TOP_BORDER].line_style = ac.CellBorderType.THIN
border_style.borders[ac.BorderType.BOTTOM_BORDER].line_style = ac.CellBorderType.THIN
border_style.borders[ac.BorderType.LEFT_BORDER].line_style = ac.CellBorderType.THIN
border_style.borders[ac.BorderType.RIGHT_BORDER].line_style = ac.CellBorderType.THIN

# Line items rows
line_items = [
    ["Product A - Widget", 2, 50.00],
    ["Product B - Gadget", 3, 75.00],
    ["Product C - Service", 1, 100.00]
]

for i in range(len(line_items)):
    row = 20 + i
    desc_cell = worksheet.cells[row, 1]
    qty_cell = worksheet.cells[row, 2]
    price_cell = worksheet.cells[row, 3]
    total_cell = worksheet.cells[row, 4]

    desc_cell.put_value(line_items[i][0])
    qty_cell.put_value(line_items[i][1])
    price_cell.put_value(line_items[i][2])
    total_cell.formula = "C" + str(row) + "*D" + str(row)

    desc_cell.set_style(border_style)
    qty_cell.set_style(border_style)
    price_cell.set_style(currency_style)
    total_cell.set_style(currency_style)

# Subtotal, tax, grand total
worksheet.cells["B24"].put_value("Subtotal:")
subtotal_cell = worksheet.cells["E24"]
subtotal_cell.formula = "SUM(E20:E22)"

worksheet.cells["B25"].put_value("Tax (10%):")
tax_cell = worksheet.cells["E25"]
tax_cell.formula = "E24*0.1"

worksheet.cells["B26"].put_value("Grand Total:")
grand_total_cell = worksheet.cells["E26"]
grand_total_cell.formula = "E24+E25"

# Bold + currency style for total values
total_style = workbook.create_style()
total_style.font.is_bold = True
total_style.custom = "\"$\"#,##0.00"

subtotal_cell.set_style(total_style)
tax_cell.set_style(total_style)
grand_total_cell.set_style(total_style)

# Bold style for total labels
bold_style = workbook.create_style()
bold_style.font.is_bold = True

worksheet.cells["B24"].set_style(bold_style)
worksheet.cells["B25"].set_style(bold_style)
worksheet.cells["B26"].set_style(bold_style)

# Save the workbook as an OFD file
workbook.save(data_dir + "Invoice.ofd", ac.SaveFormat.Ofd)

Converting an Existing Excel File to OFD

Aspose.Cells can also load an existing Excel workbook from disk and export it directly to OFD format. This is useful for batch conversion pipelines, archival workflows, and scenarios where the source workbook was produced by another tool and only needs to be re-emitted as a fixed-layout artifact. The following example loads an existing .xlsx workbook, reads data from its cells, applies optional page setup adjustments, and saves the result as an OFD document.

from datetime import datetime

dataDir = "C:\\Examples\\"

# Open an existing Excel workbook from disk
workbook = ac.Workbook(dataDir + "SampleBook.xlsx")

# (1) Read and display values from selected cells to confirm the file was loaded
firstSheet = workbook.worksheets[0]
print("First sheet name: " + firstSheet.name)
print("Cell A1: " + firstSheet.cells["A1"].string_value)
print("Cell B1: " + firstSheet.cells["B1"].string_value)
print("Cell C1: " + firstSheet.cells["C1"].string_value)

# (2) Iterate over the Worksheets collection to enumerate available sheets
print("\nAvailable worksheets:")
for i in range(workbook.worksheets.count):
    ws = workbook.worksheets[i]
    print("  [" + str(i) + "] " + ws.name)

# (3) Optionally update a timestamp cell to reflect the conversion
firstSheet.cells["A1"].put_value("Converted on: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

# Append a summary header row at the top of the data block
firstSheet.cells.insert_row(0)
firstSheet.cells["A1"].put_value("Conversion Summary")
firstSheet.cells["A2"].put_value("Generated: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

# (4) Configure PageSetup properties on the worksheet
pageSetup = firstSheet.page_setup
pageSetup.orientation = ac.PageOrientationType.LANDSCAPE
pageSetup.paper_size = ac.PaperSizeType.PAPER_A4
pageSetup.fit_to_pages_tall = 1
pageSetup.fit_to_pages_wide = 1

# (5) Optionally set the print area for the OFD output
lastRow = firstSheet.cells.max_data_row
lastCol = firstSheet.cells.max_data_column
lastColLetter = ac.CellsHelper.column_index_to_name(lastCol)
printArea = "A1:" + lastColLetter + str(lastRow + 1)
firstSheet.page_setup.print_area = printArea
print("\nPrint area set to: " + printArea)

# (6) Save the workbook as an OFD file
workbook.save(dataDir + "SampleBook.ofd", ac.SaveFormat.Ofd)
print("\nFile successfully converted to OFD format: " + dataDir + "SampleBook.ofd")
  • Splitting Excel Files into Multiple Files
  • Inserting an Image into a Cell
  • Reading and Writing DBF Files
  • Convert Sparkline to Image and HTML in Aspose.Cells for Python via .NET