ultimatepp/uppsrc/plugin/pcx/pcx.cpp
cxl 8ebdcbb0d5 uppsrc: NAMESPACE_UPP / END_UPP_NAMESPACE removed
git-svn-id: svn://ultimatepp.org/upp/trunk@10186 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-08-26 17:15:30 +00:00

181 lines
3.8 KiB
C++

#include "pcx.h"
namespace Upp {
static Size GetDotSize(Size pixel_size, int xpm, int ypm)
{
if(!xpm || !ypm)
return Size(0, 0);
static const double DOTS_PER_METER = 60000 / 2.54;
return Size(fround(pixel_size.cx * DOTS_PER_METER / xpm), fround(pixel_size.cy * DOTS_PER_METER / ypm));
}
int sFd(int x)
{
return x > 0 ? x : 120;
}
bool PCXRaster::Create()
{
Stream& stream = GetStream();
size = Size(0, 0);
if(!stream.IsOpen()) {
SetError();
return false;
}
ASSERT(stream.IsLoading());
if(!stream.GetAll(&header, sizeof(PCXHeader))) {
SetError();
return false;
}
header.SwapEndian();
if(header.manufacturer != 10) {
SetError();
return false;
}
if(header.bitsPerPixel == 8 && header.planes == 3)
fmt.Set24le(0x0000ff, 0x00ff00, 0xff0000);
else
if(header.bitsPerPixel == 1 || header.bitsPerPixel == 4 || header.bitsPerPixel == 8)
fmt.Set8();
else {
SetError();
return false;
}
size = Size(header.maxX - header.minX + 1, header.maxY - header.minY + 1);
info.kind = IMAGE_OPAQUE;
info.bpp = header.bitsPerPixel;
info.dots = Size(size.cx * 600 / sFd(header.horzDpi), size.cy * 600 / sFd(header.vertDpi));
info.hotspot = Point(0, 0);
info.colors = fmt.GetColorCount();
int colors = 1 << (header.planes * header.bitsPerPixel);
palette.Alloc(colors);
if(colors <= 16)
for(int i = 0; i < colors; i++) {
palette[i].r = header.palette[i].r;
palette[i].g = header.palette[i].g;
palette[i].b = header.palette[i].b;
palette[i].a = 255;
}
else {
if(stream.GetLeft() < 768) {
SetError();
return false;
}
stream.SeekEnd(-768);
for(int i = 0; i < 256; i++) {
palette[i].r = stream.Get();
palette[i].g = stream.Get();
palette[i].b = stream.Get();
palette[i].a = 255;
}
stream.Seek(sizeof(PCXHeader));
}
row_bytes = fmt.GetByteCount(size.cx);
scanline.Alloc(row_bytes);
buffer.Alloc(header.bytesPerLine * header.planes);
return true;
}
Size PCXRaster::GetSize()
{
return size;
}
Raster::Info PCXRaster::GetInfo()
{
return info;
}
Raster::Line PCXRaster::GetLine(int line)
{
Stream& stream = GetStream();
byte *ptr = new byte[row_bytes];
if(!IsError()) {
byte *t = buffer;
byte *e = buffer + header.bytesPerLine * header.planes;
while(t < e) {
byte b = stream.Get();
if((b & 0xc0) == 0xc0) {
int n = b & 0x3f;
if(t + n > e)
break;
memset(t, stream.Get(), n);
t += n;
}
else
*t++ = b;
}
byte *bs = buffer;
t = ptr;
e = ptr + row_bytes;
if(header.bitsPerPixel == 1)
for(int i = 0; i < header.bytesPerLine; i++) {
byte h[8];
memset(h, 0, 8);
byte *s = bs;
for(int plane = 0; plane < header.planes; plane++) {
byte sb = *s;
byte bit = 1 << plane;
for(int j = 0; j < 8; j++)
if(sb & (0x80 >> j))
h[j] |= bit;
s += header.bytesPerLine;
}
for(int q = 0; q < 8; q++) {
if(t >= e)
break;
*t++ = h[q];
}
bs++;
}
else
if(header.bitsPerPixel == 8 && header.planes == 3) {
for(int i = 0; i < size.cx; i++) {
*t++ = buffer[i];
*t++ = buffer[i + header.bytesPerLine];
*t++ = buffer[i + 2 * header.bytesPerLine];
}
}
else
if(header.bitsPerPixel == 4) {
for(;;) {
if(t >= e) break;
byte b = *bs++;
*t++ = (b & 0xf0) >> 4;
if(t >= e) break;
*t++ = b & 0x0f;
}
}
else
if(header.bitsPerPixel == 8)
memcpy(t, bs, row_bytes);
else
goto error;
return Line(ptr, this, true);
}
error:
SetError();
memset(ptr, 0, row_bytes);
return Line(ptr, this, true);
}
int PCXRaster::GetPaletteCount()
{
return fmt.GetPaletteCount();
}
RGBA *PCXRaster::GetPalette()
{
return fmt.GetPaletteCount() ? ~palette : NULL;
}
const RasterFormat *PCXRaster::GetFormat()
{
return &fmt;
}
}