ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

pcx.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "image/pcx.h"
00024 
00025 #include "common/stream.h"
00026 #include "common/textconsole.h"
00027 #include "graphics/pixelformat.h"
00028 #include "graphics/surface.h"
00029 
00037 namespace Image {
00038 
00039 PCXDecoder::PCXDecoder() {
00040     _surface = 0;
00041     _palette = 0;
00042     _paletteColorCount = 0;
00043 }
00044 
00045 PCXDecoder::~PCXDecoder() {
00046     destroy();
00047 }
00048 
00049 void PCXDecoder::destroy() {
00050     if (_surface) {
00051         _surface->free();
00052         delete _surface;
00053         _surface = 0;
00054     }
00055 
00056     delete[] _palette;
00057     _palette = 0;
00058     _paletteColorCount = 0;
00059 }
00060 
00061 bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) {
00062     destroy();
00063 
00064     if (stream.readByte() != 0x0a)  // ZSoft PCX
00065         return false;
00066 
00067     byte version = stream.readByte();   // 0 - 5
00068     if (version > 5)
00069         return false;
00070 
00071     bool compressed = stream.readByte(); // encoding, 1 = run length encoding
00072     byte bitsPerPixel = stream.readByte();  // 1, 2, 4 or 8
00073 
00074     // Window
00075     uint16 xMin = stream.readUint16LE();
00076     uint16 yMin = stream.readUint16LE();
00077     uint16 xMax = stream.readUint16LE();
00078     uint16 yMax = stream.readUint16LE();
00079 
00080     uint16 width  = xMax - xMin + 1;
00081     uint16 height = yMax - yMin + 1;
00082 
00083     if (xMax < xMin || yMax < yMin) {
00084         warning("Invalid PCX image dimensions");
00085         return false;
00086     }
00087 
00088     stream.skip(4); // HDpi, VDpi
00089 
00090     // Read the EGA palette (colormap)
00091     _palette = new byte[16 * 3];
00092     for (uint16 i = 0; i < 16; i++) {
00093         _palette[i * 3 + 0] = stream.readByte();
00094         _palette[i * 3 + 1] = stream.readByte();
00095         _palette[i * 3 + 2] = stream.readByte();
00096     }
00097 
00098     if (stream.readByte() != 0) // reserved, should be set to 0
00099         return false;
00100 
00101     byte nPlanes = stream.readByte();
00102     uint16 bytesPerLine = stream.readUint16LE();
00103     uint16 bytesPerscanLine = nPlanes * bytesPerLine;
00104 
00105     if (bytesPerscanLine < width * bitsPerPixel * nPlanes / 8) {
00106         warning("PCX data is corrupted");
00107         return false;
00108     }
00109 
00110     stream.skip(60);    // PaletteInfo, HscreenSize, VscreenSize, Filler
00111 
00112     _surface = new Graphics::Surface();
00113 
00114     byte *scanLine = new byte[bytesPerscanLine];
00115     byte *dst;
00116     int x, y;
00117 
00118     if (nPlanes == 3 && bitsPerPixel == 8) {    // 24bpp
00119         Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
00120         _surface->create(width, height, format);
00121         dst = (byte *)_surface->getPixels();
00122         _paletteColorCount = 0;
00123 
00124         for (y = 0; y < height; y++) {
00125             decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
00126 
00127             for (x = 0; x < width; x++) {
00128                 byte b = scanLine[x];
00129                 byte g = scanLine[x +  bytesPerLine];
00130                 byte r = scanLine[x + (bytesPerLine << 1)];
00131                 uint32 color = format.RGBToColor(r, g, b);
00132 
00133                 *((uint32 *)dst) = color;
00134                 dst += format.bytesPerPixel;
00135             }
00136         }
00137     } else if (nPlanes == 1 && bitsPerPixel == 8) { // 8bpp indexed
00138         _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
00139         dst = (byte *)_surface->getPixels();
00140         _paletteColorCount = 16;
00141 
00142         for (y = 0; y < height; y++, dst += _surface->pitch) {
00143             decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
00144             memcpy(dst, scanLine, width);
00145         }
00146 
00147         if (version == 5) {
00148             if (stream.readByte() != 12) {
00149                 warning("Expected a palette after the PCX image data");
00150                 delete[] scanLine;
00151                 return false;
00152             }
00153 
00154             // Read the VGA palette
00155             delete[] _palette;
00156             _palette = new byte[256 * 3];
00157             for (uint16 i = 0; i < 256; i++) {
00158                 _palette[i * 3 + 0] = stream.readByte();
00159                 _palette[i * 3 + 1] = stream.readByte();
00160                 _palette[i * 3 + 2] = stream.readByte();
00161             }
00162 
00163             _paletteColorCount = 256;
00164         }
00165     } else if ((nPlanes == 2 || nPlanes == 3 || nPlanes == 4) && bitsPerPixel == 1) {   // planar, 4, 8 or 16 colors
00166         _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
00167         dst = (byte *)_surface->getPixels();
00168         _paletteColorCount = 16;
00169 
00170         for (y = 0; y < height; y++, dst += _surface->pitch) {
00171             decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
00172 
00173             for (x = 0; x < width; x++) {
00174                 int m = 0x80 >> (x & 7), v = 0;
00175                 for (int i = nPlanes - 1; i >= 0; i--) {
00176                     v <<= 1;
00177                     v  += (scanLine[i * bytesPerLine + (x >> 3)] & m) == 0 ? 0 : 1;
00178                 }
00179                 dst[x] = v;
00180             }
00181         }
00182     } else {
00183         // Known unsupported case: 1 plane and bpp < 8 (1, 2 or 4)
00184         warning("Invalid PCX file (%d planes, %d bpp)", nPlanes, bitsPerPixel);
00185         delete[] scanLine;
00186         return false;
00187     }
00188 
00189     delete[] scanLine;
00190 
00191     return true;
00192 }
00193 
00194 void PCXDecoder::decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerscanLine, bool compressed) {
00195     uint32 i = 0;
00196     byte run, value;
00197 
00198     if (compressed) {
00199         while (i < bytesPerscanLine) {
00200             run = 1;
00201             value = stream.readByte();
00202             if (value >= 0xc0) {
00203                 run = value & 0x3f;
00204                 value = stream.readByte();
00205             }
00206             while (i < bytesPerscanLine && run--)
00207                 dst[i++] = value;
00208         }
00209     } else {
00210         stream.read(dst, bytesPerscanLine);
00211     }
00212 }
00213 
00214 } // End of namespace Image


Generated on Sat May 25 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge