/* Copyright (c) 2022-present miku-666 * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1.The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. **/ using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Text; using OMI; namespace PckStudio.Core.IO.TGA { internal class TGAWriter { private Bitmap _bitmap; private int extensionDataOffset = 0; public TGAWriter() { } private void WriteHeader(EndiannessAwareBinaryWriter writer) { writer.Write(new byte[] { 0, // header.Id.Length 0, // colormap type (byte)TGADataTypeCode.RGB }); writer.Write(0); // Colormap.Origin writer.Write(0); // Colormap.Length writer.Write(0); // Colormap.Depth writer.Write(0); // Origin.X writer.Write(0); // Origin.Y writer.Write(_bitmap.Width); writer.Write(_bitmap.Height); writer.Write(32); // BitsPerPixel writer.Write(8); // ImageDescriptor } private void WriteImage(EndiannessAwareBinaryWriter writer) { _bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); BitmapData bitmapData = _bitmap.LockBits( new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] buffer = new byte[_bitmap.Width * _bitmap.Height * 4]; Marshal.Copy(bitmapData.Scan0, buffer, 0, _bitmap.Width * _bitmap.Height * 4); writer.Write(buffer); } private void WriteFooter(EndiannessAwareBinaryWriter writer) { writer.Write(extensionDataOffset); // extensionDataOffset writer.Write(0); // developerAreaDataOffset writer.WriteString(TGAFooter.Signature); writer.Write((byte)0x2E); writer.Write((byte)0x00); } private void WriteExtensionData(EndiannessAwareBinaryWriter writer) { extensionDataOffset = Convert.ToInt32(writer.BaseStream.Position); TGAExtentionData extentionData = TGAExtentionData.Create(); writer.Write(TGAExtentionData.ExtensionSize); // Author Name writer.WriteString(extentionData.AuthorName, 41); // Author Comment writer.WriteString(extentionData.AuthorComment, 324); // Timestamp writer.Write((short)extentionData.TimeStamp.Month); writer.Write((short)extentionData.TimeStamp.Day); writer.Write((short)extentionData.TimeStamp.Year); writer.Write((short)extentionData.TimeStamp.Hour); writer.Write((short)extentionData.TimeStamp.Minute); writer.Write((short)extentionData.TimeStamp.Second); // Job id writer.WriteString(extentionData.JobID, 41); // Job time writer.Write((short)extentionData.JobTime.Hours); writer.Write((short)extentionData.JobTime.Minutes); writer.Write((short)extentionData.JobTime.Seconds); // Software Id writer.WriteString(extentionData.SoftwareID, 41); // Software version writer.Write(extentionData.SoftwareVersion, 0, 3); // Key color writer.Write(extentionData.KeyColor); // Pixel aspect ratio writer.Write(extentionData.PixelAspectRatio); // Gamma value writer.Write(extentionData.GammaValue); // Color correction offset writer.Write(extentionData.ColorCorrectionOffset); // Postage stamp offset writer.Write(extentionData.PostageStampOffset); // Scan line offset writer.Write(extentionData.ScanLineOffset); // Attributes type writer.Write(extentionData.AttributesType); } public void WriteToStream(Stream stream, Image image) { _bitmap = new Bitmap(image); using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, ByteOrder.LittleEndian)) { WriteHeader(writer); WriteImage(writer); WriteExtensionData(writer); WriteFooter(writer); } } public void WriteToFile(string filename, Image image) { using (FileStream fs = File.OpenWrite(filename)) { WriteToStream(fs, image); } } } }