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 | using System.IO; |
||
29 | using System.Drawing; |
||
30 | using System.Drawing.Imaging; |
||
31 | using System.Runtime.InteropServices; |
||
32 | |||
33 | namespace OpenMetaverse.Imaging |
||
34 | { |
||
35 | #if !NO_UNSAFE |
||
36 | /// <summary> |
||
37 | /// A Wrapper around openjpeg to encode and decode images to and from byte arrays |
||
38 | /// </summary> |
||
39 | public class OpenJPEG |
||
40 | { |
||
41 | /// <summary>TGA Header size</summary> |
||
42 | public const int TGA_HEADER_SIZE = 32; |
||
43 | |||
44 | #region JPEG2000 Structs |
||
45 | |||
46 | /// <summary> |
||
47 | /// Defines the beginning and ending file positions of a layer in an |
||
48 | /// LRCP-progression JPEG2000 file |
||
49 | /// </summary> |
||
50 | [System.Diagnostics.DebuggerDisplay("Start = {Start} End = {End} Size = {End - Start}")] |
||
51 | [StructLayout(LayoutKind.Sequential, Pack = 4)] |
||
52 | public struct J2KLayerInfo |
||
53 | { |
||
54 | public int Start; |
||
55 | public int End; |
||
56 | } |
||
57 | |||
58 | /// <summary> |
||
59 | /// This structure is used to marshal both encoded and decoded images. |
||
60 | /// MUST MATCH THE STRUCT IN dotnet.h! |
||
61 | /// </summary> |
||
62 | [StructLayout(LayoutKind.Sequential, Pack = 4)] |
||
63 | private struct MarshalledImage |
||
64 | { |
||
65 | public IntPtr encoded; // encoded image data |
||
66 | public int length; // encoded image length |
||
67 | public int dummy; // padding for 64-bit alignment |
||
68 | |||
69 | public IntPtr decoded; // decoded image, contiguous components |
||
70 | |||
71 | public int width; // width of decoded image |
||
72 | public int height; // height of decoded image |
||
73 | public int layers; // layer count |
||
74 | public int resolutions; // resolution count |
||
75 | public int components; // component count |
||
76 | public int packet_count; // packet count |
||
77 | public IntPtr packets; // pointer to the packets array |
||
78 | } |
||
79 | |||
80 | /// <summary> |
||
81 | /// Information about a single packet in a JPEG2000 stream |
||
82 | /// </summary> |
||
83 | [StructLayout(LayoutKind.Sequential, Pack = 4)] |
||
84 | private struct MarshalledPacket |
||
85 | { |
||
86 | /// <summary>Packet start position</summary> |
||
87 | public int start_pos; |
||
88 | /// <summary>Packet header end position</summary> |
||
89 | public int end_ph_pos; |
||
90 | /// <summary>Packet end position</summary> |
||
91 | public int end_pos; |
||
92 | |||
93 | public override string ToString() |
||
94 | { |
||
95 | return String.Format("start_pos: {0} end_ph_pos: {1} end_pos: {2}", |
||
96 | start_pos, end_ph_pos, end_pos); |
||
97 | } |
||
98 | } |
||
99 | |||
100 | #endregion JPEG2000 Structs |
||
101 | |||
102 | #region Unmanaged Function Declarations |
||
103 | |||
104 | |||
105 | // allocate encoded buffer based on length field |
||
106 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
107 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
108 | private static extern bool DotNetAllocEncoded(ref MarshalledImage image); |
||
109 | |||
110 | // allocate decoded buffer based on width and height fields |
||
111 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
112 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
113 | private static extern bool DotNetAllocDecoded(ref MarshalledImage image); |
||
114 | |||
115 | // free buffers |
||
116 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
117 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
118 | private static extern bool DotNetFree(ref MarshalledImage image); |
||
119 | |||
120 | // encode raw to jpeg2000 |
||
121 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
122 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
123 | private static extern bool DotNetEncode(ref MarshalledImage image, bool lossless); |
||
124 | |||
125 | // decode jpeg2000 to raw |
||
126 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
127 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
128 | private static extern bool DotNetDecode(ref MarshalledImage image); |
||
129 | |||
130 | // decode jpeg2000 to raw, get jpeg2000 file info |
||
131 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
132 | [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)] |
||
133 | private static extern bool DotNetDecodeWithInfo(ref MarshalledImage image); |
||
134 | |||
135 | // invoke 64 bit openjpeg calls |
||
136 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
137 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
138 | private static extern bool DotNetAllocEncoded64(ref MarshalledImage image); |
||
139 | |||
140 | // allocate decoded buffer based on width and height fields |
||
141 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
142 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
143 | private static extern bool DotNetAllocDecoded64(ref MarshalledImage image); |
||
144 | |||
145 | // free buffers |
||
146 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
147 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
148 | private static extern bool DotNetFree64(ref MarshalledImage image); |
||
149 | |||
150 | // encode raw to jpeg2000 |
||
151 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
152 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
153 | private static extern bool DotNetEncode64(ref MarshalledImage image, bool lossless); |
||
154 | |||
155 | // decode jpeg2000 to raw |
||
156 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
157 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
158 | private static extern bool DotNetDecode64(ref MarshalledImage image); |
||
159 | |||
160 | // decode jpeg2000 to raw, get jpeg2000 file info |
||
161 | [System.Security.SuppressUnmanagedCodeSecurity] |
||
162 | [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)] |
||
163 | private static extern bool DotNetDecodeWithInfo64(ref MarshalledImage image); |
||
164 | #endregion Unmanaged Function Declarations |
||
165 | |||
166 | /// <summary>OpenJPEG is not threadsafe, so this object is used to lock |
||
167 | /// during calls into unmanaged code</summary> |
||
168 | private static object OpenJPEGLock = new object(); |
||
169 | |||
170 | /// <summary> |
||
171 | /// Encode a <seealso cref="ManagedImage"/> object into a byte array |
||
172 | /// </summary> |
||
173 | /// <param name="image">The <seealso cref="ManagedImage"/> object to encode</param> |
||
174 | /// <param name="lossless">true to enable lossless conversion, only useful for small images ie: sculptmaps</param> |
||
175 | /// <returns>A byte array containing the encoded Image object</returns> |
||
176 | public static byte[] Encode(ManagedImage image, bool lossless) |
||
177 | { |
||
178 | if ((image.Channels & ManagedImage.ImageChannels.Color) == 0 || |
||
179 | ((image.Channels & ManagedImage.ImageChannels.Bump) != 0 && (image.Channels & ManagedImage.ImageChannels.Alpha) == 0)) |
||
180 | throw new ArgumentException("JPEG2000 encoding is not supported for this channel combination"); |
||
181 | |||
182 | byte[] encoded = null; |
||
183 | MarshalledImage marshalled = new MarshalledImage(); |
||
184 | |||
185 | // allocate and copy to input buffer |
||
186 | marshalled.width = image.Width; |
||
187 | marshalled.height = image.Height; |
||
188 | marshalled.components = 3; |
||
189 | if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) marshalled.components++; |
||
190 | if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) marshalled.components++; |
||
191 | |||
192 | lock (OpenJPEGLock) |
||
193 | { |
||
194 | |||
195 | bool allocSuccess = (IntPtr.Size == 8) ? DotNetAllocDecoded64(ref marshalled) : DotNetAllocDecoded(ref marshalled); |
||
196 | |||
197 | if (!allocSuccess) |
||
198 | throw new Exception("DotNetAllocDecoded failed"); |
||
199 | |||
200 | int n = image.Width * image.Height; |
||
201 | |||
202 | if ((image.Channels & ManagedImage.ImageChannels.Color) != 0) |
||
203 | { |
||
204 | Marshal.Copy(image.Red, 0, marshalled.decoded, n); |
||
205 | Marshal.Copy(image.Green, 0, (IntPtr)(marshalled.decoded.ToInt64() + n), n); |
||
206 | Marshal.Copy(image.Blue, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 2), n); |
||
207 | } |
||
208 | |||
209 | if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) Marshal.Copy(image.Alpha, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 3), n); |
||
210 | if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) Marshal.Copy(image.Bump, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 4), n); |
||
211 | |||
212 | // codec will allocate output buffer |
||
213 | bool encodeSuccess = (IntPtr.Size == 8) ? DotNetEncode64(ref marshalled, lossless) : DotNetEncode(ref marshalled, lossless); |
||
214 | if (!encodeSuccess) |
||
215 | throw new Exception("DotNetEncode failed"); |
||
216 | |||
217 | // copy output buffer |
||
218 | encoded = new byte[marshalled.length]; |
||
219 | Marshal.Copy(marshalled.encoded, encoded, 0, marshalled.length); |
||
220 | |||
221 | // free buffers |
||
222 | if (IntPtr.Size == 8) |
||
223 | DotNetFree64(ref marshalled); |
||
224 | else |
||
225 | DotNetFree(ref marshalled); |
||
226 | } |
||
227 | |||
228 | return encoded; |
||
229 | } |
||
230 | |||
231 | /// <summary> |
||
232 | /// Encode a <seealso cref="ManagedImage"/> object into a byte array |
||
233 | /// </summary> |
||
234 | /// <param name="image">The <seealso cref="ManagedImage"/> object to encode</param> |
||
235 | /// <returns>a byte array of the encoded image</returns> |
||
236 | public static byte[] Encode(ManagedImage image) |
||
237 | { |
||
238 | return Encode(image, false); |
||
239 | } |
||
240 | |||
241 | /// <summary> |
||
242 | /// Decode JPEG2000 data to an <seealso cref="System.Drawing.Image"/> and |
||
243 | /// <seealso cref="ManagedImage"/> |
||
244 | /// </summary> |
||
245 | /// <param name="encoded">JPEG2000 encoded data</param> |
||
246 | /// <param name="managedImage">ManagedImage object to decode to</param> |
||
247 | /// <param name="image">Image object to decode to</param> |
||
248 | /// <returns>True if the decode succeeds, otherwise false</returns> |
||
249 | public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage, out Image image) |
||
250 | { |
||
251 | managedImage = null; |
||
252 | image = null; |
||
253 | |||
254 | if (DecodeToImage(encoded, out managedImage)) |
||
255 | { |
||
256 | try |
||
257 | { |
||
258 | image = managedImage.ExportBitmap(); |
||
259 | return true; |
||
260 | } |
||
261 | catch (Exception ex) |
||
262 | { |
||
263 | Logger.Log("Failed to export and load TGA data from decoded image", Helpers.LogLevel.Error, ex); |
||
264 | return false; |
||
265 | } |
||
266 | } |
||
267 | else |
||
268 | { |
||
269 | return false; |
||
270 | } |
||
271 | } |
||
272 | |||
273 | /// <summary> |
||
274 | /// |
||
275 | /// </summary> |
||
276 | /// <param name="encoded"></param> |
||
277 | /// <param name="managedImage"></param> |
||
278 | /// <returns></returns> |
||
279 | public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage) |
||
280 | { |
||
281 | MarshalledImage marshalled = new MarshalledImage(); |
||
282 | |||
283 | // Allocate and copy to input buffer |
||
284 | marshalled.length = encoded.Length; |
||
285 | |||
286 | lock (OpenJPEGLock) |
||
287 | { |
||
288 | if (IntPtr.Size == 8) |
||
289 | DotNetAllocEncoded64(ref marshalled); |
||
290 | else |
||
291 | DotNetAllocEncoded(ref marshalled); |
||
292 | |||
293 | Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); |
||
294 | |||
295 | // Codec will allocate output buffer |
||
296 | if (IntPtr.Size == 8) |
||
297 | DotNetDecode64(ref marshalled); |
||
298 | else |
||
299 | DotNetDecode(ref marshalled); |
||
300 | |||
301 | int n = marshalled.width * marshalled.height; |
||
302 | |||
303 | switch (marshalled.components) |
||
304 | { |
||
305 | case 1: // Grayscale |
||
306 | managedImage = new ManagedImage(marshalled.width, marshalled.height, |
||
307 | ManagedImage.ImageChannels.Color); |
||
308 | Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); |
||
309 | Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); |
||
310 | Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); |
||
311 | break; |
||
312 | |||
313 | case 2: // Grayscale + alpha |
||
314 | managedImage = new ManagedImage(marshalled.width, marshalled.height, |
||
315 | ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); |
||
316 | Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); |
||
317 | Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); |
||
318 | Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); |
||
319 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Alpha, 0, n); |
||
320 | break; |
||
321 | |||
322 | case 3: // RGB |
||
323 | managedImage = new ManagedImage(marshalled.width, marshalled.height, |
||
324 | ManagedImage.ImageChannels.Color); |
||
325 | Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); |
||
326 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); |
||
327 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); |
||
328 | break; |
||
329 | |||
330 | case 4: // RGBA |
||
331 | managedImage = new ManagedImage(marshalled.width, marshalled.height, |
||
332 | ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); |
||
333 | Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); |
||
334 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); |
||
335 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); |
||
336 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n); |
||
337 | break; |
||
338 | |||
339 | case 5: // RGBAB |
||
340 | managedImage = new ManagedImage(marshalled.width, marshalled.height, |
||
341 | ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump); |
||
342 | Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); |
||
343 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); |
||
344 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); |
||
345 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n); |
||
346 | Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 4)), managedImage.Bump, 0, n); |
||
347 | break; |
||
348 | |||
349 | default: |
||
350 | Logger.Log("Decoded image with unhandled number of components: " + marshalled.components, |
||
351 | Helpers.LogLevel.Error); |
||
352 | |||
353 | if (IntPtr.Size == 8) |
||
354 | DotNetFree64(ref marshalled); |
||
355 | else |
||
356 | DotNetFree(ref marshalled); |
||
357 | |||
358 | managedImage = null; |
||
359 | return false; |
||
360 | } |
||
361 | |||
362 | if (IntPtr.Size == 8) |
||
363 | DotNetFree64(ref marshalled); |
||
364 | else |
||
365 | DotNetFree(ref marshalled); |
||
366 | } |
||
367 | |||
368 | return true; |
||
369 | } |
||
370 | |||
371 | /// <summary> |
||
372 | /// |
||
373 | /// </summary> |
||
374 | /// <param name="encoded"></param> |
||
375 | /// <param name="layerInfo"></param> |
||
376 | /// <param name="components"></param> |
||
377 | /// <returns></returns> |
||
378 | public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] layerInfo, out int components) |
||
379 | { |
||
380 | bool success = false; |
||
381 | layerInfo = null; |
||
382 | components = 0; |
||
383 | MarshalledImage marshalled = new MarshalledImage(); |
||
384 | |||
385 | // Allocate and copy to input buffer |
||
386 | marshalled.length = encoded.Length; |
||
387 | |||
388 | lock (OpenJPEGLock) |
||
389 | { |
||
390 | if (IntPtr.Size == 8) |
||
391 | DotNetAllocEncoded64(ref marshalled); |
||
392 | else |
||
393 | DotNetAllocEncoded(ref marshalled); |
||
394 | |||
395 | Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); |
||
396 | |||
397 | // Run the decode |
||
398 | bool decodeSuccess = (IntPtr.Size == 8) ? DotNetDecodeWithInfo64(ref marshalled) : DotNetDecodeWithInfo(ref marshalled); |
||
399 | if (decodeSuccess) |
||
400 | { |
||
401 | components = marshalled.components; |
||
402 | |||
403 | // Sanity check |
||
404 | if (marshalled.layers * marshalled.resolutions * marshalled.components == marshalled.packet_count) |
||
405 | { |
||
406 | // Manually marshal the array of opj_packet_info structs |
||
407 | MarshalledPacket[] packets = new MarshalledPacket[marshalled.packet_count]; |
||
408 | int offset = 0; |
||
409 | |||
410 | for (int i = 0; i < marshalled.packet_count; i++) |
||
411 | { |
||
412 | MarshalledPacket packet; |
||
413 | packet.start_pos = Marshal.ReadInt32(marshalled.packets, offset); |
||
414 | offset += 4; |
||
415 | packet.end_ph_pos = Marshal.ReadInt32(marshalled.packets, offset); |
||
416 | offset += 4; |
||
417 | packet.end_pos = Marshal.ReadInt32(marshalled.packets, offset); |
||
418 | offset += 4; |
||
419 | //double distortion = (double)Marshal.ReadInt64(marshalled.packets, offset); |
||
420 | offset += 8; |
||
421 | |||
422 | packets[i] = packet; |
||
423 | } |
||
424 | |||
425 | layerInfo = new J2KLayerInfo[marshalled.layers]; |
||
426 | |||
427 | for (int i = 0; i < marshalled.layers; i++) |
||
428 | { |
||
429 | int packetsPerLayer = marshalled.packet_count / marshalled.layers; |
||
430 | MarshalledPacket startPacket = packets[packetsPerLayer * i]; |
||
431 | MarshalledPacket endPacket = packets[(packetsPerLayer * (i + 1)) - 1]; |
||
432 | layerInfo[i].Start = startPacket.start_pos; |
||
433 | layerInfo[i].End = endPacket.end_pos; |
||
434 | } |
||
435 | |||
436 | // More sanity checking |
||
437 | if (layerInfo.Length == 0 || layerInfo[layerInfo.Length - 1].End <= encoded.Length - 1) |
||
438 | { |
||
439 | success = true; |
||
440 | |||
441 | for (int i = 0; i < layerInfo.Length; i++) |
||
442 | { |
||
443 | if (layerInfo[i].Start >= layerInfo[i].End || |
||
444 | (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End)) |
||
445 | { |
||
446 | System.Text.StringBuilder output = new System.Text.StringBuilder( |
||
447 | "Inconsistent packet data in JPEG2000 stream:\n"); |
||
448 | for (int j = 0; j < layerInfo.Length; j++) |
||
449 | output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End); |
||
450 | Logger.DebugLog(output.ToString()); |
||
451 | |||
452 | success = false; |
||
453 | break; |
||
454 | } |
||
455 | } |
||
456 | |||
457 | if (!success) |
||
458 | { |
||
459 | for (int i = 0; i < layerInfo.Length; i++) |
||
460 | { |
||
461 | if (i < layerInfo.Length - 1) |
||
462 | layerInfo[i].End = layerInfo[i + 1].Start - 1; |
||
463 | else |
||
464 | layerInfo[i].End = marshalled.length; |
||
465 | } |
||
466 | |||
467 | Logger.DebugLog("Corrected JPEG2000 packet data"); |
||
468 | success = true; |
||
469 | |||
470 | for (int i = 0; i < layerInfo.Length; i++) |
||
471 | { |
||
472 | if (layerInfo[i].Start >= layerInfo[i].End || |
||
473 | (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End)) |
||
474 | { |
||
475 | System.Text.StringBuilder output = new System.Text.StringBuilder( |
||
476 | "Still inconsistent packet data in JPEG2000 stream, giving up:\n"); |
||
477 | for (int j = 0; j < layerInfo.Length; j++) |
||
478 | output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End); |
||
479 | Logger.DebugLog(output.ToString()); |
||
480 | |||
481 | success = false; |
||
482 | break; |
||
483 | } |
||
484 | } |
||
485 | } |
||
486 | } |
||
487 | else |
||
488 | { |
||
489 | Logger.Log(String.Format( |
||
490 | "Last packet end in JPEG2000 stream extends beyond the end of the file. filesize={0} layerend={1}", |
||
491 | encoded.Length, layerInfo[layerInfo.Length - 1].End), Helpers.LogLevel.Warning); |
||
492 | } |
||
493 | } |
||
494 | else |
||
495 | { |
||
496 | Logger.Log(String.Format( |
||
497 | "Packet count mismatch in JPEG2000 stream. layers={0} resolutions={1} components={2} packets={3}", |
||
498 | marshalled.layers, marshalled.resolutions, marshalled.components, marshalled.packet_count), |
||
499 | Helpers.LogLevel.Warning); |
||
500 | } |
||
501 | } |
||
502 | |||
503 | if (IntPtr.Size == 8) |
||
504 | DotNetFree64(ref marshalled); |
||
505 | else |
||
506 | DotNetFree(ref marshalled); |
||
507 | } |
||
508 | |||
509 | return success; |
||
510 | } |
||
511 | |||
512 | /// <summary> |
||
513 | /// Encode a <seealso cref="System.Drawing.Bitmap"/> object into a byte array |
||
514 | /// </summary> |
||
515 | /// <param name="bitmap">The source <seealso cref="System.Drawing.Bitmap"/> object to encode</param> |
||
516 | /// <param name="lossless">true to enable lossless decoding</param> |
||
517 | /// <returns>A byte array containing the source Bitmap object</returns> |
||
518 | public unsafe static byte[] EncodeFromImage(Bitmap bitmap, bool lossless) |
||
519 | { |
||
520 | BitmapData bd; |
||
521 | ManagedImage decoded; |
||
522 | |||
523 | int bitmapWidth = bitmap.Width; |
||
524 | int bitmapHeight = bitmap.Height; |
||
525 | int pixelCount = bitmapWidth * bitmapHeight; |
||
526 | int i; |
||
527 | |||
528 | if ((bitmap.PixelFormat & PixelFormat.Alpha) != 0 || (bitmap.PixelFormat & PixelFormat.PAlpha) != 0) |
||
529 | { |
||
530 | // Four layers, RGBA |
||
531 | decoded = new ManagedImage(bitmapWidth, bitmapHeight, |
||
532 | ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); |
||
533 | bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), |
||
534 | ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); |
||
535 | byte* pixel = (byte*)bd.Scan0; |
||
536 | |||
537 | for (i = 0; i < pixelCount; i++) |
||
538 | { |
||
539 | // GDI+ gives us BGRA and we need to turn that in to RGBA |
||
540 | decoded.Blue[i] = *(pixel++); |
||
541 | decoded.Green[i] = *(pixel++); |
||
542 | decoded.Red[i] = *(pixel++); |
||
543 | decoded.Alpha[i] = *(pixel++); |
||
544 | } |
||
545 | } |
||
546 | else if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale) |
||
547 | { |
||
548 | // One layer |
||
549 | decoded = new ManagedImage(bitmapWidth, bitmapHeight, |
||
550 | ManagedImage.ImageChannels.Color); |
||
551 | bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), |
||
552 | ImageLockMode.ReadOnly, PixelFormat.Format16bppGrayScale); |
||
553 | byte* pixel = (byte*)bd.Scan0; |
||
554 | |||
555 | for (i = 0; i < pixelCount; i++) |
||
556 | { |
||
557 | // Normalize 16-bit data down to 8-bit |
||
558 | ushort origVal = (byte)(*(pixel) + (*(pixel + 1) << 8)); |
||
559 | byte val = (byte)(((double)origVal / (double)UInt32.MaxValue) * (double)Byte.MaxValue); |
||
560 | |||
561 | decoded.Red[i] = val; |
||
562 | decoded.Green[i] = val; |
||
563 | decoded.Blue[i] = val; |
||
564 | pixel += 2; |
||
565 | } |
||
566 | } |
||
567 | else |
||
568 | { |
||
569 | // Three layers, RGB |
||
570 | decoded = new ManagedImage(bitmapWidth, bitmapHeight, |
||
571 | ManagedImage.ImageChannels.Color); |
||
572 | bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), |
||
573 | ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); |
||
574 | byte* pixel = (byte*)bd.Scan0; |
||
575 | |||
576 | for (i = 0; i < pixelCount; i++) |
||
577 | { |
||
578 | decoded.Blue[i] = *(pixel++); |
||
579 | decoded.Green[i] = *(pixel++); |
||
580 | decoded.Red[i] = *(pixel++); |
||
581 | } |
||
582 | } |
||
583 | |||
584 | bitmap.UnlockBits(bd); |
||
585 | byte[] encoded = Encode(decoded, lossless); |
||
586 | return encoded; |
||
587 | } |
||
588 | } |
||
589 | #endif |
||
590 | } |