@uitgeteld/grainular
v1.0.0
Published
Professional film grain effects and image processing for Node.js. Perfect for Discord bots, automation, and server-side image manipulation.
Downloads
4
Maintainers
Readme
Grainular
Professional film grain effects and image processing for Node.js. Perfect for Discord bots, automation, and server-side image manipulation.
Installation
npm install grainularFeatures
- 🎞️ Film Grain Effects - Add realistic colored or black & white grain
- ✨ Image Adjustments - Brightness, saturation, and B&W conversion
- 🤖 Discord Bot Ready - Works seamlessly with Canvas/Sharp
- 🚀 Fast & Lightweight - Pure JavaScript, no heavy dependencies
- 💻 Node.js Native - Designed for server-side processing
Quick Start
const { addGrain, saturate, adjustBrightness, toBlackWhite } = require('grainular');
// Your ImageData object from Canvas or similar
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Apply effects
imageData = addGrain(imageData, 30, true); // Add colored grain (30% intensity)
imageData = saturate(imageData, 1.5); // Increase saturation (150%)
imageData = adjustBrightness(imageData, 1.2); // Increase brightness (120%)
imageData = toBlackWhite(imageData); // Convert to black & white
// Put back to canvas
ctx.putImageData(imageData, 0, 0);API Reference
addGrain(imageData, intensity, colored)
Adds film grain effect to an image.
Parameters:
imageData(ImageData) - Canvas ImageData object containing pixel dataintensity(Number) - Grain intensity from 0-100 (default: 20)colored(Boolean) -truefor colored grain,falsefor monochrome (default: false)
Returns: Modified ImageData object
Example:
// Add subtle colored grain
imageData = addGrain(imageData, 15, true);
// Add strong B&W grain
imageData = addGrain(imageData, 50, false);saturate(imageData, factor)
Adjusts image saturation.
Parameters:
imageData(ImageData) - Canvas ImageData object containing pixel datafactor(Number) - Saturation multiplier (0 = grayscale, 1 = original, >1 = more saturated)
Returns: Modified ImageData object
Example:
// Increase saturation by 50%
imageData = saturate(imageData, 1.5);
// Reduce saturation by half
imageData = saturate(imageData, 0.5);
// Full grayscale
imageData = saturate(imageData, 0);adjustBrightness(imageData, factor)
Adjusts image brightness.
Parameters:
imageData(ImageData) - Canvas ImageData object containing pixel datafactor(Number) - Brightness multiplier (0 = black, 1 = original, >1 = brighter)
Returns: Modified ImageData object
Example:
// Increase brightness by 20%
imageData = adjustBrightness(imageData, 1.2);
// Darken by 30%
imageData = adjustBrightness(imageData, 0.7);toBlackWhite(imageData)
Converts image to black and white using luminance formula.
Parameters:
imageData(ImageData) - Canvas ImageData object containing pixel data
Returns: Modified ImageData object
Example:
imageData = toBlackWhite(imageData);Usage Examples
Discord Bot with Canvas
const { createCanvas, loadImage } = require('canvas');
const { addGrain, saturate } = require('grainular');
const { AttachmentBuilder } = require('discord.js');
client.on('messageCreate', async (message) => {
if (message.content === '!grain' && message.attachments.size > 0) {
const attachment = message.attachments.first();
// Load image
const image = await loadImage(attachment.url);
const canvas = createCanvas(image.width, image.height);
const ctx = canvas.getContext('2d');
// Draw and get image data
ctx.drawImage(image, 0, 0);
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Apply effects
imageData = addGrain(imageData, 40, true);
imageData = saturate(imageData, 1.3);
// Put back and send
ctx.putImageData(imageData, 0, 0);
const buffer = canvas.toBuffer('image/png');
const attachment = new AttachmentBuilder(buffer, { name: 'grainy.png' });
await message.reply({ files: [attachment] });
}
});Processing Multiple Images
const fs = require('fs');
const { createCanvas, loadImage } = require('canvas');
const { addGrain, toBlackWhite } = require('grainular');
async function processImage(inputPath, outputPath) {
const image = await loadImage(inputPath);
const canvas = createCanvas(image.width, image.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Apply vintage film look
imageData = toBlackWhite(imageData);
imageData = addGrain(imageData, 35, false);
ctx.putImageData(imageData, 0, 0);
const buffer = canvas.toBuffer('image/png');
fs.writeFileSync(outputPath, buffer);
}
// Process batch
const images = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg'];
for (const img of images) {
await processImage(img, `processed_${img}`);
}Custom Film Presets
const { addGrain, saturate, adjustBrightness, toBlackWhite } = require('grainular');
function vintageFilm(imageData) {
imageData = toBlackWhite(imageData);
imageData = addGrain(imageData, 45, false);
imageData = adjustBrightness(imageData, 0.9);
return imageData;
}
function colorPop(imageData) {
imageData = saturate(imageData, 1.8);
imageData = addGrain(imageData, 20, true);
imageData = adjustBrightness(imageData, 1.1);
return imageData;
}
function softGlow(imageData) {
imageData = adjustBrightness(imageData, 1.15);
imageData = saturate(imageData, 0.8);
imageData = addGrain(imageData, 10, true);
return imageData;
}
// Use presets
imageData = vintageFilm(imageData);Important Notes
- ImageData Format: All functions expect and return Canvas ImageData objects
- Non-Destructive: Original imageData is not modified; a new object is returned
- Chaining: Functions can be chained for complex effects
- Performance: Processing time scales with image resolution
- Color Space: Works with RGBA color space (8-bit per channel)
Requirements
- Node.js 12.x or higher
- A Canvas implementation (e.g.,
canvaspackage) for ImageData objects
Web Version
Looking for the browser-based editor? Check out the Grainular web app.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Contact
- GitHub: uitgeteld
- NPM: uitgeteld and spacing_dev
- Discord: uitgeteld
- Instagram: @ovwastaken
License
See LICENSE file for details.
Built with ❤️ for developers and creators.
