|
7 | 7 | using Avalonia.Media.Imaging; |
8 | 8 | using Avalonia.Platform; |
9 | 9 |
|
| 10 | +using BitMiracle.LibTiff.Classic; |
10 | 11 | using Pfim; |
11 | 12 |
|
12 | 13 | namespace SourceGit.ViewModels |
@@ -39,6 +40,9 @@ public static Models.ImageDecoder GetDecoder(string file) |
39 | 40 | case ".tga": |
40 | 41 | case ".dds": |
41 | 42 | return Models.ImageDecoder.Pfim; |
| 43 | + case ".tif": |
| 44 | + case ".tiff": |
| 45 | + return Models.ImageDecoder.Tiff; |
42 | 46 | default: |
43 | 47 | return Models.ImageDecoder.None; |
44 | 48 | } |
@@ -70,86 +74,106 @@ private static ImageSource LoadFromStream(Stream stream, Models.ImageDecoder dec |
70 | 74 | var size = stream.Length; |
71 | 75 | if (size > 0) |
72 | 76 | { |
73 | | - if (decoder == Models.ImageDecoder.Builtin) |
74 | | - return DecodeWithAvalonia(stream, size); |
75 | | - else if (decoder == Models.ImageDecoder.Pfim) |
76 | | - return DecodeWithPfim(stream, size); |
| 77 | + try |
| 78 | + { |
| 79 | + switch (decoder) |
| 80 | + { |
| 81 | + case Models.ImageDecoder.Builtin: |
| 82 | + return DecodeWithAvalonia(stream, size); |
| 83 | + case Models.ImageDecoder.Pfim: |
| 84 | + return DecodeWithPfim(stream, size); |
| 85 | + case Models.ImageDecoder.Tiff: |
| 86 | + return DecodeWithTiff(stream, size); |
| 87 | + } |
| 88 | + } |
| 89 | + catch (Exception e) |
| 90 | + { |
| 91 | + Console.Out.WriteLine(e.Message); |
| 92 | + } |
77 | 93 | } |
78 | 94 |
|
79 | 95 | return new ImageSource(null, 0); |
80 | 96 | } |
81 | 97 |
|
82 | 98 | private static ImageSource DecodeWithAvalonia(Stream stream, long size) |
83 | 99 | { |
84 | | - try |
85 | | - { |
86 | | - var bitmap = new Bitmap(stream); |
87 | | - return new ImageSource(bitmap, size); |
88 | | - } |
89 | | - catch |
90 | | - { |
91 | | - return new ImageSource(null, 0); |
92 | | - } |
| 100 | + var bitmap = new Bitmap(stream); |
| 101 | + return new ImageSource(bitmap, size); |
93 | 102 | } |
94 | 103 |
|
95 | 104 | private static ImageSource DecodeWithPfim(Stream stream, long size) |
96 | 105 | { |
97 | | - try |
| 106 | + using (var pfiImage = Pfimage.FromStream(stream)) |
98 | 107 | { |
99 | | - using (var pfiImage = Pfimage.FromStream(stream)) |
100 | | - { |
101 | | - var data = pfiImage.Data; |
102 | | - var stride = pfiImage.Stride; |
| 108 | + var data = pfiImage.Data; |
| 109 | + var stride = pfiImage.Stride; |
103 | 110 |
|
104 | | - var pixelFormat = PixelFormats.Bgra8888; |
105 | | - var alphaFormat = AlphaFormat.Opaque; |
106 | | - switch (pfiImage.Format) |
107 | | - { |
108 | | - case ImageFormat.Rgb8: |
109 | | - pixelFormat = PixelFormats.Gray8; |
110 | | - break; |
111 | | - case ImageFormat.R5g5b5: |
112 | | - case ImageFormat.R5g5b5a1: |
113 | | - pixelFormat = PixelFormats.Bgr555; |
114 | | - break; |
115 | | - case ImageFormat.R5g6b5: |
116 | | - pixelFormat = PixelFormats.Bgr565; |
117 | | - break; |
118 | | - case ImageFormat.Rgb24: |
119 | | - pixelFormat = PixelFormats.Bgr24; |
120 | | - break; |
121 | | - case ImageFormat.Rgba16: |
122 | | - var pixels2 = pfiImage.DataLen / 2; |
123 | | - data = new byte[pixels2 * 4]; |
124 | | - stride = pfiImage.Width * 4; |
125 | | - for (var i = 0; i < pixels2; i++) |
126 | | - { |
127 | | - var src = BitConverter.ToUInt16(pfiImage.Data, i * 2); |
128 | | - data[i * 4 + 0] = (byte)Math.Round((src & 0x0F) / 15F * 255); // B |
129 | | - data[i * 4 + 1] = (byte)Math.Round(((src >> 4) & 0x0F) / 15F * 255); // G |
130 | | - data[i * 4 + 2] = (byte)Math.Round(((src >> 8) & 0x0F) / 15F * 255); // R |
131 | | - data[i * 4 + 3] = (byte)Math.Round(((src >> 12) & 0x0F) / 15F * 255); // A |
132 | | - } |
133 | | - |
134 | | - alphaFormat = AlphaFormat.Premul; |
135 | | - break; |
136 | | - case ImageFormat.Rgba32: |
137 | | - alphaFormat = AlphaFormat.Premul; |
138 | | - break; |
139 | | - default: |
140 | | - return new ImageSource(null, 0); |
141 | | - } |
142 | | - |
143 | | - var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); |
144 | | - var pixelSize = new PixelSize(pfiImage.Width, pfiImage.Height); |
145 | | - var dpi = new Vector(96, 96); |
146 | | - var bitmap = new Bitmap(pixelFormat, alphaFormat, ptr, pixelSize, dpi, stride); |
147 | | - return new ImageSource(bitmap, size); |
| 111 | + var pixelFormat = PixelFormats.Bgra8888; |
| 112 | + var alphaFormat = AlphaFormat.Opaque; |
| 113 | + switch (pfiImage.Format) |
| 114 | + { |
| 115 | + case ImageFormat.Rgb8: |
| 116 | + pixelFormat = PixelFormats.Gray8; |
| 117 | + break; |
| 118 | + case ImageFormat.R5g5b5: |
| 119 | + case ImageFormat.R5g5b5a1: |
| 120 | + pixelFormat = PixelFormats.Bgr555; |
| 121 | + break; |
| 122 | + case ImageFormat.R5g6b5: |
| 123 | + pixelFormat = PixelFormats.Bgr565; |
| 124 | + break; |
| 125 | + case ImageFormat.Rgb24: |
| 126 | + pixelFormat = PixelFormats.Bgr24; |
| 127 | + break; |
| 128 | + case ImageFormat.Rgba16: |
| 129 | + var pixels2 = pfiImage.DataLen / 2; |
| 130 | + data = new byte[pixels2 * 4]; |
| 131 | + stride = pfiImage.Width * 4; |
| 132 | + for (var i = 0; i < pixels2; i++) |
| 133 | + { |
| 134 | + var src = BitConverter.ToUInt16(pfiImage.Data, i * 2); |
| 135 | + data[i * 4 + 0] = (byte)Math.Round((src & 0x0F) / 15F * 255); // B |
| 136 | + data[i * 4 + 1] = (byte)Math.Round(((src >> 4) & 0x0F) / 15F * 255); // G |
| 137 | + data[i * 4 + 2] = (byte)Math.Round(((src >> 8) & 0x0F) / 15F * 255); // R |
| 138 | + data[i * 4 + 3] = (byte)Math.Round(((src >> 12) & 0x0F) / 15F * 255); // A |
| 139 | + } |
| 140 | + |
| 141 | + alphaFormat = AlphaFormat.Premul; |
| 142 | + break; |
| 143 | + case ImageFormat.Rgba32: |
| 144 | + alphaFormat = AlphaFormat.Premul; |
| 145 | + break; |
| 146 | + default: |
| 147 | + return new ImageSource(null, 0); |
148 | 148 | } |
| 149 | + |
| 150 | + var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); |
| 151 | + var pixelSize = new PixelSize(pfiImage.Width, pfiImage.Height); |
| 152 | + var dpi = new Vector(96, 96); |
| 153 | + var bitmap = new Bitmap(pixelFormat, alphaFormat, ptr, pixelSize, dpi, stride); |
| 154 | + return new ImageSource(bitmap, size); |
149 | 155 | } |
150 | | - catch |
| 156 | + } |
| 157 | + |
| 158 | + private static ImageSource DecodeWithTiff(Stream stream, long size) |
| 159 | + { |
| 160 | + using (var tiff = Tiff.ClientOpen($"{Guid.NewGuid()}.tif", "r", stream, new TiffStream())) |
151 | 161 | { |
152 | | - return new ImageSource(null, 0); |
| 162 | + if (tiff == null) |
| 163 | + return new ImageSource(null, 0); |
| 164 | + |
| 165 | + var width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt(); |
| 166 | + var height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt(); |
| 167 | + var pixels = new int[width * height]; |
| 168 | + |
| 169 | + // Currently only supports image when its `BITSPERSAMPLE` is one in [1,2,4,8,16] |
| 170 | + tiff.ReadRGBAImageOriented(width, height, pixels, Orientation.TOPLEFT); |
| 171 | + |
| 172 | + var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0); |
| 173 | + var pixelSize = new PixelSize(width, height); |
| 174 | + var dpi = new Vector(96, 96); |
| 175 | + var bitmap = new Bitmap(PixelFormats.Rgba8888, AlphaFormat.Premul, ptr, pixelSize, dpi, width * 4); |
| 176 | + return new ImageSource(bitmap, size); |
153 | 177 | } |
154 | 178 | } |
155 | 179 | } |
|
0 commit comments