Buffer Management
The PNG library uses efficient buffer management techniques for handling image data. This guide covers advanced buffer operations and best practices.
Buffer Structure
PNG images are stored in a buffer with the following characteristics:
- Each pixel takes 4 bytes (RGBA format)
- Data is stored in a linear buffer
- Buffer size = width height 4 bytes
typescript
import { PNG } from 'pngx'
const png = new PNG({
width: 100,
height: 100
})
// Buffer size = 100 * 100 * 4 = 40000 bytes
console.log(png.data.length) // 40000
Pixel Access
Direct Buffer Access
typescript
// Get pixel at (x, y)
function getPixel(x: number, y: number): [number, number, number, number] {
const idx = (y * png.width + x) * 4
return [
png.data[idx], // Red
png.data[idx + 1], // Green
png.data[idx + 2], // Blue
png.data[idx + 3] // Alpha
]
}
// Set pixel at (x, y)
function setPixel(x: number, y: number, r: number, g: number, b: number, a: number): void {
const idx = (y * png.width + x) * 4
png.data[idx] = r
png.data[idx + 1] = g
png.data[idx + 2] = b
png.data[idx + 3] = a
}
Bit Depth Handling
The library supports various bit depths (1, 2, 4, 8, 16 bits per channel):
typescript
// Example: Working with 16-bit depth
const png = new PNG({
width: 100,
height: 100,
depth: 16 // 16 bits per channel
})
// Access 16-bit values
function getPixel16Bit(x: number, y: number): [number, number, number, number] {
const idx = (y * png.width + x) * 8 // 8 bytes per pixel (4 channels * 2 bytes)
return [
png.data.readUInt16BE(idx), // Red
png.data.readUInt16BE(idx + 2), // Green
png.data.readUInt16BE(idx + 4), // Blue
png.data.readUInt16BE(idx + 6) // Alpha
]
}
Buffer Operations
Copying Regions
typescript
// Copy a region using BitBlt
png.bitblt(
destinationImage,
srcX,
srcY,
width,
height,
deltaX,
deltaY
)
Buffer Allocation
typescript
// Create a new buffer with specific size
const buffer = Buffer.alloc(width * height * 4)
// Create a buffer from existing data
const buffer = Buffer.from(existingData)
Performance Considerations
- Buffer Reuse: Reuse buffers when possible to reduce memory allocation
- Direct Access: Use direct buffer access for better performance
- TypedArrays: Consider using TypedArrays for better performance with large images
- Memory Alignment: Keep memory alignment in mind for optimal performance
Best Practices
- Bounds Checking: Always check buffer bounds before access
- Memory Management: Free buffers when no longer needed
- Error Handling: Handle buffer-related errors appropriately
- Type Safety: Use TypeScript types for buffer operations
Example: Efficient Buffer Processing
typescript
import { PNG } from 'pngx'
function processImageEfficiently(png: PNG): void {
// Get the buffer
const buffer = png.data
// Process in chunks for better performance
const chunkSize = 1024 * 4 // Process 1024 pixels at a time
for (let i = 0; i < buffer.length; i += chunkSize) {
const chunk = buffer.slice(i, i + chunkSize)
// Process chunk
for (let j = 0; j < chunk.length; j += 4) {
// Example: Convert to grayscale
const gray = (chunk[j] + chunk[j + 1] + chunk[j + 2]) / 3
chunk[j] = gray // Red
chunk[j + 1] = gray // Green
chunk[j + 2] = gray // Blue
// Alpha remains unchanged
}
}
}
Next Steps
- Learn about Gamma Correction
- Explore BitBlt Operations
- Check out Performance Tips