/// <summary> /// Creates a new instance of the TargaImage object. /// </summary> public TargaImage() { this.objTargaFooter = new TargaFooter(); this.objTargaHeader = new TargaHeader(); this.objTargaExtensionArea = new TargaExtensionArea(); this.bmpTargaImage = null; this.bmpImageThumbnail = null; }
public static IPixelArray CreatePixelArrayFromFileStream(FileStream filestream) { int tgaSize; bool isExtendedFile; long fileLength = filestream.Length; // We'll use a binary reader to make it easier // to get at the specific data types BinaryReader reader = new BinaryReader(filestream); // Targa images come in many different formats, and there are a couple of different versions // of the specification. // First thing to do is determine if the file is adhereing to version 2.0 of the spcification. // We do that by reading a 'footer', which is the last 26 bytes of the file. string targaXFileID = "TRUEVISION-XFILE"; TargaFooter footer = null; // Get the last 26 bytes of the file so we can see if the signature // is in there. long seekPosition = filestream.Seek(fileLength - 26, SeekOrigin.Begin); byte[] targaFooterBytes = reader.ReadBytes(26); string targaFooterSignature = System.Text.ASCIIEncoding.ASCII.GetString(targaFooterBytes, 8, 16); // If the strings compare favorably, then we have a match for an extended // TARGA file type. isExtendedFile = (0 == string.Compare(targaFooterSignature, targaXFileID)); if (isExtendedFile) { // Since we now know it's an extended file, // we'll create the footer object and fill // in the details. footer = new TargaFooter(); // Of the 26 bytes we read from the end of the file // the bytes are layed out as follows. //Bytes 0-3: The Extension Area Offset //Bytes 4-7: The Developer Directory Offset //Bytes 8-23: The Signature //Byte 24: ASCII Character “.” //Byte 25: Binary zero string terminator (0x00) // We take those raw bytes, and turn them into meaningful fields // in the footer object. footer.ExtensionAreaOffset = BitConverter.ToInt32(targaFooterBytes, 0); footer.DeveloperDirectoryOffset = BitConverter.ToInt32(targaFooterBytes, 4); footer.Signature = targaFooterSignature; footer.Period = (byte)'.'; footer.BinaryZero = 0; } // Now create the header that we'll fill int TargaHeader fHeader = new TargaHeader(); // Go back to the beginning of the file first filestream.Seek(0, SeekOrigin.Begin); fHeader.IDLength = reader.ReadByte(); fHeader.ColorMapType = (TargaColorMapType)reader.ReadByte(); fHeader.ImageType = (TargaImageType)reader.ReadByte(); fHeader.CMapStart = reader.ReadInt16(); fHeader.CMapLength = reader.ReadInt16(); fHeader.CMapDepth = reader.ReadByte(); // Image description fHeader.XOffset = reader.ReadInt16(); fHeader.YOffset = reader.ReadInt16(); fHeader.Width = reader.ReadInt16(); // Width of image in pixels fHeader.Height = reader.ReadInt16(); // Height of image in pixels fHeader.PixelDepth = reader.ReadByte(); // How many bits per pixel fHeader.ImageDescriptor = reader.ReadByte(); /// The single byte that is the ImageDescriptor contains the following /// information. // Bits 3-0 - number of attribute bits associated with each | // pixel. For the Targa 16, this would be 0 or | // 1. For the Targa 24, it should be 0. For | // Targa 32, it should be 8. | // Bit 4 - controls left/right transfer of pixels to /// the screen. /// 0 = left to right /// 1 = right to left // Bit 5 - controls top/bottom transfer of pixels to /// the screen. /// 0 = bottom to top /// 1 = top to bottom /// /// In Combination bits 5/4, they would have these values /// 00 = bottom left /// 01 = bottom right /// 10 = top left /// 11 = top right /// // Bits 7-6 - Data storage interleaving flag. | // 00 = non-interleaved. | // 01 = two-way (even/odd) interleaving. | // 10 = four way interleaving. | // 11 = reserved. byte desc = fHeader.ImageDescriptor; byte attrBits = (byte)(desc & 0x0F); byte horizontalOrder = (byte)((desc & 0x10) >> 4); byte verticalOrder = (byte)((desc & 0x20) >> 5); byte interleave = (byte)((desc & 0xC0) >> 6); // We can't deal with the compressed image types, so if we encounter // any of them, we'll just return null. if ((TargaImageType.TrueColor != fHeader.ImageType) && (TargaImageType.Monochrome != fHeader.ImageType)) { return null; } PixmapOrientation pixmapOrientation = PixmapOrientation.BottomToTop; if (0 == verticalOrder) pixmapOrientation = PixmapOrientation.BottomToTop; else pixmapOrientation = PixmapOrientation.TopToBottom; int bytesPerPixel = fHeader.PixelDepth / 8; // Skip past the Image Identification field if there is one byte[] ImageIdentification; if (fHeader.IDLength > 0) ImageIdentification = reader.ReadBytes(fHeader.IDLength); // calculate image size based on bytes per pixel, width and height. int bytesPerRow = fHeader.Width * bytesPerPixel; tgaSize = bytesPerPixel * fHeader.Height; byte[] imageData = reader.ReadBytes((int)tgaSize); // Create the correct pixel array for the data switch (bytesPerPixel) { case 3: { PixelArray<BGRb> pixmap = new PixelArray<BGRb>(fHeader.Width, fHeader.Height, imageData); return pixmap; } case 4: { PixelArray<BGRAb> pixmap = new PixelArray<BGRAb>(fHeader.Width, fHeader.Height, imageData); return pixmap; } case 1: { PixelArray<Lumb> pixmap = new PixelArray<Lumb>(fHeader.Width, fHeader.Height, imageData); return pixmap; } } return null; }
public static IPixelArray CreatePixelArrayFromFile(string filename) { int tgaSize; bool isExtendedFile; // Open the file. if ((null == filename) || (string.Empty == filename)) return null; FileStream filestream = new FileStream(filename, FileMode.Open, FileAccess.Read); BinaryReader reader = new BinaryReader(filestream); // Targa images come in many different formats, and there are a couple of different versions // of the specification. // First thing to do is determine if the file is adhereing to version 2.0 of the spcification. // We do that by reading a 'footer', which is the last 26 bytes of the file. long fileLength = filestream.Length; long seekPosition = filestream.Seek(fileLength - 26, SeekOrigin.Begin); byte[] targaFooterBytes = reader.ReadBytes(26); string targaXFileID = "TRUEVISION-XFILE"; string targaFooterSignature = System.Text.ASCIIEncoding.ASCII.GetString(targaFooterBytes, 8, 16); TargaFooter footer=null; isExtendedFile = (0 == string.Compare(targaFooterSignature, targaXFileID)); if (isExtendedFile) { // Since we now know it's an extended file, // we'll create the footer object and fill // in the details. footer = new TargaFooter(); // Of the 26 bytes we read from the end of the file // the bytes are layed out as follows. //Bytes 0-3: The Extension Area Offset //Bytes 4-7: The Developer Directory Offset //Bytes 8-23: The Signature //Byte 24: ASCII Character “.” //Byte 25: Binary zero string terminator (0x00) // We take those raw bytes, and turn them into meaningful fields // in the footer object. footer.ExtensionAreaOffset = BitConverter.ToInt32(targaFooterBytes, 0); footer.DeveloperDirectoryOffset = BitConverter.ToInt32(targaFooterBytes, 4); footer.Signature = targaFooterSignature; footer.Period = (byte)'.'; footer.BinaryZero = 0; } TargaHeader fHeader = new TargaHeader(); // If you want to use unsafe code, you could do the following // there are two primary drawbacks. // 1. The targa image data is in Little-Endian format. On platforms // that are big-endian, the data will not necessarily show up correctly in the header. // 2. You must compile with unsafe code. That may or may not be a problem depending // on the application, but it really isn't a necessity. // // The speed gain may not be realized, so there's really no reason for the added complexity. // First, just reader enough of bytes from the file to capture the // header into a chunk of memory. //byte[] headerBytes = reader.ReadBytes(Marshal.SizeOf(fHeader)); //IntPtr headerPtr; //unsafe //{ // GCHandle dataHandle = GCHandle.Alloc(headerBytes, GCHandleType.Pinned); // try // { // headerPtr = (IntPtr)dataHandle.AddrOfPinnedObject(); // // Now use the marshaller to copy the header bytes into a structure // fHeader = (TargaHeader)Marshal.PtrToStructure(headerPtr, typeof(TargaHeader)); // } // finally // { // dataHandle.Free(); // } //} filestream.Seek(0, SeekOrigin.Begin); fHeader.IDLength = reader.ReadByte(); fHeader.ColorMapType = (TargaColorMapType)reader.ReadByte(); fHeader.ImageType = (TargaImageType)reader.ReadByte(); fHeader.CMapStart = reader.ReadInt16(); fHeader.CMapLength = reader.ReadInt16(); fHeader.CMapDepth = reader.ReadByte(); // Image description fHeader.XOffset = reader.ReadInt16(); fHeader.YOffset = reader.ReadInt16(); fHeader.Width = reader.ReadInt16(); // Width of image in pixels fHeader.Height = reader.ReadInt16(); // Height of image in pixels fHeader.PixelDepth = reader.ReadByte(); // How many bits per pixel fHeader.ImageDescriptor = reader.ReadByte(); // Image Descriptor Byte. | // Bits 3-0 - number of attribute bits associated with each | // pixel. For the Targa 16, this would be 0 or | // 1. For the Targa 24, it should be 0. For | // Targa 32, it should be 8. | // Bit 4 - controls left/right transfer of pixels to /// the screen. /// 0 = left to right /// 1 = right to left // Bit 5 - controls top/bottom transfer of pixels to /// the screen. /// 0 = bottom to top /// 1 = top to bottom /// /// In Combination bits 5/4, they would have these values /// 00 = bottom left /// 01 = bottom right /// 10 = top left /// 11 = top right /// // Bits 7-6 - Data storage interleaving flag. | // 00 = non-interleaved. | // 01 = two-way (even/odd) interleaving. | // 10 = four way interleaving. | // 11 = reserved. byte desc = fHeader.ImageDescriptor; byte attrBits = (byte)(desc & 0x0F); ImageOrigin origin = (ImageOrigin)(desc & (byte)ImageOrigin.OriginMask); byte interleave = (byte)((desc & 0xC0) >> 6); // This routine can only deal with the uncompressed image types. // So, fail if this is not the case. if ((TargaImageType.TrueColor != fHeader.ImageType) && (TargaImageType.Monochrome != fHeader.ImageType)) { filestream.Close(); return null; } PixmapOrientation pixmapOrientation = PixmapOrientation.BottomToTop; if ((ImageOrigin.BottomLeft == origin) || (ImageOrigin.BottomRight == origin)) pixmapOrientation = PixmapOrientation.BottomToTop; else pixmapOrientation = PixmapOrientation.TopToBottom; int bytesPerPixel = fHeader.PixelDepth / 8; // Skip past the Image Identification field byte[] ImageIdentification; if (fHeader.IDLength > 0) ImageIdentification = reader.ReadBytes(fHeader.IDLength); // calculate image size based on bytes per pixel, width and height. tgaSize = fHeader.Width * fHeader.Height * bytesPerPixel; byte[] imageData = reader.ReadBytes((int)tgaSize); filestream.Close(); // Pin the array in mememory, and get a data pointer to it IntPtr dataPtr; unsafe { GCHandle dataHandle = GCHandle.Alloc(imageData, GCHandleType.Pinned); dataPtr = (IntPtr)dataHandle.AddrOfPinnedObject(); // Create the appropriate PixelArray // then create an accessor to match // Copy the data from the buffer pointer to the new array switch (bytesPerPixel) { case 3: { PixelAccessorBGRb srcAccess = new PixelAccessorBGRb(fHeader.Width, fHeader.Height, pixmapOrientation, dataPtr); PixelArray<BGRb> pixmap = new PixelArray<BGRb>(srcAccess); return pixmap; } break; case 4: { PixelAccessorBGRAb srcAccess = new PixelAccessorBGRAb(fHeader.Width, fHeader.Height, pixmapOrientation, dataPtr); PixelArray<BGRAb> pixmap = new PixelArray<BGRAb>(srcAccess); return pixmap; } break; case 1: { PixelAccessorLumb srcAccess = new PixelAccessorLumb(fHeader.Width, fHeader.Height, pixmapOrientation, dataPtr); PixelArray<Lumb> pixmap = new PixelArray<Lumb>(srcAccess); return pixmap; } break; } } return null; }
/// <summary> /// Clears out all objects and resources. /// </summary> private void ClearAll() { if (this.bmpTargaImage != null) { this.bmpTargaImage.Dispose(); this.bmpTargaImage = null; } if (this.ImageByteHandle.IsAllocated) this.ImageByteHandle.Free(); if (this.ThumbnailByteHandle.IsAllocated) this.ThumbnailByteHandle.Free(); this.objTargaHeader = new TargaHeader(); this.objTargaExtensionArea = new TargaExtensionArea(); this.objTargaFooter = new TargaFooter(); this.eTGAFormat = TGAFormat.UNKNOWN; this.intStride = 0; this.intPadding = 0; this.rows.Clear(); this.row.Clear(); this.strFileName = string.Empty; }