Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

All notable changes for each version of this project will be documented in this file.

# 21.1.0

## New Features

### PDF Exporter
- **Custom Font Support for CJK and Arabic Scripts**: Added pre-configured font constants for easy PDF export with non-Latin character support:
- `NOTO_SANS_FONT` - Supports Latin, Cyrillic, and Greek characters
- `NOTO_SANS_CJK_FONT` - Supports Chinese, Japanese, and Korean characters (CJK)
- `NOTO_SANS_ARABIC_FONT` - Supports Arabic script and related languages

These fonts can be imported from `igniteui-angular/grids/core` and used with `IgxPdfExporterOptions.customFont`:

```typescript
import { NOTO_SANS_CJK_FONT } from 'igniteui-angular/grids/core';

const options = new IgxPdfExporterOptions('Export');
options.customFont = NOTO_SANS_CJK_FONT;

## 21.0.0

### New Features
Expand Down
1 change: 1 addition & 0 deletions projects/igniteui-angular/grids/core/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export * from './services/excel/excel-exporter';
export * from './services/excel/excel-exporter-options';
export * from './services/pdf/pdf-exporter';
export * from './services/pdf/pdf-exporter-options';
export * from './services/pdf/fonts/noto-fonts';

/*

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { NOTO_SANS_BASE64, NOTO_SANS_BOLD_BASE64 } from './noto-sans';
import { NOTO_SANS_ARABIC_BASE64, NOTO_SANS_ARABIC_BOLD_BASE64 } from './noto-sans-arabic';
import { NOTO_SANS_CJK_BASE64, NOTO_SANS_CJK_BOLD_BASE64 } from './noto-sans-cjk';

/**
* Pre-configured Noto Sans font for PDF exports
* Supports Latin, Cyrillic, Greek, and extended Latin characters
*
* @example
* ```typescript
* import { NOTO_SANS_FONT } from 'igniteui-angular/pdf-fonts';
*
* const options = new IgxPdfExporterOptions('Export');
* options.customFont = NOTO_SANS_FONT;
* ```
*
* @publicApi
*/
export const NOTO_SANS_FONT = {
data: NOTO_SANS_BASE64,
name: 'NotoSans',
bold: {
data: NOTO_SANS_BOLD_BASE64,
name: 'NotoSans-Bold'
}
};

/**
* Pre-configured Noto Sans CJK font for PDF exports
*
* @publicApi
*/
export const NOTO_SANS_CJK_FONT = {
data: NOTO_SANS_CJK_BASE64,
name: 'NotoSansCJK',
bold: {
data: NOTO_SANS_CJK_BOLD_BASE64,
name: 'NotoSansCJK-Bold'
}
};

/**
* Pre-configured Noto Sans Arabic font for PDF exports
*
* @publicApi
*/
export const NOTO_SANS_ARABIC_FONT = {
data: NOTO_SANS_ARABIC_BASE64,
name: 'NotoSansArabic',
bold: {
data: NOTO_SANS_ARABIC_BOLD_BASE64,
name: 'NotoSansCJK-Bold'
}
};

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fontData from './noto-sans-arabic.json'
/**
* Base64-encoded Noto Sans Arabic font data (Regular weight).
*
* This font provides comprehensive support for Arabic script and related languages,
* including Arabic, Persian/Farsi, Urdu, Pashto, and Kurdish (Sorani).
*
* @remarks
* This constant is used with `IgxPdfExporterOptions.customFont` to enable
* Arabic and related right-to-left (RTL) scripts in exported PDF documents.
*
* The font uses the SIL Open Font License 1.1.
* Source: https://fonts.google.com/noto/specimen/Noto+Sans+Arabic
*
* @example
* ```typescript
* const options = new IgxPdfExporterOptions('MyExport');
* options.customFont = {
* name: 'Noto Sans Arabic',
* data: NOTO_SANS_ARABIC_BASE64,
* bold: { data: NOTO_SANS_ARABIC_BOLD_BASE64 }
* };
* ```
*/
export const NOTO_SANS_ARABIC_BASE64 = fontData.normal;

/**
* Base64-encoded Noto Sans Arabic Bold font data.
*
* This is the bold variant of the Noto Sans Arabic font, used for headers and emphasized text
* in PDF exports with Arabic script support.
*
* @remarks
* Pair this with `NOTO_SANS_ARABIC_BASE64` in the `IgxPdfExporterOptions.customFont.bold` property
* to ensure consistent rendering of both regular and bold Arabic text.
*
* @see NOTO_SANS_ARABIC_BASE64
*/
export const NOTO_SANS_ARABIC_BOLD_BASE64 = fontData.bold;

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import fontData from './noto-sans-cjk.json';

/**
* Base64-encoded Noto Sans CJK font data (Regular weight).
*
* This font provides comprehensive support for CJK (Chinese, Japanese, Korean) characters,
* including Hiragana, Katakana, Kanji, Hangul, and CJK Unified Ideographs, as well as
* Latin, Cyrillic, and Greek scripts.
*
* @remarks
* This is a large font file (~15-25MB when Base64-encoded). Consider loading it
* asynchronously or on-demand to avoid impacting initial application load time.
*
* The font uses the SIL Open Font License 1.1.
* Source: https://fonts.google.com/noto/specimen/Noto+Sans+JP
*
* This constant is used with `IgxPdfExporterOptions.customFont` to enable
* CJK characters in exported PDF documents.
*
* @example
* ```typescript
* const options = new IgxPdfExporterOptions('MyExport');
* options.customFont = {
* name: 'Noto Sans CJK',
* data: NOTO_SANS_CJK_BASE64,
* bold: { data: NOTO_SANS_CJK_BOLD_BASE64 }
* };
* ```
*/
export const NOTO_SANS_CJK_BASE64 = (fontData as any).normal;

/**
* Base64-encoded Noto Sans CJK Bold font data.
*
* This is the bold variant of the Noto Sans CJK font, used for headers and emphasized text
* in PDF exports with CJK character support.
*
* @remarks
* Pair this with `NOTO_SANS_CJK_BASE64` in the `IgxPdfExporterOptions.customFont.bold` property
* to ensure consistent rendering of both regular and bold CJK text.
*
* Like the regular weight, this is a large font file that may impact bundle size.
*
* @see NOTO_SANS_CJK_BASE64
*/
export const NOTO_SANS_CJK_BOLD_BASE64 = (fontData as any).bold;

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import fontData from './noto-sans.json';

/**
* Base64-encoded Noto Sans font data (Regular weight).
*
* This font provides extended Latin, Cyrillic, and Greek character support.
* For CJK (Chinese, Japanese, Korean) character support, use a CJK-specific font
* such as Noto Sans CJK or Arial Unicode MS.
*
* @remarks
* This constant is used with `IgxPdfExporterOptions.customFont` to enable
* non-Latin characters in exported PDF documents.
*
* @example
* ```typescript
* const options = new IgxPdfExporterOptions('MyExport');
* options.customFont = {
* name: 'Noto Sans',
* data: NOTO_SANS_BASE64,
* bold: { data: NOTO_SANS_BOLD_BASE64 }
* };
* ```
*/
export const NOTO_SANS_BASE64 = fontData.normal;

/**
* Base64-encoded Noto Sans Bold font data.
*
* This is the bold variant of the Noto Sans font, used for headers and emphasized text
* in PDF exports.
*
* @remarks
* Pair this with `NOTO_SANS_BASE64` in the `IgxPdfExporterOptions.customFont.bold` property
* to ensure consistent rendering of both regular and bold text.
*
* @see NOTO_SANS_BASE64
*/
export const NOTO_SANS_BOLD_BASE64 = fontData.bold;
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,41 @@ export class IgxPdfExporterOptions extends IgxExporterOptionsBase {
*/
public fontSize = 10;

/**
* Custom font data for Unicode support (optional).
* If not provided, uses Helvetica (Latin characters only).
*
* @example
* ```typescript
* import { NOTO_SANS_FONT } from './fonts';
*
* const options = new IgxPdfExporterOptions('Export');
* options.customFont = {
* data: NOTO_SANS_FONT,
* name: 'NotoSans'
* };
* ```
*/
public customFont?: PdfUnicodeFont;

constructor(fileName: string) {
super(fileName, '.pdf');
}
}

/**
* Font configuration for PDF export
*/
export interface PdfUnicodeFont {
/** Base64-encoded font data */
data: string;
/** Font family name */
name: string;
/** Bold variant of the font (optional) */
bold?: {
/** Base64-encoded bold font data */
data: string;
/** Font family name (usually same as normal) */
name: string;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export class IgxPdfExporterService extends IgxBaseExporter {
*/
public override exportEnded = new EventEmitter<IPdfExportEndedEventArgs>();

private _currentFontName = 'helvetica';
private _hasBoldFont = true;

protected exportDataImplementation(data: IExportRecord[], options: IgxPdfExporterOptions, done: () => void): void {
const firstDataElement = data[0];
const isHierarchicalGrid = firstDataElement?.type === ExportRecordType.HierarchicalGridRecord;
Expand Down Expand Up @@ -222,6 +225,32 @@ export class IgxPdfExporterService extends IgxBaseExporter {
format: options.pageSize
});

// Reset font name to default
this._currentFontName = 'helvetica';

// Add custom Unicode font if provided
if (options.customFont) {
this._hasBoldFont = !!options.customFont.bold;
try {
pdf.addFileToVFS(`${options.customFont.name}.ttf`, options.customFont.data);
pdf.addFont(`${options.customFont.name}.ttf`, options.customFont.name, 'normal', 'Identity-H');

if (this._hasBoldFont) {
pdf.addFileToVFS(`${options.customFont.name}-Bold.ttf`, options.customFont.bold.data);
pdf.addFont(
`${options.customFont.name}-Bold.ttf`,
options.customFont.name,
'bold',
'Identity-H'
);
}
this._currentFontName = options.customFont.name;
} catch (error) {
console.warn('Failed to load custom font, falling back to Helvetica:', error);
this._currentFontName = 'helvetica';
}
}

const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const margin = 40;
Expand Down Expand Up @@ -268,7 +297,7 @@ export class IgxPdfExporterService extends IgxBaseExporter {
}

// Draw data rows
pdf.setFont('helvetica', 'normal');
pdf.setFont(this._currentFontName, 'normal');

// Check if this is a tree grid export (tree grids can have both TreeGridRecord and DataRecord types for nested children)
const isTreeGridExport = data.some(record => record.type === ExportRecordType.TreeGridRecord);
Expand Down Expand Up @@ -423,7 +452,7 @@ export class IgxPdfExporterService extends IgxBaseExporter {
allColumns?: any[]
): number {
let yPosition = yStart;
pdf.setFont('helvetica', 'bold');
pdf.setFont(this._currentFontName, this._hasBoldFont ? 'bold' : 'normal');

// First, draw row dimension header labels (for pivot grids) if present
// Draw headers if we have any row dimension headers, regardless of maxRowLevel
Expand Down Expand Up @@ -633,7 +662,7 @@ export class IgxPdfExporterService extends IgxBaseExporter {
yPosition = yStart + totalHeaderHeight;
}

pdf.setFont('helvetica', 'normal');
pdf.setFont(this._currentFontName, 'normal');
return yPosition;
}

Expand Down Expand Up @@ -842,7 +871,7 @@ export class IgxPdfExporterService extends IgxBaseExporter {
tableWidth: number,
options: IgxPdfExporterOptions
): void {
pdf.setFont('helvetica', 'bold');
pdf.setFont(this._currentFontName, this._hasBoldFont ? 'bold' : 'normal');
pdf.setFillColor(240, 240, 240);

if (options.showTableBorders) {
Expand Down Expand Up @@ -908,7 +937,7 @@ export class IgxPdfExporterService extends IgxBaseExporter {
pdf.text(headerText, textX, textY);
});

pdf.setFont('helvetica', 'normal');
pdf.setFont(this._currentFontName, 'normal');
}

private drawDataRow(
Expand Down
4 changes: 2 additions & 2 deletions src/app/grid-export/grid-export.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h4 class="sample-title">Grid Export</h4>
<igx-paginator></igx-paginator>
<igx-column #col field="ProductID" header="Product ID" [headerClasses]="'prodId'">
</igx-column>
<igx-column #col field="ProductName" header="Product Name" [headerClasses]="'prodId'" [hasSummary]="col.hasSummary">
<igx-column #col field="ProductName" header="フィルター" [headerClasses]="'prodId'" [hasSummary]="col.hasSummary">
<ng-template igxCell let-cell="cell" let-val>
{{val}}
</ng-template>
Expand All @@ -17,7 +17,7 @@ <h4 class="sample-title">Grid Export</h4>
<igx-icon class="header-icon" style.color="{{ col.hasSummary ? '#e41c77' : '' }}" (click)="toggleSummary(col)">functions</igx-icon>
</ng-template>
</igx-column>
<igx-column #col field="UnitPrice" header="Price" [filterable]="false" [editable]="true" dataType="currency"
<igx-column #col field="UnitPrice" header="Цена" [filterable]="false" [editable]="true" dataType="currency"
[hasSummary]="true">
<ng-template igxHeader let-col>
<div class="header-text">{{col.field}}</div>
Expand Down
8 changes: 6 additions & 2 deletions src/app/grid-export/grid-export.sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { DatePipe } from '@angular/common';
import { HGRID_DATA } from './hGridData';
import { GRID_DATA } from './gridData';
import { TGRID_DATA } from './tGridData';
import { ColumnType, IGridToolbarExportEventArgs, IgxCellHeaderTemplateDirective, IgxCellTemplateDirective, IgxColumnComponent, IgxGridComponent, IgxGridToolbarComponent, IgxGridToolbarExporterComponent, IgxHierarchicalGridComponent, IgxIconComponent, IgxNumberSummaryOperand, IgxPaginatorComponent, IgxRowIslandComponent, IgxSummaryResult, IgxTreeGridComponent } from 'igniteui-angular';
import { ColumnType, IGridToolbarExportEventArgs, IgxCellHeaderTemplateDirective, IgxCellTemplateDirective, IgxColumnComponent, IgxGridComponent, IgxGridToolbarComponent, IgxGridToolbarExporterComponent, IgxHierarchicalGridComponent, IgxIconComponent, IgxNumberSummaryOperand, IgxPaginatorComponent, IgxPdfExporterOptions, IgxRowIslandComponent, IgxSummaryResult, IgxTreeGridComponent } from 'igniteui-angular';
import { NOTO_SANS_CJK_FONT } from 'igniteui-angular/grids/core';

class GridSummary {
public operate(data?: any[]): IgxSummaryResult[] {
Expand Down Expand Up @@ -88,8 +89,11 @@ export class GridExportComponent {

public configureExport(args: IGridToolbarExportEventArgs) {
console.log(args);
// const options: IgxExporterOptionsBase = args.options;
const options: IgxPdfExporterOptions = args.options as IgxPdfExporterOptions;

// options.fileName = `Report_${new Date().toDateString()}`;
// Set the Japanese font explicitly
options.customFont = NOTO_SANS_CJK_FONT;
// // Change exporter options

// options.fileName = `Report_${new Date().toDateString()}`;
Expand Down
Loading
Loading