Solución:
De acuerdo con la sección de Sintaxis y estructura de la página JPEG en wikipedia, el ancho y alto de la imagen no parecen estar almacenados en la imagen en sí, o, al menos, no de una manera que sea fácil de encontrar.
Aún así, citando las preguntas frecuentes sobre compresión de imágenes JPEG, parte 1/2:
Tema: [22] ¿Cómo puede mi programa extraer las dimensiones de la imagen de un archivo JPEG?
El encabezado de un archivo JPEG consta de una serie de bloques, llamados “marcadores”.
La altura y el ancho de la imagen se almacenan en un marcador de tipo SOFn (Inicio de fotograma, tipo N).
Para encontrar el SOFn debe omitir los marcadores anteriores; no es necesario que sepas qué hay en los otros tipos de marcadores, solo usa sus palabras de longitud para omitirlos.
La lógica mínima necesaria es quizás una página de código C.
(Algunas personas han recomendado buscar simplemente el par de bytes que representa SOFn, sin prestar atención a la estructura del bloque de marcador. Esto no es seguro porque un marcador anterior podría contener el patrón SOFn, ya sea por casualidad o porque contiene una imagen en miniatura comprimida en JPEG. Si no sigue la estructura del marcador, recuperará el tamaño de la miniatura en lugar del tamaño de la imagen principal).
Un ejemplo profusamente comentado en C se puede encontrar en rdjpgcom.c en la distribución IJG (ver parte 2, ítem 15).
El código Perl se puede encontrar en wwwis, desde http://www.tardis.ed.ac.uk/~ark/wwwis/.
(Ergh, ese vínculo parece roto …)
Sin embargo, aquí hay una parte del código C que podría ayudarlo: Decodificar el ancho y el alto de un archivo JPEG (JFIF)
Esta función leerá las propiedades de JPEG
function jpegProps(data) { // data is an array of bytes
var off = 0;
while(off<data.length) {
while(data[off]==0xff) off++;
var mrkr = data[off]; off++;
if(mrkr==0xd8) continue; // SOI
if(mrkr==0xd9) break; // EOI
if(0xd0<=mrkr && mrkr<=0xd7) continue;
if(mrkr==0x01) continue; // TEM
var len = (data[off]<<8) | data[off+1]; off+=2;
if(mrkr==0xc0) return {
bpc : data[off], // precission (bits per channel)
w : (data[off+1]<<8) | data[off+2],
h : (data[off+3]<<8) | data[off+4],
cps : data[off+5] // number of color components
}
off+=len-2;
}
}