¿Qué es un Cloud Optimized GeoTIFF (COG)? Cómo comprobar uno y cómo crear uno

Un Cloud Optimized GeoTIFF no es un formato de archivo nuevo. Es un GeoTIFF común cuyos bytes están organizados para que un programa que lo lee por la red pueda pedir los pocos kilobytes que necesita en lugar del archivo completo. El mismo .tif se sigue abriendo en QGIS, en ArcGIS, en Python, en cualquier cosa que alguna vez haya abierto un TIFF. Un COG es una convención de organización interna, no un formato — vale la pena decirlo primero, porque es el malentendido más común, y porque un archivo que no lo es no está roto, solo está mal organizado para la red.

Todo lo que sigue se corrió el 11 de septiembre de 2026 con GDAL 3.13.3 contra imágenes reales de Sentinel-2. Cuando una afirmación viene de la documentación y no de una prueba propia, lo decimos.

Qué es realmente un COG

Tres propiedades convierten un GeoTIFF en un COG, y las tres viven dentro del mismo archivo.

  • Tiles internos en vez de franjas. Una exportación de escritorio guarda la imagen en franjas de ancho completo — cuántas filas entran en cada una lo decide el codificador, y las nuestras salieron con una fila por franja — así que un cuadrado pequeño en el medio cuesta cientos de ellas. Un COG guarda bloques cuadrados, de 512 píxeles de lado por defecto, así que una ventana son unas pocas lecturas contiguas.
  • Overviews dentro del mismo archivo. Las copias de resolución reducida se escriben antes de los datos de resolución completa — en un archivo -of COG el nivel de pirámide más chico queda en los primeros kilobytes — así que un visor que necesita una miniatura lee la miniatura en vez de decodificar 120 millones de píxeles y descartar la mayoría.
  • Un encabezado que un cliente puede leer en una o dos solicitudes. Los image file directories — los bloques de etiquetas que dicen qué tan grande es la imagen y dónde empieza cada tile — están al principio, así que un cliente los lee una vez y después pide solo los tiles que quiere.

En un archivo real: un asset Sentinel-2 en color verdadero del bucket abierto sentinel-cogs reporta LAYOUT=COG, COMPRESSION=DEFLATE, Band 1 Block=1024x1024 y Overviews: 5490x5490, 2745x2745, 1373x1373, 687x687. Si volvés a escribir los mismos píxeles con gdal_translate -of GTiff -co TILED=NO -co COMPRESS=NONE, esa imagen cuadrada de 10,980 píxeles pasa a pesar 361,747,558 bytes con Band 1 Block=10980x1: una franja por fila, sin overviews, sin compresión. Los mismos píxeles, inútiles en la red.

Cómo comprobar si un GeoTIFF es un COG

El validador en el navegador

La comprobación más rápida no necesita instalar nada: soltá el archivo en el validador de COG. Lee el encabezado en tu navegador con geotiff.js y reporta cuatro cosas. No hay caja de URL y no se sube nada — solo ve el archivo que soltás.

  • Georreferenciado — el archivo lleva un CRS, y un resultado exitoso lo nombra: Georreferenciado (EPSG:32719).
  • Tiles internos — bloques cuadrados en vez de franjas. Un resultado exitoso imprime el tamaño de bloque, Dividido en tiles internos (512×512).; una falla imprime En franjas (striped), sin tiles — el COG requiere tiles internos.
  • Overviews (pirámides) — niveles de resolución reducida dentro del mismo archivo, con el conteo. Una falla imprime Sin overviews (pirámides) — obligatorios para un COG.
  • Compresión — una recomendación, y la que más sorprende. Es una advertencia, nunca una falla. Armamos un archivo con tiles y overviews y -co COMPRESS=NONE, lo soltamos, y la herramienta respondió ✓ Es un COG válido con la línea de compresión como una nota que dice Sin compresión — válido, pero DEFLATE/LZW reducirían el tamaño del archivo. En un archivo que el validador lee como comprimido, esa línea nombra el códec en su lugar.

Entonces el veredicto son las primeras tres juntas. Si falta cualquiera de ellas, el archivo no es un COG; si solo falta la recomendación de compresión, igual lo es. "Un COG tiene que estar comprimido" no pertenece a tu checklist.

gdalinfo, y las tres líneas que son ausencias

Con GDAL instalado, gdalinfo file.tif responde la misma pregunta, y el truco es que cada "no" se imprime como la ausencia total de algo.

  • Los tiles internos son el valor Block= de cada banda. Block=512x512 está tiled; Block=10980x1, el ancho de la imagen por uno, está en franjas (striped).
  • Overviews son una línea Overviews: debajo de la banda que lista cada nivel. Sin pirámide, gdalinfo no dice "ninguna" — no imprime esa línea y ahí termina la estrofa de la banda.
  • Compresión es una línea COMPRESSION= dentro de Image Structure Metadata. Sin compresión es la ausencia de esa línea, no COMPRESSION=NONE.

Una línea que parece una comprobación y no lo es: OVR_RESAMPLING_ALG, que se copia del archivo que hayas convertido. Medimos dos salidas construidas con resampling distinto que imprimen la misma etiqueta y tienen checksums de overview diferentes.

La tercera opción, en Python, es rio cogeo validate, del plugin rio-cogeo para rasterio. No lo corrimos — no está instalado acá, así que esta frase se apoya en su documentación, no en una prueba propia.

Cómo crear un COG con gdal_translate

GDAL trae un driver para esto, así que la conversión es un solo comando: gdal_translate -of COG input.tif output.tif. Eso convirtió el archivo en franjas de 361,747,558 bytes de arriba en un COG de 2,232,769 bytes en unos tres segundos, con Block=512x512, COMPRESSION=LZW y cinco niveles de overview hasta 343 píxeles de lado.

Dos detalles ahí importan. El driver COG comprime por defectoCOMPRESS usa LZW por defecto, por eso esa corrida reporta COMPRESSION=LZW sin pedirlo, así que la afirmación común de que -of COG te deja sin comprimir es falsa en un GDAL moderno. Y construyó cinco niveles de overview donde la fuente tenía cuatro, reduciendo a la mitad hasta que el más chico entra en un bloque: la profundidad de la pirámide sigue a tu imagen, no a la entrada.

Las opciones de creación que importan

Cada una es un flag -co NAME=VALUE en ese comando, y cada número viene de una corrida sobre la misma entrada.

  • COMPRESS-co COMPRESS=DEFLATE para sin pérdida, -co COMPRESS=JPEG para imágenes con pérdida de 8 bits, -co COMPRESS=WEBP para el resultado con pérdida más chico. GDAL reescribe un pedido JPEG sobre datos RGB como COMPRESSION=YCbCr JPEG; eso es esperable, y ahí está la mayor parte del ahorro de JPEG.
  • BLOCKSIZE — el lado del tile, 512 por defecto. -co BLOCKSIZE=1024 hizo el resultado más chico, 1,830,891 bytes contra 2,232,769, porque tiles más grandes y menos numerosos significan menos contabilidad interna. El trade-off es granularidad: un cliente que quiere un píxel trae un cuadrado de 1024 píxeles.
  • OVERVIEW_RESAMPLING — cómo se reduce la resolución de la pirámide, como en -co OVERVIEW_RESAMPLING=NEAREST. Usá nearest para rásters categóricos como cobertura del suelo, donde promediar dos códigos de clase inventa un tercero; promediar es mejor para datos continuos.
  • OVERVIEWS-co OVERVIEWS=NONE suprime la pirámide, y está acá como una advertencia y no como una recomendación.
  • BIGTIFF-co BIGTIFF=YES cambia a offsets de 64 bits, necesario cuando un archivo se acerca al techo de 4 GiB del TIFF clásico. Es invisible en gdalinfo y visible en los primeros cuatro bytes del archivo, II* para el clásico contra II+ para BigTIFF. Forzarlo costó 3,364 bytes extra acá.

OVERVIEWS=NONE es la trampa más filosa del driver: GDAL igual escribe LAYOUT=COG, porque produjo un archivo con layout de COG que da la casualidad de que tiene un solo nivel de resolución, y el validador entonces lo hace fallar por overviews. La etiqueta de layout no es el veredicto. Fijate en el conteo de overviews en su lugar.

Compresión, medida en una ventana

Estas seis corridas parten de una misma ventana de 2048 píxeles de lado, tres bandas, de una imagen de desierto sin nubes. No son una tabla universal — una escena mayormente vacía comprime mucho mejor, por eso la ventana es 100 % píxeles válidos.

  • Sin comprimir — 16,517,434 bytes, la base.
  • LZW, el valor por defecto del driver — 15,929,384 bytes, apenas 4 % menos. LZW se justifica en rásters planos o sintéticos, no en fotografía.
  • DEFLATE — 13,094,841 bytes, 21 % menos, y sin pérdida: los checksums coinciden con el original en las tres bandas.
  • JPEG — 1,047,694 bytes con la calidad por defecto de 75, un recorte del 94 %, y con pérdida: los checksums difieren en cada banda. Con calidad 90 son 1,815,578 bytes, un recorte del 89 % con daño visiblemente menor.
  • WEBP — 828,166 bytes, el más chico de los seis, y con pérdida por defecto.

La elección depende de para qué es el ráster: sin pérdida para todo lo que vayas a medir, con pérdida para imagen de fondo que un humano solo mira.

Por qué importa: el range request

Todo esto existe por una sola característica de HTTP. Un servidor que responde Accept-Ranges: bytes le permite a un cliente pedir un tramo de bytes y recibir 206 Partial Content en vez del archivo completo, y un COG es el arreglo que hace que esos pedidos caigan sobre algo útil. Lo medimos contra un COG Sentinel-2 de 313,765,265 bytes leído por /vsicurl/, sin copia local.

  • Leer el encabezado completo y la lista de overviews — tamaño, CRS, layout de bloques, cada nivel de pirámide — costó 2 solicitudes GET y 16,716 bytes, o 0.005 % del archivo.
  • Extraer una ventana de 2048 píxeles de lado del medio costó 7 solicitudes GET y 22,672,068 bytes, o 7.2 % del archivo.

Contra un GeoTIFF en franjas y sin comprimir, las dos cuestan el archivo completo.

Una salvedad, sobre los navegadores. Nuestro visor de GeoTIFF acepta una URL, y la caja de URL descarga el archivo completo antes de renderizar nada. Lo confirmamos en un navegador real: la primera solicitud es un GET simple sin encabezado Range que devuelve 200 y trae el 100 % del archivo, y recién ahí el renderer hace lecturas 206 genuinas por rangos — que no cuestan bytes extra, porque el cuerpo ya está en caché. Así que pegá una URL cuando el archivo es chico y descargalo cuando no lo es. Soltar el archivo es el único modo que tiene el validador de todas formas.

Archivos de prueba que podés usar

Cada URL acá se pidió el 11 de septiembre de 2026 con un user agent de navegador, registrando el status, Accept-Ranges, el header de CORS y el tamaño total. Una lista así se pudre, así que leela como una foto de un día y una red.

Un hábito primero: revisá el content type antes de llamar ráster a una URL. Un 206 solo prueba que el servidor soporta rangos de bytes, y un montón de páginas HTML también responden 206 — seis lo hicieron en nuestra campaña paralela de fuentes de elevación. Los rásters de abajo responden todos content-type: image/tiff.

  • Sentinel-2 en AWS, encontrado con una búsqueda y no con una clave adivinada. El bucket sentinel-cogs guarda cada escena Sentinel-2 Level-2A como COG, abierto y con CORS abierto: 206, accept-ranges: bytes, access-control-allow-origin: *. No copies una ruta de escena de un tutorial — los ids de escena codifican una fecha, y una clave vecina adivinada devuelve 404 NoSuchKey, que parece un bucket muerto y en realidad es una clave equivocada. Consultá la API STAC en cambio: mandá un bounding box y un rango de fechas a el endpoint de earth-search y usá los hrefs de assets que devuelve. El documento de la colección responde 200 y no pone accept-ranges, por ser un catálogo y no un archivo. Licencia: los datos Copernicus Sentinel son libres y abiertos bajo los términos de Copernicus, con atribución.
  • Una escena chica que podés pegar directo en el visor. pesa 1,412,993 bytes. En un navegador real transfirió 1,413,682 bytes en 2 solicitudes: ✓ COG válido, 4 tiles · EPSG:32723, 6.3 segundos.
  • Una más grande, también verificada en un navegador. pesa 5,810,809 bytes, y transfirió 5,811,498 bytes en 5 solicitudes: ✓ COG válido, 84 tiles · EPSG:32723, 16 segundos.
  • El tamaño de un asset es una propiedad de la escena, no del nombre de la banda. Misma colección, mismo día: TCI.tif pesaba 1,412,993 bytes sobre la costa de São Paulo y 313,765,265 bytes sobre el Atacama, una diferencia de 222 veces, porque la primera escena es 90 % nodata enmascarada por nubes. Fijate el tamaño en el resultado de la búsqueda antes de pegar una URL; por encima de unos 64 MiB, descargá en cambio.
  • Elevación USGS 3DEP, abierta y demasiado grande para pegar. responde 206 con accept-ranges: bytes y access-control-allow-origin: *, y pesa 222,936,410 bytes. Un COG genuino, pero la caja de URL traería los 212.6 MiB completos primero. Descargalo y soltalo. Licencia: dominio público de EE. UU.
  • Copernicus GLO-30, que funciona en todos lados menos en una app de navegador. responde 206 con accept-ranges: bytes y pesa 44,155,932 bytes, pero no manda header access-control-allow-origin. Un cliente HTTP simple lo lee sin problema; una página de navegador no puede. Lo pegamos en el visor para estar seguros, y el navegador lo rechazó en el preflight de CORS sin que cruzara ni un byte. Licencia: los términos del DEM de Copernicus en el readme del bucket, que exigen atribución.
  • OpenTopography, el host más amigable que medimos. es un tile SRTM de un grado, de 15,340,529 bytes: 206, cross-origin permitido, y el único host de esta tanda que también expone Content-Range a los scripts de la página. No lo cargamos nosotros mismos en el visor, así que por ahora descargalo y soltalo. Licencia: según el dataset, en OpenTopography.
  • Una que está muerta, para que dejes de buscar. El índice de eventos de Maxar Open Data en maxar-opendata.s3.amazonaws.com/events/index.html todavía aparece enlazado por todos lados y hoy devuelve 404 NoSuchKey, igual que varios directorios de descarga de NASA LP DAAC en tutoriales viejos. Cuando una ruta S3 da 404, fijate si el bucket responde antes de concluir que los datos desaparecieron.

Las fuentes de elevación tienen un tratamiento más largo, con resolución, datum vertical y cobertura, en nuestra lista de fuentes gratuitas de datos de elevación DEM.

Los errores explicados

Cuando una herramienta rechaza tu ráster o lo renderiza dolorosamente lento, casi siempre es uno de estos casos.

  • En franjas, no en tiles. Block=<width>x1 en gdalinfo; el archivo tiene que leerse casi de punta a punta para entregar cualquier ventana. Solucionalo con gdal_translate -of COG.
  • En franjas y grande, que es cuando un visor se detiene y pregunta. Nuestro visor clasifica los rásters en cuatro niveles y solo el de franjas-y-grande interrumpe: por encima de 100 megapíxeles, unos 10,000 píxeles de lado, un archivo en franjas recibe el encabezado Este TIFF no es cloud-optimized, un botón Cargar de todos modos y una sugerencia de convertir a COG. Un archivo en franjas de 4 megapíxeles se renderiza sin advertencia, y lo mismo pasa con uno de 120 megapíxeles que está tiled pero no tiene pirámide, etiquetado tiled, sin overviews — el umbral se consulta solo en la rama de franjas.
  • Un sidecar .ovr externo no cuenta. Una pirámide construida al lado del archivo en vez de adentro cae en un segundo objeto, file.tif.ovr. Bien en un disco local, inútil por HTTP: un cliente que pidió file.tif tiene un solo objeto y los overviews están en otro que no tiene motivo para pedir. Un validador de navegador no puede ver un sidecar que no soltaste.
  • JPEG donde correspondía DEFLATE. JPEG-en-TIFF es dramáticamente más chico — 1,047,694 bytes contra 13,094,841 en nuestra ventana — y cambia los valores de tus píxeles. En elevación, reflectancia o cualquier cosa que dependa de un límite de clase, eso es corrupción de datos con un archivo más chico.
  • El techo de 4 GiB. El TIFF clásico usa offsets de 32 bits, así que un archivo no puede superar los 4 GiB. Más allá de eso necesitás BigTIFF, con offsets de 64 bits y un número mágico distinto, II+ en vez de II*. Nada en gdalinfo lo anuncia, así que si un archivo grande no abre en software viejo, revisá los bytes mágicos antes de culpar a los datos.

Servir COGs sin correr GDAL vos mismo

Convertir un archivo es un comando; convertir cada ráster que sube un equipo de campo, mantener las pirámides al día y servir los tiles es un pipeline, y esa es la parte que hace Geodocs. Las dos herramientas de arriba son gratis y no piden cuenta: revisá un archivo, o abrí uno en un mapa. Para la convención en sí, mirá el sitio de la especificación y la página del driver COG de GDAL.

Artículos Relacionados

Navegação