Skip to content

Instantly share code, notes, and snippets.

@neutrixs
Last active October 4, 2025 13:10
Show Gist options
  • Select an option

  • Save neutrixs/c6b3635678bd1a523d02fd1ac7aef949 to your computer and use it in GitHub Desktop.

Select an option

Save neutrixs/c6b3635678bd1a523d02fd1ac7aef949 to your computer and use it in GitHub Desktop.
Convert your EXR + tonemapped jpg to google's ultra HDR format that instagram accepts
// vibe coded. it works tho, so don't ask me
import puppeteer from 'puppeteer';
import { promises as fs } from 'fs';
import http from 'http';
import path from 'path';
async function createUltraHDR(hdrPath, sdrPath, outputPath) {
console.log('Starting local file server...');
// Create a simple HTTP server to serve files
const server = http.createServer(async (req, res) => {
const filePath = path.join(process.cwd(), req.url.slice(1));
try {
const data = await fs.readFile(filePath);
res.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': '*'
});
res.end(data);
} catch (err) {
res.writeHead(404, {
'Access-Control-Allow-Origin': '*'
});
res.end('Not found');
}
});
await new Promise(resolve => server.listen(8888, resolve));
console.log('File server running on http://localhost:8888');
console.log('Starting browser...');
const browser = await puppeteer.launch({
headless: false, // Change to false to see what's happening
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
devtools: true // Open devtools automatically
});
const page = await browser.newPage();
// Increase timeout
page.setDefaultTimeout(120000); // 2 minutes
// Log console messages from the page
page.on('console', msg => console.log('PAGE:', msg.text()));
page.on('pageerror', err => console.error('PAGE ERROR:', err));
// Use local file URLs instead of base64
const hdrUrl = `http://localhost:8888/${hdrPath}`;
const sdrUrl = `http://localhost:8888/${sdrPath}`;
const hdrFormat = hdrPath.endsWith('.exr') ? 'exr' : hdrPath.endsWith('.hdr') ? 'hdr' : 'other';
// Create a page with the encoding script
await page.setContent(`
<!DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/examples/": "https://unpkg.com/[email protected]/examples/",
"@monogrid/gainmap-js/encode": "https://unpkg.com/@monogrid/[email protected]/dist/encode.js",
"@monogrid/gainmap-js/libultrahdr": "https://unpkg.com/@monogrid/[email protected]/dist/libultrahdr.js"
}
}
</script>
</head>
<body>
<canvas id="canvas" style="display:none"></canvas>
<script type="module">
import { encode, findTextureMinMax } from '@monogrid/gainmap-js/encode';
import { encodeJPEGMetadata } from '@monogrid/gainmap-js/libultrahdr';
import * as THREE from 'three';
import { EXRLoader } from 'https://unpkg.com/[email protected]/examples/jsm/loaders/EXRLoader.js';
import { RGBELoader } from 'https://unpkg.com/[email protected]/examples/jsm/loaders/RGBELoader.js';
window.encodeUltraHDR = async function(hdrDataUrl, sdrDataUrl, hdrFormat) {
try {
let hdrTexture;
// Load HDR based on format
if (hdrFormat === 'exr') {
const loader = new EXRLoader();
hdrTexture = await loader.loadAsync(hdrDataUrl);
} else if (hdrFormat === 'hdr') {
const loader = new RGBELoader();
hdrTexture = await loader.loadAsync(hdrDataUrl);
} else {
const hdrImg = await new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => resolve(img);
img.onerror = reject;
img.src = hdrDataUrl;
});
hdrTexture = new THREE.Texture(hdrImg);
hdrTexture.needsUpdate = true;
}
// Find max content boost
const textureMax = findTextureMinMax(hdrTexture);
const maxContentBoost = Math.max(...textureMax);
console.log('Max content boost:', maxContentBoost);
// Encode gain map
const encodingResult = encode({
image: hdrTexture,
maxContentBoost: maxContentBoost
});
// Load SDR image to check dimensions and re-compress in consistent format
const sdrImg = await new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => resolve(img);
img.onerror = reject;
img.src = sdrDataUrl;
});
console.log('SDR actual dimensions:', sdrImg.width, 'x', sdrImg.height);
// Re-compress SDR through canvas to ensure consistent format with gain map
const sdrCanvas = document.createElement('canvas');
sdrCanvas.width = sdrImg.width;
sdrCanvas.height = sdrImg.height;
const sdrCtx = sdrCanvas.getContext('2d');
sdrCtx.drawImage(sdrImg, 0, 0);
const sdrDataUrl2 = sdrCanvas.toDataURL('image/jpeg', 0.95);
const sdrResponse2 = await fetch(sdrDataUrl2);
const sdrArrayBuffer2 = await sdrResponse2.arrayBuffer();
const sdrJpeg = new Uint8Array(sdrArrayBuffer2);
console.log('Re-compressed SDR JPEG size:', sdrJpeg.length, 'First bytes:', Array.from(sdrJpeg.slice(0, 4)));
// Get gain map ImageData
const gainMapImageData = new ImageData(
encodingResult.gainMap.toArray(),
encodingResult.gainMap.width,
encodingResult.gainMap.height
);
console.log('Gain map dimensions:', gainMapImageData.width, 'x', gainMapImageData.height);
// Compress gain map to JPEG with vertical flip
const tempCanvas = document.createElement('canvas');
tempCanvas.width = gainMapImageData.width;
tempCanvas.height = gainMapImageData.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.putImageData(gainMapImageData, 0, 0);
const canvas = document.createElement('canvas');
canvas.width = gainMapImageData.width;
canvas.height = gainMapImageData.height;
const ctx = canvas.getContext('2d');
// Flip vertically
ctx.translate(0, canvas.height);
ctx.scale(1, -1);
ctx.drawImage(tempCanvas, 0, 0);
const gainMapDataUrl = canvas.toDataURL('image/jpeg', 0.95);
const gainMapResponse = await fetch(gainMapDataUrl);
const gainMapArrayBuffer = await gainMapResponse.arrayBuffer();
const gainMapJpeg = new Uint8Array(gainMapArrayBuffer);
console.log('Gain map JPEG size:', gainMapJpeg.length, 'First bytes:', Array.from(gainMapJpeg.slice(0, 4)));
// Get metadata
const metadata = encodingResult.getMetadata();
// Encode final JPEG with proper format
const ultraHDRJpeg = await encodeJPEGMetadata({
...metadata,
sdr: {
data: sdrJpeg,
mimeType: 'image/jpeg',
width: sdrImg.width,
height: sdrImg.height
},
gainMap: {
data: gainMapJpeg,
mimeType: 'image/jpeg',
width: gainMapImageData.width,
height: gainMapImageData.height
}
});
// Cleanup
encodingResult.gainMap.dispose();
encodingResult.sdr.dispose();
hdrTexture.dispose();
// Convert to base64 in chunks to avoid stack overflow
const chunkSize = 8192;
let base64 = '';
for (let i = 0; i < ultraHDRJpeg.length; i += chunkSize) {
const chunk = ultraHDRJpeg.subarray(i, i + chunkSize);
base64 += String.fromCharCode(...chunk);
}
return btoa(base64);
} catch (err) {
console.error('Encoding error:', err);
throw err;
}
};
console.log('Ready');
</script>
</body>
</html>
`);
// Wait for script to load
await page.waitForFunction(() => window.encodeUltraHDR !== undefined);
console.log('Browser ready, encoding...');
// Run encoding with direct URLs
const resultBase64 = await page.evaluate(
async (hdrUrl, sdrUrl, format) => {
return await window.encodeUltraHDR(hdrUrl, sdrUrl, format);
},
hdrUrl,
sdrUrl,
hdrFormat
);
console.log('Writing output...');
const outputBuffer = Buffer.from(resultBase64, 'base64');
await fs.writeFile(outputPath, outputBuffer);
await browser.close();
server.close();
console.log(`Ultra HDR JPEG saved to: ${outputPath}`);
}
// Usage - Change these to your actual file names
const hdrPath = 'test.exr'; // Your EXR or HDR file
const sdrPath = 'test.jpg'; // Your custom tone-mapped JPEG
const outputPath = 'output_ultrahdr.jpg';
createUltraHDR(hdrPath, sdrPath, outputPath)
.then(() => console.log('Done! Upload output_ultrahdr.jpg to Instagram'))
.catch(err => console.error('Error:', err));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment