ImageData ReadV5(Stream stream, TlgMetaData info) { using (var src = new ArcView.Reader(stream)) { int width = (int)info.Width; int height = (int)info.Height; int colors = info.BPP / 8; int blockheight = src.ReadInt32(); int blockcount = (height - 1) / blockheight + 1; // skip block size section src.BaseStream.Seek(blockcount * 4, SeekOrigin.Current); int stride = width * 4; var image_bits = new byte[height * stride]; var text = new byte[4096]; for (int i = 0; i < 4096; ++i) { text[i] = 0; } var inbuf = new byte[blockheight * width + 10]; byte [][] outbuf = new byte[4][]; for (int i = 0; i < colors; i++) { outbuf[i] = new byte[blockheight * width + 10]; } int z = 0; int prevline = -1; for (int y_blk = 0; y_blk < height; y_blk += blockheight) { // read file and decompress for (int c = 0; c < colors; c++) { byte mark = src.ReadByte(); int size; size = src.ReadInt32(); if (mark == 0) { // modified LZSS compressed data if (size != src.Read(inbuf, 0, size)) { return(null); } z = TVPTLG5DecompressSlide(outbuf[c], inbuf, size, text, z); } else { // raw data src.Read(outbuf[c], 0, size); } } // compose colors and store int y_lim = y_blk + blockheight; if (y_lim > height) { y_lim = height; } int outbuf_pos = 0; for (int y = y_blk; y < y_lim; y++) { int current = y * stride; int current_org = current; if (prevline >= 0) { // not first line switch (colors) { case 3: TVPTLG5ComposeColors3To4(image_bits, current, prevline, outbuf, outbuf_pos, width); break; case 4: TVPTLG5ComposeColors4To4(image_bits, current, prevline, outbuf, outbuf_pos, width); break; } } else { // first line switch (colors) { case 3: for (int pr = 0, pg = 0, pb = 0, x = 0; x < width; x++) { int b = outbuf[0][outbuf_pos + x]; int g = outbuf[1][outbuf_pos + x]; int r = outbuf[2][outbuf_pos + x]; b += g; r += g; image_bits[current++] = (byte)(pb += b); image_bits[current++] = (byte)(pg += g); image_bits[current++] = (byte)(pr += r); image_bits[current++] = 0xff; } break; case 4: for (int pr = 0, pg = 0, pb = 0, pa = 0, x = 0; x < width; x++) { int b = outbuf[0][outbuf_pos + x]; int g = outbuf[1][outbuf_pos + x]; int r = outbuf[2][outbuf_pos + x]; int a = outbuf[3][outbuf_pos + x]; b += g; r += g; image_bits[current++] = (byte)(pb += b); image_bits[current++] = (byte)(pg += g); image_bits[current++] = (byte)(pr += r); image_bits[current++] = (byte)(pa += a); } break; } } outbuf_pos += width; prevline = current_org; } } PixelFormat format = 4 == colors ? PixelFormats.Bgra32 : PixelFormats.Bgr32; return(ImageData.Create(info, format, null, image_bits, stride)); } }
ImageData ReadV6(Stream stream, TlgMetaData info) { using (var src = new ArcView.Reader(stream)) { int width = (int)info.Width; int height = (int)info.Height; int colors = info.BPP / 8; int max_bit_length = src.ReadInt32(); int x_block_count = ((width - 1) / TVP_TLG6_W_BLOCK_SIZE) + 1; int y_block_count = ((height - 1) / TVP_TLG6_H_BLOCK_SIZE) + 1; int main_count = width / TVP_TLG6_W_BLOCK_SIZE; int fraction = width - main_count * TVP_TLG6_W_BLOCK_SIZE; var image_bits = new uint[height * width]; var bit_pool = new byte[max_bit_length / 8 + 5]; var pixelbuf = new uint[width * TVP_TLG6_H_BLOCK_SIZE + 1]; var filter_types = new byte[x_block_count * y_block_count]; var zeroline = new uint[width]; var LZSS_text = new byte[4096]; // initialize zero line (virtual y=-1 line) uint zerocolor = 3 == colors ? 0xff000000 : 0x00000000; for (var i = 0; i < width; ++i) { zeroline[i] = zerocolor; } uint[] prevline = zeroline; int prevline_index = 0; // initialize LZSS text (used by chroma filter type codes) int p = 0; for (uint i = 0; i < 32 * 0x01010101; i += 0x01010101) { for (uint j = 0; j < 16 * 0x01010101; j += 0x01010101) { LZSS_text[p++] = (byte)(i & 0xff); LZSS_text[p++] = (byte)(i >> 8 & 0xff); LZSS_text[p++] = (byte)(i >> 16 & 0xff); LZSS_text[p++] = (byte)(i >> 24 & 0xff); LZSS_text[p++] = (byte)(j & 0xff); LZSS_text[p++] = (byte)(j >> 8 & 0xff); LZSS_text[p++] = (byte)(j >> 16 & 0xff); LZSS_text[p++] = (byte)(j >> 24 & 0xff); } } // read chroma filter types. // chroma filter types are compressed via LZSS as used by TLG5. { int inbuf_size = src.ReadInt32(); byte[] inbuf = src.ReadBytes(inbuf_size); if (inbuf_size != inbuf.Length) { return(null); } TVPTLG5DecompressSlide(filter_types, inbuf, inbuf_size, LZSS_text, 0); } // for each horizontal block group ... for (int y = 0; y < height; y += TVP_TLG6_H_BLOCK_SIZE) { int ylim = y + TVP_TLG6_H_BLOCK_SIZE; if (ylim >= height) { ylim = height; } int pixel_count = (ylim - y) * width; // decode values for (int c = 0; c < colors; c++) { // read bit length int bit_length = src.ReadInt32(); // get compress method int method = (bit_length >> 30) & 3; bit_length &= 0x3fffffff; // compute byte length int byte_length = bit_length / 8; if (0 != (bit_length % 8)) { byte_length++; } // read source from input src.Read(bit_pool, 0, byte_length); // decode values // two most significant bits of bitlength are // entropy coding method; // 00 means Golomb method, // 01 means Gamma method (not yet suppoted), // 10 means modified LZSS method (not yet supported), // 11 means raw (uncompressed) data (not yet supported). switch (method) { case 0: if (c == 0 && colors != 1) { TVPTLG6DecodeGolombValuesForFirst(pixelbuf, pixel_count, bit_pool); } else { TVPTLG6DecodeGolombValues(pixelbuf, c * 8, pixel_count, bit_pool); } break; default: throw new InvalidFormatException("Unsupported entropy coding method"); } } // for each line int ft = (y / TVP_TLG6_H_BLOCK_SIZE) * x_block_count; // within filter_types int skipbytes = (ylim - y) * TVP_TLG6_W_BLOCK_SIZE; for (int yy = y; yy < ylim; yy++) { int curline = yy * width; int dir = (yy & 1) ^ 1; int oddskip = ((ylim - yy - 1) - (yy - y)); if (0 != main_count) { int start = ((width < TVP_TLG6_W_BLOCK_SIZE) ? width : TVP_TLG6_W_BLOCK_SIZE) * (yy - y); TVPTLG6DecodeLineGeneric( prevline, prevline_index, image_bits, curline, width, 0, main_count, filter_types, ft, skipbytes, pixelbuf, start, zerocolor, oddskip, dir); } if (main_count != x_block_count) { int ww = fraction; if (ww > TVP_TLG6_W_BLOCK_SIZE) { ww = TVP_TLG6_W_BLOCK_SIZE; } int start = ww * (yy - y); TVPTLG6DecodeLineGeneric( prevline, prevline_index, image_bits, curline, width, main_count, x_block_count, filter_types, ft, skipbytes, pixelbuf, start, zerocolor, oddskip, dir); } prevline = image_bits; prevline_index = curline; // Array.Copy (image_bits, curline, prevline, 0, width); } } unsafe { fixed(void *data = image_bits) { int stride = width * 4; PixelFormat format = 32 == info.BPP ? PixelFormats.Bgra32 : PixelFormats.Bgr32; var bitmap = BitmapSource.Create(width, height, ImageData.DefaultDpiX, ImageData.DefaultDpiY, format, null, (IntPtr)data, height * stride, stride); bitmap.Freeze(); return(new ImageData(bitmap, info)); } } } }