
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
hexagon_wasm
Advanced tools
[](https://www.npmjs.com/package/pixel-art-detector) [](https://opensource.org/licenses/MIT)
Automatic detection and restoration of upscaled pixel art images.
This WebAssembly module intelligently detects if an image is upscaled pixel art and restores it to its original resolution, even handling compressed/artifacted images (JPEG, PNG lossy compression).
npm install pixel-art-detector
import init, { process_pixel_art_v2 } from 'pixel-art-detector';
async function detectPixelArt(imageData, width, height) {
// Initialize the WASM module
await init();
// Process the image (RGBA format)
const result = process_pixel_art_v2(imageData, width, height, 256);
if (result.is_pixel_art()) {
console.log('✅ Pixel art detected!');
console.log(`Scale: ${result.get_scale_h()}x${result.get_scale_v()}`);
console.log(`Confidence: ${(result.get_confidence() * 100).toFixed(1)}%`);
console.log(`Resolution: ${result.get_width()}x${result.get_height()}`);
// Get the restored image data
const restoredData = result.get_data();
const restoredWidth = result.get_width();
const restoredHeight = result.get_height();
return {
success: true,
data: restoredData,
width: restoredWidth,
height: restoredHeight,
metrics: {
confidence: result.get_confidence(),
artifactLevel: result.get_artifact_level(),
scaleH: result.get_scale_h(),
scaleV: result.get_scale_v(),
originalColors: result.get_original_colors(),
finalColors: result.get_final_colors()
}
};
} else {
console.log('❌ Not pixel art');
return { success: false };
}
}
import init, { process_pixel_art_v2 } from 'pixel-art-detector';
async function processImageFromFile(file) {
await init();
// Load image
const img = new Image();
img.src = URL.createObjectURL(file);
await new Promise(resolve => img.onload = resolve);
// Get image data
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
// Process with pixel art detector
const result = process_pixel_art_v2(
imageData.data,
img.width,
img.height,
256 // max colors in palette
);
if (result.is_pixel_art()) {
// Create new canvas with restored image
const outputCanvas = document.createElement('canvas');
outputCanvas.width = result.get_width();
outputCanvas.height = result.get_height();
const outputCtx = outputCanvas.getContext('2d');
const restoredImageData = new ImageData(
new Uint8ClampedArray(result.get_data()),
result.get_width(),
result.get_height()
);
outputCtx.putImageData(restoredImageData, 0, 0);
// Display results
console.log({
isPixelArt: true,
originalSize: `${img.width}x${img.height}`,
restoredSize: `${result.get_width()}x${result.get_height()}`,
scale: `${result.get_scale_h()}x${result.get_scale_v()}`,
confidence: result.get_confidence(),
artifactLevel: result.get_artifact_level(),
colors: `${result.get_original_colors()} → ${result.get_final_colors()}`
});
return outputCanvas;
} else {
console.log('Not pixel art detected');
return null;
}
}
// Usage
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const restoredCanvas = await processImageFromFile(file);
if (restoredCanvas) {
document.body.appendChild(restoredCanvas);
}
});
process_pixel_art_v2(data, width, height, max_colors)Processes an image and detects/restores pixel art.
Parameters:
data: Uint8Array - RGBA image data (width × height × 4 bytes)width: number - Image width in pixelsheight: number - Image height in pixelsmax_colors: number - Maximum colors in the final palette (e.g., 256)Returns: ProcessedImage object
interface ProcessedImage {
// Core results
is_pixel_art(): boolean; // Was pixel art detected?
get_data(): Uint8Array; // Restored image data (RGBA)
get_width(): number; // Restored image width
get_height(): number; // Restored image height
// Detection metrics
get_confidence(): number; // Detection confidence (0.0-1.0)
get_artifact_level(): number; // Compression artifact level (0.0-1.0)
get_scale_h(): number; // Horizontal scale factor detected
get_scale_v(): number; // Vertical scale factor detected
// Color metrics
get_original_colors(): number; // Number of colors before processing
get_final_colors(): number; // Number of colors after quantization
}
// Input: 512x512 image, 8x upscaled, pure colors
// Output: ✅ Detected, 64x64, confidence: 0.95
const result = process_pixel_art_v2(cleanImageData, 512, 512, 128);
// Input: 400x400 image, JPEG compression, visible artifacts
// Output: ✅ Detected (thanks to preprocessing!), 100x100, confidence: 0.72
const result = process_pixel_art_v2(compressedImageData, 400, 400, 256);
console.log(`Artifact level: ${result.get_artifact_level()}`); // e.g., 0.65
// Input: 1920x1080 HD photo
// Output: ❌ Rejected (high entropy)
const result = process_pixel_art_v2(photoData, 1920, 1080, 256);
console.log(result.is_pixel_art()); // false
For difficult cases, you can adjust detection sensitivity:
// Note: This requires importing the Rust configuration interface
// (Available in future versions)
// For heavily compressed images
config.base_confidence = 0.55; // More permissive
config.color_merge_radius = 20.0; // Aggressive color merging
config.denoise_strength = 0.8; // Strong denoising
// For strict detection (clean images only)
config.base_confidence = 0.80; // Stricter
config.color_merge_radius = 8.0; // Less color merging
const artifactLevel = result.get_artifact_level();
if (artifactLevel > 0.7) {
console.warn('⚠️ Image heavily compressed - consider using higher quality source');
} else if (artifactLevel > 0.4) {
console.log('ℹ️ Moderate compression detected - preprocessing applied');
}
const confidence = result.get_confidence();
if (confidence < 0.7 && result.is_pixel_art()) {
console.log('⚠️ Low confidence detection - manual verification recommended');
}
┌─────────────────────────────────────┐
│ PHASE 1: ANALYSIS & PREPROCESSING │
│ • Detect artifact level │
│ • Adaptive config adjustment │
│ • Color clustering │
│ • Bilateral filtering │
│ • Selective sharpening │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ PHASE 2: QUICK REJECTION │
│ • Entropy check (reject photos) │
│ • Color count check │
│ • Grid pattern detection │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ PHASE 3: MULTI-METHOD DETECTION │
│ • Run-length analysis │
│ • Spatial autocorrelation │
│ • Grid uniformity analysis │
│ • Combine results intelligently │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ PHASE 4: VALIDATION │
│ • Downscale + upscale │
│ • SSIM comparison │
│ • Adaptive tolerance │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ PHASE 5: RESTORATION │
│ • Smart downscaling │
│ - Median (noisy images) │
│ - Weighted avg (moderate) │
│ - Simple avg (clean) │
│ • Palette quantization │
│ • Post-processing │
└─────────────────────────────────────┘
Solutions:
if (!result.is_pixel_art()) {
console.log('Debug info:');
console.log('Artifact level:', result.get_artifact_level());
console.log('Original colors:', result.get_original_colors());
}
Rare but possible with:
// Verify with metrics
if (result.is_pixel_art()) {
const colors = result.get_original_colors();
const confidence = result.get_confidence();
if (colors > 1000 || confidence < 0.6) {
console.warn('Possible false positive - verify manually');
}
}
const scaleH = result.get_scale_h();
const scaleV = result.get_scale_v();
if (scaleH !== scaleV) {
console.log('Non-uniform scaling detected');
}
if (scaleH === 1) {
console.log('No upscaling detected - image may be at original resolution');
}
Optimization tips:
--release flag for production| Feature | v1.0 | v2.0 |
|---|---|---|
| Clean pixel art | ✅ Excellent | ✅ Excellent |
| JPEG compressed | ❌ Fails | ✅ Works |
| PNG artifacts | ⚠️ Sometimes | ✅ Works |
| Game screenshots | ⚠️ Variable | ✅ Robust |
| Detection rate | ~70% | ~92% |
| False positives | ~5% | ~2% |
| Speed (clean) | 50ms | 55ms |
| Speed (compressed) | N/A | 85ms |
async function processBatch(imageFiles) {
await init();
const results = await Promise.all(
imageFiles.map(async (file) => {
const imageData = await loadImageData(file);
const result = process_pixel_art_v2(
imageData.data,
imageData.width,
imageData.height,
256
);
return {
filename: file.name,
isPixelArt: result.is_pixel_art(),
confidence: result.get_confidence(),
scale: result.is_pixel_art()
? `${result.get_scale_h()}x${result.get_scale_v()}`
: 'N/A'
};
})
);
console.table(results);
}
const fs = require('fs');
const { createCanvas, loadImage } = require('canvas');
const { process_pixel_art_v2 } = require('pixel-art-detector');
async function processPixelArt(inputPath, outputPath) {
const img = await loadImage(inputPath);
const canvas = createCanvas(img.width, img.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
const result = process_pixel_art_v2(imageData.data, img.width, img.height, 256);
if (result.is_pixel_art()) {
const outCanvas = createCanvas(result.get_width(), result.get_height());
const outCtx = outCanvas.getContext('2d');
const outImageData = outCtx.createImageData(result.get_width(), result.get_height());
outImageData.data.set(result.get_data());
outCtx.putImageData(outImageData, 0, 0);
const buffer = outCanvas.toBuffer('image/png');
fs.writeFileSync(outputPath, buffer);
console.log(`✅ Restored: ${outputPath}`);
console.log(` Scale: ${result.get_scale_h()}x${result.get_scale_v()}`);
console.log(` Size: ${img.width}x${img.height} → ${result.get_width()}x${result.get_height()}`);
} else {
console.log('❌ Not pixel art');
}
}
MIT License - see LICENSE file for details
Contributions welcome! Please feel free to submit a Pull Request.
For questions or issues:
Made with ❤️ using Rust and WebAssembly
FAQs
[](https://www.npmjs.com/package/pixel-art-detector) [](https://opensource.org/licenses/MIT)
We found that hexagon_wasm demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.