source: OniSplit/Imaging/TgaWriter.cs

Last change on this file was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 4.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4
5namespace Oni.Imaging
6{
7 internal static class TgaWriter
8 {
9 public static void Write(Surface surface, string filePath)
10 {
11 surface = surface.Convert(SurfaceFormat.BGRA);
12
13 var imageType = TgaImageType.TrueColor;
14 byte[] rleData = null;
15
16 if (surface.Width > 2 && surface.Height > 2)
17 {
18 rleData = Rle32Compress(surface.Width, surface.Height, surface.Data);
19
20 if (rleData.Length > surface.Data.Length)
21 rleData = null;
22 else
23 imageType = TgaImageType.RleTrueColor;
24 }
25
26 var header = TgaHeader.Create(surface.Width, surface.Height, imageType);
27
28 Directory.CreateDirectory(Path.GetDirectoryName(filePath));
29
30 using (var stream = File.Create(filePath))
31 using (var writer = new BinaryWriter(stream))
32 {
33 header.Write(writer);
34
35 if (rleData != null)
36 writer.Write(rleData, 0, rleData.Length);
37 else
38 writer.Write(surface.Data, 0, surface.Data.Length);
39 }
40 }
41
42 private static byte[] Rle32Compress(int width, int height, byte[] sourceData)
43 {
44 var result = new List<byte>();
45
46 for (int y = height - 1; y >= 0; y--)
47 {
48 int lineOffset = y * width * 4;
49 int lastPixel = BitConverter.ToInt32(sourceData, y * width * 4);
50 int runStart = 0;
51 byte packetType = 64;
52
53 for (int x = 1; x < width; x++)
54 {
55 int pixel = BitConverter.ToInt32(sourceData, x * 4 + lineOffset);
56
57 if (pixel == lastPixel)
58 {
59 if (packetType == 0)
60 {
61 Rle32WritePackets(result, packetType, sourceData, runStart, x - 1, lineOffset);
62 runStart = x - 1;
63 }
64
65 packetType = 128;
66 }
67 else
68 {
69 if (packetType == 128)
70 {
71 Rle32WritePackets(result, packetType, sourceData, runStart, x, lineOffset);
72 runStart = x;
73 }
74
75 packetType = 0;
76 }
77
78 lastPixel = pixel;
79
80 if (x == width - 1)
81 {
82 Rle32WritePackets(result, packetType, sourceData, runStart, width, lineOffset);
83 }
84 }
85 }
86
87 return result.ToArray();
88 }
89
90 private static void Rle32WritePackets(List<byte> result, byte packetType, byte[] sourceData, int xStart, int xStop, int lineOffset)
91 {
92 int count = xStop - xStart;
93
94 if (count == 0)
95 return;
96
97 int startOffset = (xStart * 4) + lineOffset;
98
99 if (packetType == 128)
100 {
101 for (; count > 128; count -= 128)
102 {
103 result.Add((byte)(packetType | 127));
104
105 for (int i = 0; i < 4; i++)
106 result.Add(sourceData[startOffset + i]);
107 }
108
109 result.Add((byte)(packetType | (count - 1)));
110
111 for (int i = 0; i < 4; i++)
112 result.Add(sourceData[startOffset + i]);
113 }
114 else
115 {
116 for (; count > 128; count -= 128)
117 {
118 result.Add((byte)(packetType | 127));
119
120 for (int i = 0; i < 4 * 128; i++)
121 result.Add(sourceData[startOffset + i]);
122
123 startOffset += 4 * 128;
124 }
125
126 result.Add((byte)(packetType | (count - 1)));
127
128 for (int i = 0; i < 4 * count; i++)
129 result.Add(sourceData[startOffset + i]);
130 }
131 }
132 }
133}
Note: See TracBrowser for help on using the repository browser.