[Code]Loading a PCX file

Discuss using and improving Lua and the Lua Player specific to the PSP.

Moderators: Shine, Insert_witty_name

Post Reply
Ferrero
Posts: 15
Joined: Mon Dec 19, 2005 7:26 pm
Contact:

[Code]Loading a PCX file

Post by Ferrero »

Hi everybody, I've developped a little class to load and blit a PCX file.

The interest of this :

- You can have an image larger than 512x512 pixels.

Another thing :

- As a PCX file is an indexed color image file (compressed), finally you have an array of byte which you can fill with a picture editor. So in this file you can store a map to have a 2D tiled game, and this file is compressed.

Here's the class :

Code: Select all

-------------------------------------------------------------------------------			
--
--	Author		:	Lepecq Michael (Ferrero)
--	Version		:	1.0
--	Copyright	:	2005 - 2006		
--
-------------------------------------------------------------------------------
--
--  This object is designed to manage PCX Files
--
--  Methods :
--
--		Public :
--			
--			load : load a PCX file 
--
--		Private :
--
--			decodeHeader 	: Decode the header of a pcx file
--			loadPalette256	: Load the 256 colors palette of the file
--			readPixel		: Read the Pixel of the file
--
--	Properties :
--	
--
--		Public :
--
--			BitsPerPixel 		: The number of bits per pixel per plane in the image data.
--			MaxNumberOfColors 	: The maximum number of colors allowed in the file
--			Palette				: Hold the different colors of the image
--			ImageWidth			: Width of the image in pixel
--			ImageHeight			: Hieght of the image in scanlines
--			BlitTo				: Blit the PCX to an image
--
--		Private :
--
--   		XStart		 	: Left of the image
--			YStart		 	: Top of the image
--			XEnd		 	: Right of the image
--			YEnd		 	: Bottom of the image
--			NumBitPlanes	: Number of bit planes
--			BytesPerLine	: Length of an unencoded line in a plane
--			ScanLineLength	: Length of an unencoded line
--			Pixel			: Array of pixels [y][x]
--			LinePaddingSize : Padding of a scanline (end of a scan line)
--
-------------------------------------------------------------------------------

clsPCX = 
{
    BitsPerPixel = 0, 
    XStart		 = 0,
    YStart		 = 0,
    XEnd		 = 0,
    YEnd		 = 0,
    NumBitPlanes = 0,
    MaxNumberOfColors = 0,
    BytesPerLine = 0,
    Palette		 = {},
    ImageWidth	 = 0,
    ImageHeight  = 0,
    Pixel		 = {},
    LinePaddingSize = 0
}

function clsPCX:new()
   mtbPCX = {};
   setmetatable(mtbPCX, self);
   self.__index = self;
   return mtbPCX;
end

function clsPCX:load(filename)
	
	local file 	 = assert(io.open(filename, "rb"));
    local header = file:read(128);
    
    -- Decoding the header
    
    assert(self:decodeHeader(header));
      
	-- Reading the Pixel
	
	assert(self:readPixel(file));
	
	 -- Loading the palette
    
    if (self.MaxNumberOfColors == 256) then
    	assert(self:loadPalette256(file));
	else	
		return nil, "This palette mode is not supported yet";
	end
	
	-- Closing the file
	
    assert(file:close());
    
    return true
    
end 

function clsPCX:decodeHeader(header)
	
	if (string.byte(header, 1) == 10) then
		
		self.BitsPerPixel = string.byte(header, 4);
		self.XStart	= string.byte(header, 6) * 256 + string.byte(header, 5);
		self.YStart	= string.byte(header, 8) * 256 + string.byte(header, 7);
		self.XEnd	= string.byte(header, 10) * 256 + string.byte(header, 9);
		self.YEnd	= string.byte(header, 12) * 256 + string.byte(header, 11);
		self.NumBitPlanes = string.byte(header, 66);
		self.BytesPerLine = string.byte(header, 68) * 256 + string.byte(header, 67);
		
		self.MaxNumberOfColors = (2^self.BitsPerPixel * self.NumBitPlanes);
		self.ScanLineLength = self.NumBitPlanes * self.BytesPerLine;
		self.ImageWidth  = self.XEnd - self.XStart + 1;
		self.ImageHeight = self.YEnd - self.YStart + 1;
		self.LinePaddingSize = ((self.BytesPerLine * self.NumBitPlanes) * (8 / self.BitsPerPixel)) - ((self.XEnd - self.XStart) + 1);
   
	else
		return nil, "This is not a valid PCX file";
	end
	
	return true;
end 

function clsPCX:loadPalette256(file)

    file:seek("end", -769);
    local CheckByte = file:read(1);
    local Palette	= file:read(768);
	local j=0; 
	local i=0;   
    
    if (string.byte(CheckByte) == 12) then
    	for i=1,768,3 do
    		self.Palette[j] = Color.new(string.byte(Palette, i), string.byte(Palette, i+1), string.byte(Palette, i + 2));
    		j = j + 1;
    		
    	end
	else
		return nil, "256 colors palette not found:"..CheckByte;
	end
    
    return true;
    
end

function clsPCX:readPixel(file)

	local y;
	local runcount;
	local byte; 
	local x;
	local i;

	for y=0,self.ImageHeight-1 do
		self.Pixel[y] = {};
		x = 0;
		while &#40;x<self.ScanLineLength&#41; do
			
			byte = string.byte&#40;file&#58;read&#40;1&#41;&#41;;
			if &#40;byte >= 192&#41; then
				runcount = byte - 192;
				byte = string.byte&#40;file&#58;read&#40;1&#41;&#41;;
				for i=0, runcount do
					self.Pixel&#91;y&#93;&#91;x+i&#93; = byte;
				end
				x = x + runcount;
				
			else
				
				self.Pixel&#91;y&#93;&#91;x&#93; = byte;
				x = x + 1;
			end 
			
		end
		
	end
	
    return true;
    
end

function clsPCX&#58;blitTo&#40;image_x, image_y, image, rect_left, rect_top, rect_right, rect_bottom&#41;

	local line;
	local y;
	local x;
	local color;
	
	local ymin;
	local ymax;
	local xmin;
	local xmax;
	
	-- Computing the clipping
	
	if image_y < 0 then 
		rect_top = rect_top - image_y;
		ymin = 0;
	else
		ymin = image_y;
	end
	
	if image_x < 0 then 
		rect_left = rect_left - image_x;
		xmin = 0;
	else
		xmin = image_x;
	end
	
	if ymin + &#40;rect_bottom - rect_top&#41; >= image&#58;height&#40;&#41; then
		ymax = image&#58;height&#40;&#41; - 1;
	else
		ymax = ymin + &#40;rect_bottom - rect_top&#41;;
	end
		
	if xmin + &#40;rect_right - rect_left&#41; >= image&#58;width&#40;&#41; then
		xmax = image&#58;width&#40;&#41; - 1;
	else
		xmax = xmin + &#40;rect_right - rect_left&#41;;
	end
	
	if &#40;xmax + rect_left >= self.ImageWidth&#41; then
		xmax = self.ImageWidth - rect_left - 1;
	end
	
	if &#40;ymax + rect_top >= self.ImageHeight&#41; then
		ymax = self.ImageHeight - rect_top - 1;
	end
	
	-- Drawing the image
	
	for y=ymin,ymax do
		
		line = rect_top + y - image_y;
		
		for x=xmin, xmax do
			color = self.Palette&#91;self.Pixel&#91;line&#93;&#91;rect_left + x - image_x&#93;&#93;;
			image&#58;pixel&#40;x, y, color&#41;;
		end	
		
	end

    return true;
    
end
And how to use it :

Code: Select all

map=clsPCX&#58;new&#40;&#41;;
assert&#40;map&#58;load&#40;"..\\maps\\map1560.pcx"&#41;&#41;;

screen&#58;clear&#40;&#41;;
map&#58;blitTo&#40;0,0,screen,0,0,480,272&#41;;
screen.flip&#40;&#41;;
control = Controls.read&#40;&#41;;

while control&#58;start&#40;&#41; == false do	
	control = Controls.read&#40;&#41;;
	screen.waitVblankStart&#40;&#41;;
end
LuMo
Posts: 410
Joined: Sun Aug 21, 2005 2:45 am
Location: Austria
Contact:

Post by LuMo »

how fast is it?
did you test it running compared to normal blit?
greets
lumo

PS: interesting!
"Good artists copy, great artists steal."
Pablo Picasso
go2lumo.com
Ferrero
Posts: 15
Joined: Mon Dec 19, 2005 7:26 pm
Contact:

Post by Ferrero »

The blit is quite slow,

I use it like this :

First, I blit it to an 512*512 image and I use this image to blit onto the screen.
And when the image does not contain the needed datas I blit a portion of the image on itself to keep the datas I need, and then blit the portion of the PCX I need.
LuMo
Posts: 410
Joined: Sun Aug 21, 2005 2:45 am
Location: Austria
Contact:

Post by LuMo »

only blit the really needed data, otherwise it really slows down...
480x272px more is never needed
greets
lumo
"Good artists copy, great artists steal."
Pablo Picasso
go2lumo.com
Post Reply