Code archives/File Utilities/HOT.IFFILBMloader

This code has been declared by its author to be Public Domain code.

Download source code

HOT.IFFILBMloader by Hotcakes2005
Used exactly like the png/jpg/bmp loaders, this module attaches itself to LoadPixmap (and LoadImage) to provide support for IFF ILBM images (of Amiga days).

An extra function allows the loading of images with alternate Colour Maps (palettes).

http://members.dodo.com.au/~tzuyd/hotmods.rar
Strict

Rem
bbdoc: IFF ILBM loader
End Rem
Module HOT.IFFILBMLoader

ModuleInfo "Version: 1.00"
ModuleInfo "Author: Toby Zuijdveld"
ModuleInfo "License: Blitz Shared Source Code"
ModuleInfo "Copyright: Jerry Morrison, Electronic Arts (public domain)"
ModuleInfo "Modserver: n/a"

ModuleInfo "History: 1.00 Release"

Import BRL.Pixmap
Import BRL.EndianStream

Private

Function ReadTag$( stream:TStream )
	Local tag:Byte[4]
	If stream.ReadBytes( tag,4 )<>4 Return
	Return Chr(tag[0])+Chr(tag[1])+Chr(tag[2])+Chr(tag[3])
End Function

Function UStoSI%(a:Short)
	If a>$7FFF Then Return -($8000-(a-$8000)) Else Return a
End Function	' unsigned short to signed integer

Rem
	"cmpByteRun1" is the byte run encoding
End Rem ' End Rem
Const	cmpNone		= 0
Const	cmpByteRun1	= 1

Global	ColourMapRed[]	= Null
Global	ColourMapGreen[]
Global	ColourMapBlue[]	' dodginess!

Public

Rem
bbdoc: Preload a Colour Map for use when loading future ILBM images
about:
#IFFCMAP loads CMAP information from the given @url file.<br>
<br>
Every subsequent ILBM image will be loaded using this palette.<br>
<br>
By default, the CMAP information stored with an ILBM picture would be used.  To restore that behaviour, use #IFFCMAP without a @url specified.<br>
If the Colour Map cannot be loaded, 0 is returned and this function's default behaviour will apply.<br>
End Rem
Function IFFCMAP( url:Object="" )
	If url=""
		ColourMapRed	= Null
		ColourMapGreen	= Null
		ColourMapBlue	= Null
		Return 1
	EndIf
	Local stream:TStream=ReadStream( url )
	If Not stream
		ColourMapRed	= Null
		ColourMapGreen	= Null
		ColourMapBlue	= Null
		Return 0
	EndIf
	stream	= BigEndianStream(stream)
	If ReadTag( stream )<>"FORM" Return
	Local	dud%	= stream.Readint()	' length of file after ILBM header
	If ReadTag( stream )<>"ILBM" Return
	Local	cmap%	= 0
	Local	i%		= 0
	Local	n%		= 0
	While Not stream.Eof()
		Local blahblah$=ReadTag$(stream)
		Select	blahblah$'Readtag$(stream)
			Case	"CMAP"	' ColorMap
				dud		= stream.ReadInt()	' length of ColourMap chunk
				cmap	= dud/3
				ColourMapRed	= ColourMapRed[..cmap+1]
				ColourMapGreen	= ColourMapGreen[..cmap+1]
				ColourMapBlue	= ColourMapBlue[..cmap+1]
				For i=1 To cmap
					ColourMapRed[i]		= stream.ReadByte()
					ColourMapGreen[i]	= stream.ReadByte()
					ColourMapBlue[i]	= stream.ReadByte()
				Next	' i=1 To cmap
				n=1
				Exit
			Default			' unsupported chunks
				stream.SkipBytes(stream.ReadInt())	' skip chunk
		End Select	' ReadTag$(stream)
		If n=0 Then Exit
	Wend	' Not stream.EOF()
	stream.Close
	Return n
End Function

Private

Type TPixmapLoaderILBM Extends TPixmapLoader
	Method LoadPixmap:TPixmap(stream:TStream)
		stream=BigEndianStream( stream )
		
		If ReadTag( stream )<>"FORM" Return

		Local	dud%					= stream.Readint()	' length of file after ILBM header

		If ReadTag( stream )<>"ILBM" Return

		Local	cmap%					= 0
		Local	w:Short					= 0
		Local	h:Short					= 0
		Local	x%						= 0
		Local	y%						= 0
		Local	nPlanes:Byte			= 0
		Local	masking:Byte			= 0
		Local	compression:Byte		= 0
		Local	transparentColour:Short	= 0
		Local	xAspect:Byte			= 0
		Local	yAspect:Byte			= 0
		Local	pageWidth%				= 0
		Local	pageHeight%				= 0
		Local	plane%					= 0
		Local	scanline%				= 1
		Local	i%						= 0
		Local	n%						= 0
		Local	nn%						= 0
		Local	pixmap:TPixmap			= Null
		Local	buffer2:Byte[]
		
		While Not stream.Eof()
			Local blahblah$=ReadTag$(stream)
			Select	blahblah$'Readtag$(stream)
				Case	"BMHD"	' BitMapHeader
					dud					= stream.ReadInt()				' length of BitMapHeader chunk
					w					= stream.ReadShort()
					h					= stream.ReadShort()			' raster width & height in pixels
					x					= UStoSI(stream.ReadShort())
					y					= UStoSI(stream.ReadShort())	' pixel position for this image
					nPlanes				= stream.ReadByte()				' # source bitplanes
					masking				= stream.ReadByte()				' Choice of masking technique.
					compression			= stream.ReadByte()				' Choice of compression algorithm applied to the rows of all source and mask planes. 
					Local	dud2%		= stream.ReadByte()				' unused; for consistency, put 0 here
					transparentColour	= stream.ReadShort()			' transparent "colour number" (sort of)
					xAspect				= stream.ReadByte()
					yAspect				= stream.ReadByte()				' pixel aspect, a ratio width : height
					pageWidth			= UStoSI(stream.ReadShort())
					pageHeight			= UStoSI(stream.ReadShort())	' source "page" size in pixels
					stream.SkipBytes(dud-20)							' extended chunk compatibility
				Case	"CMAP"	' ColorMap
							dud			= stream.ReadInt()				' length of ColourMap chunk
					If Not ColourMapRed
						cmap		= dud/3
						ColourMapRed	= ColourMapRed[..cmap+1]
						ColourMapGreen	= ColourMapGreen[..cmap+1]
						ColourMapBlue	= ColourMapBlue[..cmap+1]
						For i=1 To cmap
							ColourMapRed[i]		= stream.ReadByte()
							ColourMapGreen[i]	= stream.ReadByte()
							ColourMapBlue[i]	= stream.ReadByte()
						Next	' i=1 To cmap
						If dud & 1 Then stream.SkipBytes(1)				' padded chunk compatibility
					Else
						stream.SkipBytes(dud)							' skip chunk
						If dud & 1 Then stream.SkipBytes(1)				' padded chunk compatibility
					EndIf	' ColourMap=Null
				Case	"BODY"	' 
							dud				= stream.ReadInt()			' length of BODY chunk
					Local	row[]
					Local	buffer%[17]
							pixmap			= TPixmap.Create(w,h,PF_RGB888)
					If 2^nPlanes>cmap
						ColourMapRed=ColourMapRed[..(2^nPlanes)+1]
						ColourMapGreen=ColourMapGreen[..(2^nPlanes)+1]
						ColourMapBlue=ColourMapBlue[..(2^nPlanes)+1]
					EndIf	' 2^nPlanes>cmap
					For Local column%=1 To h
						row			= New Int[w+17]
						Select	compression
							Case	cmpNone
								For plane=1 To nPlanes
									For scanline=1 To w Step 16
										buffer[1]	= stream.ReadShort()
										For dud=2 To 16
											buffer[dud]				= (buffer[1] Shr (dud-1)) & 1
										Next	' dud=2 To 16
										buffer[1]	= buffer[1] & 1
										For dud=1 To 16
											row[scanline+(16-dud)]	= row[scanline+(16-dud)]+(buffer[dud] Shl (plane-1))
										Next	' dud=1 To 16
									Next	' scanline=1 To w Step 8
								Next	' plane=1 To nPlanes
							Case	cmpByteRun1
								Local	dud2	= 1
										nn		= 1
								Local	ii
								If Not buffer2
									buffer2	= New Byte[w*h*(nPlanes+1)]
									Repeat
										n=stream.ReadByte();dud2:+1
										If n>127 Then n:-256	' unsigned to signed conversion
										If n<>-128	' noop
											If n<0	' replicate the next byte -n+1 times
												n	= Abs(n)+1
												ii	= stream.ReadByte();dud2:+1
												For i=1 To n
													buffer2[nn]=ii;nn:+1
												Next	' i=1 To n
											Else	' copy the next n+1 bytes literally
												For i=0 To n
													buffer2[nn]=stream.ReadByte();dud2:+1;nn:+1
												Next	' i=0 To n
											EndIf	' n<0
										EndIf	' n<>-128
									Until dud2>dud
								EndIf	' Not buffer2
								For plane=1 To nPlanes
									For i=1 To w Step 16
										buffer[1]	= buffer2[scanline+1]+(buffer2[scanline] Shl 8);scanline:+2
										For dud=2 To 16
											buffer[dud]				= (buffer[1] Shr (dud-1)) & 1
										Next	' dud=2 To 16
										buffer[1]	= buffer[1] & 1
										For dud=1 To 16
											row[i+(16-dud)]	= row[i+(16-dud)]+(buffer[dud] Shl (plane-1))
										Next	' dud=1 To 16
									Next	' i=1 To w Step 16
								Next	' plane=1 To nPlanes
							Default	' unsupported compression algorithm
								dud	= 0
								Exit
						End Select	' compression
						If dud=0 Then pixmap			= Null;Exit
						For dud=1 To w
							pixmap.WritePixel dud-1,column-1,(ColourMapRed[row[dud]+1] Shl 16)+(ColourMapGreen[row[dud]+1] Shl 8)+ColourMapBlue[row[dud]+1]
						Next	' row=1 To w
					Next	' column=1 To h
					If cmap Then ColourMapRed	= Null
					Exit
				Default			' unsupported chunks
					stream.SkipBytes(stream.ReadInt())									' skip chunk
			End Select	' ReadTag$(stream)
			
			If pixmap Then Exit
		Wend	' Not stream.EOF()
		
		Return pixmap
	End Method

End Type

New TPixmapLoaderILBM

Comments

ozak2006
Sweet!


skidracer2015
When nPlanes is 24 there is no palette so the code should not be using a lookup.

This change seems to work for me:




Code Archives Forum