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