corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * Copyright (c) 2006-2014, openmetaverse.org |
||
3 | * All rights reserved. |
||
4 | * |
||
5 | * - Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * |
||
8 | * - Redistributions of source code must retain the above copyright notice, this |
||
9 | * list of conditions and the following disclaimer. |
||
10 | * - Neither the name of the openmetaverse.org nor the names |
||
11 | * of its contributors may be used to endorse or promote products derived from |
||
12 | * this software without specific prior written permission. |
||
13 | * |
||
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
||
18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
24 | * POSSIBILITY OF SUCH DAMAGE. |
||
25 | */ |
||
26 | |||
27 | using System; |
||
28 | |||
29 | namespace OpenMetaverse.Imaging |
||
30 | { |
||
31 | #if !NO_UNSAFE |
||
32 | |||
33 | /// <summary> |
||
34 | /// Capability to load TGAs to Bitmap |
||
35 | /// </summary> |
||
36 | public class LoadTGAClass |
||
37 | { |
||
38 | struct tgaColorMap |
||
39 | { |
||
40 | public ushort FirstEntryIndex; |
||
41 | public ushort Length; |
||
42 | public byte EntrySize; |
||
43 | |||
44 | public void Read(System.IO.BinaryReader br) |
||
45 | { |
||
46 | FirstEntryIndex = br.ReadUInt16(); |
||
47 | Length = br.ReadUInt16(); |
||
48 | EntrySize = br.ReadByte(); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | struct tgaImageSpec |
||
53 | { |
||
54 | public ushort XOrigin; |
||
55 | public ushort YOrigin; |
||
56 | public ushort Width; |
||
57 | public ushort Height; |
||
58 | public byte PixelDepth; |
||
59 | public byte Descriptor; |
||
60 | |||
61 | public void Read(System.IO.BinaryReader br) |
||
62 | { |
||
63 | XOrigin = br.ReadUInt16(); |
||
64 | YOrigin = br.ReadUInt16(); |
||
65 | Width = br.ReadUInt16(); |
||
66 | Height = br.ReadUInt16(); |
||
67 | PixelDepth = br.ReadByte(); |
||
68 | Descriptor = br.ReadByte(); |
||
69 | } |
||
70 | |||
71 | public byte AlphaBits |
||
72 | { |
||
73 | get |
||
74 | { |
||
75 | return (byte)(Descriptor & 0xF); |
||
76 | } |
||
77 | set |
||
78 | { |
||
79 | Descriptor = (byte)((Descriptor & ~0xF) | (value & 0xF)); |
||
80 | } |
||
81 | } |
||
82 | |||
83 | public bool BottomUp |
||
84 | { |
||
85 | get |
||
86 | { |
||
87 | return (Descriptor & 0x20) == 0x20; |
||
88 | } |
||
89 | set |
||
90 | { |
||
91 | Descriptor = (byte)((Descriptor & ~0x20) | (value ? 0x20 : 0)); |
||
92 | } |
||
93 | } |
||
94 | } |
||
95 | |||
96 | struct tgaHeader |
||
97 | { |
||
98 | public byte IdLength; |
||
99 | public byte ColorMapType; |
||
100 | public byte ImageType; |
||
101 | |||
102 | public tgaColorMap ColorMap; |
||
103 | public tgaImageSpec ImageSpec; |
||
104 | |||
105 | public void Read(System.IO.BinaryReader br) |
||
106 | { |
||
107 | this.IdLength = br.ReadByte(); |
||
108 | this.ColorMapType = br.ReadByte(); |
||
109 | this.ImageType = br.ReadByte(); |
||
110 | this.ColorMap = new tgaColorMap(); |
||
111 | this.ImageSpec = new tgaImageSpec(); |
||
112 | this.ColorMap.Read(br); |
||
113 | this.ImageSpec.Read(br); |
||
114 | } |
||
115 | |||
116 | public bool RleEncoded |
||
117 | { |
||
118 | get |
||
119 | { |
||
120 | return ImageType >= 9; |
||
121 | } |
||
122 | } |
||
123 | } |
||
124 | |||
125 | struct tgaCD |
||
126 | { |
||
127 | public uint RMask, GMask, BMask, AMask; |
||
128 | public byte RShift, GShift, BShift, AShift; |
||
129 | public uint FinalOr; |
||
130 | public bool NeedNoConvert; |
||
131 | } |
||
132 | |||
133 | static uint UnpackColor( |
||
134 | uint sourceColor, ref tgaCD cd) |
||
135 | { |
||
136 | if (cd.RMask == 0xFF && cd.GMask == 0xFF && cd.BMask == 0xFF) |
||
137 | { |
||
138 | // Special case to deal with 8-bit TGA files that we treat as alpha masks |
||
139 | return sourceColor << 24; |
||
140 | } |
||
141 | else |
||
142 | { |
||
143 | uint rpermute = (sourceColor << cd.RShift) | (sourceColor >> (32 - cd.RShift)); |
||
144 | uint gpermute = (sourceColor << cd.GShift) | (sourceColor >> (32 - cd.GShift)); |
||
145 | uint bpermute = (sourceColor << cd.BShift) | (sourceColor >> (32 - cd.BShift)); |
||
146 | uint apermute = (sourceColor << cd.AShift) | (sourceColor >> (32 - cd.AShift)); |
||
147 | uint result = |
||
148 | (rpermute & cd.RMask) | (gpermute & cd.GMask) |
||
149 | | (bpermute & cd.BMask) | (apermute & cd.AMask) | cd.FinalOr; |
||
150 | |||
151 | return result; |
||
152 | } |
||
153 | } |
||
154 | |||
155 | static unsafe void decodeLine( |
||
156 | System.Drawing.Imaging.BitmapData b, |
||
157 | int line, |
||
158 | int byp, |
||
159 | byte[] data, |
||
160 | ref tgaCD cd) |
||
161 | { |
||
162 | if (cd.NeedNoConvert) |
||
163 | { |
||
164 | // fast copy |
||
165 | uint* linep = (uint*)((byte*)b.Scan0.ToPointer() + line * b.Stride); |
||
166 | fixed (byte* ptr = data) |
||
167 | { |
||
168 | uint* sptr = (uint*)ptr; |
||
169 | for (int i = 0; i < b.Width; ++i) |
||
170 | { |
||
171 | linep[i] = sptr[i]; |
||
172 | } |
||
173 | } |
||
174 | } |
||
175 | else |
||
176 | { |
||
177 | byte* linep = (byte*)b.Scan0.ToPointer() + line * b.Stride; |
||
178 | |||
179 | uint* up = (uint*)linep; |
||
180 | |||
181 | int rdi = 0; |
||
182 | |||
183 | fixed (byte* ptr = data) |
||
184 | { |
||
185 | for (int i = 0; i < b.Width; ++i) |
||
186 | { |
||
187 | uint x = 0; |
||
188 | for (int j = 0; j < byp; ++j) |
||
189 | { |
||
190 | x |= ((uint)ptr[rdi]) << (j << 3); |
||
191 | ++rdi; |
||
192 | } |
||
193 | up[i] = UnpackColor(x, ref cd); |
||
194 | } |
||
195 | } |
||
196 | } |
||
197 | } |
||
198 | |||
199 | static void decodeRle( |
||
200 | System.Drawing.Imaging.BitmapData b, |
||
201 | int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) |
||
202 | { |
||
203 | try |
||
204 | { |
||
205 | int w = b.Width; |
||
206 | // make buffer larger, so in case of emergency I can decode |
||
207 | // over line ends. |
||
208 | byte[] linebuffer = new byte[(w + 128) * byp]; |
||
209 | int maxindex = w * byp; |
||
210 | int index = 0; |
||
211 | |||
212 | for (int j = 0; j < b.Height; ++j) |
||
213 | { |
||
214 | while (index < maxindex) |
||
215 | { |
||
216 | byte blocktype = br.ReadByte(); |
||
217 | |||
218 | int bytestoread; |
||
219 | int bytestocopy; |
||
220 | |||
221 | if (blocktype >= 0x80) |
||
222 | { |
||
223 | bytestoread = byp; |
||
224 | bytestocopy = byp * (blocktype - 0x80); |
||
225 | } |
||
226 | else |
||
227 | { |
||
228 | bytestoread = byp * (blocktype + 1); |
||
229 | bytestocopy = 0; |
||
230 | } |
||
231 | |||
232 | //if (index + bytestoread > maxindex) |
||
233 | // throw new System.ArgumentException ("Corrupt TGA"); |
||
234 | |||
235 | br.Read(linebuffer, index, bytestoread); |
||
236 | index += bytestoread; |
||
237 | |||
238 | for (int i = 0; i != bytestocopy; ++i) |
||
239 | { |
||
240 | linebuffer[index + i] = linebuffer[index + i - bytestoread]; |
||
241 | } |
||
242 | index += bytestocopy; |
||
243 | } |
||
244 | if (!bottomUp) |
||
245 | decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); |
||
246 | else |
||
247 | decodeLine(b, j, byp, linebuffer, ref cd); |
||
248 | |||
249 | if (index > maxindex) |
||
250 | { |
||
251 | Array.Copy(linebuffer, maxindex, linebuffer, 0, index - maxindex); |
||
252 | index -= maxindex; |
||
253 | } |
||
254 | else |
||
255 | index = 0; |
||
256 | |||
257 | } |
||
258 | } |
||
259 | catch (System.IO.EndOfStreamException) |
||
260 | { |
||
261 | } |
||
262 | } |
||
263 | |||
264 | static void decodePlain( |
||
265 | System.Drawing.Imaging.BitmapData b, |
||
266 | int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) |
||
267 | { |
||
268 | int w = b.Width; |
||
269 | byte[] linebuffer = new byte[w * byp]; |
||
270 | |||
271 | for (int j = 0; j < b.Height; ++j) |
||
272 | { |
||
273 | br.Read(linebuffer, 0, w * byp); |
||
274 | |||
275 | if (!bottomUp) |
||
276 | decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); |
||
277 | else |
||
278 | decodeLine(b, j, byp, linebuffer, ref cd); |
||
279 | } |
||
280 | } |
||
281 | |||
282 | static void decodeStandard8( |
||
283 | System.Drawing.Imaging.BitmapData b, |
||
284 | tgaHeader hdr, |
||
285 | System.IO.BinaryReader br) |
||
286 | { |
||
287 | tgaCD cd = new tgaCD(); |
||
288 | cd.RMask = 0x000000ff; |
||
289 | cd.GMask = 0x000000ff; |
||
290 | cd.BMask = 0x000000ff; |
||
291 | cd.AMask = 0x000000ff; |
||
292 | cd.RShift = 0; |
||
293 | cd.GShift = 0; |
||
294 | cd.BShift = 0; |
||
295 | cd.AShift = 0; |
||
296 | cd.FinalOr = 0x00000000; |
||
297 | if (hdr.RleEncoded) |
||
298 | decodeRle(b, 1, cd, br, hdr.ImageSpec.BottomUp); |
||
299 | else |
||
300 | decodePlain(b, 1, cd, br, hdr.ImageSpec.BottomUp); |
||
301 | } |
||
302 | |||
303 | static void decodeSpecial16( |
||
304 | System.Drawing.Imaging.BitmapData b, tgaHeader hdr, System.IO.BinaryReader br) |
||
305 | { |
||
306 | // i must convert the input stream to a sequence of uint values |
||
307 | // which I then unpack. |
||
308 | tgaCD cd = new tgaCD(); |
||
309 | cd.RMask = 0x00f00000; |
||
310 | cd.GMask = 0x0000f000; |
||
311 | cd.BMask = 0x000000f0; |
||
312 | cd.AMask = 0xf0000000; |
||
313 | cd.RShift = 12; |
||
314 | cd.GShift = 8; |
||
315 | cd.BShift = 4; |
||
316 | cd.AShift = 16; |
||
317 | cd.FinalOr = 0; |
||
318 | |||
319 | if (hdr.RleEncoded) |
||
320 | decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); |
||
321 | else |
||
322 | decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); |
||
323 | } |
||
324 | |||
325 | static void decodeStandard16( |
||
326 | System.Drawing.Imaging.BitmapData b, |
||
327 | tgaHeader hdr, |
||
328 | System.IO.BinaryReader br) |
||
329 | { |
||
330 | // i must convert the input stream to a sequence of uint values |
||
331 | // which I then unpack. |
||
332 | tgaCD cd = new tgaCD(); |
||
333 | cd.RMask = 0x00f80000; // from 0xF800 |
||
334 | cd.GMask = 0x0000fc00; // from 0x07E0 |
||
335 | cd.BMask = 0x000000f8; // from 0x001F |
||
336 | cd.AMask = 0x00000000; |
||
337 | cd.RShift = 8; |
||
338 | cd.GShift = 5; |
||
339 | cd.BShift = 3; |
||
340 | cd.AShift = 0; |
||
341 | cd.FinalOr = 0xff000000; |
||
342 | |||
343 | if (hdr.RleEncoded) |
||
344 | decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); |
||
345 | else |
||
346 | decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); |
||
347 | } |
||
348 | |||
349 | |||
350 | static void decodeSpecial24(System.Drawing.Imaging.BitmapData b, |
||
351 | tgaHeader hdr, System.IO.BinaryReader br) |
||
352 | { |
||
353 | // i must convert the input stream to a sequence of uint values |
||
354 | // which I then unpack. |
||
355 | tgaCD cd = new tgaCD(); |
||
356 | cd.RMask = 0x00f80000; |
||
357 | cd.GMask = 0x0000fc00; |
||
358 | cd.BMask = 0x000000f8; |
||
359 | cd.AMask = 0xff000000; |
||
360 | cd.RShift = 8; |
||
361 | cd.GShift = 5; |
||
362 | cd.BShift = 3; |
||
363 | cd.AShift = 8; |
||
364 | cd.FinalOr = 0; |
||
365 | |||
366 | if (hdr.RleEncoded) |
||
367 | decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); |
||
368 | else |
||
369 | decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); |
||
370 | } |
||
371 | |||
372 | static void decodeStandard24(System.Drawing.Imaging.BitmapData b, |
||
373 | tgaHeader hdr, System.IO.BinaryReader br) |
||
374 | { |
||
375 | // i must convert the input stream to a sequence of uint values |
||
376 | // which I then unpack. |
||
377 | tgaCD cd = new tgaCD(); |
||
378 | cd.RMask = 0x00ff0000; |
||
379 | cd.GMask = 0x0000ff00; |
||
380 | cd.BMask = 0x000000ff; |
||
381 | cd.AMask = 0x00000000; |
||
382 | cd.RShift = 0; |
||
383 | cd.GShift = 0; |
||
384 | cd.BShift = 0; |
||
385 | cd.AShift = 0; |
||
386 | cd.FinalOr = 0xff000000; |
||
387 | |||
388 | if (hdr.RleEncoded) |
||
389 | decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); |
||
390 | else |
||
391 | decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); |
||
392 | } |
||
393 | |||
394 | static void decodeStandard32(System.Drawing.Imaging.BitmapData b, |
||
395 | tgaHeader hdr, System.IO.BinaryReader br) |
||
396 | { |
||
397 | // i must convert the input stream to a sequence of uint values |
||
398 | // which I then unpack. |
||
399 | tgaCD cd = new tgaCD(); |
||
400 | cd.RMask = 0x00ff0000; |
||
401 | cd.GMask = 0x0000ff00; |
||
402 | cd.BMask = 0x000000ff; |
||
403 | cd.AMask = 0xff000000; |
||
404 | cd.RShift = 0; |
||
405 | cd.GShift = 0; |
||
406 | cd.BShift = 0; |
||
407 | cd.AShift = 0; |
||
408 | cd.FinalOr = 0x00000000; |
||
409 | cd.NeedNoConvert = true; |
||
410 | |||
411 | if (hdr.RleEncoded) |
||
412 | decodeRle(b, 4, cd, br, hdr.ImageSpec.BottomUp); |
||
413 | else |
||
414 | decodePlain(b, 4, cd, br, hdr.ImageSpec.BottomUp); |
||
415 | } |
||
416 | |||
417 | |||
418 | public static System.Drawing.Size GetTGASize(string filename) |
||
419 | { |
||
420 | System.IO.FileStream f = System.IO.File.OpenRead(filename); |
||
421 | |||
422 | System.IO.BinaryReader br = new System.IO.BinaryReader(f); |
||
423 | |||
424 | tgaHeader header = new tgaHeader(); |
||
425 | header.Read(br); |
||
426 | br.Close(); |
||
427 | |||
428 | return new System.Drawing.Size(header.ImageSpec.Width, header.ImageSpec.Height); |
||
429 | |||
430 | } |
||
431 | |||
432 | public static System.Drawing.Bitmap LoadTGA(System.IO.Stream source) |
||
433 | { |
||
434 | byte[] buffer = new byte[source.Length]; |
||
435 | source.Read(buffer, 0, buffer.Length); |
||
436 | |||
437 | System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); |
||
438 | |||
439 | using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) |
||
440 | { |
||
441 | tgaHeader header = new tgaHeader(); |
||
442 | header.Read(br); |
||
443 | |||
444 | if (header.ImageSpec.PixelDepth != 8 && |
||
445 | header.ImageSpec.PixelDepth != 16 && |
||
446 | header.ImageSpec.PixelDepth != 24 && |
||
447 | header.ImageSpec.PixelDepth != 32) |
||
448 | throw new ArgumentException("Not a supported tga file."); |
||
449 | |||
450 | if (header.ImageSpec.AlphaBits > 8) |
||
451 | throw new ArgumentException("Not a supported tga file."); |
||
452 | |||
453 | if (header.ImageSpec.Width > 4096 || |
||
454 | header.ImageSpec.Height > 4096) |
||
455 | throw new ArgumentException("Image too large."); |
||
456 | |||
457 | System.Drawing.Bitmap b; |
||
458 | System.Drawing.Imaging.BitmapData bd; |
||
459 | |||
460 | // Create a bitmap for the image. |
||
461 | // Only include an alpha layer when the image requires one. |
||
462 | if (header.ImageSpec.AlphaBits > 0 || |
||
463 | header.ImageSpec.PixelDepth == 8 || // Assume 8 bit images are alpha only |
||
464 | header.ImageSpec.PixelDepth == 32) // Assume 32 bit images are ARGB |
||
465 | { // Image needs an alpha layer |
||
466 | b = new System.Drawing.Bitmap( |
||
467 | header.ImageSpec.Width, |
||
468 | header.ImageSpec.Height, |
||
469 | System.Drawing.Imaging.PixelFormat.Format32bppArgb); |
||
470 | |||
471 | bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height), |
||
472 | System.Drawing.Imaging.ImageLockMode.WriteOnly, |
||
473 | System.Drawing.Imaging.PixelFormat.Format32bppPArgb); |
||
474 | } |
||
475 | else |
||
476 | { // Image does not need an alpha layer, so do not include one. |
||
477 | b = new System.Drawing.Bitmap( |
||
478 | header.ImageSpec.Width, |
||
479 | header.ImageSpec.Height, |
||
480 | System.Drawing.Imaging.PixelFormat.Format32bppRgb); |
||
481 | |||
482 | bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height), |
||
483 | System.Drawing.Imaging.ImageLockMode.WriteOnly, |
||
484 | System.Drawing.Imaging.PixelFormat.Format32bppRgb); |
||
485 | } |
||
486 | |||
487 | switch (header.ImageSpec.PixelDepth) |
||
488 | { |
||
489 | case 8: |
||
490 | decodeStandard8(bd, header, br); |
||
491 | break; |
||
492 | case 16: |
||
493 | if (header.ImageSpec.AlphaBits > 0) |
||
494 | decodeSpecial16(bd, header, br); |
||
495 | else |
||
496 | decodeStandard16(bd, header, br); |
||
497 | break; |
||
498 | case 24: |
||
499 | if (header.ImageSpec.AlphaBits > 0) |
||
500 | decodeSpecial24(bd, header, br); |
||
501 | else |
||
502 | decodeStandard24(bd, header, br); |
||
503 | break; |
||
504 | case 32: |
||
505 | decodeStandard32(bd, header, br); |
||
506 | break; |
||
507 | default: |
||
508 | b.UnlockBits(bd); |
||
509 | b.Dispose(); |
||
510 | return null; |
||
511 | } |
||
512 | |||
513 | b.UnlockBits(bd); |
||
514 | return b; |
||
515 | } |
||
516 | } |
||
517 | |||
518 | public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source) |
||
519 | { |
||
520 | return LoadTGAImage(source, false); |
||
521 | } |
||
522 | |||
523 | public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source, bool mask) |
||
524 | { |
||
525 | byte[] buffer = new byte[source.Length]; |
||
526 | source.Read(buffer, 0, buffer.Length); |
||
527 | |||
528 | System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); |
||
529 | |||
530 | using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) |
||
531 | { |
||
532 | tgaHeader header = new tgaHeader(); |
||
533 | header.Read(br); |
||
534 | |||
535 | if (header.ImageSpec.PixelDepth != 8 && |
||
536 | header.ImageSpec.PixelDepth != 16 && |
||
537 | header.ImageSpec.PixelDepth != 24 && |
||
538 | header.ImageSpec.PixelDepth != 32) |
||
539 | throw new ArgumentException("Not a supported tga file."); |
||
540 | |||
541 | if (header.ImageSpec.AlphaBits > 8) |
||
542 | throw new ArgumentException("Not a supported tga file."); |
||
543 | |||
544 | if (header.ImageSpec.Width > 4096 || |
||
545 | header.ImageSpec.Height > 4096) |
||
546 | throw new ArgumentException("Image too large."); |
||
547 | |||
548 | byte[] decoded = new byte[header.ImageSpec.Width * header.ImageSpec.Height * 4]; |
||
549 | System.Drawing.Imaging.BitmapData bd = new System.Drawing.Imaging.BitmapData(); |
||
550 | |||
551 | fixed (byte* pdecoded = &decoded[0]) |
||
552 | { |
||
553 | bd.Width = header.ImageSpec.Width; |
||
554 | bd.Height = header.ImageSpec.Height; |
||
555 | bd.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb; |
||
556 | bd.Stride = header.ImageSpec.Width * 4; |
||
557 | bd.Scan0 = (IntPtr)pdecoded; |
||
558 | |||
559 | switch (header.ImageSpec.PixelDepth) |
||
560 | { |
||
561 | case 8: |
||
562 | decodeStandard8(bd, header, br); |
||
563 | break; |
||
564 | case 16: |
||
565 | if (header.ImageSpec.AlphaBits > 0) |
||
566 | decodeSpecial16(bd, header, br); |
||
567 | else |
||
568 | decodeStandard16(bd, header, br); |
||
569 | break; |
||
570 | case 24: |
||
571 | if (header.ImageSpec.AlphaBits > 0) |
||
572 | decodeSpecial24(bd, header, br); |
||
573 | else |
||
574 | decodeStandard24(bd, header, br); |
||
575 | break; |
||
576 | case 32: |
||
577 | decodeStandard32(bd, header, br); |
||
578 | break; |
||
579 | default: |
||
580 | return null; |
||
581 | } |
||
582 | } |
||
583 | |||
584 | int n = header.ImageSpec.Width * header.ImageSpec.Height; |
||
585 | ManagedImage image; |
||
586 | |||
587 | if (mask && header.ImageSpec.AlphaBits == 0 && header.ImageSpec.PixelDepth == 8) |
||
588 | { |
||
589 | image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, |
||
590 | ManagedImage.ImageChannels.Alpha); |
||
591 | int p = 3; |
||
592 | |||
593 | for (int i = 0; i < n; i++) |
||
594 | { |
||
595 | image.Alpha[i] = decoded[p]; |
||
596 | p += 4; |
||
597 | } |
||
598 | } |
||
599 | else |
||
600 | { |
||
601 | image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, |
||
602 | ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); |
||
603 | int p = 0; |
||
604 | |||
605 | for (int i = 0; i < n; i++) |
||
606 | { |
||
607 | image.Blue[i] = decoded[p++]; |
||
608 | image.Green[i] = decoded[p++]; |
||
609 | image.Red[i] = decoded[p++]; |
||
610 | image.Alpha[i] = decoded[p++]; |
||
611 | } |
||
612 | } |
||
613 | |||
614 | br.Close(); |
||
615 | return image; |
||
616 | } |
||
617 | } |
||
618 | |||
619 | public static System.Drawing.Bitmap LoadTGA(string filename) |
||
620 | { |
||
621 | try |
||
622 | { |
||
623 | using (System.IO.FileStream f = System.IO.File.OpenRead(filename)) |
||
624 | { |
||
625 | return LoadTGA(f); |
||
626 | } |
||
627 | } |
||
628 | catch (System.IO.DirectoryNotFoundException) |
||
629 | { |
||
630 | return null; // file not found |
||
631 | } |
||
632 | catch (System.IO.FileNotFoundException) |
||
633 | { |
||
634 | return null; // file not found |
||
635 | } |
||
636 | } |
||
637 | } |
||
638 | |||
639 | #endif |
||
640 | } |