La cadena: 5 recetas nuevas (girara, xxhash, poppler-glib, zathura,
zathura-pdf-poppler) y 5 promociones GRATIS al corpus (json-glib, lcms2, glib-shared,
pcre2-shared, bzip2-shared — todas con hash idéntico desde la cola y desde el corpus,
medido con hammer hash antes de mover nada).
NO va en escritorio-kde, y está escrito en tres sitios para que no se liste por
descuido: su backend necesita una poppler con ENABLE_GLIB=ON, y esa imagen ya trae la
de Qt6 vía okular. Las dos instalan /usr/lib/libpoppler.so.146 y son artefactos
DISTINTOS ⇒ hidratar las dos pone dos ficheros en la misma ruta. La salida no sería
listarla igual, sería jubilar una de las dos popplers.
LAS TRES COSAS QUE SE ROMPIERON, que valen más que las recetas:
1. -DENABLE_GLIB=ON SE APAGA SOLO Y EL BUILD SALE OK. CMakeLists:260 hace
`if(NOT CAIRO_FOUND) set(ENABLE_GLIB OFF)`: no falla, obedece distinto. El primer
artefacto selló sin nada de glib, exit 0, sin aviso. La causa era una línea que este
repo ya tiene como patrón: `.pc Requires` → `[deps].build`. cairo.pc pide pixman-1 y
pixman no estaba declarado ⇒ `pkg-config --exists cairo` falso ⇒ CAIRO_FOUND falso.
Un .pc que falta a tres saltos apaga una FUNCIÓN, no una librería. La receta ahora
comprueba en install que poppler-glib.pc y libpoppler-glib.so existan.
2. DOS COPIAS ESTÁTICAS DE GObject EN UN PROCESO. Con la glib estática del corpus todo
sella y zathura arranca — y al dlopen del plugin escupe «cannot register existing
type 'gchar'» y no abre nada. No son dos ficheros en una ruta: son dos copias del
sistema de tipos dentro del mismo proceso, una en el ejecutable y otra dentro de
libpoppler-glib.so. Un .a NO duplica (sólo tiene símbolos sin definir, se resuelven
al ligar); el problema aparece sólo cuando dos objetos enlazados por separado meten
cada uno la suya. Arreglo: las TRES recetas de la cadena declaran glib-shared.
3. FUGA AL LAB, cazada por scripts/vigia-sonames.py: zathura selló con
NEEDED libsqlite3.so.0, un SONAME que ningún artefacto del cierre publica — meson
había resuelto dependency('sqlite3') contra el sysroot Alpine DEL LAB. Y declarar la
dep NO alcanzó: el .pc da un -lsqlite3 pelado y el linker prefiere la .so del lab
sobre la .a del store. Lo arregla -Dprefer_static=true. Medido: los NEEDED bajaron de
DIEZ a CUATRO y los cuatro los publica el cierre.
DOS DEFECTOS DE IMAGEN PREEXISTENTES que salieron de paso:
- libbz2.so.1 no lo publicaba nadie y freetype-shared lo pide, en los TRES perfiles.
Se vio de verdad al probar el visor (el plugin no hacía dlopen). bzip2-shared existía
sólo en incoming-kde; promovida y puesta de raíz junto a expat-shared/libffi-shared.
- escritorio-gnome NO TRAÍA NI UN FICHERO DE FUENTE. Contado sobre los artefactos del
cierre: gnome=0, sway=22, kde=1 (una de rebote dentro de qtbase). Tenía fontconfig,
que es el MOTOR que busca fuentes, no una fuente. Un PDF con base-14 se ve VACÍO y sin
error. Añadida dejavu-fonts, la única receta de fuentes del catálogo entero.
⚠ KDE queda igual y NO se toca acá: no lleva zathura y su árbol lo trabaja otro frente.
EVIDENCIA DE QUE ANDA, no de que sella:
- `zathura --version` con el plugin lista «(plugin) pdf-poppler (2026.07.18)» sin un
solo GObject-CRITICAL.
- poppler-render-check, receta-TESTIGO en el espíritu de gtk4-hello: arma un PDF a mano,
lo abre con poppler-glib, lo rasteriza sobre cairo y CUENTA PÍXELES — 9600 negros,
exactamente el rectángulo de 160x60. Un lienzo blanco no pasa. Su primera versión
medía el TEXTO y falló: el sandbox no tiene fuentes, que es cómo se descubrió el
hueco de arriba. El assert quedó sobre el rectángulo, que no depende de tipografía, y
el texto se informa aparte.
Los cinco grafos quedan en N/N con cero deuda.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XB2iEmxeLZgzqNfhWChrLo
128 lines
6.4 KiB
TOML
128 lines
6.4 KiB
TOML
# poppler-render-check — receta-TESTIGO del camino de PDF, en el espíritu de `gtk4-hello`:
|
|
# no aporta nada a ninguna imagen, prueba que la cadena SIRVE y no sólo que sella.
|
|
#
|
|
# ══ QUÉ PRUEBA, Y POR QUÉ HACÍA FALTA ══════════════════════════════════════════════════════════
|
|
# `zathura` es GTK4: sin compositor no abre ventana, así que «arranca» no se puede comprobar de la
|
|
# forma barata. Pero lo que de verdad importaba comprobar no es la ventana: es que
|
|
# **`poppler-glib` decodifique y RASTERICE**, que es exactamente el camino que recorre
|
|
# `zathura-pdf-poppler/render.c` — `poppler_document_new_from_file` → `poppler_page_render` sobre
|
|
# un surface de cairo. Eso sí se puede correr sin display, y es lo que hace este programa.
|
|
#
|
|
# Escribe un PDF mínimo A MANO (catálogo, páginas, una página con un rectángulo relleno Y texto
|
|
# Helvetica, más su xref), lo renderiza y comprueba tres cosas MEDIDAS, no un exit code:
|
|
# 1. que el documento abra y reporte 1 página de 200x100,
|
|
# 2. que la imagen tenga PÍXELES NEGROS — o sea que algo se DIBUJÓ. Sin esto, un render que
|
|
# devuelve un lienzo blanco pasa la prueba, que es el modo de fallar que este repo persigue
|
|
# (el mismo criterio que contar colores del PPM en el arranque de sway),
|
|
# 3. que el PNG salga y tenga cabecera PNG de verdad.
|
|
#
|
|
# ══ POR QUÉ EL ASSERT ES SOBRE UN RECTÁNGULO Y NO SOBRE EL TEXTO ═══════════════════════════════
|
|
# La primera versión de esta receta dibujaba SÓLO texto y **falló**, con `pixeles_oscuros=0` y un
|
|
# `some font thing failed` de poppler. No es un fallo de la cadena: es que el sandbox de build no
|
|
# tiene NI UNA FUENTE, y las «base-14» de PDF (Helvetica, Times…) no vienen dentro del documento —
|
|
# el visor tiene que sustituirlas por fontconfig. Un rectángulo no depende de eso, así que aísla lo
|
|
# que esta receta quiere probar (¿decodifica y rasteriza?) de lo que no le toca (¿hay fuentes?).
|
|
# El texto se dibuja igual y se INFORMA aparte, sin condicionar el veredicto — así queda a la vista
|
|
# si algún día el sandbox sí tiene fuentes.
|
|
#
|
|
# ⚠ **Y deja una consecuencia escrita para las imágenes:** un PDF con fuentes base-14 se ve VACÍO
|
|
# si la imagen no trae fuentes. Los tres perfiles que llevan zathura tienen que traerlas; no es
|
|
# problema de esta receta pero es donde se descubre.
|
|
#
|
|
# Reutiliza el tarball de poppler sólo como acarreo de `[source]`; ignora su árbol.
|
|
name = "poppler-render-check"
|
|
version = "25.02.0"
|
|
license = "GPL-2.0-or-later"
|
|
|
|
[source]
|
|
tarball = "https://poppler.freedesktop.org/poppler-25.02.0.tar.xz"
|
|
sha256 = "21234cb2a9647d73c752ce4031e65a79d11a511a835f2798284c2497b8701dee"
|
|
|
|
[build]
|
|
compiler = "zig-cc"
|
|
target = "x86_64-linux-musl"
|
|
link = "dynamic"
|
|
|
|
[build.phases]
|
|
configure = "true"
|
|
compile = '''
|
|
set -e
|
|
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
|
|
cat > check.c <<'CEOF'
|
|
#include <poppler.h>
|
|
#include <cairo.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
int main(void) {
|
|
GError *e = NULL;
|
|
char *uri = g_filename_to_uri("/src/prueba.pdf", NULL, &e);
|
|
PopplerDocument *doc = poppler_document_new_from_file(uri, NULL, &e);
|
|
if (!doc) { fprintf(stderr, "FALLO: no abre el PDF: %s\n", e ? e->message : "?"); return 1; }
|
|
int n = poppler_document_get_n_pages(doc);
|
|
PopplerPage *pg = poppler_document_get_page(doc, 0);
|
|
double w, h; poppler_page_get_size(pg, &w, &h);
|
|
printf("paginas=%d tamano=%.0fx%.0f\n", n, w, h);
|
|
if (n != 1 || (int)w != 200 || (int)h != 100) { fprintf(stderr, "FALLO: geometria inesperada\n"); return 1; }
|
|
cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)w, (int)h);
|
|
cairo_t *cr = cairo_create(s);
|
|
cairo_set_source_rgb(cr, 1, 1, 1); cairo_paint(cr);
|
|
poppler_page_render(pg, cr);
|
|
cairo_destroy(cr);
|
|
cairo_surface_flush(s);
|
|
/* Tercera comprobacion: contar pixeles oscuros. Un lienzo blanco NO puede pasar. */
|
|
unsigned char *d = cairo_image_surface_get_data(s);
|
|
int stride = cairo_image_surface_get_stride(s), oscuros = 0;
|
|
for (int y = 0; y < (int)h; y++)
|
|
for (int x = 0; x < (int)w; x++) {
|
|
unsigned char *px = d + y * stride + x * 4;
|
|
if (px[0] < 100 && px[1] < 100 && px[2] < 100) oscuros++;
|
|
}
|
|
printf("pixeles_oscuros=%d\n", oscuros);
|
|
/* El rectangulo son 160x60 = 9600 px. Con la mitad ya esta probado que rasterizo. */
|
|
if (oscuros < 4000) { fprintf(stderr, "FALLO: se renderizo un lienzo vacio\n"); return 1; }
|
|
printf("texto_base14=%s (informativo: depende de que haya fuentes, no de esta cadena)\n",
|
|
oscuros > 9600 + 50 ? "si" : "no");
|
|
if (cairo_surface_write_to_png(s, "salida.png") != CAIRO_STATUS_SUCCESS) {
|
|
fprintf(stderr, "FALLO: no escribe PNG\n"); return 1;
|
|
}
|
|
printf("OK: poppler-glib abre, rasteriza y dibuja\n");
|
|
return 0;
|
|
}
|
|
CEOF
|
|
zig cc -mcpu=baseline check.c -o check $(pkg-config --cflags --libs poppler-glib cairo)
|
|
'''
|
|
install = '''
|
|
set -e
|
|
# El PDF de prueba se arma acá y no se versiona: son 583 bytes de estructura PDF a mano.
|
|
python3 - <<'PYEOF'
|
|
objs = [
|
|
b"<< /Type /Catalog /Pages 2 0 R >>",
|
|
b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
|
|
b"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 100] /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>",
|
|
None,
|
|
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
|
|
]
|
|
# Rectangulo relleno (no depende de fuentes) + texto (si que depende). Ver la cabecera.
|
|
stream = b"0 0 0 rg 20 20 160 60 re f\nBT /F1 12 Tf 30 45 Td 1 1 1 rg (HAMMER OK) Tj ET"
|
|
objs[3] = b"<< /Length %d >>\nstream\n" % len(stream) + stream + b"\nendstream"
|
|
out = b"%PDF-1.4\n"; offs = []
|
|
for i, o in enumerate(objs, 1):
|
|
offs.append(len(out)); out += b"%d 0 obj\n" % i + o + b"\nendobj\n"
|
|
xref = len(out)
|
|
out += b"xref\n0 %d\n" % (len(objs) + 1) + b"0000000000 65535 f \n"
|
|
for off in offs: out += b"%010d 00000 n \n" % off
|
|
out += b"trailer\n<< /Size %d /Root 1 0 R >>\nstartxref\n%d\n%%%%EOF\n" % (len(objs) + 1, xref)
|
|
open("/src/prueba.pdf", "wb").write(out)
|
|
PYEOF
|
|
./check
|
|
head -c 8 salida.png | od -An -tx1 | grep -q "89 50 4e 47" || { echo "FALLO: el PNG no tiene cabecera PNG" >&2; exit 1; }
|
|
mkdir -p /out/usr/share/poppler-render-check
|
|
cp salida.png /out/usr/share/poppler-render-check/
|
|
'''
|
|
|
|
[deps]
|
|
build = ["pkgconf", "python3", "poppler-glib", "glib-shared", "pcre2-shared", "cairo", "pixman",
|
|
"libffi", "zlib", "zlib-shared", "bzip2-shared",
|
|
"freetype-shared", "fontconfig-shared", "expat", "lcms2",
|
|
"libjpeg-turbo-shared", "libpng-shared"]
|