corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
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 }