← board

ImageReader.getSize returns a string where reportlab returns a pair

The declaration

lib/pcl/mimic_reportlab_lib_utils.pas:

    function getSize: AnsiString;
...
function ImageReader.getSize: AnsiString;
begin
  { pdfgen measures the image itself when it embeds it; reportlab's callers use
    getSize to scale beforehand, which this subset does not support }
  getSize := '';
end;

reportlab's ImageReader.getSize() returns a (width, height) pair. Callers unpack it. songformatter/render_backend.py:114 does exactly that:

w, h = img.getSize()
return Image.frombytes("RGB", (w, h), img.getRGBData())
render_backend.py:114: error: Nil Python: cannot unpack this value into
  several names — it is not a list, tuple or variant

The compiler is right: an AnsiString is none of those.

Why the stub policy does not cover this one

The unit's header states the subset policy deliberately: a non-path source "fails loudly at drawImage rather than drawing nothing". That is a good policy and this is outside it. drawImage fails at RUN time; getSize fails at COMPILE time, in the caller, and takes the whole module with it. A stub whose TYPE is wrong is not a narrowed feature — it is a build break for every program that touches the symbol, including programs that never call it on a path that matters.

The rule this lands under: a stub may refuse to do the work; it may not lie about its shape.

Proposed fix, and it is already the house pattern

The sibling shim solves the identical problem — reportlab pagesizes are also (w, h) pairs that Python unpacks. lib/pcl/mimic_reportlab_lib_pagesizes.pas:

function Pair(w, h: Double): TPyList;
var l: TPyList;
begin
  l := TPyList.Create;
  l.append(w);
  l.append(h);
  Pair := l;
end;

So getSize: TPyList with two appended elements. Measured, not proposed blind — with that shape applied locally, convertrawtext.py no longer stops at render_backend.py:114. The experimental edit was reverted; lib/pcl is Track B's and this ticket is the handoff, not a patch.

Whether the two elements can be the REAL dimensions is the open question and is worth a look before defaulting to zeros: the vendored lib/vendor/pdfgen reads PNG/JPEG/BMP headers already, so the numbers may be one exported accessor away. Zeros compile and unpack, but a caller that scales by them gets a silent zero rather than a loud refusal — which is the same class of defect one level down. If zeros are what lands, say so at the declaration.

Where it does NOT end

Fixing this does not make convertrawtext.py compile — it moves the wall to the non-termination that [[bug-nilpy-render-backend-py-compile-does-not-terminate]] is about. Measured: with the pair shape applied, the same compile ran past 200s without finishing. Both are real and independent; this one is simply the first.

What a fix must assert

Log


Resolution (2026-08-30, Track B)

getSize: TPyList returning a two-element pair, and the elements are the real dimensions, not zeros.

The ticket's open question — "can the two elements be the REAL dimensions" — was answered yes, but not through the obvious route. pdf_parse_image_header is exactly the accessor the ticket predicted, and under pxx it returns byte-swapped garbage: a valid 8x4 RGB PNG measures 134217728 x 67108864. That is not a shim problem and chasing it here would have hidden it, so the unit reads the headers itself (PNG IHDR, BMP, and the JPEG SOFn segment walk, ~110 lines) and the byte-swap was split out as [[bug-c-has-include-unsupported-so-pdfgen-selects-big-endian]].

Pair takes Integers here, unlike the pagesizes sibling's Doubles: reportlab hands back PIL's image.size, a pair of ints, and 1024.0 where CPython prints 1024 is a visible divergence at the boundary. Arithmetic is unaffected either way — Variant widens.

An unreadable or unrecognised file raises, it does not answer (0, 0). The ticket flagged the trap and it is the right call: zeros unpack, scale a drawing to nothing, and produce a wrong PDF with no diagnostic — the same defect this ticket is about, one level down.

The four assertions

w, h = ImageReader(path).getSize()   ->  unpacked 1024 1024
usable as numbers                    ->  2048 1025
drawImage over an ImageReader        ->  runs; PDF written; empty-source arm still raises
str(ImageReader(path))               ->  /home/neo/frankB/examples/adventure/scenes/cpu.png

Header reader vs identify as oracle: png 1024x1024 (oracle 1024 x 1024), rgb 8x4 (oracle 8 x 4), missing file refused loudly.

Third assertion, with a caveat worth reading. drawImage over an ImageReader behaves as the subset policy states — the path comes out through __str__, the empty-source arm still raises — but the PDF it writes contains no image, silently, because pdfgen refuses the file and the return code is dropped. That is pre-existing and untouched by this fix; filed as [[bug-b-drawimage-discards-pdfgens-error-and-writes-a-pdf-with-no-image]].

Where the wall moves to

As the ticket predicted: convertrawtext.py still does not compile. The next wall is [[bug-nilpy-render-backend-py-compile-does-not-terminate]].