rhino/demo/c/dr_libs/old/dr_pcx.h
Go to the documentation of this file.
1 // PCX image loader. Public domain. See "unlicense" statement at the end of this file.
2 // dr_pcx - v0.3.1 - 2018-09-11
3 //
4 // David Reid - mackron@gmail.com
5 
6 // USAGE
7 //
8 // dr_pcx is a single-file library. To use it, do something like the following in one .c file.
9 // #define DR_PCX_IMPLEMENTATION
10 // #include "dr_pcx.h"
11 //
12 // You can then #include this file in other parts of the program as you would with any other header file. Do something like
13 // the following to load and decode an image:
14 //
15 // int width;
16 // int height;
17 // int components
18 // drpcx_uint8* pImageData = drpcx_load_file("my_image.pcx", DRPCX_FALSE, &width, &height, &components, 0);
19 // if (pImageData == NULL) {
20 // // Failed to load image.
21 // }
22 //
23 // ...
24 //
25 // drpcx_free(pImageData);
26 //
27 // The boolean parameter (second argument in the above example) is whether or not the image should be flipped upside down.
28 //
29 //
30 //
31 // OPTIONS
32 // #define these options before including this file.
33 //
34 // #define DR_PCX_NO_STDIO
35 // Disable drpcx_load_file().
36 //
37 //
38 //
39 // QUICK NOTES
40 // - 2-bpp/4-plane and 4-bpp/1-plane formats have not been tested.
41 
42 #ifndef dr_pcx_h
43 #define dr_pcx_h
44 
45 #include <stddef.h>
46 
47 #if defined(_MSC_VER) && _MSC_VER < 1600
48 typedef signed char drpcx_int8;
49 typedef unsigned char drpcx_uint8;
50 typedef signed short drpcx_int16;
51 typedef unsigned short drpcx_uint16;
52 typedef signed int drpcx_int32;
53 typedef unsigned int drpcx_uint32;
54 typedef signed __int64 drpcx_int64;
55 typedef unsigned __int64 drpcx_uint64;
56 #else
57 #include <stdint.h>
58 typedef int8_t drpcx_int8;
59 typedef uint8_t drpcx_uint8;
60 typedef int16_t drpcx_int16;
61 typedef uint16_t drpcx_uint16;
62 typedef int32_t drpcx_int32;
63 typedef uint32_t drpcx_uint32;
64 typedef int64_t drpcx_int64;
65 typedef uint64_t drpcx_uint64;
66 #endif
69 #define DRPCX_TRUE 1
70 #define DRPCX_FALSE 0
71 
72 #ifdef __cplusplus
73 extern "C" {
74 #endif
75 
76 // Callback for when data is read. Return value is the number of bytes actually read.
77 typedef size_t (* drpcx_read_proc)(void* userData, void* bufferOut, size_t bytesToRead);
78 
79 
80 // Loads a PCX file using the given callbacks.
81 drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
82 
83 // Frees memory returned by drpcx_load() and family.
84 void drpcx_free(void* pReturnValueFromLoad);
85 
86 
87 #ifndef DR_PCX_NO_STDIO
88 // Loads an PCX file from an actual file.
89 drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
90 #endif
91 
92 // Helper for loading an PCX file from a block of memory.
93 drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents);
94 
95 
96 #ifdef __cplusplus
97 }
98 #endif
99 
100 #endif // dr_pcx_h
101 
102 
104 //
105 // IMPLEMENTATION
106 //
108 #ifdef DR_PCX_IMPLEMENTATION
109 #include <stdlib.h>
110 #include <string.h>
111 #include <assert.h>
112 
113 #ifndef DR_PCX_NO_STDIO
114 #include <stdio.h>
115 
116 static size_t drpcx__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
117 {
118  return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
119 }
120 
121 drpcx_uint8* drpcx_load_file(const char* filename, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
122 {
123  FILE* pFile;
124 #ifdef _MSC_VER
125  if (fopen_s(&pFile, filename, "rb") != 0) {
126  return NULL;
127  }
128 #else
129  pFile = fopen(filename, "rb");
130  if (pFile == NULL) {
131  return NULL;
132  }
133 #endif
134 
135  drpcx_uint8* pImageData = drpcx_load(drpcx__on_read_stdio, pFile, flipped, x, y, internalComponents, desiredComponents);
136 
137  fclose(pFile);
138  return pImageData;
139 }
140 #endif // DR_PCX_NO_STDIO
141 
142 
143 typedef struct
144 {
145  // A pointer to the beginning of the data. We use a char as the type here for easy offsetting.
146  const unsigned char* data;
147  size_t dataSize;
148  size_t currentReadPos;
149 } drpcx_memory;
150 
151 static size_t drpcx__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
152 {
153  drpcx_memory* memory = (drpcx_memory*)pUserData;
154  assert(memory != NULL);
155  assert(memory->dataSize >= memory->currentReadPos);
156 
157  size_t bytesRemaining = memory->dataSize - memory->currentReadPos;
158  if (bytesToRead > bytesRemaining) {
159  bytesToRead = bytesRemaining;
160  }
161 
162  if (bytesToRead > 0) {
163  memcpy(bufferOut, memory->data + memory->currentReadPos, bytesToRead);
164  memory->currentReadPos += bytesToRead;
165  }
166 
167  return bytesToRead;
168 }
169 
170 drpcx_uint8* drpcx_load_memory(const void* data, size_t dataSize, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
171 {
172  drpcx_memory memory;
173  memory.data = (const unsigned char*)data;
174  memory.dataSize = dataSize;
175  memory.currentReadPos = 0;
176  return drpcx_load(drpcx__on_read_memory, &memory, flipped, x, y, internalComponents, desiredComponents);
177 }
178 
179 
180 typedef struct
181 {
184  drpcx_uint8 encoding;
185  drpcx_uint8 bpp;
186  drpcx_uint16 left;
187  drpcx_uint16 top;
188  drpcx_uint16 right;
189  drpcx_uint16 bottom;
190  drpcx_uint16 hres;
191  drpcx_uint16 vres;
192  drpcx_uint8 palette16[48];
193  drpcx_uint8 reserved1;
194  drpcx_uint8 bitPlanes;
195  drpcx_uint16 bytesPerLine;
196  drpcx_uint16 paletteType;
197  drpcx_uint16 screenSizeH;
198  drpcx_uint16 screenSizeV;
199  drpcx_uint8 reserved2[54];
200 } drpcx_header;
201 
202 typedef struct
203 {
204  drpcx_read_proc onRead;
205  void* pUserData;
206  drpcx_bool32 flipped;
207  drpcx_header header;
208 
209  drpcx_uint32 width;
210  drpcx_uint32 height;
211  drpcx_uint32 components; // 3 = RGB; 4 = RGBA. Only 3 and 4 are supported.
212  drpcx_uint8* pImageData;
213 } drpcx;
214 
215 
216 static drpcx_uint8 drpcx__read_byte(drpcx* pPCX)
217 {
218  drpcx_uint8 byte = 0;
219  pPCX->onRead(pPCX->pUserData, &byte, 1);
220 
221  return byte;
222 }
223 
224 static drpcx_uint8* drpcx__row_ptr(drpcx* pPCX, drpcx_uint32 row)
225 {
226  drpcx_uint32 stride = pPCX->width * pPCX->components;
227 
228  drpcx_uint8* pRow = pPCX->pImageData;
229  if (pPCX->flipped) {
230  pRow += (pPCX->height - row - 1) * stride;
231  } else {
232  pRow += row * stride;
233  }
234 
235  return pRow;
236 }
237 
238 static drpcx_uint8 drpcx__rle(drpcx* pPCX, drpcx_uint8* pRLEValueOut)
239 {
240  drpcx_uint8 rleCount;
241  drpcx_uint8 rleValue;
242 
243  rleValue = drpcx__read_byte(pPCX);
244  if ((rleValue & 0xC0) == 0xC0) {
245  rleCount = rleValue & 0x3F;
246  rleValue = drpcx__read_byte(pPCX);
247  } else {
248  rleCount = 1;
249  }
250 
251 
252  *pRLEValueOut = rleValue;
253  return rleCount;
254 }
255 
256 
257 drpcx_bool32 drpcx__decode_1bit(drpcx* pPCX)
258 {
259  drpcx_uint8 rleCount = 0;
260  drpcx_uint8 rleValue = 0;
261 
262  switch (pPCX->header.bitPlanes)
263  {
264  case 1:
265  {
266  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
267  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
268  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
269  if (rleCount == 0) {
270  rleCount = drpcx__rle(pPCX, &rleValue);
271  }
272  rleCount -= 1;
273 
274  for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
275  drpcx_uint8 mask = (1 << (7 - bit));
276  drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
277 
278  pRow[0] = paletteIndex * 255;
279  pRow[1] = paletteIndex * 255;
280  pRow[2] = paletteIndex * 255;
281  pRow += 3;
282  }
283  }
284  }
285 
286  return DRPCX_TRUE;
287 
288  } break;
289 
290  case 2:
291  case 3:
292  case 4:
293  {
294  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
295  for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
296  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
297  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
298  if (rleCount == 0) {
299  rleCount = drpcx__rle(pPCX, &rleValue);
300  }
301  rleCount -= 1;
302 
303  for (int bit = 0; (bit < 8) && ((x*8 + bit) < pPCX->width); ++bit) {
304  drpcx_uint8 mask = (1 << (7 - bit));
305  drpcx_uint8 paletteIndex = (rleValue & mask) >> (7 - bit);
306 
307  pRow[0] |= ((paletteIndex & 0x01) << c);
308  pRow += pPCX->components;
309  }
310  }
311  }
312 
313 
314  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
315  for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
316  drpcx_uint8 paletteIndex = pRow[0];
317  for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
318  pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
319  }
320 
321  pRow += pPCX->components;
322  }
323  }
324 
325  return DRPCX_TRUE;
326  }
327 
328  default: return DRPCX_FALSE;
329  }
330 }
331 
332 drpcx_bool32 drpcx__decode_2bit(drpcx* pPCX)
333 {
334  drpcx_uint8 rleCount = 0;
335  drpcx_uint8 rleValue = 0;
336 
337  switch (pPCX->header.bitPlanes)
338  {
339  case 1:
340  {
341  drpcx_uint8 paletteCGA[48];
342  paletteCGA[ 0] = 0x00; paletteCGA[ 1] = 0x00; paletteCGA[ 2] = 0x00; // #000000
343  paletteCGA[ 3] = 0x00; paletteCGA[ 4] = 0x00; paletteCGA[ 5] = 0xAA; // #0000AA
344  paletteCGA[ 6] = 0x00; paletteCGA[ 7] = 0xAA; paletteCGA[ 8] = 0x00; // #00AA00
345  paletteCGA[ 9] = 0x00; paletteCGA[10] = 0xAA; paletteCGA[11] = 0xAA; // #00AAAA
346  paletteCGA[12] = 0xAA; paletteCGA[13] = 0x00; paletteCGA[14] = 0x00; // #AA0000
347  paletteCGA[15] = 0xAA; paletteCGA[16] = 0x00; paletteCGA[17] = 0xAA; // #AA00AA
348  paletteCGA[18] = 0xAA; paletteCGA[19] = 0x55; paletteCGA[20] = 0x00; // #AA5500
349  paletteCGA[21] = 0xAA; paletteCGA[22] = 0xAA; paletteCGA[23] = 0xAA; // #AAAAAA
350  paletteCGA[24] = 0x55; paletteCGA[25] = 0x55; paletteCGA[26] = 0x55; // #555555
351  paletteCGA[27] = 0x55; paletteCGA[28] = 0x55; paletteCGA[29] = 0xFF; // #5555FF
352  paletteCGA[30] = 0x55; paletteCGA[31] = 0xFF; paletteCGA[32] = 0x55; // #55FF55
353  paletteCGA[33] = 0x55; paletteCGA[34] = 0xFF; paletteCGA[35] = 0xFF; // #55FFFF
354  paletteCGA[36] = 0xFF; paletteCGA[37] = 0x55; paletteCGA[38] = 0x55; // #FF5555
355  paletteCGA[39] = 0xFF; paletteCGA[40] = 0x55; paletteCGA[41] = 0xFF; // #FF55FF
356  paletteCGA[42] = 0xFF; paletteCGA[43] = 0xFF; paletteCGA[44] = 0x55; // #FFFF55
357  paletteCGA[45] = 0xFF; paletteCGA[46] = 0xFF; paletteCGA[47] = 0xFF; // #FFFFFF
358 
359  drpcx_uint8 cgaBGColor = pPCX->header.palette16[0] >> 4;
360  drpcx_uint8 i = (pPCX->header.palette16[3] & 0x20) >> 5;
361  drpcx_uint8 p = (pPCX->header.palette16[3] & 0x40) >> 6;
362  //drpcx_uint8 c = (pPCX->header.palette16[3] & 0x80) >> 7; // Color or monochrome. How is monochrome handled?
363 
364  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
365  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
366  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
367  if (rleCount == 0) {
368  rleCount = drpcx__rle(pPCX, &rleValue);
369  }
370  rleCount -= 1;
371 
372  for (int bit = 0; bit < 4; ++bit) {
373  if (x*4 + bit < pPCX->width) {
374  drpcx_uint8 mask = (3 << ((3 - bit) * 2));
375  drpcx_uint8 paletteIndex = (rleValue & mask) >> ((3 - bit) * 2);
376 
377  drpcx_uint8 cgaIndex;
378  if (paletteIndex == 0) { // Background.
379  cgaIndex = cgaBGColor;
380  } else { // Foreground
381  cgaIndex = (((paletteIndex << 1) + p) + (i << 3));
382  }
383 
384  pRow[0] = paletteCGA[cgaIndex*3 + 0];
385  pRow[1] = paletteCGA[cgaIndex*3 + 1];
386  pRow[2] = paletteCGA[cgaIndex*3 + 2];
387  pRow += 3;
388  }
389  }
390  }
391  }
392 
393  // TODO: According to http://www.fysnet.net/pcxfile.htm, we should use the palette at the end of the file
394  // instead of the standard CGA palette if the version is equal to 5. With my test files the palette
395  // at the end of the file does not exist. Research this one.
396  if (pPCX->header.version == 5) {
397  drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
398  if (paletteMarker == 0x0C) {
399  // TODO: Implement Me.
400  }
401  }
402 
403  return DRPCX_TRUE;
404  };
405 
406  case 4:
407  {
408  // NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
409  // TODO: Test Me.
410 
411  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
412  for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
413  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
414  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
415  if (rleCount == 0) {
416  rleCount = drpcx__rle(pPCX, &rleValue);
417  }
418  rleCount -= 1;
419 
420  for (int bitpair = 0; (bitpair < 4) && ((x*4 + bitpair) < pPCX->width); ++bitpair) {
421  drpcx_uint8 mask = (4 << (3 - bitpair));
422  drpcx_uint8 paletteIndex = (rleValue & mask) >> (3 - bitpair);
423 
424  pRow[0] |= ((paletteIndex & 0x03) << (c*2));
425  pRow += pPCX->components;
426  }
427  }
428  }
429 
430 
431  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
432  for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
433  drpcx_uint8 paletteIndex = pRow[0];
434  for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
435  pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
436  }
437 
438  pRow += pPCX->components;
439  }
440  }
441 
442  return DRPCX_TRUE;
443  };
444 
445  default: return DRPCX_FALSE;
446  }
447 }
448 
449 drpcx_bool32 drpcx__decode_4bit(drpcx* pPCX)
450 {
451  // NOTE: This is completely untested. If anybody knows where I can get a test file please let me know or send it through to me!
452  // TODO: Test Me.
453 
454  if (pPCX->header.bitPlanes > 1) {
455  return DRPCX_FALSE;
456  }
457 
458  drpcx_uint8 rleCount = 0;
459  drpcx_uint8 rleValue = 0;
460 
461  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
462  for (drpcx_uint32 c = 0; c < pPCX->header.bitPlanes; ++c) {
463  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
464  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
465  if (rleCount == 0) {
466  rleCount = drpcx__rle(pPCX, &rleValue);
467  }
468  rleCount -= 1;
469 
470  for (int nibble = 0; (nibble < 2) && ((x*2 + nibble) < pPCX->width); ++nibble)
471  {
472  drpcx_uint8 mask = (4 << (1 - nibble));
473  drpcx_uint8 paletteIndex = (rleValue & mask) >> (1 - nibble);
474 
475  pRow[0] |= ((paletteIndex & 0x0F) << (c*4));
476  pRow += pPCX->components;
477  }
478  }
479  }
480 
481 
482  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
483  for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
484  drpcx_uint8 paletteIndex = pRow[0];
485  for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
486  pRow[c] = pPCX->header.palette16[paletteIndex*3 + c];
487  }
488 
489  pRow += pPCX->components;
490  }
491  }
492 
493  return DRPCX_TRUE;
494 }
495 
496 drpcx_bool32 drpcx__decode_8bit(drpcx* pPCX)
497 {
498  drpcx_uint8 rleCount = 0;
499  drpcx_uint8 rleValue = 0;
500  drpcx_uint32 stride = pPCX->width * pPCX->components;
501 
502  switch (pPCX->header.bitPlanes)
503  {
504  case 1:
505  {
506  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
507  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
508  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
509  if (rleCount == 0) {
510  rleCount = drpcx__rle(pPCX, &rleValue);
511  }
512  rleCount -= 1;
513 
514  if (x < pPCX->width) {
515  pRow[0] = rleValue;
516  pRow[1] = rleValue;
517  pRow[2] = rleValue;
518  pRow += 3;
519  }
520  }
521  }
522 
523  // At this point we can know if we are dealing with a palette or a grayscale image by checking the next byte. If it's equal to 0x0C, we
524  // need to do a simple palette lookup.
525  drpcx_uint8 paletteMarker = drpcx__read_byte(pPCX);
526  if (paletteMarker == 0x0C) {
527  // A palette is present - we need to do a second pass.
528  drpcx_uint8 palette256[768];
529  if (pPCX->onRead(pPCX->pUserData, palette256, sizeof(palette256)) != sizeof(palette256)) {
530  return DRPCX_FALSE;
531  }
532 
533  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
534  drpcx_uint8* pRow = pPCX->pImageData + (y * stride);
535  for (drpcx_uint32 x = 0; x < pPCX->width; ++x) {
536  drpcx_uint8 index = pRow[0];
537  pRow[0] = palette256[index*3 + 0];
538  pRow[1] = palette256[index*3 + 1];
539  pRow[2] = palette256[index*3 + 2];
540  pRow += 3;
541  }
542  }
543  }
544 
545  return DRPCX_TRUE;
546  }
547 
548  case 3:
549  case 4:
550  {
551  for (drpcx_uint32 y = 0; y < pPCX->height; ++y) {
552  for (drpcx_uint32 c = 0; c < pPCX->components; ++c) {
553  drpcx_uint8* pRow = drpcx__row_ptr(pPCX, y);
554  for (drpcx_uint32 x = 0; x < pPCX->header.bytesPerLine; ++x) {
555  if (rleCount == 0) {
556  rleCount = drpcx__rle(pPCX, &rleValue);
557  }
558  rleCount -= 1;
559 
560  if (x < pPCX->width) {
561  pRow[c] = rleValue;
562  pRow += pPCX->components;
563  }
564  }
565  }
566  }
567 
568  return DRPCX_TRUE;
569  }
570  }
571 
572  return DRPCX_TRUE;
573 }
574 
575 drpcx_uint8* drpcx_load(drpcx_read_proc onRead, void* pUserData, drpcx_bool32 flipped, int* x, int* y, int* internalComponents, int desiredComponents)
576 {
577  if (onRead == NULL) return NULL;
578  if (desiredComponents > 4) return NULL;
579 
580  drpcx pcx;
581  pcx.onRead = onRead;
582  pcx.pUserData = pUserData;
583  pcx.flipped = flipped;
584  if (onRead(pUserData, &pcx.header, sizeof(pcx.header)) != sizeof(pcx.header)) {
585  return NULL; // Failed to read the header.
586  }
587 
588  if (pcx.header.header != 10) {
589  return NULL; // Not a PCX file.
590  }
591 
592  if (pcx.header.encoding != 1) {
593  return NULL; // Not supporting non-RLE encoding. Would assume a value of 0 indicates raw, unencoded, but that is apparently never used.
594  }
595 
596  if (pcx.header.bpp != 1 && pcx.header.bpp != 2 && pcx.header.bpp != 4 && pcx.header.bpp != 8) {
597  return NULL; // Unsupported pixel format.
598  }
599 
600 
601  if (pcx.header.left > pcx.header.right) {
602  drpcx_uint16 temp = pcx.header.left;
603  pcx.header.left = pcx.header.right;
604  pcx.header.right = temp;
605  }
606  if (pcx.header.top > pcx.header.bottom) {
607  drpcx_uint16 temp = pcx.header.top;
608  pcx.header.top = pcx.header.bottom;
609  pcx.header.bottom = temp;
610  }
611 
612  pcx.width = pcx.header.right - pcx.header.left + 1;
613  pcx.height = pcx.header.bottom - pcx.header.top + 1;
614  pcx.components = (pcx.header.bpp == 8 && pcx.header.bitPlanes == 4) ? 4 : 3;
615 
616  size_t dataSize = pcx.width * pcx.height * pcx.components;
617  pcx.pImageData = (drpcx_uint8*)calloc(1, dataSize); // <-- Clearing to zero is important! Required for proper decoding.
618  if (pcx.pImageData == NULL) {
619  return NULL; // Failed to allocate memory.
620  }
621 
622  drpcx_bool32 result = DRPCX_FALSE;
623  switch (pcx.header.bpp)
624  {
625  case 1:
626  {
627  result = drpcx__decode_1bit(&pcx);
628  } break;
629 
630  case 2:
631  {
632  result = drpcx__decode_2bit(&pcx);
633  } break;
634 
635  case 4:
636  {
637  result = drpcx__decode_4bit(&pcx);
638  } break;
639 
640  case 8:
641  {
642  result = drpcx__decode_8bit(&pcx);
643  } break;
644  }
645 
646  if (!result) {
647  free(pcx.pImageData);
648  return NULL;
649  }
650 
651  // There's an annoying amount of branching when loading PCX files so for simplicity I'm doing the component conversion as
652  // a second pass.
653  if (desiredComponents == 0) desiredComponents = pcx.components;
654  if (desiredComponents != (int)pcx.components) {
655  drpcx_uint8* pNewImageData = (drpcx_uint8*)malloc(pcx.width * pcx.height * desiredComponents);
656  if (pNewImageData == NULL) {
657  free(pcx.pImageData);
658  return NULL;
659  }
660 
661  drpcx_uint8* pSrcData = pcx.pImageData;
662  drpcx_uint8* pDstData = pNewImageData;
663  if (desiredComponents < (int)pcx.components) {
664  // We're reducing the number of components. Just drop the excess.
665  for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
666  for (int c = 0; c < desiredComponents; ++c) {
667  pDstData[c] = pSrcData[c];
668  }
669 
670  pSrcData += pcx.components;
671  pDstData += desiredComponents;
672  }
673  } else {
674  // We're increasing the number of components. Always ensure the alpha channel is set to 0xFF.
675  if (pcx.components == 1) {
676  for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
677  for (int c = 0; c < desiredComponents; ++c) {
678  pDstData[c] = pSrcData[0];
679  }
680 
681  pSrcData += pcx.components;
682  pDstData += desiredComponents;
683  }
684  } else if (pcx.components == 2) {
685  for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
686  pDstData[0] = pSrcData[0];
687  pDstData[1] = pSrcData[1];
688  pDstData[2] = 0x00;
689  if (desiredComponents == 4) pDstData[3] = 0xFF;
690 
691  pSrcData += pcx.components;
692  pDstData += desiredComponents;
693  }
694  } else {
695  assert(pcx.components == 3);
696  assert(desiredComponents == 4);
697  for (drpcx_uint32 i = 0; i < pcx.width*pcx.height; ++i) {
698  pDstData[0] = pSrcData[0];
699  pDstData[1] = pSrcData[1];
700  pDstData[2] = pSrcData[2];
701  pDstData[3] = 0xFF;
702 
703  pSrcData += pcx.components;
704  pDstData += desiredComponents;
705  }
706  }
707  }
708 
709  free(pcx.pImageData);
710  pcx.pImageData = pNewImageData;
711  }
712 
713  if (x) *x = pcx.width;
714  if (y) *y = pcx.height;
715  if (internalComponents) *internalComponents = pcx.components;
716  return pcx.pImageData;
717 }
718 
719 void drpcx_free(void* pReturnValueFromLoad)
720 {
721  free(pReturnValueFromLoad);
722 }
723 
724 #endif // DR_PCX_IMPLEMENTATION
725 
726 
727 // REVISION HISTORY
728 //
729 // v0.3.1 - 2018-09-11
730 // - Styling fixes.
731 // - Fix a typo.
732 //
733 // v0.3 - 2018-02-08
734 // - API CHANGE: Rename dr_* types to drpcx_*.
735 //
736 // v0.2c - 2018-02-07
737 // - Fix a crash.
738 //
739 // v0.2b - 2018-02-02
740 // - Fix compilation error.
741 //
742 // v0.2a - 2017-07-16
743 // - Change underlying type for booleans to unsigned.
744 //
745 // v0.2 - 2016-10-28
746 // - API CHANGE: Add a parameter to drpcx_load() and family to control the number of output components.
747 // - Use custom sized types rather than built-in ones to improve support for older MSVC compilers.
748 //
749 // v0.1c - 2016-10-23
750 // - A minor change to drpcx_bool8 and drpcx_bool32 types.
751 //
752 // v0.1b - 2016-10-11
753 // - Use drpcx_bool32 instead of the built-in "bool" type. The reason for this change is that it helps maintain API/ABI consistency
754 // between C and C++ builds.
755 //
756 // v0.1a - 2016-09-18
757 // - Change date format to ISO 8601 (YYYY-MM-DD)
758 //
759 // v0.1 - 2016-05-04
760 // - Initial versioned release.
761 
762 
763 // TODO
764 // - Test 2-bpp/4-plane and 4-bpp/1-plane formats.
765 
766 
767 /*
768 This is free and unencumbered software released into the public domain.
769 
770 Anyone is free to copy, modify, publish, use, compile, sell, or
771 distribute this software, either in source code form or as a compiled
772 binary, for any purpose, commercial or non-commercial, and by any
773 means.
774 
775 In jurisdictions that recognize copyright laws, the author or authors
776 of this software dedicate any and all copyright interest in the
777 software to the public domain. We make this dedication for the benefit
778 of the public at large and to the detriment of our heirs and
779 successors. We intend this dedication to be an overt act of
780 relinquishment in perpetuity of all present and future rights to this
781 software under copyright law.
782 
783 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
784 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
785 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
786 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
787 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
788 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
789 OTHER DEALINGS IN THE SOFTWARE.
790 
791 For more information, please refer to <http://unlicense.org/>
792 */
793 
drpcx_int32
int32_t drpcx_int32
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:62
drpcx_uint8
uint8_t drpcx_uint8
Definition: porcupine/demo/c/dr_libs/old/dr_pcx.h:59
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
drpcx_read_proc
size_t(* drpcx_read_proc)(void *userData, void *bufferOut, size_t bytesToRead)
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:77
DRPCX_TRUE
#define DRPCX_TRUE
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:69
drpcx_uint16
uint16_t drpcx_uint16
Definition: porcupine/demo/c/dr_libs/old/dr_pcx.h:61
drpcx_uint64
uint64_t drpcx_uint64
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:65
drpcx_load_memory
drpcx_uint8 * drpcx_load_memory(const void *data, size_t dataSize, drpcx_bool32 flipped, int *x, int *y, int *internalComponents, int desiredComponents)
drpcx_uint8
uint8_t drpcx_uint8
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:59
drpcx_int64
int64_t drpcx_int64
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:64
drpcx_load
drpcx_uint8 * drpcx_load(drpcx_read_proc onRead, void *pUserData, drpcx_bool32 flipped, int *x, int *y, int *internalComponents, int desiredComponents)
drpcx_bool32
drpcx_uint32 drpcx_bool32
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:68
DRPCX_FALSE
#define DRPCX_FALSE
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:70
drpcx_int8
int8_t drpcx_int8
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:58
drpcx_int16
int16_t drpcx_int16
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:60
drpcx_uint32
uint32_t drpcx_uint32
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:63
drpcx_load_file
drpcx_uint8 * drpcx_load_file(const char *filename, drpcx_bool32 flipped, int *x, int *y, int *internalComponents, int desiredComponents)
drpcx_uint16
uint16_t drpcx_uint16
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:61
drpcx_uint32
uint32_t drpcx_uint32
Definition: porcupine/demo/c/dr_libs/old/dr_pcx.h:63
python.setup.version
version
Definition: porcupine/binding/python/setup.py:70
header
const std::string header
assert.h
drpcx_bool32
drpcx_uint32 drpcx_bool32
Definition: porcupine/demo/c/dr_libs/old/dr_pcx.h:68
drpcx_free
void drpcx_free(void *pReturnValueFromLoad)
drpcx_bool8
drpcx_uint8 drpcx_bool8
Definition: rhino/demo/c/dr_libs/old/dr_pcx.h:67


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:13:55