void GImage::decodeTGA( BinaryInput& input) { // This is a simple TGA loader that can handle uncompressed // truecolor TGA files (TGA type 2). // Verify this is a TGA file by looking for the TRUEVISION tag. int pos = input.getPosition(); input.setPosition(input.size() - 18); std::string tag = input.readString(16); if (tag != "TRUEVISION-XFILE") { throw Error("Not a TGA file", input.getFilename()); } input.setPosition(pos); int IDLength = input.readUInt8(); int colorMapType = input.readUInt8(); int imageType = input.readUInt8(); (void)colorMapType; // 2 is the type supported by this routine. if (imageType != 2 && imageType != 10) { throw Error("TGA images must be type 2 (Uncompressed truecolor) or 10 (Run-length truecolor)", input.getFilename()); } // Color map specification input.skip(5); // Image specification // Skip x and y offsets input.skip(4); m_width = input.readInt16(); m_height = input.readInt16(); int colorDepth = input.readUInt8(); if ((colorDepth != 24) && (colorDepth != 32)) { throw Error("TGA files must be 24 or 32 bit.", input.getFilename()); } if (colorDepth == 32) { m_channels = 4; } else { m_channels = 3; } // Image descriptor contains overlay data as well // as data indicating where the origin is int imageDescriptor = input.readUInt8(); (void)imageDescriptor; // Image ID input.skip(IDLength); m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels); debugAssert(m_byte); // Pixel data int x; int y; if (imageType == 2) { // Uncompressed if (m_channels == 3) { for (y = m_height - 1; y >= 0; --y) { for (x = 0; x < m_width; ++x) { int i = (x + y * m_width) * 3; readBGR(m_byte + i, input); } } } else { for (y = m_height - 1; y >= 0; --y) { for (x = 0; x < m_width; ++x) { int i = (x + y * m_width) * 4; readBGRA(m_byte + i, input); } } } } else if (imageType == 10) { // Run-length encoded for (y = m_height - 1; y >= 0; --y) { for (int x = 0; x < m_width; /* intentionally no x increment */) { // The specification guarantees that no packet will wrap past the end of a row const uint8 repetitionCount = input.readUInt8(); const uint8 numValues = (repetitionCount & (~128)) + 1; int byteOffset = (x + y * m_width) * 3; if (repetitionCount & 128) { // When the high bit is 1, this is a run-length packet if (m_channels == 3) { Color3uint8 value; readBGR((uint8*)(&value), input); for (int i = 0; i < numValues; ++i, ++x) { for (int b = 0; b < 3; ++b, ++byteOffset) { m_byte[byteOffset] = value[b]; } } } else { Color4uint8 value; readBGRA((uint8*)(&value), input); for (int i = 0; i < numValues; ++i, ++x) { for (int b = 0; b < 3; ++b, ++byteOffset) { m_byte[byteOffset] = value[b]; } } } } else { // When the high bit is 0, this is a raw packet for (int i = 0; i < numValues; ++i, ++x, byteOffset += m_channels) { readBGR(m_byte + byteOffset, input); } } } } } else { alwaysAssertM(false, "Unsupported type"); } }
void GImage::decodeJPEG( BinaryInput& input) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; int loc = 0; channels = 3; // We have to set up the error handler, in case initialization fails. cinfo.err = jpeg_std_error(&jerr); // Initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); // Specify data source (eg, a file, for us, memory) jpeg_memory_src(&cinfo, const_cast<uint8*>(input.getCArray()), input.size()); // Read the parameters with jpeg_read_header() jpeg_read_header(&cinfo, TRUE); // Set parameters for decompression // (We do nothing here since the defaults are fine) // Start decompressor jpeg_start_decompress(&cinfo); // Get and set the values of interest to this object this->width = cinfo.output_width; this->height = cinfo.output_height; // Prepare the pointer object for the pixel data _byte = (uint8*)System::malloc(width * height * 3); // JSAMPLEs per row in output buffer int bpp = cinfo.output_components; int row_stride = cinfo.output_width * bpp; // Make a one-row-high sample array that will go away when done with image JSAMPARRAY temp = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); // Read data on a scanline by scanline basis while (cinfo.output_scanline < cinfo.output_height) { // We may need to adjust the output based on the // number of channels it has. switch (bpp) { case 1: // Grayscale; decompress to temp. jpeg_read_scanlines(&cinfo, temp, 1); // Expand to three channels { uint8* scan = &(_byte[loc * 3]); uint8* endScan = scan + (width * 3); uint8* t = *temp; while (scan < endScan) { uint8 value = t[0]; // Spread the value 3x. scan[0] = value; scan[1] = value; scan[2] = value; scan += 3; t += 1; } } break; case 3: // Read directly into the array { // Need one extra level of indirection. uint8* scan = _byte + loc; JSAMPARRAY ptr = &scan; jpeg_read_scanlines(&cinfo, ptr, 1); } break; case 4: // RGBA; decompress to temp. jpeg_read_scanlines(&cinfo, temp, 1); // Drop the 3rd channel { uint8* scan = &(_byte[loc * 3]); uint8* endScan = scan + width * 3; uint8* t = *temp; while (scan < endScan) { scan[0] = t[0]; scan[1] = t[1]; scan[2] = t[2]; scan += 3; t += 4; } } break; default: throw Error("Unexpected number6 of channels.", input.getFilename()); } loc += row_stride; } // Finish decompression jpeg_finish_decompress(&cinfo); // Release JPEG decompression object jpeg_destroy_decompress(&cinfo); }
void GImage::decodeTGA( BinaryInput& input) { // This is a simple TGA loader that can handle uncompressed // truecolor TGA files (TGA type 2). // Verify this is a TGA file by looking for the TRUEVISION tag. int pos = input.getPosition(); input.setPosition(input.size() - 18); std::string tag = input.readString(16); if (tag != "TRUEVISION-XFILE") { throw Error("Not a TGA file", input.getFilename()); } input.setPosition(pos); int IDLength = input.readUInt8(); int colorMapType = input.readUInt8(); int imageType = input.readUInt8(); (void)colorMapType; // 2 is the type supported by this routine. if (imageType != 2) { throw Error("TGA images must be type 2 (Uncompressed truecolor)", input.getFilename()); } // Color map specification input.skip(5); // Image specification // Skip x and y offsets input.skip(4); m_width = input.readInt16(); m_height = input.readInt16(); int colorDepth = input.readUInt8(); if ((colorDepth != 24) && (colorDepth != 32)) { throw Error("TGA files must be 24 or 32 bit.", input.getFilename()); } if (colorDepth == 32) { m_channels = 4; } else { m_channels = 3; } // Image descriptor contains overlay data as well // as data indicating where the origin is int imageDescriptor = input.readUInt8(); (void)imageDescriptor; // Image ID input.skip(IDLength); m_byte = (uint8*)m_memMan->alloc(m_width * m_height * m_channels); debugAssert(m_byte); // Pixel data int x; int y; if (m_channels == 3) { for (y = m_height - 1; y >= 0; --y) { for (x = 0; x < m_width; ++x) { int b = input.readUInt8(); int g = input.readUInt8(); int r = input.readUInt8(); int i = (x + y * m_width) * 3; m_byte[i + 0] = r; m_byte[i + 1] = g; m_byte[i + 2] = b; } } } else { for (y = m_height - 1; y >= 0; --y) { for (x = 0; x < m_width; ++x) { int b = input.readUInt8(); int g = input.readUInt8(); int r = input.readUInt8(); int a = input.readUInt8(); int i = (x + y * m_width) * 4; m_byte[i + 0] = r; m_byte[i + 1] = g; m_byte[i + 2] = b; m_byte[i + 3] = a; } } } }