// ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // The functions of processing *.tga files. // ---------------------------------------------------------------------- private static unsafe Bitmap GetUnCompressed(byte[] buffer, HEADER_TGA sgHeader) { Bitmap bmp = null; int Width, Height, bpp, bytesPerPixel, stride; // ---- try { // Определяем ширину TGA изображения; Width = sgHeader.Width; // Определяем высоту TGA изображения; Height = sgHeader.Height; // Получаем кол-во бит на пиксель; (16, 24, 32); bpp = sgHeader.PixelDepth; // Делим на 8 для получения байт/пиксель; bytesPerPixel = bpp/8; // Вычисляем количество байт в строке; stride = Width*bytesPerPixel; // ---- const int Isb32p = 32; // ---- byte* row = null; IntPtr rowP = IntPtr.Zero; int x = 0, y = 0, pt = 0, iStep = 0; var line = new byte[stride]; // ---- bool LeftToRight = ((sgHeader.ImageDescriptor & (1 << (8 - 4))) == 0); bool TopToBottom = ((sgHeader.ImageDescriptor & (1 << (8 - 5))) == 0); if (bpp < 32) TopToBottom = !TopToBottom; // ---- PixelFormat px = PixelFormat.Format32bppArgb; switch (bpp) { case 24: px = PixelFormat.Format24bppRgb; break; case 32: px = PixelFormat.Format32bppArgb; break; } bmp = new Bitmap(Width, Height, px); var rect = new Rectangle(0, 0, Width, Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); // ---- if (LeftToRight) // Вывод изображения слева на право; { if (TopToBottom) // Вывод изобрадения сверху вниз; { for (y = 0; y < Height; y++) // Проход по всем строкам; { /* Array.Copy(buffer, iStep, line, 0, stride); iStep += stride; x = 0; // ---- row = (byte*)bmpData.Scan0 + (y * bmpData.Stride); // ---- for (pt = 0; pt < stride; pt += bytesPerPixel, x += bytesPerPixel) // Проход по строке; { row[x + 0] = line[pt + 0]; row[x + 1] = line[pt + 1]; row[x + 2] = line[pt + 2]; if (bpp == 32) row[x + 3] = line[pt + 3]; } */ // ---- ///* rowP = (IntPtr) ((int) bmpData.Scan0 + (y*bmpData.Stride)); // ---- Marshal.Copy(buffer, iStep, rowP, stride); iStep += stride; //*/ } } else // Вывод изобрадения сниху вверх; { for (y = Height - 1; y >= 0; y--) // Проход по всем строкам; { /* Array.Copy(buffer, iStep, line, 0, stride); iStep += stride; x = 0; // ---- row = (byte*)bmpData.Scan0 + (y * bmpData.Stride); // ---- for (pt = 0; pt < stride; pt += bytesPerPixel, x += bytesPerPixel) // Проход по строке; { row[x + 0] = line[pt + 0]; row[x + 1] = line[pt + 1]; row[x + 2] = line[pt + 2]; if (bpp == 32) row[x + 3] = line[pt + 3]; } */ // ---- ///* rowP = (IntPtr) ((int) bmpData.Scan0 + (y*bmpData.Stride)); // ---- Marshal.Copy(buffer, iStep, rowP, stride); iStep += stride; //*/ } } } else // Вывод изображения справо на лево; { if (TopToBottom) // Вывод изобрадения сверху вниз; { for (y = 0; y < Height; y++) // Проход по всем строкам; { Array.Copy(buffer, iStep, line, 0, stride); iStep += stride; x = 0; // ---- row = (byte*) bmpData.Scan0 + (y*bmpData.Stride); // ---- for (pt = stride - 1; pt >= 0; pt -= bytesPerPixel, x += bytesPerPixel) // Проход по строке; { row[x + 0] = line[pt - 3]; row[x + 1] = line[pt - 2]; row[x + 2] = line[pt - 1]; if (bpp == Isb32p) row[x + 3] = line[pt - 0]; } } } else // Вывод изобрадения сниху вверх; { for (y = Height - 1; y >= 0; y--) // Проход по всем строкам; { Array.Copy(buffer, iStep, line, 0, stride); iStep += stride; x = 0; // ---- row = (byte*) bmpData.Scan0 + (y*bmpData.Stride); // ---- for (pt = stride - 1; pt >= 0; pt -= bytesPerPixel, x += bytesPerPixel) // Проход по строке; { row[x + 0] = line[pt - 3]; row[x + 1] = line[pt - 2]; row[x + 2] = line[pt - 1]; if (bpp == Isb32p) row[x + 3] = line[pt - 0]; } } } } // ---- bmp.UnlockBits(bmpData); } catch (Exception) { bmp = null; } // ---- return bmp; }
// StructLayout; LayoutKind; Marshal; // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // Developed by: S@nek[BoR] // Creation Date: 18.08.2008 // Last Update: 10.05.2009 // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // # DATA/IMAGE TYPES: // 0 - No image data included. // 1 - Uncompressed, color-mapped images. // 2 - Uncompressed, Unmapped RGB images. // 3 - Uncompressed, black and white images. // 9 - Run length encoded, color-mapped images. // 10 - Run length encoded, RGB images. // 11 - Compressed, black and white images. // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- public static Bitmap GetFromFile(string FilePath) { Bitmap bmp = null; FileStream fs = null; byte[] header = null; // ---- if (!File.Exists(FilePath)) return null; // ---- try { fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read); // ---- int iHeaderSize = 0; unsafe { iHeaderSize = sizeof (HEADER_TGA); } header = new byte[iHeaderSize]; // header; // ---- int bLength = (int) fs.Length - iHeaderSize; var buffer = new byte[bLength]; // ---- fs.Position = 0; fs.Read(header, 0, iHeaderSize); // Маркер сдвинут на 18 байтов, так как произошло чтение; fs.Read(buffer, 0, bLength); fs.Close(); // ---- var sgHeader = new HEADER_TGA(); unsafe { Marshal.Copy(header, 0, new IntPtr(&sgHeader), sizeof (HEADER_TGA)); } // ---- if (sgHeader.PixelDepth == 16 || sgHeader.PixelDepth == 24 || sgHeader.PixelDepth == 32) { switch (sgHeader.ImageType) { case 0: bmp = GetUnCompressed(buffer, sgHeader); break; case 1: break; case 2: bmp = GetUnCompressed(buffer, sgHeader); break; case 3: bmp = GetUnCompressed(buffer, sgHeader); break; case 9: break; case 10: bmp = GetCompressed(buffer, sgHeader); break; case 11: break; default: break; } } } catch (Exception) { bmp = null; } finally { if (fs != null) { fs.Close(); fs.Dispose(); } } // ---- return bmp; }
private static Bitmap GetCompressed(byte[] buffer, HEADER_TGA sgHeader) { Bitmap bmp = null; MemoryStream nms = null; int Width, Height, bpp, bytesPerPixel; // ---- try { // Определяем ширину TGA изображения; Width = sgHeader.Width; // Определяем высоту TGA изображения; Height = sgHeader.Height; // Получаем кол-во бит на пиксель; (16, 24, 32); bpp = sgHeader.PixelDepth; // Делим на 8 для получения байт/пиксель; bytesPerPixel = bpp/8; // ---- const int iRAWSection = 127; // ---- uint j = 0; int iStep = 0; int bpCount = 0; uint currentpixel = 0; uint pixelcount = Convert.ToUInt32(Width*Height); // Количество пикселей в изображении; var colorbuffer = new byte[bytesPerPixel]; byte chunkheader = 0; // ---- nms = new MemoryStream(); // ---- while (currentpixel < pixelcount) { chunkheader = buffer[iStep]; iStep++; // ---- if (chunkheader <= iRAWSection) // Если секция является 'RAW' секцией; { chunkheader++; // Добавляем единицу для получения количества RAW пикселей; // ---- /* for (j = 0; j < chunkheader; j++) { Array.Copy(buffer, iStep, colorbuffer, 0, bytesPerPixel); iStep += bytesPerPixel; // ---- nms.Write(colorbuffer, 0, bytesPerPixel); } */ // ---- // bpCount = bytesPerPixel*chunkheader; nms.Write(buffer, iStep, bpCount); iStep += bpCount; // // ---- currentpixel += chunkheader; } else // Если это RLE идентификатор; { chunkheader -= iRAWSection; // Вычитаем 127 для получения количества повторений; // ---- Array.Copy(buffer, iStep, colorbuffer, 0, bytesPerPixel); // Считываем 1 пиксель; iStep += bytesPerPixel; // ---- for (j = 0; j < chunkheader; j++) nms.Write(colorbuffer, 0, bytesPerPixel); // ---- currentpixel += chunkheader; } } // ---- var contentBuffer = new byte[nms.Length]; nms.Position = 0; //Сброс позиции старта nms.Read(contentBuffer, 0, contentBuffer.Length); bmp = GetUnCompressed(contentBuffer, sgHeader); } catch (Exception) { bmp = null; } finally { if (nms != null) { nms.Close(); nms.Dispose(); } } // ---- return bmp; }