Generador de hojas de contactos
Planificar una hoja de contactos no debería exigir repetidos intentos de redimensionado.
Ejecutar — gratis
Indique el ancho y el alto en píxeles de cada imagen, además del ancho máximo disponible, y esta calculadora devolverá una cuadrícula práctica con un marco uniforme para las miniaturas. El resultado incluye columnas, filas, dimensiones de miniatura y dimensiones finales de la hoja. El diseño admite todas las proporciones de origen, respeta el límite de ancho y utiliza operaciones deterministas que siempre producen el mismo resultado.
Prepare las dimensiones y el límite de ancho
Empiece con un registro por cada imagen que vaya a aparecer en la hoja de contactos. Cada registro necesita un ancho y un alto en píxeles, ambos expresados como enteros positivos. Los archivos no se cargan ni se decodifican: solo hacen falta sus dimensiones. Incluya todas las imágenes, porque el número de registros determina cuántas celdas debe ofrecer la cuadrícula, mientras que los mayores valores de ancho y alto definen un marco común capaz de contener toda la colección sin recortes. Después, establezca max_sheet_width con el ancho en píxeles disponible en su documento, exportación, panel de galería o flujo de impresión. La calculadora lo considera un límite estricto. No reserva espacio para márgenes externos, pies de foto, separaciones, bordes ni sangrado de impresión; reste antes esas zonas si otro sistema las añadirá posteriormente. Una lista vacía se rechaza porque las columnas, las filas y el tamaño de miniatura carecen de sentido sin elementos. También se rechazan dimensiones fraccionarias, nulas, negativas o no válidas para que los procesos automatizados sean previsibles.
Comprenda cómo se elige la cuadrícula
El algoritmo evalúa todas las cantidades posibles de columnas, desde una hasta el número total de imágenes. Para cada candidata calcula las filas necesarias redondeando hacia arriba, divide el ancho máximo de la hoja en celdas de ancho entero uniforme y obtiene una altura correspondiente a partir de la envolvente de dimensiones de origen. Así se crea un marco homogéneo adecuado para una colocación de tipo contain: el renderizador escala cada imagen proporcionalmente hasta encajarla, quizá dejando espacio libre en un eje, pero sin exigir recortes. A continuación se comparan el ancho y el alto de la hoja resultante y se escoge la opción más cercana a un cuadrado. Una hoja compacta y equilibrada suele resultar más legible y evita la tira extrema de una sola columna que surgiría al maximizar únicamente las miniaturas. Si dos opciones tienen la misma diferencia, gana la que ofrece mayor área de miniatura; si todavía empatan, se prefieren menos columnas. El ancho de miniatura tampoco supera el de la fuente más ancha, lo que evita ampliaciones innecesarias. Todos los cálculos usan píxeles enteros y desempates deterministas.
Aplique el resultado en un renderizador
La respuesta incluye count, columns, rows, thumbnail_size, sheet_size, max_sheet_width y el modo fit. Cree un lienzo con sheet_size.width y sheet_size.height. Después coloque el elemento de índice i en la columna correspondiente a i módulo columns y en la fila igual a la parte entera de i dividida entre columns. Cada celda utiliza el ancho y el alto devueltos para la miniatura. Escale la fuente con una operación contain, céntrela en la celda si lo desea y conserve su proporción original. Como la última fila puede quedar incompleta, su renderizador puede dejar celdas finales vacías o centrar esa fila; el lienzo calculado conserva deliberadamente una geometría rectangular sencilla. El resultado no incorpora separaciones ni pies de foto. Para añadir, por ejemplo, diez píxeles entre celdas, reserve el ancho total de esas separaciones antes de llamar a la calculadora o reduzca uniformemente las dimensiones devueltas. El endpoint sirve tanto para uso interactivo como para lotes repetibles: una misma entrada siempre produce la misma salida, no realiza solicitudes de red y nunca examina el contenido visual. Cada solicitud mediante API cuesta $0.002, mientras que el navegador puede ejecutar localmente el mismo cálculo puro.
Qué puede hacer con ella
Planificar una hoja de pruebas fotográficas
Elija una cuadrícula equilibrada que respete un ancho fijo antes de cargar o redimensionar las fotografías originales.
Crear la vista previa de una biblioteca
Convierta los metadatos de imágenes guardadas en columnas, filas y dimensiones de celda deterministas para una galería.
Preparar páginas de muestras de datos
Distribuya ejemplos verticales, horizontales y cuadrados en marcos uniformes de tipo contain sin recortarlos.
Preguntas frecuentes
¿Cuánto cuesta?
La ejecución mediante API cuesta $0.002 por solicitud. El mismo cálculo también puede ejecutarse gratis y localmente en el navegador.
¿Se redimensionan o combinan mis imágenes?
No. Solo se devuelven medidas de diseño; su renderizador realiza el escalado y la composición reales.
¿Se recortarán las imágenes verticales u horizontales?
No es necesario recortarlas. El tamaño de miniatura es un marco destinado a una colocación contain que conserva la proporción.
¿Se incluyen separaciones, pies o márgenes?
No. Reserve el espacio para separaciones, etiquetas, bordes, márgenes o sangrado antes de indicar el ancho máximo.
¿Por qué una lista de imágenes vacía genera un error?
Una cuadrícula sin elementos no tiene un número útil de filas ni un tamaño de miniatura, por lo que se rechaza expresamente.
Para desarrolladores — acceso por API
Todo lo de esta página está disponible por programación. Esta sección es para equipos que quieren integrarlo en sus sistemas; el resto puede usar la herramienta de arriba sin más.
Endpoint de API
¿Prefiere automatizarlo? Un POST autenticado crea la tarea; el resultado llega por webhook o enlace firmado. La misma capacidad también se ejecuta aquí en la web, por email y desde Telegram — y pronto también desde nuestra app.
Llámela desde su stack
curl -X POST https://api.kit.forhosting.com/image/contact-sheet-layout \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"images":[{"width":1600,"height":900},{"width":1200,"height":1600},{"width":2048,"height":1365},{"width":800,"height":800},{"width":1920,"height":1080}],"max_sheet_width":1200}'const res = await fetch("https://api.kit.forhosting.com/image/contact-sheet-layout", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"images": [
{
"width": 1600,
"height": 900
},
{
"width": 1200,
"height": 1600
},
{
"width": 2048,
"height": 1365
},
{
"width": 800,
"height": 800
},
{
"width": 1920,
"height": 1080
}
],
"max_sheet_width": 1200
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/image/contact-sheet-layout",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"images": [
{
"width": 1600,
"height": 900
},
{
"width": 1200,
"height": 1600
},
{
"width": 2048,
"height": 1365
},
{
"width": 800,
"height": 800
},
{
"width": 1920,
"height": 1080
}
],
"max_sheet_width": 1200
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/image/contact-sheet-layout", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"images":[{"width":1600,"height":900},{"width":1200,"height":1600},{"width":2048,"height":1365},{"width":800,"height":800},{"width":1920,"height":1080}],"max_sheet_width":1200}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"images":[{"width":1600,"height":900},{"width":1200,"height":1600},{"width":2048,"height":1365},{"width":800,"height":800},{"width":1920,"height":1080}],"max_sheet_width":1200}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/image/contact-sheet-layout", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Ejemplo de solicitud
{
"images": [
{
"width": 1600,
"height": 900
},
{
"width": 1200,
"height": 1600
},
{
"width": 2048,
"height": 1365
},
{
"width": 800,
"height": 800
},
{
"width": 1920,
"height": 1080
}
],
"max_sheet_width": 1200
}Ejemplo de respuesta
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "image.contact_sheet_layout",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}La API es asíncrona: la llamada devuelve un task_id al instante y el resultado llega por webhook. El polling está limitado a 1 req/s por tarea.
Precio
Precio publicado — sin tokens ni créditos inventados. Una tarea fallida no se cobra.
Límites
max_mb | 15 |
max_megapixels | 12 |
Errores
| HTTP | Código | Significado |
|---|---|---|
401 | unauthorized | API key ausente o inválida. |
402 | insufficient_balance | El saldo no cubre el precio de la tarea. |
404 | unknown_type | El tipo de tarea no existe. |
429 | rate_limited | Demasiadas peticiones. Use el webhook en vez de sondear. |