mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
181 lines
3.8 KiB
C++
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;
|
|
}
|
|
|
|
}
|