diff --git a/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj b/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj index 6cd03aab..07e7e324 100644 --- a/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj +++ b/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj @@ -50,7 +50,7 @@ - + diff --git a/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs b/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs index 82fbbb85..73f91e58 100644 --- a/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs +++ b/LibreMetaverse.Rendering.Meshmerizer/MeshmerizerR.cs @@ -1,5 +1,5 @@ /* Copyright (c) 2008 Robert Adams - * Copyright (c) 2021-2022, Sjofn LLC. All rights reserved. + * Copyright (c) 2021-2024, Sjofn LLC. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,8 +35,8 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; +using IronSoftware.Drawing; using OpenMetaverse.StructuredData; using LibreMetaverse.PrimMesher; @@ -130,7 +130,7 @@ namespace OpenMetaverse.Rendering /// Sculpt texture /// Level of detail to generate the mesh at /// The generated mesh or null on failure - public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod) + public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, AnyBitmap sculptTexture, DetailLevel lod) { var faceted = GenerateFacetedSculptMesh(prim, sculptTexture, lod); @@ -225,7 +225,7 @@ namespace OpenMetaverse.Rendering /// routine since all the context for finding teh texture is elsewhere. /// /// The faceted mesh or null if can't do it - public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap scupltTexture, DetailLevel lod) + public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, AnyBitmap scupltTexture, DetailLevel lod) { LibreMetaverse.PrimMesher.SculptMesh.SculptType smSculptType; switch (prim.Sculpt.Type) diff --git a/LibreMetaverse.Rendering.Simple/SimpleRenderer.cs b/LibreMetaverse.Rendering.Simple/SimpleRenderer.cs index e2ff37fe..d5e4284d 100644 --- a/LibreMetaverse.Rendering.Simple/SimpleRenderer.cs +++ b/LibreMetaverse.Rendering.Simple/SimpleRenderer.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2024, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -24,8 +25,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using System.Drawing; using System.Collections.Generic; +using IronSoftware.Drawing; namespace OpenMetaverse.Rendering { @@ -47,7 +48,7 @@ namespace OpenMetaverse.Rendering return mesh; } - public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod) + public SimpleMesh GenerateSimpleSculptMesh(Primitive prim, AnyBitmap sculptTexture, DetailLevel lod) { return GenerateSimpleMesh(prim, lod); } @@ -66,7 +67,7 @@ namespace OpenMetaverse.Rendering return mesh; } - public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod) + public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, AnyBitmap sculptTexture, DetailLevel lod) { return GenerateFacetedMesh(prim, lod); } diff --git a/LibreMetaverse/Imaging/BakeLayer.cs b/LibreMetaverse/Imaging/BakeLayer.cs index f3778a17..fa27efee 100644 --- a/LibreMetaverse/Imaging/BakeLayer.cs +++ b/LibreMetaverse/Imaging/BakeLayer.cs @@ -27,7 +27,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Drawing; +using IronSoftware.Drawing; using OpenMetaverse.Assets; namespace OpenMetaverse.Imaging @@ -356,14 +356,14 @@ namespace OpenMetaverse.Imaging { try { - Bitmap bitmap = null; + AnyBitmap bitmap = null; lock (ResourceSync) { using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR)) { if (stream != null) { - bitmap = LoadTGAClass.LoadTGA(stream); + bitmap = SkiaSharp.SKImage.FromEncodedData(stream); } } } diff --git a/LibreMetaverse/Imaging/ManagedImage.cs b/LibreMetaverse/Imaging/ManagedImage.cs index 80217ec6..3bd26907 100644 --- a/LibreMetaverse/Imaging/ManagedImage.cs +++ b/LibreMetaverse/Imaging/ManagedImage.cs @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co + * Copyright (c) 2024, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -25,8 +26,7 @@ */ using System; -using System.Drawing; -using System.Drawing.Imaging; +using IronSoftware.Drawing; namespace OpenMetaverse.Imaging { @@ -41,11 +41,6 @@ namespace OpenMetaverse.Imaging Bump = 8 } - public enum ImageResizeAlgorithm - { - NearestNeighbor - } - /// /// Image width /// @@ -118,109 +113,70 @@ namespace OpenMetaverse.Imaging Bump = new byte[n]; } -#if !NO_UNSAFE /// - /// + /// Constructs ManagedImage class from AnyBitmap /// - /// - public ManagedImage(Bitmap bitmap) + /// Input AnyBitmap + public ManagedImage(AnyBitmap bitmap) { Width = bitmap.Width; Height = bitmap.Height; + var pixelCount = Width * Height; + var bpp = bitmap.BitsPerPixel; - int pixelCount = Width * Height; - - if (bitmap.PixelFormat == PixelFormat.Format32bppArgb) + switch (bpp) { - Channels = ImageChannels.Alpha | ImageChannels.Color; - Red = new byte[pixelCount]; - Green = new byte[pixelCount]; - Blue = new byte[pixelCount]; - Alpha = new byte[pixelCount]; - - BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), - ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - unsafe - { - byte* pixel = (byte*)bd.Scan0; - - for (int i = 0; i < pixelCount; i++) + case 32: + Channels = ImageChannels.Alpha | ImageChannels.Color; + Red = new byte[pixelCount]; + Green = new byte[pixelCount]; + Blue = new byte[pixelCount]; + Alpha = new byte[pixelCount]; + + unsafe { - // GDI+ gives us BGRA and we need to turn that in to RGBA - Blue[i] = *(pixel++); - Green[i] = *(pixel++); - Red[i] = *(pixel++); - Alpha[i] = *(pixel++); + byte* pixel = (byte*)bitmap.Scan0; + + for (var i = 0; i < pixelCount; ++i) + { + // GDI+ gives us BGRA and we need to turn that in to RGBA + Blue[i] = *pixel++; + Green[i] = *pixel++; + Red[i] = *pixel++; + Alpha[i] = *pixel++; + } } - } - bitmap.UnlockBits(bd); - } - else if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale) - { - Channels = ImageChannels.Gray; - Red = new byte[pixelCount]; + break; + case 24: + Channels = ImageChannels.Color; + Red = new byte[pixelCount]; + Green = new byte[pixelCount]; + Blue = new byte[pixelCount]; - throw new NotImplementedException("16bpp grayscale image support is incomplete"); - } - else if (bitmap.PixelFormat == PixelFormat.Format24bppRgb) - { - Channels = ImageChannels.Color; - Red = new byte[pixelCount]; - Green = new byte[pixelCount]; - Blue = new byte[pixelCount]; - - BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), - ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); - - unsafe - { - byte* pixel = (byte*)bd.Scan0; - - for (int i = 0; i < pixelCount; i++) + unsafe { - // GDI+ gives us BGR and we need to turn that in to RGB - Blue[i] = *(pixel++); - Green[i] = *(pixel++); - Red[i] = *(pixel++); + byte* pixel = (byte*)bitmap.Scan0; + + for (var i = 0; i < pixelCount; ++i) + { + // GDI+ gives us BGR and we need to turn that in to RGB + Blue[i] = *pixel++; + Green[i] = *pixel++; + Red[i] = *pixel++; + } } - } - bitmap.UnlockBits(bd); - } - else if (bitmap.PixelFormat == PixelFormat.Format32bppRgb) - { - Channels = ImageChannels.Color; - Red = new byte[pixelCount]; - Green = new byte[pixelCount]; - Blue = new byte[pixelCount]; - - BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), - ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); - - unsafe - { - byte* pixel = (byte*)bd.Scan0; - - for (int i = 0; i < pixelCount; i++) - { - // GDI+ gives us BGR and we need to turn that in to RGB - Blue[i] = *(pixel++); - Green[i] = *(pixel++); - Red[i] = *(pixel++); - pixel++; // Skip over the empty byte where the Alpha info would normally be - } - } - - bitmap.UnlockBits(bd); - } - else - { - throw new NotSupportedException("Unrecognized pixel format: " + bitmap.PixelFormat); + break; + case 16: + Channels = ImageChannels.Gray; + Red = new byte[pixelCount]; + + throw new NotImplementedException("16bpp grayscale image support is incomplete"); + default: + throw new NotSupportedException($"Pixel depth of {bpp} is not supported."); } } -#endif /// /// Convert the channels in the image. Channels are created or destroyed as required. @@ -293,7 +249,7 @@ namespace OpenMetaverse.Imaging { for (int x = 0; x < width; x++) { - si = (y * Height / height) * Width + (x * Width / width); + si = y * Height / height * Width + x * Width / width; if (Red != null) red[di] = Red[si]; if (Green != null) green[di] = Green[si]; if (Blue != null) blue[di] = Blue[si]; @@ -384,39 +340,35 @@ namespace OpenMetaverse.Imaging /// origin, suitable for feeding directly into OpenGL /// /// A byte array containing raw texture data - public Bitmap ExportBitmap() + public AnyBitmap ExportBitmap() { - byte[] raw = new byte[Width * Height * 4]; + var raw = new byte[Width * Height * 4]; if ((Channels & ImageChannels.Alpha) != 0) { if ((Channels & ImageChannels.Color) != 0) - { // RGBA - for (int pos = 0; pos < Height * Width; pos++) + for (var pos = 0; pos < Height * Width; pos++) { raw[pos * 4 + 0] = Blue[pos]; raw[pos * 4 + 1] = Green[pos]; raw[pos * 4 + 2] = Red[pos]; raw[pos * 4 + 3] = Alpha[pos]; } - } else - { // Alpha only - for (int pos = 0; pos < Height * Width; pos++) + for (var pos = 0; pos < Height * Width; pos++) { raw[pos * 4 + 0] = Alpha[pos]; raw[pos * 4 + 1] = Alpha[pos]; raw[pos * 4 + 2] = Alpha[pos]; raw[pos * 4 + 3] = byte.MaxValue; } - } } else { // RGB - for (int pos = 0; pos < Height * Width; pos++) + for (var pos = 0; pos < Height * Width; pos++) { raw[pos * 4 + 0] = Blue[pos]; raw[pos * 4 + 1] = Green[pos]; @@ -425,20 +377,7 @@ namespace OpenMetaverse.Imaging } } - Bitmap b = new Bitmap( - Width, - Height, - PixelFormat.Format32bppArgb); - - BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - ImageLockMode.WriteOnly, - PixelFormat.Format32bppArgb); - - System.Runtime.InteropServices.Marshal.Copy(raw, 0, bd.Scan0, Width * Height * 4); - - b.UnlockBits(bd); - - return b; + return AnyBitmap.FromBytes(raw); } public byte[] ExportTGA() diff --git a/LibreMetaverse/Imaging/TGALoader.cs b/LibreMetaverse/Imaging/TGALoader.cs deleted file mode 100644 index e28046ce..00000000 --- a/LibreMetaverse/Imaging/TGALoader.cs +++ /dev/null @@ -1,654 +0,0 @@ -/* - * Copyright (c) 2006-2016, openmetaverse.co - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the openmetaverse.co nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Drawing; -using System.Drawing.Imaging; - -namespace OpenMetaverse.Imaging -{ -#if !NO_UNSAFE - - /// - /// Capability to load TGAs to Bitmap - /// - public class LoadTGAClass - { - struct tgaColorMap - { - public ushort FirstEntryIndex; - public ushort Length; - public byte EntrySize; - - public void Read(System.IO.BinaryReader br) - { - FirstEntryIndex = br.ReadUInt16(); - Length = br.ReadUInt16(); - EntrySize = br.ReadByte(); - } - } - - struct tgaImageSpec - { - public ushort XOrigin; - public ushort YOrigin; - public ushort Width; - public ushort Height; - public byte PixelDepth; - public byte Descriptor; - - public void Read(System.IO.BinaryReader br) - { - XOrigin = br.ReadUInt16(); - YOrigin = br.ReadUInt16(); - Width = br.ReadUInt16(); - Height = br.ReadUInt16(); - PixelDepth = br.ReadByte(); - Descriptor = br.ReadByte(); - } - - public byte AlphaBits - { - get - { - return (byte)(Descriptor & 0xF); - } - set - { - Descriptor = (byte)((Descriptor & ~0xF) | (value & 0xF)); - } - } - - public bool BottomUp - { - get - { - return (Descriptor & 0x20) == 0x20; - } - set - { - Descriptor = (byte)((Descriptor & ~0x20) | (value ? 0x20 : 0)); - } - } - } - - struct tgaHeader - { - public byte IdLength; - public byte ColorMapType; - public byte ImageType; - - public tgaColorMap ColorMap; - public tgaImageSpec ImageSpec; - - public void Read(System.IO.BinaryReader br) - { - this.IdLength = br.ReadByte(); - this.ColorMapType = br.ReadByte(); - this.ImageType = br.ReadByte(); - this.ColorMap = new tgaColorMap(); - this.ImageSpec = new tgaImageSpec(); - this.ColorMap.Read(br); - this.ImageSpec.Read(br); - } - - public bool RleEncoded - { - get - { - return ImageType >= 9; - } - } - } - - struct tgaCD - { - public uint RMask, GMask, BMask, AMask; - public byte RShift, GShift, BShift, AShift; - public uint FinalOr; - public bool NeedNoConvert; - } - - static uint UnpackColor( - uint sourceColor, ref tgaCD cd) - { - if (cd.RMask == 0xFF && cd.GMask == 0xFF && cd.BMask == 0xFF) - { - // Special case to deal with 8-bit TGA files that we treat as alpha masks - return sourceColor << 24; - } - else - { - uint rpermute = (sourceColor << cd.RShift) | (sourceColor >> (32 - cd.RShift)); - uint gpermute = (sourceColor << cd.GShift) | (sourceColor >> (32 - cd.GShift)); - uint bpermute = (sourceColor << cd.BShift) | (sourceColor >> (32 - cd.BShift)); - uint apermute = (sourceColor << cd.AShift) | (sourceColor >> (32 - cd.AShift)); - uint result = - (rpermute & cd.RMask) | (gpermute & cd.GMask) - | (bpermute & cd.BMask) | (apermute & cd.AMask) | cd.FinalOr; - - return result; - } - } - - static unsafe void decodeLine( - BitmapData b, - int line, - int byp, - byte[] data, - ref tgaCD cd) - { - if (cd.NeedNoConvert) - { - // fast copy - uint* linep = (uint*)((byte*)b.Scan0.ToPointer() + line * b.Stride); - fixed (byte* ptr = data) - { - uint* sptr = (uint*)ptr; - for (int i = 0; i < b.Width; ++i) - { - linep[i] = sptr[i]; - } - } - } - else - { - byte* linep = (byte*)b.Scan0.ToPointer() + line * b.Stride; - - uint* up = (uint*)linep; - - int rdi = 0; - - fixed (byte* ptr = data) - { - for (int i = 0; i < b.Width; ++i) - { - uint x = 0; - for (int j = 0; j < byp; ++j) - { - x |= ((uint)ptr[rdi]) << (j << 3); - ++rdi; - } - up[i] = UnpackColor(x, ref cd); - } - } - } - } - - static void decodeRle( - BitmapData b, - int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) - { - try - { - int w = b.Width; - // make buffer larger, so in case of emergency I can decode - // over line ends. - byte[] linebuffer = new byte[(w + 128) * byp]; - int maxindex = w * byp; - int index = 0; - - for (int j = 0; j < b.Height; ++j) - { - while (index < maxindex) - { - byte blocktype = br.ReadByte(); - - int bytestoread; - int bytestocopy; - - if (blocktype >= 0x80) - { - bytestoread = byp; - bytestocopy = byp * (blocktype - 0x80); - } - else - { - bytestoread = byp * (blocktype + 1); - bytestocopy = 0; - } - - //if (index + bytestoread > maxindex) - // throw new System.ArgumentException ("Corrupt TGA"); - - br.Read(linebuffer, index, bytestoread); - index += bytestoread; - - for (int i = 0; i != bytestocopy; ++i) - { - linebuffer[index + i] = linebuffer[index + i - bytestoread]; - } - index += bytestocopy; - } - if (!bottomUp) - decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); - else - decodeLine(b, j, byp, linebuffer, ref cd); - - if (index > maxindex) - { - Array.Copy(linebuffer, maxindex, linebuffer, 0, index - maxindex); - index -= maxindex; - } - else - index = 0; - - } - } - catch (System.IO.EndOfStreamException) - { - } - } - - static void decodePlain( - BitmapData b, - int byp, tgaCD cd, System.IO.BinaryReader br, bool bottomUp) - { - int w = b.Width; - byte[] linebuffer = new byte[w * byp]; - - for (int j = 0; j < b.Height; ++j) - { - br.Read(linebuffer, 0, w * byp); - - if (!bottomUp) - decodeLine(b, b.Height - j - 1, byp, linebuffer, ref cd); - else - decodeLine(b, j, byp, linebuffer, ref cd); - } - } - - static void decodeStandard8( - BitmapData b, - tgaHeader hdr, - System.IO.BinaryReader br) - { - tgaCD cd = new tgaCD(); - cd.RMask = 0x000000ff; - cd.GMask = 0x000000ff; - cd.BMask = 0x000000ff; - cd.AMask = 0x000000ff; - cd.RShift = 0; - cd.GShift = 0; - cd.BShift = 0; - cd.AShift = 0; - cd.FinalOr = 0x00000000; - if (hdr.RleEncoded) - decodeRle(b, 1, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 1, cd, br, hdr.ImageSpec.BottomUp); - } - - static void decodeSpecial16( - BitmapData b, tgaHeader hdr, System.IO.BinaryReader br) - { - // i must convert the input stream to a sequence of uint values - // which I then unpack. - tgaCD cd = new tgaCD(); - cd.RMask = 0x00f00000; - cd.GMask = 0x0000f000; - cd.BMask = 0x000000f0; - cd.AMask = 0xf0000000; - cd.RShift = 12; - cd.GShift = 8; - cd.BShift = 4; - cd.AShift = 16; - cd.FinalOr = 0; - - if (hdr.RleEncoded) - decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); - } - - static void decodeStandard16( - BitmapData b, - tgaHeader hdr, - System.IO.BinaryReader br) - { - // i must convert the input stream to a sequence of uint values - // which I then unpack. - tgaCD cd = new tgaCD(); - cd.RMask = 0x00f80000; // from 0xF800 - cd.GMask = 0x0000fc00; // from 0x07E0 - cd.BMask = 0x000000f8; // from 0x001F - cd.AMask = 0x00000000; - cd.RShift = 8; - cd.GShift = 5; - cd.BShift = 3; - cd.AShift = 0; - cd.FinalOr = 0xff000000; - - if (hdr.RleEncoded) - decodeRle(b, 2, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 2, cd, br, hdr.ImageSpec.BottomUp); - } - - - static void decodeSpecial24(BitmapData b, - tgaHeader hdr, System.IO.BinaryReader br) - { - // i must convert the input stream to a sequence of uint values - // which I then unpack. - tgaCD cd = new tgaCD(); - cd.RMask = 0x00f80000; - cd.GMask = 0x0000fc00; - cd.BMask = 0x000000f8; - cd.AMask = 0xff000000; - cd.RShift = 8; - cd.GShift = 5; - cd.BShift = 3; - cd.AShift = 8; - cd.FinalOr = 0; - - if (hdr.RleEncoded) - decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); - } - - static void decodeStandard24(BitmapData b, - tgaHeader hdr, System.IO.BinaryReader br) - { - // i must convert the input stream to a sequence of uint values - // which I then unpack. - tgaCD cd = new tgaCD(); - cd.RMask = 0x00ff0000; - cd.GMask = 0x0000ff00; - cd.BMask = 0x000000ff; - cd.AMask = 0x00000000; - cd.RShift = 0; - cd.GShift = 0; - cd.BShift = 0; - cd.AShift = 0; - cd.FinalOr = 0xff000000; - - if (hdr.RleEncoded) - decodeRle(b, 3, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 3, cd, br, hdr.ImageSpec.BottomUp); - } - - static void decodeStandard32(BitmapData b, - tgaHeader hdr, System.IO.BinaryReader br) - { - // i must convert the input stream to a sequence of uint values - // which I then unpack. - tgaCD cd = new tgaCD(); - cd.RMask = 0x00ff0000; - cd.GMask = 0x0000ff00; - cd.BMask = 0x000000ff; - cd.AMask = 0xff000000; - cd.RShift = 0; - cd.GShift = 0; - cd.BShift = 0; - cd.AShift = 0; - cd.FinalOr = 0x00000000; - cd.NeedNoConvert = true; - - if (hdr.RleEncoded) - decodeRle(b, 4, cd, br, hdr.ImageSpec.BottomUp); - else - decodePlain(b, 4, cd, br, hdr.ImageSpec.BottomUp); - } - - - public static System.Drawing.Size GetTGASize(string filename) - { - System.IO.FileStream f = System.IO.File.OpenRead(filename); - - System.IO.BinaryReader br = new System.IO.BinaryReader(f); - - tgaHeader header = new tgaHeader(); - header.Read(br); - br.Close(); - - return new System.Drawing.Size(header.ImageSpec.Width, header.ImageSpec.Height); - - } - - public static Bitmap LoadTGA(System.IO.Stream source) - { - byte[] buffer = new byte[source.Length]; - source.Read(buffer, 0, buffer.Length); - - System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); - - using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) - { - tgaHeader header = new tgaHeader(); - header.Read(br); - - if (header.ImageSpec.PixelDepth != 8 && - header.ImageSpec.PixelDepth != 16 && - header.ImageSpec.PixelDepth != 24 && - header.ImageSpec.PixelDepth != 32) - { - throw new ArgumentException("Not a supported tga file."); - } - - if (header.ImageSpec.AlphaBits > 8) - throw new ArgumentException("Not a supported tga file."); - - if (header.ImageSpec.Width > 4096 || - header.ImageSpec.Height > 4096) - { - throw new ArgumentException("Image too large."); - } - - Bitmap b; - BitmapData bd; - - // Create a bitmap for the image. - // Only include an alpha layer when the image requires one. - if (header.ImageSpec.AlphaBits > 0 || - header.ImageSpec.PixelDepth == 8 || // Assume 8 bit images are alpha only - header.ImageSpec.PixelDepth == 32) // Assume 32 bit images are ARGB - { // Image needs an alpha layer - b = new Bitmap( - header.ImageSpec.Width, - header.ImageSpec.Height, - PixelFormat.Format32bppArgb); - - bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - ImageLockMode.WriteOnly, - PixelFormat.Format32bppPArgb); - } - else - { // Image does not need an alpha layer, so do not include one. - b = new Bitmap( - header.ImageSpec.Width, - header.ImageSpec.Height, - PixelFormat.Format32bppRgb); - - bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), - ImageLockMode.WriteOnly, - PixelFormat.Format32bppRgb); - } - - switch (header.ImageSpec.PixelDepth) - { - case 8: - decodeStandard8(bd, header, br); - break; - case 16: - if (header.ImageSpec.AlphaBits > 0) - decodeSpecial16(bd, header, br); - else - decodeStandard16(bd, header, br); - break; - case 24: - if (header.ImageSpec.AlphaBits > 0) - decodeSpecial24(bd, header, br); - else - decodeStandard24(bd, header, br); - break; - case 32: - decodeStandard32(bd, header, br); - break; - default: - b.UnlockBits(bd); - b.Dispose(); - return null; - } - - b.UnlockBits(bd); - return b; - } - } - - public static ManagedImage LoadTGAImage(System.IO.Stream source) - { - return LoadTGAImage(source, false); - } - - public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source, bool mask) - { - byte[] buffer = new byte[source.Length]; - source.Read(buffer, 0, buffer.Length); - - System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); - - using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) - { - tgaHeader header = new tgaHeader(); - header.Read(br); - - if (header.ImageSpec.PixelDepth != 8 && - header.ImageSpec.PixelDepth != 16 && - header.ImageSpec.PixelDepth != 24 && - header.ImageSpec.PixelDepth != 32) - { - throw new ArgumentException("Not a supported tga file."); - } - - if (header.ImageSpec.AlphaBits > 8) - throw new ArgumentException("Not a supported tga file."); - - if (header.ImageSpec.Width > 4096 || - header.ImageSpec.Height > 4096) - { - throw new ArgumentException("Image too large."); - } - - byte[] decoded = new byte[header.ImageSpec.Width * header.ImageSpec.Height * 4]; - BitmapData bd = new BitmapData(); - - fixed (byte* pdecoded = &decoded[0]) - { - bd.Width = header.ImageSpec.Width; - bd.Height = header.ImageSpec.Height; - bd.PixelFormat = PixelFormat.Format32bppPArgb; - bd.Stride = header.ImageSpec.Width * 4; - bd.Scan0 = (IntPtr)pdecoded; - - switch (header.ImageSpec.PixelDepth) - { - case 8: - decodeStandard8(bd, header, br); - break; - case 16: - if (header.ImageSpec.AlphaBits > 0) - decodeSpecial16(bd, header, br); - else - decodeStandard16(bd, header, br); - break; - case 24: - if (header.ImageSpec.AlphaBits > 0) - decodeSpecial24(bd, header, br); - else - decodeStandard24(bd, header, br); - break; - case 32: - decodeStandard32(bd, header, br); - break; - default: - return null; - } - } - - int n = header.ImageSpec.Width * header.ImageSpec.Height; - ManagedImage image; - - if (mask && header.ImageSpec.AlphaBits == 0 && header.ImageSpec.PixelDepth == 8) - { - image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, - ManagedImage.ImageChannels.Alpha); - int p = 3; - - for (int i = 0; i < n; i++) - { - image.Alpha[i] = decoded[p]; - p += 4; - } - } - else - { - image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, - ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); - int p = 0; - - for (int i = 0; i < n; i++) - { - image.Blue[i] = decoded[p++]; - image.Green[i] = decoded[p++]; - image.Red[i] = decoded[p++]; - image.Alpha[i] = decoded[p++]; - } - } - - br.Close(); - return image; - } - } - - public static Bitmap LoadTGA(string filename) - { - try - { - using (System.IO.FileStream f = System.IO.File.OpenRead(filename)) - { - if (f != null) - { - return LoadTGA(f); - } - } - return null; // file stream error - } - catch (System.IO.DirectoryNotFoundException) - { - return null; // file not found - } - catch (System.IO.FileNotFoundException) - { - return null; // file not found - } - } - } - -#endif -} diff --git a/LibreMetaverse/ImportExport/ColladalLoader.cs b/LibreMetaverse/ImportExport/ColladalLoader.cs index cac6fe66..b96b566f 100644 --- a/LibreMetaverse/ImportExport/ColladalLoader.cs +++ b/LibreMetaverse/ImportExport/ColladalLoader.cs @@ -1,6 +1,6 @@ /* * Copyright (c) 2006-2016, openmetaverse.co - * Copyright (c) 2021-2022, Sjofn LLC. + * Copyright (c) 2021-2024, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -31,13 +31,13 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using System.IO; using System.Xml; -using System.Drawing; -using System.Drawing.Drawing2D; using System.Linq; using System.Xml.Serialization; +using IronSoftware.Drawing; using OpenMetaverse.ImportExport.Collada14; using OpenMetaverse.Rendering; using OpenMetaverse.Imaging; +using SkiaSharp; namespace OpenMetaverse.ImportExport { @@ -120,7 +120,7 @@ namespace OpenMetaverse.ImportExport { string ext = System.IO.Path.GetExtension(material.Texture).ToLower(); - Bitmap bitmap = null; + AnyBitmap bitmap; switch (ext) { @@ -128,11 +128,8 @@ namespace OpenMetaverse.ImportExport case ".j2c": material.TextureData = File.ReadAllBytes(fname); return; - case ".tga": - bitmap = LoadTGAClass.LoadTGA(fname); - break; default: - bitmap = (Bitmap)Image.FromFile(fname); + bitmap = AnyBitmap.FromFile(fname); break; } @@ -153,16 +150,11 @@ namespace OpenMetaverse.ImportExport Logger.Log("Image has irregular dimensions " + origWidth + "x" + origHieght + ". Resizing to " + width + "x" + height, Helpers.LogLevel.Info); - Bitmap resized = new Bitmap(width, height, bitmap.PixelFormat); - Graphics graphics = Graphics.FromImage(resized); - - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = - InterpolationMode.HighQualityBicubic; - graphics.DrawImage(bitmap, 0, 0, width, height); - - bitmap.Dispose(); - bitmap = resized; + var info = new SKImageInfo(width, height); + var scaledImage = SKImage.Create(info); + var skImage = SKImage.FromBitmap(bitmap); + skImage.ScalePixels(scaledImage.PeekPixels(), SKFilterQuality.High); + bitmap = scaledImage; } using (var writer = new OpenJpegDotNet.IO.Writer(bitmap)) @@ -174,7 +166,7 @@ namespace OpenMetaverse.ImportExport } catch (Exception ex) { - Logger.Log("Failed loading " + fname + ": " + ex.Message, Helpers.LogLevel.Warning); + Logger.Log($"Failed loading {fname}: {ex.Message}", Helpers.LogLevel.Warning); } } diff --git a/LibreMetaverse/Interfaces/IRendering.cs b/LibreMetaverse/Interfaces/IRendering.cs index d0a916db..14e5f2a5 100644 --- a/LibreMetaverse/Interfaces/IRendering.cs +++ b/LibreMetaverse/Interfaces/IRendering.cs @@ -26,7 +26,7 @@ using System; using System.Collections.Generic; -using System.Drawing; +using IronSoftware.Drawing; namespace OpenMetaverse.Rendering { @@ -67,7 +67,7 @@ namespace OpenMetaverse.Rendering /// Sculpt texture /// Level of detail to generate the mesh at /// The generated mesh - SimpleMesh GenerateSimpleSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod); + SimpleMesh GenerateSimpleSculptMesh(Primitive prim, AnyBitmap sculptTexture, DetailLevel lod); /// /// Generates a series of faces, each face containing a mesh and @@ -86,7 +86,7 @@ namespace OpenMetaverse.Rendering /// Sculpt texture /// Level of detail to generate the mesh at /// The generated mesh - FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod); + FacetedMesh GenerateFacetedSculptMesh(Primitive prim, AnyBitmap sculptTexture, DetailLevel lod); /// /// Apply texture coordinate modifications from a diff --git a/LibreMetaverse/LibreMetaverse.csproj b/LibreMetaverse/LibreMetaverse.csproj index 6412b94b..5f892ef5 100644 --- a/LibreMetaverse/LibreMetaverse.csproj +++ b/LibreMetaverse/LibreMetaverse.csproj @@ -43,11 +43,13 @@ True + - - + + + diff --git a/PrimMesher/LibreMetaverse.PrimMesher.csproj b/PrimMesher/LibreMetaverse.PrimMesher.csproj index 268da745..a6e94ed0 100644 --- a/PrimMesher/LibreMetaverse.PrimMesher.csproj +++ b/PrimMesher/LibreMetaverse.PrimMesher.csproj @@ -46,12 +46,14 @@ true TRACE;VERTEX_INDEXER - - - + + + + + diff --git a/PrimMesher/SculptMap.cs b/PrimMesher/SculptMap.cs index 3c52cebb..101c168f 100644 --- a/PrimMesher/SculptMap.cs +++ b/PrimMesher/SculptMap.cs @@ -27,8 +27,8 @@ using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; +using IronSoftware.Drawing; +using SkiaSharp; namespace LibreMetaverse.PrimMesher { @@ -44,7 +44,7 @@ namespace LibreMetaverse.PrimMesher { } - public SculptMap(Bitmap bm, int lod) + public SculptMap(AnyBitmap bm, int lod) { var bmW = bm.Width; var bmH = bm.Height; @@ -71,8 +71,7 @@ namespace LibreMetaverse.PrimMesher try { if (needsScaling) - bm = ScaleImage(bm, width, height, - InterpolationMode.NearestNeighbor); + bm = ScaleImage(bm, width, height); } catch (Exception e) @@ -164,21 +163,12 @@ namespace LibreMetaverse.PrimMesher return rows; } - private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight, - InterpolationMode interpMode) + private AnyBitmap ScaleImage(AnyBitmap srcImage, int destWidth, int destHeight) { - var scaledImage = new Bitmap(srcImage, destWidth, destHeight); - scaledImage.SetResolution(96.0f, 96.0f); - - var grPhoto = Graphics.FromImage(scaledImage); - grPhoto.InterpolationMode = interpMode; - - grPhoto.DrawImage(srcImage, - new Rectangle(0, 0, destWidth, destHeight), - new Rectangle(0, 0, srcImage.Width, srcImage.Height), - GraphicsUnit.Pixel); - - grPhoto.Dispose(); + var info = new SKImageInfo(destWidth, destHeight); + var scaledImage = SKImage.Create(info); + var skImage = SKImage.FromBitmap(srcImage); + skImage.ScalePixels(scaledImage.PeekPixels(), SKFilterQuality.High); return scaledImage; } } diff --git a/PrimMesher/SculptMesh.cs b/PrimMesher/SculptMesh.cs index 00b31d6e..132f3b1a 100644 --- a/PrimMesher/SculptMesh.cs +++ b/PrimMesher/SculptMesh.cs @@ -27,8 +27,9 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; +using IronSoftware.Drawing; +using Color = IronSoftware.Drawing.Color; namespace LibreMetaverse.PrimMesher { @@ -52,7 +53,7 @@ namespace LibreMetaverse.PrimMesher public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) { - var bitmap = (Bitmap) Image.FromFile(fileName); + var bitmap = AnyBitmap.FromFile(fileName); _SculptMesh(bitmap, (SculptType) sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); bitmap.Dispose(); } @@ -164,12 +165,12 @@ namespace LibreMetaverse.PrimMesher calcVertexNormals(SculptType.plane, numXElements, numYElements); } - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) + public SculptMesh(AnyBitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); } - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, + public SculptMesh(AnyBitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); @@ -191,7 +192,7 @@ namespace LibreMetaverse.PrimMesher public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) { - var bitmap = (Bitmap) Image.FromFile(fileName); + var bitmap = AnyBitmap.FromFile(fileName); var sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); bitmap.Dispose(); return sculptMesh; @@ -207,7 +208,7 @@ namespace LibreMetaverse.PrimMesher /// /// /// - private List> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) + private List> bitmap2Coords(AnyBitmap bitmap, int scale, bool mirror) { var numRows = bitmap.Height / scale; var numCols = bitmap.Width / scale; @@ -254,7 +255,7 @@ namespace LibreMetaverse.PrimMesher return rows; } - private List> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror) + private List> bitmap2CoordsSampled(AnyBitmap bitmap, int scale, bool mirror) { var numRows = bitmap.Height / scale; var numCols = bitmap.Width / scale; @@ -293,7 +294,7 @@ namespace LibreMetaverse.PrimMesher } - private void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, + private void _SculptMesh(AnyBitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert); diff --git a/Programs/Baker/Oven.cs b/Programs/Baker/Oven.cs index 00028e05..7e76fc89 100644 --- a/Programs/Baker/Oven.cs +++ b/Programs/Baker/Oven.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using System.Runtime.InteropServices; namespace Baker diff --git a/Programs/Baker/frmBaker.cs b/Programs/Baker/frmBaker.cs index 2afeedb0..2ddcc708 100644 --- a/Programs/Baker/frmBaker.cs +++ b/Programs/Baker/frmBaker.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using System.Windows.Forms; using System.IO; using OpenMetaverse.Imaging; diff --git a/Programs/examples/GridAccountant/frmGridAccountant.cs b/Programs/examples/GridAccountant/frmGridAccountant.cs index 3581c872..da597fb7 100644 --- a/Programs/examples/GridAccountant/frmGridAccountant.cs +++ b/Programs/examples/GridAccountant/frmGridAccountant.cs @@ -25,7 +25,6 @@ */ using System; -using System.Drawing; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; diff --git a/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs index 6f3855c2..36a5e403 100644 --- a/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs @@ -27,9 +27,8 @@ using System; using System.Threading; -using System.Drawing; -using System.Drawing.Drawing2D; -using OpenMetaverse.Imaging; +using IronSoftware.Drawing; +using SkiaSharp; namespace OpenMetaverse.TestClient { @@ -96,18 +95,18 @@ namespace OpenMetaverse.TestClient private byte[] LoadImage(string fileName) { - byte[] UploadData = { }; + byte[] uploadData; string lowfilename = fileName.ToLower(); - Bitmap bitmap = null; try { + AnyBitmap bitmap; if (lowfilename.EndsWith(".jp2") || lowfilename.EndsWith(".j2c")) { // Upload JPEG2000 images untouched - UploadData = System.IO.File.ReadAllBytes(fileName); + uploadData = System.IO.File.ReadAllBytes(fileName); - using (var reader = new OpenJpegDotNet.IO.Reader(UploadData)) + using (var reader = new OpenJpegDotNet.IO.Reader(uploadData)) { reader.ReadHeader(); bitmap = reader.DecodeToBitmap(); @@ -115,25 +114,18 @@ namespace OpenMetaverse.TestClient } else { - if (lowfilename.EndsWith(".tga")) { - bitmap = LoadTGAClass.LoadTGA(fileName); - } else { - bitmap = (Bitmap)Image.FromFile(fileName); - } + bitmap = AnyBitmap.FromFile(fileName); int oldwidth = bitmap.Width; int oldheight = bitmap.Height; if (!IsPowerOfTwo((uint)oldwidth) || !IsPowerOfTwo((uint)oldheight)) { - Bitmap resized = new Bitmap(256, 256, bitmap.PixelFormat); - Graphics graphics = Graphics.FromImage(resized); + var info = new SKImageInfo(256, 256); + var scaledImage = SKImage.Create(info); + var skImage = SKImage.FromBitmap(bitmap); + skImage.ScalePixels(scaledImage.PeekPixels(), SKFilterQuality.High); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.DrawImage(bitmap, 0, 0, 256, 256); - - bitmap.Dispose(); - bitmap = resized; + bitmap = scaledImage; oldwidth = 256; oldheight = 256; @@ -145,21 +137,18 @@ namespace OpenMetaverse.TestClient int newwidth = (oldwidth > 1024) ? 1024 : oldwidth; int newheight = (oldheight > 1024) ? 1024 : oldheight; - Bitmap resized = new Bitmap(newwidth, newheight, bitmap.PixelFormat); - Graphics graphics = Graphics.FromImage(resized); + var info = new SKImageInfo(newwidth, newheight); + var scaledImage = SKImage.Create(info); + var skImage = SKImage.FromBitmap(bitmap); + skImage.ScalePixels(scaledImage.PeekPixels(), SKFilterQuality.High); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = - InterpolationMode.HighQualityBicubic; - graphics.DrawImage(bitmap, 0, 0, newwidth, newheight); + bitmap = scaledImage; + } + } - bitmap.Dispose(); - bitmap = resized; - } - using (var writer = new OpenJpegDotNet.IO.Writer(bitmap)) - { - UploadData = writer.Encode(); - } + using (var writer = new OpenJpegDotNet.IO.Writer(bitmap)) + { + uploadData = writer.Encode(); } } catch (Exception ex) @@ -167,7 +156,7 @@ namespace OpenMetaverse.TestClient Console.WriteLine(ex + " SL Image Upload "); return null; } - return UploadData; + return uploadData; } private static bool IsPowerOfTwo(uint n)