TensorFlow backend for TensorFlow.js via Node.js - provides native TensorFlow execution in backend JavaScript applications under the Node.js runtime, accelerated by the TensorFlow C binary under the hood
—
TensorFlow.js Node provides native image processing capabilities that allow you to decode various image formats directly into tensors and encode tensors back to image formats. These operations are optimized for performance using native implementations.
Automatically detects and decodes BMP, GIF, JPEG, and PNG images.
/**
* Decode an image from a buffer into a tensor
* @param contents - Image data as Uint8Array
* @param channels - Number of color channels (0=auto, 1=grayscale, 3=RGB, 4=RGBA)
* @param dtype - Output tensor data type (currently only 'int32' supported)
* @param expandAnimations - If true, return 4D tensor for animated images
* @returns 3D tensor [height, width, channels] or 4D [frames, height, width, channels] for animations
*/
function decodeImage(
contents: Uint8Array,
channels?: number,
dtype?: 'int32',
expandAnimations?: boolean
): Tensor3D | Tensor4D;Usage Example:
import * as tf from '@tensorflow/tfjs-node';
import * as fs from 'fs';
// Read image file
const imageBuffer = fs.readFileSync('path/to/image.jpg');
const imageArray = new Uint8Array(imageBuffer);
// Decode to tensor
const imageTensor = tf.node.decodeImage(imageArray, 3); // RGB channels
console.log('Image shape:', imageTensor.shape); // [height, width, 3]
// Process the tensor
const normalizedImage = imageTensor.div(255.0); // Normalize to [0,1]Decode JPEG images with advanced options for quality and performance tuning.
/**
* Decode JPEG image with advanced options
* @param contents - JPEG image data as Uint8Array
* @param channels - Number of color channels (0=auto, 1=grayscale, 3=RGB)
* @param ratio - Downscaling ratio for performance (1=full resolution)
* @param fancyUpscaling - Use slower but higher quality chroma upscaling
* @param tryRecoverTruncated - Attempt to recover truncated images
* @param acceptableFraction - Minimum fraction of lines required for truncated recovery
* @param dctMethod - DCT decompression method ("INTEGER_FAST" or "INTEGER_ACCURATE")
* @returns 3D tensor [height, width, channels]
*/
function decodeJpeg(
contents: Uint8Array,
channels?: number,
ratio?: number,
fancyUpscaling?: boolean,
tryRecoverTruncated?: boolean,
acceptableFraction?: number,
dctMethod?: string
): Tensor3D;Usage Example:
// High-quality JPEG decoding
const jpegTensor = tf.node.decodeJpeg(
imageArray,
3, // RGB channels
1, // Full resolution
true, // High-quality upscaling
false, // Don't recover truncated
1.0, // Require 100% of lines
"INTEGER_ACCURATE" // High-quality DCT
);
// Fast JPEG decoding for thumbnails
const thumbnailTensor = tf.node.decodeJpeg(
imageArray,
3, // RGB channels
4, // 1/4 resolution (4x downscale)
false, // Fast upscaling
false, // Don't recover truncated
1.0, // Require 100% of lines
"INTEGER_FAST" // Fast DCT
);Decode PNG images with support for various bit depths and transparency.
/**
* Decode PNG image
* @param contents - PNG image data as Uint8Array
* @param channels - Number of color channels (0=auto, 1=grayscale, 3=RGB, 4=RGBA)
* @param dtype - Output tensor data type
* @returns 3D tensor [height, width, channels]
*/
function decodePng(
contents: Uint8Array,
channels?: number,
dtype?: 'int32' | 'uint8' | 'float32'
): Tensor3D;Decode Windows Bitmap (BMP) images.
/**
* Decode BMP image
* @param contents - BMP image data as Uint8Array
* @param channels - Number of color channels (0=auto, 1=grayscale, 3=RGB)
* @returns 3D tensor [height, width, channels]
*/
function decodeBmp(
contents: Uint8Array,
channels?: number
): Tensor3D;Decode GIF images, including animated GIFs.
/**
* Decode GIF image (supports animation)
* @param contents - GIF image data as Uint8Array
* @returns 4D tensor [frames, height, width, channels] for animated GIFs
*/
function decodeGif(contents: Uint8Array): Tensor4D;Usage Example with Animated GIF:
const gifBuffer = fs.readFileSync('animated.gif');
const gifArray = new Uint8Array(gifBuffer);
// Decode animated GIF
const gifTensor = tf.node.decodeGif(gifArray);
console.log('GIF shape:', gifTensor.shape); // [frames, height, width, channels]
// Process each frame
const frameCount = gifTensor.shape[0];
for (let i = 0; i < frameCount; i++) {
const frame = gifTensor.slice([i, 0, 0, 0], [1, -1, -1, -1]).squeeze([0]);
// Process individual frame...
}Encode tensors back to JPEG format with quality and format options.
/**
* Encode tensor as JPEG image
* @param image - Input tensor [height, width, channels]
* @param format - Output format (''=auto, 'grayscale', 'rgb')
* @param quality - JPEG quality 0-100 (default: 95)
* @param progressive - Use progressive JPEG encoding
* @param optimizeSize - Optimize file size over quality
* @param chromaDownsampling - Enable chroma subsampling for smaller files
* @param densityUnit - DPI unit ('in' or 'cm')
* @param xDensity - Horizontal DPI
* @param yDensity - Vertical DPI
* @param xmpMetadata - XMP metadata string
* @returns Promise resolving to JPEG data as Uint8Array
*/
function encodeJpeg(
image: Tensor3D,
format?: '' | 'grayscale' | 'rgb',
quality?: number,
progressive?: boolean,
optimizeSize?: boolean,
chromaDownsampling?: boolean,
densityUnit?: 'in' | 'cm',
xDensity?: number,
yDensity?: number,
xmpMetadata?: string
): Promise<Uint8Array>;Usage Example:
// Create or process an image tensor
const imageTensor = tf.randomUniform([224, 224, 3], 0, 255).cast('int32');
// High-quality JPEG encoding
const highQualityJpeg = await tf.node.encodeJpeg(
imageTensor,
'rgb', // RGB format
95, // High quality
false, // Not progressive
false, // Don't optimize size over quality
false, // No chroma downsampling
'in', // Inches
300, // 300 DPI horizontal
300 // 300 DPI vertical
);
// Save to file
fs.writeFileSync('output-high-quality.jpg', Buffer.from(highQualityJpeg));
// Optimized JPEG for web
const webJpeg = await tf.node.encodeJpeg(
imageTensor,
'rgb', // RGB format
85, // Good quality for web
true, // Progressive loading
true, // Optimize for size
true // Enable chroma downsampling
);
fs.writeFileSync('output-web.jpg', Buffer.from(webJpeg));Encode tensors as PNG images with compression options.
/**
* Encode tensor as PNG image
* @param image - Input tensor [height, width, channels]
* @param compression - Compression level 0-9 (0=none, 9=max, default: 1)
* @returns Promise resolving to PNG data as Uint8Array
*/
function encodePng(
image: Tensor3D,
compression?: number
): Promise<Uint8Array>;Usage Example:
// Create or process an image tensor
const imageTensor = tf.randomUniform([224, 224, 4], 0, 255).cast('int32'); // RGBA
// Fast PNG encoding (low compression)
const fastPng = await tf.node.encodePng(imageTensor, 1);
fs.writeFileSync('output-fast.png', Buffer.from(fastPng));
// Maximum compression PNG
const compressedPng = await tf.node.encodePng(imageTensor, 9);
fs.writeFileSync('output-compressed.png', Buffer.from(compressedPng));Determine the format of image data from file headers.
/**
* Detect image format from file header bytes
* @param content - Image data as Uint8Array (first few bytes sufficient)
* @returns Image format string ('jpeg', 'png', 'gif', 'bmp', or 'unknown')
*/
function getImageType(content: Uint8Array): string;Usage Example:
const imageBuffer = fs.readFileSync('unknown-image.data');
const imageArray = new Uint8Array(imageBuffer);
const imageType = tf.node.getImageType(imageArray);
console.log('Detected format:', imageType);
// Use appropriate decoder based on format
let decodedTensor;
switch (imageType) {
case 'jpeg':
decodedTensor = tf.node.decodeJpeg(imageArray);
break;
case 'png':
decodedTensor = tf.node.decodePng(imageArray);
break;
case 'gif':
decodedTensor = tf.node.decodeGif(imageArray);
break;
case 'bmp':
decodedTensor = tf.node.decodeBmp(imageArray);
break;
default:
throw new Error('Unsupported image format: ' + imageType);
}enum ImageType {
JPEG = 'jpeg',
PNG = 'png',
GIF = 'gif',
BMP = 'BMP'
}
type ImageFormat = '' | 'grayscale' | 'rgb';
type DensityUnit = 'in' | 'cm';import * as tf from '@tensorflow/tfjs-node';
import * as fs from 'fs';
async function preprocessImage(imagePath: string): Promise<Tensor4D> {
// Load image
const imageBuffer = fs.readFileSync(imagePath);
const imageArray = new Uint8Array(imageBuffer);
// Decode image
const imageTensor = tf.node.decodeImage(imageArray, 3); // RGB
// Resize to model input size
const resized = tf.image.resizeBilinear(imageTensor, [224, 224]);
// Normalize to [0,1]
const normalized = resized.div(255.0);
// Add batch dimension
const batched = normalized.expandDims(0);
// Clean up intermediate tensors
imageTensor.dispose();
resized.dispose();
normalized.dispose();
return batched;
}async function augmentAndSave(inputPath: string, outputPath: string) {
const imageBuffer = fs.readFileSync(inputPath);
const imageArray = new Uint8Array(imageBuffer);
// Decode
const original = tf.node.decodeImage(imageArray, 3);
// Apply augmentations
const flipped = tf.image.flipLeftRight(original);
const rotated = tf.image.rot90(original);
const brightened = tf.image.adjustBrightness(original, 0.2);
// Encode and save variations
const flippedJpeg = await tf.node.encodeJpeg(flipped.cast('int32'));
const rotatedJpeg = await tf.node.encodeJpeg(rotated.cast('int32'));
const brightenedJpeg = await tf.node.encodeJpeg(brightened.cast('int32'));
fs.writeFileSync(`${outputPath}/flipped.jpg`, Buffer.from(flippedJpeg));
fs.writeFileSync(`${outputPath}/rotated.jpg`, Buffer.from(rotatedJpeg));
fs.writeFileSync(`${outputPath}/brightened.jpg`, Buffer.from(brightenedJpeg));
// Clean up
original.dispose();
flipped.dispose();
rotated.dispose();
brightened.dispose();
}Install with Tessl CLI
npx tessl i tessl/npm-tensorflow--tfjs-node