1 #include "pcx.h"
2
3 namespace Upp {
4
GetDotSize(Size pixel_size,int xpm,int ypm)5 static Size GetDotSize(Size pixel_size, int xpm, int ypm)
6 {
7 if(!xpm || !ypm)
8 return Size(0, 0);
9 static const double DOTS_PER_METER = 60000 / 2.54;
10 return Size(fround(pixel_size.cx * DOTS_PER_METER / xpm), fround(pixel_size.cy * DOTS_PER_METER / ypm));
11 }
12
sFd(int x)13 int sFd(int x)
14 {
15 return x > 0 ? x : 120;
16 }
17
Create()18 bool PCXRaster::Create()
19 {
20 Stream& stream = GetStream();
21 size = Size(0, 0);
22 if(!stream.IsOpen()) {
23 SetError();
24 return false;
25 }
26 ASSERT(stream.IsLoading());
27
28 if(!stream.GetAll(&header, sizeof(PCXHeader))) {
29 SetError();
30 return false;
31 }
32 header.SwapEndian();
33 if(header.manufacturer != 10) {
34 SetError();
35 return false;
36 }
37
38 if(header.bitsPerPixel == 8 && header.planes == 3)
39 fmt.Set24le(0x0000ff, 0x00ff00, 0xff0000);
40 else
41 if(header.bitsPerPixel == 1 || header.bitsPerPixel == 4 || header.bitsPerPixel == 8)
42 fmt.Set8();
43 else {
44 SetError();
45 return false;
46 }
47 size = Size(header.maxX - header.minX + 1, header.maxY - header.minY + 1);
48 info.kind = IMAGE_OPAQUE;
49 info.bpp = header.bitsPerPixel;
50 info.dots = Size(size.cx * 600 / sFd(header.horzDpi), size.cy * 600 / sFd(header.vertDpi));
51 info.hotspot = Point(0, 0);
52 info.colors = fmt.GetColorCount();
53 int colors = 1 << (header.planes * header.bitsPerPixel);
54 palette.Alloc(colors);
55 if(colors <= 16)
56 for(int i = 0; i < colors; i++) {
57 palette[i].r = header.palette[i].r;
58 palette[i].g = header.palette[i].g;
59 palette[i].b = header.palette[i].b;
60 palette[i].a = 255;
61 }
62 else {
63 if(stream.GetLeft() < 768) {
64 SetError();
65 return false;
66 }
67 stream.SeekEnd(-768);
68 for(int i = 0; i < 256; i++) {
69 palette[i].r = stream.Get();
70 palette[i].g = stream.Get();
71 palette[i].b = stream.Get();
72 palette[i].a = 255;
73 }
74 stream.Seek(sizeof(PCXHeader));
75 }
76
77 row_bytes = fmt.GetByteCount(size.cx);
78 scanline.Alloc(row_bytes);
79 buffer.Alloc(header.bytesPerLine * header.planes);
80 return true;
81 }
82
GetSize()83 Size PCXRaster::GetSize()
84 {
85 return size;
86 }
87
GetInfo()88 Raster::Info PCXRaster::GetInfo()
89 {
90 return info;
91 }
92
GetLine(int line)93 Raster::Line PCXRaster::GetLine(int line)
94 {
95 Stream& stream = GetStream();
96 byte *ptr = new byte[row_bytes];
97 if(!IsError()) {
98 byte *t = buffer;
99 byte *e = buffer + header.bytesPerLine * header.planes;
100 while(t < e) {
101 byte b = stream.Get();
102 if((b & 0xc0) == 0xc0) {
103 int n = b & 0x3f;
104 if(t + n > e)
105 break;
106 memset(t, stream.Get(), n);
107 t += n;
108 }
109 else
110 *t++ = b;
111 }
112 byte *bs = buffer;
113 t = ptr;
114 e = ptr + row_bytes;
115 if(header.bitsPerPixel == 1)
116 for(int i = 0; i < header.bytesPerLine; i++) {
117 byte h[8];
118 memset(h, 0, 8);
119 byte *s = bs;
120 for(int plane = 0; plane < header.planes; plane++) {
121 byte sb = *s;
122 byte bit = 1 << plane;
123 for(int j = 0; j < 8; j++)
124 if(sb & (0x80 >> j))
125 h[j] |= bit;
126 s += header.bytesPerLine;
127 }
128 for(int q = 0; q < 8; q++) {
129 if(t >= e)
130 break;
131 *t++ = h[q];
132 }
133 bs++;
134 }
135 else
136 if(header.bitsPerPixel == 8 && header.planes == 3) {
137 for(int i = 0; i < size.cx; i++) {
138 *t++ = buffer[i];
139 *t++ = buffer[i + header.bytesPerLine];
140 *t++ = buffer[i + 2 * header.bytesPerLine];
141 }
142 }
143 else
144 if(header.bitsPerPixel == 4) {
145 for(;;) {
146 if(t >= e) break;
147 byte b = *bs++;
148 *t++ = (b & 0xf0) >> 4;
149 if(t >= e) break;
150 *t++ = b & 0x0f;
151 }
152 }
153 else
154 if(header.bitsPerPixel == 8)
155 memcpy(t, bs, row_bytes);
156 else
157 goto error;
158 return Line(ptr, this, true);
159 }
160 error:
161 SetError();
162 memset(ptr, 0, row_bytes);
163 return Line(ptr, this, true);
164 }
165
GetPaletteCount()166 int PCXRaster::GetPaletteCount()
167 {
168 return fmt.GetPaletteCount();
169 }
170
GetPalette()171 RGBA *PCXRaster::GetPalette()
172 {
173 return fmt.GetPaletteCount() ? ~palette : NULL;
174 }
175
GetFormat()176 const RasterFormat *PCXRaster::GetFormat()
177 {
178 return &fmt;
179 }
180
181 }
182