npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hemia/image-kit

v0.0.1

Published

Package for image processing

Downloads

6

Readme

@hemia/image-kit

Package profesional para procesamiento de imágenes con Sharp. Incluye compresión, watermarks y extracción de metadatos.

📦 Instalación

npm install @hemia/image-kit

🚀 Uso Rápido

import { ImageKit } from '@hemia/image-kit';

// Comprimir imagen
const result = await ImageKit.compress('input.jpg', { quality: 80 }, 'output.jpg');

// Agregar watermark
const watermarked = await ImageKit.watermark('input.jpg', { text: 'Mi Marca' }, 'output.jpg');

// Obtener metadatos
const metadata = await ImageKit.getMetadata('input.jpg');

// Aplicar filtros
const blurred = await ImageKit.blur('photo.jpg', 10, 'blurred.jpg');
const bw = await ImageKit.grayscale('photo.jpg', 'blackwhite.jpg');

// Generar thumbnail inteligente
const thumb = await ImageKit.thumbnail('image.jpg', 300, 300, 'thumb.jpg');

// Obtener color dominante
const color = await ImageKit.getDominantColor('image.jpg'); // "#a3124c"

// Generar placeholder base64
const placeholder = await ImageKit.placeholder('image.jpg');

📚 API Reference

compress(input, options, outputPath?)

Comprime una imagen con opciones personalizables de calidad, formato y dimensiones.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen a comprimir | | options | CompressionOptions | Opciones de compresión (ver tabla abajo) | | outputPath | string \| null (opcional) | Ruta donde guardar el archivo. Si es null o no se proporciona, retorna un Buffer |

Opciones de Compresión (CompressionOptions)

| Opción | Tipo | Por Defecto | Descripción | |--------|------|-------------|-------------| | quality | number | 80 | Calidad de compresión (1-100). Valores más altos = mejor calidad pero mayor tamaño | | format | 'jpeg' \| 'png' \| 'webp' \| 'avif' | 'jpeg' | Formato de salida de la imagen | | width | number | - | Ancho deseado en píxeles. Mantiene aspecto si no se especifica height | | height | number | - | Alto deseado en píxeles. Mantiene aspecto si no se especifica width | | fit | 'cover' \| 'contain' \| 'fill' \| 'inside' \| 'outside' | 'cover' | Estrategia de redimensionamiento cuando se especifican ambas dimensiones | | progressive | boolean | true | Habilita carga progresiva (solo JPEG) | | compressionLevel | number | 9 | Nivel de compresión para PNG (0-9). Mayor = más compresión |

Retorno

  • Con outputPath: Promise<CompressionResult> - Objeto con información del resultado
  • Sin outputPath: Promise<Buffer> - Buffer con la imagen comprimida
interface CompressionResult {
    success: boolean;
    originalSize: number;    // Tamaño original en bytes
    compressedSize: number;  // Tamaño comprimido en bytes
    savedPercentage: number; // Porcentaje de reducción
    width: number;           // Ancho final
    height: number;          // Alto final
    format: string;          // Formato final
    path?: string;           // Ruta del archivo guardado
}

Ejemplos

Compresión básica con calidad personalizada:

const result = await compress('photo.jpg', { quality: 85 }, 'photo-compressed.jpg');
console.log(`Reducción: ${result.savedPercentage}%`);

Convertir a WebP y redimensionar:

const result = await compress('image.png', {
    format: 'webp',
    quality: 90,
    width: 800,
    height: 600,
    fit: 'cover'
}, 'image.webp');

Trabajar con Buffers (sin guardar archivo):

const imageBuffer = await fs.readFile('input.jpg');
const compressedBuffer = await compress(imageBuffer, { quality: 75 });
// Enviar buffer por API, etc.

Redimensionar manteniendo aspecto:

const result = await compress('large.jpg', {
    width: 1200,  // Solo especificar ancho
    quality: 80
}, 'thumbnail.jpg');

addWatermark(input, options, outputPath)

Agrega una marca de agua de texto a una imagen.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen | | options | WatermarkOptions | Opciones del watermark (ver tabla abajo) | | outputPath | string | Ruta donde guardar la imagen con watermark. Si no se proporciona, retorna Buffer |

Opciones de Watermark (WatermarkOptions)

| Opción | Tipo | Por Defecto | Descripción | |--------|------|-------------|-------------| | text | string | 'Hemia' | Texto de la marca de agua | | gravity | 'southeast' \| 'southwest' \| 'northeast' \| 'northwest' \| 'center' | 'southeast' | Posición del watermark en la imagen | | opacity | number | 50 | Opacidad del texto (0-100). 0 = transparente, 100 = opaco | | fontSize | number | 30 | Tamaño de la fuente en píxeles |

Retorno

  • Con outputPath: Promise<WatermarkResult> - Objeto con información del resultado
  • Sin outputPath: Promise<Buffer> - Buffer con la imagen marcada
interface WatermarkResult {
    success: boolean;
    width: number;   // Ancho de la imagen
    height: number;  // Alto de la imagen
    format: string;  // Formato de la imagen
    path?: string;   // Ruta del archivo guardado
}

Ejemplos

Watermark básico en esquina inferior derecha:

const result = await addWatermark('photo.jpg', {
    text: '© Mi Empresa 2024'
}, 'photo-watermarked.jpg');

Watermark centrado con opacidad personalizada:

const result = await addWatermark('banner.png', {
    text: 'CONFIDENCIAL',
    gravity: 'center',
    opacity: 30,
    fontSize: 50
}, 'banner-marked.png');

Watermark en esquina superior izquierda:

const result = await addWatermark('image.jpg', {
    text: 'Draft',
    gravity: 'northwest',
    opacity: 70,
    fontSize: 25
}, 'draft.jpg');

Trabajar con Buffer (sin guardar):

const buffer = await addWatermark('input.jpg', {
    text: 'Sample',
    opacity: 40
});
// Retorna Buffer directamente

getMetadata(input)

Extrae información de metadatos de una imagen.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen |

Retorno

Promise<Metadata> - Objeto con los metadatos de la imagen:

interface Metadata {
    format: string;          // Formato de la imagen (jpeg, png, webp, etc.)
    width: number;           // Ancho en píxeles
    height: number;          // Alto en píxeles
    hasAlpha: boolean;       // Si tiene canal alpha (transparencia)
    isProgressive: boolean;  // Si es progresiva (JPEG)
}

Ejemplos

Obtener información básica:

const meta = await getMetadata('photo.jpg');
console.log(`Dimensiones: ${meta.width}x${meta.height}`);
console.log(`Formato: ${meta.format}`);

Validar dimensiones antes de procesar:

const meta = await getMetadata('upload.png');

if (meta.width > 4000 || meta.height > 4000) {
    console.log('Imagen demasiado grande, comprimiendo...');
    await compress('upload.png', { width: 2000 }, 'resized.png');
}

Verificar transparencia:

const meta = await getMetadata('logo.png');

if (meta.hasAlpha) {
    console.log('La imagen tiene transparencia');
    // Usar PNG o WebP para preservar alpha
} else {
    // Puede convertirse a JPEG sin pérdida
    await compress('logo.png', { format: 'jpeg' }, 'logo.jpg');
}

blur(input, sigma, outputPath?)

Aplica un desenfoque Gaussiano a la imagen.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen | | sigma | number | Intensidad del desenfoque (0.3 a 1000). Por defecto: 5 | | outputPath | string (opcional) | Ruta donde guardar el archivo. Si no se proporciona, retorna un Buffer |

Retorno

  • Con outputPath: Promise<FileResult> - Objeto con información del resultado
  • Sin outputPath: Promise<Buffer> - Buffer con la imagen procesada
interface FileResult {
    success: boolean;
    path: string;
    width?: number;
    height?: number;
    format?: string;
    size?: number;
}

Ejemplos

Desenfoque suave:

const result = await ImageKit.blur('photo.jpg', 3, 'soft-blur.jpg');

Desenfoque intenso para efecto artístico:

const result = await ImageKit.blur('background.jpg', 20, 'blurred-bg.jpg');

Trabajar con Buffer:

const blurredBuffer = await ImageKit.blur('image.jpg', 10);
// Usar buffer en memoria

grayscale(input, outputPath?)

Convierte la imagen a escala de grises (blanco y negro).

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen | | outputPath | string (opcional) | Ruta donde guardar el archivo. Si no se proporciona, retorna un Buffer |

Retorno

  • Con outputPath: Promise<FileResult> - Objeto con información del resultado
  • Sin outputPath: Promise<Buffer> - Buffer con la imagen procesada

Ejemplos

Convertir a blanco y negro:

const result = await ImageKit.grayscale('color-photo.jpg', 'bw-photo.jpg');

Procesar múltiples imágenes:

const images = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg'];

for (const img of images) {
    await ImageKit.grayscale(img, `bw-${img}`);
}

Efecto vintage combinado:

// Primero convertir a B&N, luego aplicar desenfoque sutil
const bwBuffer = await ImageKit.grayscale('photo.jpg');
const vintage = await ImageKit.blur(bwBuffer, 1, 'vintage.jpg');

thumbnail(input, width, height, outputPath?)

Crea una miniatura recortada inteligentemente usando detección de "atención" para no cortar caras u objetos importantes.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen | | width | number | Ancho deseado del thumbnail en píxeles | | height | number | Alto deseado del thumbnail en píxeles | | outputPath | string (opcional) | Ruta donde guardar el archivo. Si no se proporciona, retorna un Buffer |

Retorno

  • Con outputPath: Promise<FileResult> - Objeto con información del resultado
  • Sin outputPath: Promise<Buffer> - Buffer con la imagen procesada

Características

  • Recorte inteligente: Usa sharp.strategy.attention para enfocar la zona más interesante
  • Fit cover: Recorta lo que sobre para mantener las dimensiones exactas
  • Ideal para: Avatares, previews de productos, galerías de imágenes

Ejemplos

Thumbnail cuadrado para avatar:

const thumb = await ImageKit.thumbnail('profile.jpg', 200, 200, 'avatar.jpg');

Thumbnails para galería:

const images = await getImagesFromDB();

for (const img of images) {
    await ImageKit.thumbnail(img.path, 400, 300, `thumbs/${img.id}.jpg`);
}

Generar múltiples tamaños:

const sizes = [
    { w: 150, h: 150, name: 'small' },
    { w: 300, h: 300, name: 'medium' },
    { w: 600, h: 600, name: 'large' }
];

for (const size of sizes) {
    await ImageKit.thumbnail(
        'original.jpg',
        size.w,
        size.h,
        `thumb-${size.name}.jpg`
    );
}

placeholder(input)

Genera un string Base64 de muy baja resolución ideal para usar como placeholder mientras carga la imagen original (alternativa a Blurhash).

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen |

Retorno

Promise<string> - String en formato data:image/jpeg;base64,... listo para usar en src de <img>

Características

  • Tamaño mínimo: Redimensiona a 20px con blur
  • Carga instantánea: Peso mínimo para carga ultra rápida
  • UX mejorada: Evita el "salto" visual cuando carga la imagen real

Ejemplos

Uso básico en HTML:

const placeholderData = await ImageKit.placeholder('large-image.jpg');

// En tu HTML/JSX:
// <img src={placeholderData} data-src="large-image.jpg" />

React con lazy loading:

import { useState, useEffect } from 'react';

function LazyImage({ src }) {
    const [placeholder, setPlaceholder] = useState('');
    const [loaded, setLoaded] = useState(false);
    
    useEffect(() => {
        ImageKit.placeholder(src).then(setPlaceholder);
    }, [src]);
    
    return (
        <img
            src={loaded ? src : placeholder}
            onLoad={() => setLoaded(true)}
            style={{ filter: loaded ? 'none' : 'blur(10px)' }}
        />
    );
}

Generar placeholders para galería:

const images = ['img1.jpg', 'img2.jpg', 'img3.jpg'];

const placeholders = await Promise.all(
    images.map(img => ImageKit.placeholder(img))
);

// Guardar en base de datos o cache

Next.js Image con placeholder:

// En tu API route o getStaticProps
const placeholderData = await ImageKit.placeholder('/public/hero.jpg');

// En tu componente
<Image
    src="/hero.jpg"
    placeholder="blur"
    blurDataURL={placeholderData}
    width={1200}
    height={600}
/>

getDominantColor(input)

Analiza la imagen y devuelve el color predominante en formato hexadecimal.

Parámetros

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | input | string \| Buffer | Ruta del archivo o Buffer de la imagen |

Retorno

Promise<string> - Color en formato hexadecimal (ej: "#a3124c")

Casos de Uso

  • Temas dinámicos: Generar paletas de colores basadas en imágenes
  • Fondos adaptativos: Crear fondos que combinen con la imagen
  • Diseño automático: Ajustar UI según el color dominante de una foto

Ejemplos

Obtener color dominante:

const color = await ImageKit.getDominantColor('product.jpg');
console.log(color); // "#3a7bd5"

Generar tema dinámico:

const dominantColor = await ImageKit.getDominantColor('album-cover.jpg');

// Usar en CSS
const theme = {
    primary: dominantColor,
    background: `${dominantColor}20`, // Con transparencia
    border: dominantColor
};

Crear fondo adaptativo:

const images = await getGalleryImages();

for (const img of images) {
    const color = await ImageKit.getDominantColor(img.path);
    
    await saveToDatabase({
        imageId: img.id,
        dominantColor: color,
        backgroundColor: `linear-gradient(135deg, ${color}, #ffffff)`
    });
}

React component con color dinámico:

function ProductCard({ imageSrc }) {
    const [bgColor, setBgColor] = useState('#f0f0f0');
    
    useEffect(() => {
        ImageKit.getDominantColor(imageSrc).then(color => {
            setBgColor(color + '30'); // Agregar transparencia
        });
    }, [imageSrc]);
    
    return (
        <div style={{ backgroundColor: bgColor }}>
            <img src={imageSrc} alt="Product" />
        </div>
    );
}

Validar contraste para accesibilidad:

const bgColor = await ImageKit.getDominantColor('background.jpg');

// Función helper para calcular luminancia
function getLuminance(hex: string) {
    // ... cálculo de luminancia
}

const luminance = getLuminance(bgColor);
const textColor = luminance > 0.5 ? '#000000' : '#ffffff';

console.log(`Usar texto ${textColor} sobre fondo ${bgColor}`);

🔄 Flujo de Trabajo Completo

Ejemplo de procesamiento completo de una imagen:

import { ImageKit } from '@hemia/image-kit';

async function processImage(inputPath: string) {
    // 1. Obtener metadatos originales
    const originalMeta = await ImageKit.getMetadata(inputPath);
    console.log(`Original: ${originalMeta.width}x${originalMeta.height}`);
    
    // 2. Comprimir y redimensionar
    const compressed = await ImageKit.compress(inputPath, {
        format: 'webp',
        quality: 85,
        width: 1920,
        fit: 'inside'
    }, 'temp-compressed.webp');
    
    console.log(`Reducción: ${compressed.savedPercentage}%`);
    
    // 3. Agregar watermark
    const final = await ImageKit.watermark('temp-compressed.webp', {
        text: '© Mi Marca 2024',
        gravity: 'southeast',
        opacity: 60,
        fontSize: 24
    }, 'final-output.webp');
    
    console.log(`Imagen final: ${final.width}x${final.height}`);
    
    return final;
}

processImage('input.jpg');

🎨 Casos de Uso Avanzados

Galería de Imágenes con Placeholders

async function createGallery(images: string[]) {
    const gallery = [];
    
    for (const img of images) {
        // Generar thumbnail
        const thumb = await ImageKit.thumbnail(img, 400, 300, `thumbs/${img}`);
        
        // Generar placeholder
        const placeholder = await ImageKit.placeholder(img);
        
        // Obtener color dominante
        const color = await ImageKit.getDominantColor(img);
        
        gallery.push({
            original: img,
            thumbnail: thumb.path,
            placeholder,
            dominantColor: color
        });
    }
    
    return gallery;
}

Procesamiento de Imágenes de Productos

async function processProductImage(productImage: string) {
    // 1. Crear versión optimizada
    await ImageKit.compress(productImage, {
        format: 'webp',
        quality: 90,
        maxWidth: 2000
    }, 'product-hd.webp');
    
    // 2. Crear thumbnails en múltiples tamaños
    await ImageKit.thumbnail(productImage, 800, 800, 'product-large.webp');
    await ImageKit.thumbnail(productImage, 400, 400, 'product-medium.webp');
    await ImageKit.thumbnail(productImage, 150, 150, 'product-small.webp');
    
    // 3. Generar placeholder para carga rápida
    const placeholder = await ImageKit.placeholder(productImage);
    
    // 4. Extraer color para tema de la página
    const themeColor = await ImageKit.getDominantColor(productImage);
    
    return {
        images: {
            hd: 'product-hd.webp',
            large: 'product-large.webp',
            medium: 'product-medium.webp',
            small: 'product-small.webp'
        },
        placeholder,
        themeColor
    };
}

Efectos Artísticos

async function createArtisticEffect(input: string) {
    // Efecto vintage: B&N + desenfoque sutil
    const bwBuffer = await ImageKit.grayscale(input);
    await ImageKit.blur(bwBuffer, 0.5, 'vintage.jpg');
    
    // Efecto dramático: B&N + watermark
    const dramatic = await ImageKit.grayscale(input);
    await ImageKit.watermark(dramatic, {
        text: 'DRAMATIC',
        gravity: 'center',
        opacity: 20,
        fontSize: 80
    }, 'dramatic.jpg');
    
    // Background blur para destacar sujeto
    await ImageKit.blur(input, 15, 'background-blur.jpg');
}

📝 Notas Importantes

  • Formatos soportados: JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF
  • Buffers vs Paths: Todas las funciones aceptan tanto rutas de archivo como Buffers para máxima flexibilidad
  • Salida opcional: Si no especificas outputPath, obtienes un Buffer para procesamiento en memoria
  • Calidad recomendada:
    • JPEG: 80-90 para fotos
    • WebP: 80-85 (mejor compresión que JPEG)
    • PNG: usar compressionLevel 9 para máxima compresión
  • Performance: WebP y AVIF ofrecen mejor compresión que JPEG/PNG pero requieren más procesamiento

🛠️ Tecnologías

  • Sharp: Motor de procesamiento de imágenes de alto rendimiento
  • TypeScript: Tipado completo para mejor DX

📄 Licencia

ISC