Custom Profiles
Create reusable configuration profiles for different use cases and image types.
Profile System
Basic Profile Structure
typescript
interface PNGProfile {
name: string
description: string
options: {
colorType: number
bitDepth: 8 | 16
deflateLevel: number
deflateStrategy: number
filterType: number
deflateChunkSize?: number
}
}Profile Registry
typescript
class ProfileRegistry {
private profiles = new Map<string, PNGProfile>()
register(profile: PNGProfile) {
this.profiles.set(profile.name, profile)
}
get(name: string): PNGProfile | undefined {
return this.profiles.get(name)
}
list(): string[] {
return Array.from(this.profiles.keys())
}
}
const registry = new ProfileRegistry()Built-in Profiles
Web Optimized
typescript
const webProfile: PNGProfile = {
name: 'web',
description: 'Optimized for web delivery with small file sizes',
options: {
colorType: 6,
bitDepth: 8,
deflateLevel: 9,
deflateStrategy: 3,
filterType: -1,
},
}Print Quality
typescript
const printProfile: PNGProfile = {
name: 'print',
description: 'High quality for print production',
options: {
colorType: 6,
bitDepth: 16,
deflateLevel: 9,
deflateStrategy: 0,
filterType: -1,
},
}Thumbnail
typescript
const thumbnailProfile: PNGProfile = {
name: 'thumbnail',
description: 'Fast encoding for preview images',
options: {
colorType: 6,
bitDepth: 8,
deflateLevel: 6,
deflateStrategy: 2,
filterType: 0,
},
}Archive
typescript
const archiveProfile: PNGProfile = {
name: 'archive',
description: 'Maximum quality for long-term storage',
options: {
colorType: 6,
bitDepth: 16,
deflateLevel: 9,
deflateStrategy: 0,
filterType: -1,
},
}Fast Processing
typescript
const fastProfile: PNGProfile = {
name: 'fast',
description: 'Fastest encoding for development',
options: {
colorType: 6,
bitDepth: 8,
deflateLevel: 1,
deflateStrategy: 2,
filterType: 0,
deflateChunkSize: 64 * 1024,
},
}Content-Specific Profiles
Screenshot Profile
typescript
const screenshotProfile: PNGProfile = {
name: 'screenshot',
description: 'Optimized for screenshots and UI captures',
options: {
colorType: 6,
bitDepth: 8,
deflateLevel: 9,
deflateStrategy: 3, // RLE works well for UI
filterType: -1,
},
}Photo Profile
typescript
const photoProfile: PNGProfile = {
name: 'photo',
description: 'Optimized for photographic images',
options: {
colorType: 6,
bitDepth: 8,
deflateLevel: 9,
deflateStrategy: 0,
filterType: 4, // Paeth filter for photos
},
}Icon Profile
typescript
const iconProfile: PNGProfile = {
name: 'icon',
description: 'Optimized for icons and small images',
options: {
colorType: 6, // Keep alpha for icons
bitDepth: 8,
deflateLevel: 9,
deflateStrategy: 3,
filterType: -1,
},
}Chart Profile
typescript
const chartProfile: PNGProfile = {
name: 'chart',
description: 'Optimized for charts and graphs',
options: {
colorType: 2, // RGB without alpha
bitDepth: 8,
deflateLevel: 9,
deflateStrategy: 3,
filterType: 1, // Sub filter for horizontal lines
},
}Profile Manager
Complete Implementation
typescript
import { PNG } from 'pngx'
class PNGProfileManager {
private profiles = new Map<string, PNGProfile>()
constructor() {
// Register default profiles
this.register(webProfile)
this.register(printProfile)
this.register(thumbnailProfile)
this.register(archiveProfile)
this.register(fastProfile)
this.register(screenshotProfile)
this.register(photoProfile)
this.register(iconProfile)
this.register(chartProfile)
}
register(profile: PNGProfile): void {
this.profiles.set(profile.name, profile)
}
get(name: string): PNGProfile {
const profile = this.profiles.get(name)
if (!profile) {
throw new Error(`Profile not found: ${name}`)
}
return profile
}
list(): PNGProfile[] {
return Array.from(this.profiles.values())
}
createPNG(width: number, height: number, profileName: string): PNG {
const profile = this.get(profileName)
return new PNG({
width,
height,
...profile.options,
})
}
encode(
data: Buffer,
width: number,
height: number,
profileName: string
): Buffer {
const png = this.createPNG(width, height, profileName)
data.copy(png.data)
return PNG.sync.write(png)
}
}
export const profiles = new PNGProfileManager()Usage
typescript
// Create PNG with profile
const png = profiles.createPNG(800, 600, 'web')
// Fill data
// ...
// Write
const buffer = PNG.sync.write(png)
// Or encode directly
const encoded = profiles.encode(pixelData, 800, 600, 'thumbnail')Custom Profile Creation
From Base Profile
typescript
function extendProfile(
base: PNGProfile,
overrides: Partial<PNGProfile['options']>,
newName: string,
description?: string
): PNGProfile {
return {
name: newName,
description: description || base.description,
options: {
...base.options,
...overrides,
},
}
}
// Create grayscale version of web profile
const grayscaleWebProfile = extendProfile(
webProfile,
{ colorType: 0 },
'grayscale-web',
'Grayscale images for web'
)Profile Builder
typescript
class ProfileBuilder {
private options: Partial<PNGProfile['options']> = {}
private _name: string = 'custom'
private _description: string = 'Custom profile'
name(name: string): this {
this._name = name
return this
}
description(desc: string): this {
this._description = desc
return this
}
colorType(type: 0 | 2 | 3 | 4 | 6): this {
this.options.colorType = type
return this
}
bitDepth(depth: 8 | 16): this {
this.options.bitDepth = depth
return this
}
compression(level: number, strategy?: number): this {
this.options.deflateLevel = level
if (strategy !== undefined) {
this.options.deflateStrategy = strategy
}
return this
}
filter(type: -1 | 0 | 1 | 2 | 3 | 4): this {
this.options.filterType = type
return this
}
chunkSize(size: number): this {
this.options.deflateChunkSize = size
return this
}
build(): PNGProfile {
return {
name: this._name,
description: this._description,
options: {
colorType: this.options.colorType ?? 6,
bitDepth: this.options.bitDepth ?? 8,
deflateLevel: this.options.deflateLevel ?? 6,
deflateStrategy: this.options.deflateStrategy ?? 0,
filterType: this.options.filterType ?? -1,
deflateChunkSize: this.options.deflateChunkSize,
},
}
}
}
// Usage
const customProfile = new ProfileBuilder()
.name('custom-web')
.description('Custom web-optimized profile')
.colorType(6)
.bitDepth(8)
.compression(9, 3)
.filter(-1)
.build()Profile Selection
Automatic Selection
typescript
function selectProfile(
width: number,
height: number,
hasAlpha: boolean,
purpose: 'web' | 'print' | 'archive'
): string {
const pixels = width * height
// Small images
if (pixels < 10000) {
return 'icon'
}
// Thumbnails
if (pixels < 100000 && purpose === 'web') {
return 'thumbnail'
}
// Based on purpose
switch (purpose) {
case 'print':
return 'print'
case 'archive':
return 'archive'
case 'web':
default:
return 'web'
}
}Content-Based Selection
typescript
function selectProfileByContent(
data: Buffer,
width: number,
height: number
): string {
const analysis = analyzeImage(data, width, height)
if (analysis.isPhoto) {
return 'photo'
}
if (analysis.hasLargeUniformAreas) {
return 'screenshot'
}
if (width <= 128 && height <= 128) {
return 'icon'
}
return 'web'
}
function analyzeImage(data: Buffer, width: number, height: number) {
// Analyze color distribution, patterns, etc.
return {
isPhoto: false,
hasLargeUniformAreas: false,
colorCount: 0,
}
}Profile Benchmarking
typescript
interface BenchmarkResult {
profile: string
size: number
encodeTime: number
compressionRatio: number
}
async function benchmarkProfiles(
data: Buffer,
width: number,
height: number
): Promise<BenchmarkResult[]> {
const results: BenchmarkResult[] = []
const rawSize = width * height * 4
for (const profile of profiles.list()) {
const start = performance.now()
const encoded = profiles.encode(data, width, height, profile.name)
const encodeTime = performance.now() - start
results.push({
profile: profile.name,
size: encoded.length,
encodeTime,
compressionRatio: rawSize / encoded.length,
})
}
return results.sort((a, b) => a.size - b.size)
}Best Practices
- Use Profiles Consistently: Apply same profile for similar content types
- Profile for Purpose: Match profile to final use (web, print, archive)
- Benchmark Your Content: Test profiles on your actual images
- Create Custom Profiles: Build profiles for your specific needs
- Document Profiles: Keep clear descriptions for team use
Next Steps
- Performance - Optimization techniques
- CI/CD Integration - Automated workflows
- Configuration - Detailed settings