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 (x<self.ScanLineLength) do
			
			byte = string.byte(file:read(1));
			if (byte >= 192) then
				runcount = byte - 192;
				byte = string.byte(file:read(1));
				for i=0, runcount do
					self.Pixel[y][x+i] = byte;
				end
				x = x + runcount;
				
			else
				
				self.Pixel[y][x] = byte;
				x = x + 1;
			end 
			
		end
		
	end
	
    return true;
    
end
function clsPCX:blitTo(image_x, image_y, image, rect_left, rect_top, rect_right, rect_bottom)
	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 + (rect_bottom - rect_top) >= image:height() then
		ymax = image:height() - 1;
	else
		ymax = ymin + (rect_bottom - rect_top);
	end
		
	if xmin + (rect_right - rect_left) >= image:width() then
		xmax = image:width() - 1;
	else
		xmax = xmin + (rect_right - rect_left);
	end
	
	if (xmax + rect_left >= self.ImageWidth) then
		xmax = self.ImageWidth - rect_left - 1;
	end
	
	if (ymax + rect_top >= self.ImageHeight) 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[self.Pixel[line][rect_left + x - image_x]];
			image:pixel(x, y, color);
		end	
		
	end
    return true;
    
endCode: Select all
map=clsPCX:new();
assert(map:load("..\\maps\\map1560.pcx"));
screen:clear();
map:blitTo(0,0,screen,0,0,480,272);
screen.flip();
control = Controls.read();
while control:start() == false do	
	control = Controls.read();
	screen.waitVblankStart();
end