1 /* 2 * Copyright 2008, Jérôme Duval, korli@users.berlios.de. All rights reserved. 3 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include "StreamBuffer.h" 8 #include "PCX.h" 9 #include "PCXTranslator.h" 10 11 #include <ByteOrder.h> 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 18 //#define TRACE_PCX 19 #ifdef TRACE_PCX 20 # define TRACE(x...) printf(x) 21 #else 22 # define TRACE(x...) ; 23 #endif 24 25 26 using namespace PCX; 27 28 29 class TempAllocator { 30 public: 31 TempAllocator() : fMemory(NULL) {} 32 ~TempAllocator() { free(fMemory); } 33 34 void *Allocate(size_t size) { return fMemory = malloc(size); } 35 36 private: 37 void *fMemory; 38 }; 39 40 41 bool 42 pcx_header::IsValid() const 43 { 44 TRACE("manufacturer:%u version:%u encoding:%u bitsPerPixel:%u nPlanes:%u bytesPerLine:%u\n", manufacturer, version, encoding, bitsPerPixel, nPlanes, bytesPerLine); 45 return manufacturer == 10 46 && version == 5 47 && encoding == 1 48 && (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) 49 && (nPlanes == 1 || nPlanes == 3) 50 && (bitsPerPixel == 8 || nPlanes == 1) 51 && (bytesPerLine & 1) == 0; 52 } 53 54 55 void 56 pcx_header::SwapToHost() 57 { 58 swap_data(B_UINT16_TYPE, this, sizeof(pcx_header), B_SWAP_LENDIAN_TO_HOST); 59 } 60 61 62 void 63 pcx_header::SwapFromHost() 64 { 65 swap_data(B_UINT16_TYPE, this, sizeof(pcx_header), B_SWAP_HOST_TO_LENDIAN); 66 } 67 68 69 // #pragma mark - 70 71 72 static status_t 73 convert_data_to_bits(pcx_header &header, StreamBuffer &source, 74 BPositionIO &target) 75 { 76 uint16 bitsPerPixel = header.bitsPerPixel; 77 uint16 bytesPerLine = header.bytesPerLine; 78 uint16 width = header.xMax - header.xMin + 1; 79 uint16 height = header.yMax - header.yMin + 1; 80 uint16 nPlanes = header.nPlanes; 81 uint32 scanLineLength = nPlanes * bytesPerLine; 82 83 // allocate buffers 84 TempAllocator scanLineAllocator; 85 TempAllocator paletteAllocator; 86 uint8 *scanLineData[height]; 87 uint8 *palette = (uint8 *)paletteAllocator.Allocate(3 * 256); 88 89 for (uint32 row = 0; row < height; row++) { 90 TRACE("scanline %ld\n", row); 91 scanLineData[row] = (uint8 *)scanLineAllocator.Allocate(scanLineLength); 92 if (scanLineData[row] == NULL) 93 return B_NO_MEMORY; 94 uint8 *line = scanLineData[row]; 95 uint32 index = 0; 96 uint8 x; 97 do { 98 if (source.Read(&x, 1) != 1) 99 return B_IO_ERROR; 100 if ((x & 0xc0) == 0xc0) { 101 uint32 count = x & 0x3f; 102 if (index + count - 1 > scanLineLength) 103 return B_IO_ERROR; 104 if (source.Read(&x, 1) != 1) 105 return B_IO_ERROR; 106 for (uint32 i = 0; i < count; i++) 107 line[index++] = x; 108 } else { 109 line[index++] = x; 110 } 111 } while (index < scanLineLength); 112 } 113 114 115 if (bitsPerPixel == 8 && nPlanes == 1) { 116 TRACE("palette reading %p 8\n", palette); 117 uint8 x; 118 if (source.Read(&x, 1) != 1) 119 return B_IO_ERROR; 120 if (x != 12) 121 return B_IO_ERROR; 122 if (source.Read(palette, 256 * 3) != 256 * 3) 123 return B_IO_ERROR; 124 } else { 125 TRACE("palette reading %p palette\n", palette); 126 memcpy(palette, &header.paletteInfo, 48); 127 } 128 129 uint8 alpha = 255; 130 if (bitsPerPixel == 1 && nPlanes == 1) { 131 TRACE("target writing 1\n"); 132 palette[0] = palette[1] = palette[2] = 0; 133 palette[3] = palette[4] = palette[5] = 0xff; 134 for (uint32 row = 0; row < height; row++) { 135 uint8 *line = scanLineData[row]; 136 uint8 mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; 137 for (int i = 0; i < width; i++) { 138 bool isBit = ((line[i >> 3] & mask[i & 7]) != 0) ? true : false; 139 target.Write(&palette[!isBit ? 2 : 5], 1); 140 target.Write(&palette[!isBit ? 1 : 4], 1); 141 target.Write(&palette[!isBit ? 0 : 3], 1); 142 target.Write(&alpha, 1); 143 } 144 } 145 } else if (bitsPerPixel == 4 && nPlanes == 1) { 146 TRACE("target writing 4\n"); 147 for (uint32 row = 0; row < height; row++) { 148 uint8 *line = scanLineData[row]; 149 for (int i = 0; i < width; i++) { 150 uint16 index; 151 if ((i & 1) == 0) 152 index = (line[i >> 1] >> 4) & 15; 153 else 154 index = line[i >> 1] & 15; 155 TRACE("target writing 4 i %d index %d\n", i, index); 156 index += (index + index); 157 target.Write(&palette[index+2], 1); 158 target.Write(&palette[index+1], 1); 159 target.Write(&palette[index], 1); 160 target.Write(&alpha, 1); 161 } 162 } 163 } else if (bitsPerPixel == 8 && nPlanes == 1) { 164 TRACE("target writing 8\n"); 165 for (uint32 row = 0; row < height; row++) { 166 TRACE("target writing 8 row %ld\n", row); 167 uint8 *line = scanLineData[row]; 168 for (int i = 0; i < width; i++) { 169 uint16 index = line[i]; 170 index += (index + index); 171 target.Write(&palette[index+2], 1); 172 target.Write(&palette[index+1], 1); 173 target.Write(&palette[index], 1); 174 target.Write(&alpha, 1); 175 } 176 177 } 178 } else { 179 TRACE("target writing raw\n"); 180 for (uint32 row = 0; row < height; row++) { 181 uint8 *line = scanLineData[row]; 182 for (int i = 0; i < width; i++) { 183 target.Write(&line[i + 2 * bytesPerLine], 1); 184 target.Write(&line[i + bytesPerLine], 1); 185 target.Write(&line[i], 1); 186 target.Write(&alpha, 1); 187 } 188 } 189 } 190 191 return B_OK; 192 } 193 194 195 // #pragma mark - 196 197 198 status_t 199 PCX::identify(BMessage *settings, BPositionIO &stream, uint8 &type, int32 &bitsPerPixel) 200 { 201 // read in the header 202 203 pcx_header header; 204 if (stream.Read(&header, sizeof(pcx_header)) != (ssize_t)sizeof(pcx_header)) 205 return B_BAD_VALUE; 206 207 header.SwapToHost(); 208 209 // check header 210 211 if (!header.IsValid()) 212 return B_BAD_VALUE; 213 214 bitsPerPixel = header.bitsPerPixel; 215 216 TRACE("PCX::identify OK\n"); 217 218 return B_OK; 219 } 220 221 222 /** Converts an PCX image of any type into a B_RGBA32 B_TRANSLATOR_BITMAP. 223 */ 224 225 status_t 226 PCX::convert_pcx_to_bits(BMessage *settings, BPositionIO &source, BPositionIO &target) 227 { 228 StreamBuffer sourceBuf(&source, 2048); 229 if (sourceBuf.InitCheck() != B_OK) 230 return B_IO_ERROR; 231 232 pcx_header header; 233 if (sourceBuf.Read(&header, sizeof(pcx_header)) != (ssize_t)sizeof(pcx_header)) 234 return B_BAD_VALUE; 235 236 header.SwapToHost(); 237 238 // check header 239 240 if (!header.IsValid()) 241 return B_BAD_VALUE; 242 243 uint16 width = header.xMax - header.xMin + 1; 244 uint16 height = header.yMax - header.yMin + 1; 245 246 TranslatorBitmap bitsHeader; 247 bitsHeader.magic = B_TRANSLATOR_BITMAP; 248 bitsHeader.bounds.left = 0; 249 bitsHeader.bounds.top = 0; 250 bitsHeader.bounds.right = width - 1; 251 bitsHeader.bounds.bottom = height - 1; 252 bitsHeader.bounds.Set(0, 0, width - 1, height - 1); 253 bitsHeader.rowBytes = width * 4; 254 bitsHeader.colors = B_RGB32; 255 bitsHeader.dataSize = bitsHeader.rowBytes * height; 256 257 // write out Be's Bitmap header 258 swap_data(B_UINT32_TYPE, &bitsHeader, sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN); 259 target.Write(&bitsHeader, sizeof(TranslatorBitmap)); 260 261 return convert_data_to_bits(header, sourceBuf, target); 262 } 263