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;
end
Code: 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