STUDIO B12  Büro für digitale Kommunikation  T  0531 28 853 78 0  E  info@studio-b12.de

Abmessungen eines JPGs auslesen ohne das Bild komplett zu laden

In dem Blog von Antti Kupila (ganz nebenbei – er ist einer der Crew12) habe ich eine AS3-Klasse gefunden, die ich schon in vielen Projekt hätte gebrauchen können (wenn sie denn AS3 gewesen wären): eine Klasse (JPGSizeExtractor.as), die mir vor dem Laden eines Bildes schon die Abmessungen, sprich width und height, des zu ladenen Bildes wiedergibt. Mit der Info kann man dann wunderbar schon Rahmen, Hintergründe zeichen, bevor das Bild geladen ist…

Das ganze funktioniert dadurch, dass Antti bei Laden jedes einzelne Byte sofort analysiert. Wenn er dann den JFIF-Header in der jpg-Datei findet, kann er die Größe des Bildes auslesen und den Ladevorgang abbrechen.

Leider warnt er auch davor, dass diese Technik nicht bei allen JPGs funktionieren soll, da bei einigen die Headerinformation nicht gefunden werden kann. Also Fallback-Lösung einplanen in den Projekten…

Die Analyse der Bytes ist etwas komplizierter, aber in kurzen Worten gefaßt: In einem Hex-Editor wird einem ein JPG-Bild mit seinen Hex-Nummern angezeigt. Dort sucht man jetzt einfach nach der gewünschten Hex-Kombination (0xFF 0xC0 0x00 0x11 0x08), die für die Größe des Bildes steht. Diese Kombi sucht dann die Klasse und liest dementsprechend die Werte aus:

Hex-Werte eines JPG Bild

Hier der komplette Code dafür:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
protected function progressHandler( e : ProgressEvent ) : void {
dataLoaded = bytesAvailable;
var APPSections : Array = new Array( );
for ( var i : int = 1; i <16; i++ ) {
APPSections[ i ] = [ 0xFF, 0xE0 + i ];
}
var index : uint = 0;
var byte : int = 0;
var address : int = 0;
while ( bytesAvailable>= SOF0.length + 4 ) {
var match : Boolean = false;
// Only look for new APP table if no jump is in queue
if ( jumpLength == 0 ) {
byte = readUnsignedByte( );
address++;
// Check for APP table
for each ( var APP : Array in APPSections ) {
if ( byte == APP[ index ] ) {
match = true;
if ( index+1>= APP.length ) {
if ( traceDebugInfo ) trace( "APP" + Number( byte - 0xE0 ).toString( 16 ).toUpperCase( ) +  " found at 0x" + address.toString( 16 ).toUpperCase( ) );
// APP table found, skip it as it may contain thumbnails in JPG (we don't want their SOF's)
jumpLength = readUnsignedShort( ) - 2; // -2 for the short we just read
}
}
}
}
// Jump here, so that data has always loaded
if ( jumpLength> 0 ) {
if ( traceDebugInfo ) trace( "Trying to jump " + jumpLength + " bytes (available " + Math.round( Math.min( bytesAvailable / jumpLength, 1 ) * 100 ) + "%)" );
if ( bytesAvailable>= jumpLength ) {
if ( traceDebugInfo ) trace( "Jumping " + jumpLength + " bytes to 0x" + Number( address + jumpLength ).toString( 16 ).toUpperCase( ) );
jumpBytes( jumpLength );
match = false;
jumpLength = 0;
} else break; // Load more data and continue
} else {
// Check for SOF
if ( byte == SOF0[ index ] ) {
match = true;
if ( index+1>= SOF0.length ) {
// Matched SOF0
if ( traceDebugInfo ) trace( "SOF0 found at 0x" + address.toString( 16 ).toUpperCase( ) );
jpgHeight = readUnsignedShort( );
jpgWidth = readUnsignedShort( );
if ( traceDebugInfo ) trace( "Dimensions: " + jpgWidth + " x " + jpgHeight );
removeEventListener( ProgressEvent.PROGRESS, progressHandler ); // No need to look for dimensions anymore
if ( stopWhenParseComplete && connected ) close( );
dispatchEvent( new Event( PARSE_COMPLETE ) );
break;
}
}
if ( match ) {
index++;
} else {
index = 0;
}
}
}
}
protected function jumpBytes( count : uint ) : void {
for ( var i : uint = 0; i
readByte( );
}
}

Download der Klasse, mit einem Beispiel

Bookmark and Share

Dein Kommentar