-
Notifications
You must be signed in to change notification settings - Fork 2
/
PBIO.C
388 lines (330 loc) · 10.9 KB
/
PBIO.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*--pbio.c----------------------------------------------------------*
* *
* Routines to read & write PC Paintbrush files. *
* *
* Date Who Changes *
* --------- --- -------------------------------------------------- *
* 31-Mar-89 mjc band read & write to allow large files. *
* 19-Apr-89 mjc 256 color palette added at end of paintbrush file. *
* *
* TBD: haven't added scroll-offset logic to "to planar" case, since
* ANIMDISK is only 8 bpp.
*------------------------------------------------------------------*/
#include "main.h"
#include <fcntl.h>
#include <malloc.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#define local static
/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
#define RowBytes(w) (((w) + 15) >> 4 << 1)
/*------------------------------------------------------------------
* 256 Color Palette
*
* When reading the paintbrush file, the 256 color palette is
* sought only if the version number in the header is 5 and the
* bits per pixel * planes == 8. The last 769 bytes of the file
* must start with 0x0C, and be followed by the 768 byte palette.
*
* When writing the paintbrush file, we write
* version 5 in the header, and append the palette to the end of
* the file in the same format as above (0x0C followed by 768
* bytes of palette).
*------------------------------------------------------------------
*/
/* Return SUCCESS, FAIL, or specific errors ... */
#define PB_NOT_ENUF_MEM 2
#define PB_NO_256_PALETTE 3
local WORD readCount; /* For compression. */
local UBYTE readChar;
/* --- Forward declarations. */
void GetByte(WORD file);
BOOL PutBytes(BYTE far * ptr, WORD bytes, WORD file);
/*-----------------------------------------------------------------*/
typedef struct {
BYTE manufacturer;
BYTE version;
BYTE encoding;
BYTE bitsperpixel;
WORD xmin, ymin, xmax, ymax;
WORD hres, vres;
BYTE colormap[16][3];
BYTE reserved;
BYTE nplanes;
WORD bytesperline;
} PCPAINTBRUSH_HEADER;
local PCPAINTBRUSH_HEADER *pbh = NULL; /* paintbrush header pointer */
/* Global pointer so can allocate in header, use fields in body. */
/*--------------------- Bad Paintbrush Header ----------------------*/
#define BadPbHeader(s) (FAIL)
/*-------------------- Invalid Paintbrush File ---------------------*/
#define InvalidPbFile() (FAIL)
#define WrongPbFileType() (FAIL) /* Expected different data format.*/
#define PCXNo256PaletteMsg()
/*-----------------------------------------------------------------*
* Read the header of a pc paintbrush file.
* Sets bmHdr fields. Calls reSize if necessary.
* Returns SUCCESS or FAIL.
*-----------------------------------------------------------------*/
BOOL ReadPCX_Header(WORD file, BITMAP *bitmap, LONG *palette,
BitMapHeader *bmHdr)
{
register WORD i;
UBYTE c, palet[256][3];
if (!pbh) /* Test in case we come through twice w/o freeing. */
pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
if (!pbh)
return (FAIL);
if (read(file, (char *)pbh, sizeof(PCPAINTBRUSH_HEADER)) !=
sizeof(PCPAINTBRUSH_HEADER))
return (InvalidPbFile());
/* --- To start of pixel data. */
if (0 > lseek(file, (LONG) 128, SEEK_SET))
return (InvalidPbFile());
/* --- Check that the header info is valid. */
if (pbh->manufacturer != 10)
return (InvalidPbFile());
/* --- Expecting version with palette at end. */
if (pbh->version != 5)
return (BadPbHeader(s_wrongPBVersion));
if (pbh->encoding != 1)
return (BadPbHeader(s_unknownEncoding));
if (pbh->bitsperpixel != 1 && pbh->nplanes != 1)
return (BadPbHeader(s_wrongLayout));
if (pbh->bitsperpixel != 8)
return (WrongPbFileType());
/* --- Compute dimensions and # colors. */
setmem(bmHdr, sizeof(BitMapHeader), 0);
bmHdr->w = 1 + pbh->xmax - pbh->xmin;
bmHdr->h = 1 + pbh->ymax - pbh->ymin;
bmHdr->nPlanes = pbh->bitsperpixel * pbh->nplanes;
/* MAY BE PACKED. */
/* --- Get the color map. */
if (palette != NULL) {
/* If a 256 color palette should be present at the end of the
* file, try to fetch it from disk and copy it to the palette.
*/
c = 0;
if (lseek(file, (LONG)-769, SEEK_END) >= 0)
if (read(file, &c, 1) == 1)
if (read(file, (UBYTE *)&palet[0][0], 768) == 768)
if (c == 0x0C)
for (i = 0; i < 256; ++i)
palette[i] = ((LONG)palet[i][0] << 16) +
((LONG)palet[i][1] << 8) +
((LONG)palet[i][2]);
/* --- To start of pixel data (again). */
lseek(file, (LONG)128, SEEK_SET);
if (c != 0x0C) {
/* ---- We couldn't read a 256 color palette at the end
* of the file.
*/
PCXNo256PaletteMsg();
return (PB_NO_256_PALETTE);
}
}
return (SUCCESS); /* Header done; BODY yet to do. */
}
/*-----------------------------------------------------------------*
* Read the pixel data into the bitmap. Return SUCCESS or FAIL.
*-----------------------------------------------------------------*/
#define MaxPCXPlanes 8 /* 256-color, no mask. */
BOOL ReadPCX_BODY(WORD file, BITMAP *bitmap, BitMapHeader *bmHdr)
{
register WORD i, iPlane;
BOOL result = SUCCESS;
BYTE far *dest;
WORD bodyNRows, srcPlanesToUse;
WORD bodyIRow; /* Increment from 0..bodyNRows-1. */
BYTE far *dests[MaxPCXPlanes]; /* Ptrs to dest scan lines. */
WORD useBytes;
/* --------- Initialization. ---------- */
readCount = 0; /* For compression. */
bodyNRows = MIN(bmHdr->h, bitmap->box.h);
srcPlanesToUse = MIN(bitmap->planes + bpp_minus1, bmHdr->nPlanes);
/* ---------- Read all scan lines. ---------- */
OpenIOBuffer(FALSE);
for (bodyIRow = 0; bodyIRow < bodyNRows; ++bodyIRow) {
readCount = 0; /* Just in case, supposed to start anew each line. */
useBytes = MIN(bitmap->width, pbh->bytesperline);
/* ----- Read a scan line. */
dest = (BYTE far *)BMLineStart(bitmap, bodyIRow, 0);
for (i = 0; i < pbh->bytesperline; i++) {
GetByte(file);
if (i < useBytes)
*dest++ = readChar;
}
}
CloseIOBuffer(file);
done:
return (result);
}
/*--------------------- Close Paintbrush File ---------------------*/
/* --- NOTE: if change, must change WritePCX_Done, since it calls this. */
void ReadPCX_Done()
{
/* --- Free pbh, which is shared by header & body routines. */
if (pbh)
free(pbh);
pbh = NULL;
}
void WritePCX_Done()
{
ReadPCX_Done();
}
/*---------------------------- Get Byte ---------------------------*/
/* Set readCount & readChar. At EOF or file error, returns 0's forever. */
void GetByte(WORD file)
{
UBYTE c;
/* --- if in the middle of a run of encoded bytes, don't read any
* more
*/
if (readCount > 0) {
--readCount;
return;
}
readCount = 0;
if (GReadOne(file, &c) != 1) {
sawEOF:
readCount = 32767; /* Huge count of 0's to pad the end. */
readChar = 0;
return;
}
if ((c & 0xc0) == 0xc0) {
readCount = (0x3f & c) - 1; /* "-1": consuming one of count. */
if (GReadOne(file, &c) != 1)
goto sawEOF;
}
readChar = c;
}
/*----------------------------------------------------------------------*
Output File Routines & Variables
*----------------------------------------------------------------------*/
/*---------------------------------------------------------------*
Output header for a PC Paintbrush file with the given number
of bitsperpixel and planes. One of these two parms must be 1.
ASSUMES OKAY TO TRASH buffer[].
Returns SUCCESS or FAIL.
*---------------------------------------------------------------*/
BOOL WritePCX_Header(WORD file, BITMAP *bitmap, LONG *palette)
{
register PCPAINTBRUSH_HEADER *ppbh;
WORD i;
#define GAP_SIZE (128 - sizeof(PCPAINTBRUSH_HEADER))
UBYTE buffer1[GAP_SIZE];
/* --- init the header that we'll write.
* Note: since DPaint never reads & writes at the same time,
* it is okay to share the same read & write structure,
* unlike in CONVERT.EXE.
*/
if (!pbh) /* Test in case we come through twice w/o
* freeing. */
pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
if (!pbh)
return (FAIL);
ppbh = pbh; /* Register variable for smaller, faster code. */
setmem(ppbh, sizeof(PCPAINTBRUSH_HEADER) + 4, 0);
ppbh->manufacturer = 10;
ppbh->version = 5;
ppbh->encoding = 1;
ppbh->bitsperpixel = bpp;
ppbh->xmin = ppbh->ymin = 0;
ppbh->xmax = bitmap->box.w - 1;
ppbh->ymax = bitmap->box.h - 1;
ppbh->hres = N_COLUMNS;
ppbh->vres = N_LINES;
/* --- bytesperline doesn't take into account multiple planes.
* Output in same format as bitmap (planar vs packed).
*/
ppbh->bytesperline = bitmap->width;
ppbh->nplanes = bitmap->planes;
ppbh->reserved = 0;
/* --- First 16 colors of our palette info. */
for (i = 0; i < 16; ++i) {
ppbh->colormap[i][0] = (BYTE)(palette[i] >> 16);
ppbh->colormap[i][1] = (BYTE)(palette[i] >> 8);
ppbh->colormap[i][2] = (BYTE) palette[i];
}
/* --- write the 128-byte header */
if (GWrite(file, (char *)ppbh, sizeof(PCPAINTBRUSH_HEADER))
!= sizeof(PCPAINTBRUSH_HEADER))
goto error;
setmem(buffer1, GAP_SIZE, 0);
if (GWrite(file, buffer1, GAP_SIZE) != GAP_SIZE)
error:
return (FAIL);
return (SUCCESS);
}
/* --------------- WritePCX_BODY ---------------
* Write the pixel data.
* Returns SUCCESS or an error condition.
* -------------------------------------------------------------------
*/
WORD WritePCX_BODY(WORD file, BITMAP *bitmap)
{
register WORD y;
/* --- Write to a bit-packed file. */
for (y = 0; y < bitmap->box.h; ++y) { /* for each line in band */
if (PutBytes((BYTE far *)BMLineStart(bitmap, y, 0),
pbh->bytesperline, file))
return FAIL;
}
return SUCCESS;
}
/*-------------------- Output any 256-color palette ------------------------*/
BOOL WritePCX_256Palette(WORD file, LONG *palette)
{
register WORD i;
UBYTE c, palet[256][3];
if (pbh->version == 5 && pbh->bitsperpixel == 8) {
for (i = 0; i < 256; ++i) {
palet[i][0] = (BYTE)(palette[i] >> 16);
palet[i][1] = (BYTE)(palette[i] >> 8);
palet[i][2] = (BYTE) palette[i];
}
c = 0x0C;
if (GWrite(file, &c, 1) != 1 ||
GWrite(file, (char *)&palet[0][0], 768) != 768)
return FAIL;
}
return SUCCESS;
}
/*-------------------------------------------------------------------
* Write bytes to a file, handling packing as it goes.
* Returns SUCCESS or FAIL.
*-------------------------------------------------------------------
*/
BOOL PutBytes(BYTE far *ptr, WORD bytes, WORD file)
{
register WORD startbyte, count;
char b;
while (bytes > 0) {
/* --- check for a repeating byte value */
startbyte = *ptr++;
--bytes;
count = 1;
while (*ptr == startbyte && bytes > 0 && count < 63) {
++ptr;
--bytes;
++count;
}
/* --- If we can pack the sequence, or if we have to add a
* byte before it because the top 2 bits of the value
* are 1's, write a packed sequence of 2 bytes.
* Otherwise, just write the byte value.
*/
if (count > 1 || (startbyte & 0xc0) == 0xc0) {
b = 0xc0 | count;
if (GWrite(file, &b, 1) != 1)
return FAIL;
}
b = startbyte;
if (GWrite(file, &b, 1) != 1)
return FAIL;
}
return SUCCESS;
}