├── tests
├── Stb.Native
│ ├── app.rc
│ ├── app.ico
│ ├── resource.h
│ ├── Stb.Native.cpp
│ ├── Stdafx.h
│ ├── Stdafx.cpp
│ ├── AssemblyInfo.cpp
│ ├── ReadMe.txt
│ ├── Stb.Native.vcxproj
│ └── Stb.Native.h
├── SafeStbImageSharp.Tests
│ ├── Resources
│ │ ├── DockPanes.jpg
│ │ └── J7dAdPl.png
│ ├── SafeStbImageSharp.Tests.csproj
│ ├── Utility
│ │ └── Res.cs
│ └── Tests.cs
└── StbImageSharp.Testing
│ ├── app.config
│ ├── packages.config
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── StbImageSharp.Testing.csproj
│ └── Program.cs
├── samples
├── SafeStbImageSharp.Samples.MonoGame
│ ├── image.jpg
│ ├── Program.cs
│ ├── SafeStbImageSharp.Samples.MonoGame.csproj
│ └── Game1.cs
└── SafeStbImageSharp.Samples.WinForms
│ ├── App.config
│ ├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
│ ├── Program.cs
│ ├── Form1.cs
│ ├── SafeStbImageSharp.Samples.WinForms.csproj
│ ├── Form1.Designer.cs
│ └── Form1.resx
├── src
├── AnimatedFrameResult.cs
├── ColorComponents.cs
├── SafeStbImageSharp.csproj
├── Utility
│ ├── ArrayExtensions.cs
│ ├── MathExtensions.cs
│ ├── IOUtils.cs
│ ├── FakePtr.cs
│ └── Conversion.cs
├── ImageInfo.cs
├── Decoding
│ ├── Decoder.cs
│ ├── PsdDecoder.cs
│ ├── TgaDecoder.cs
│ ├── BmpDecoder.cs
│ ├── ZLib.cs
│ ├── GifDecoder.cs
│ └── PngDecoder.cs
└── ImageResult.cs
├── .github
└── workflows
│ └── build-and-publish.yml
├── README.md
├── .gitignore
└── SafeStbImageSharp.sln
/tests/Stb.Native/app.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StbSharp/SafeStbImageSharp/HEAD/tests/Stb.Native/app.rc
--------------------------------------------------------------------------------
/tests/Stb.Native/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StbSharp/SafeStbImageSharp/HEAD/tests/Stb.Native/app.ico
--------------------------------------------------------------------------------
/tests/Stb.Native/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by app.rc
4 |
--------------------------------------------------------------------------------
/tests/Stb.Native/Stb.Native.cpp:
--------------------------------------------------------------------------------
1 | // This is the main DLL file.
2 |
3 | #include "stdafx.h"
4 |
5 | #include "Stb.Native.h"
6 |
7 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.MonoGame/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StbSharp/SafeStbImageSharp/HEAD/samples/SafeStbImageSharp.Samples.MonoGame/image.jpg
--------------------------------------------------------------------------------
/tests/SafeStbImageSharp.Tests/Resources/DockPanes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StbSharp/SafeStbImageSharp/HEAD/tests/SafeStbImageSharp.Tests/Resources/DockPanes.jpg
--------------------------------------------------------------------------------
/tests/SafeStbImageSharp.Tests/Resources/J7dAdPl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StbSharp/SafeStbImageSharp/HEAD/tests/SafeStbImageSharp.Tests/Resources/J7dAdPl.png
--------------------------------------------------------------------------------
/tests/Stb.Native/Stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently,
3 | // but are changed infrequently
4 |
5 | #pragma once
6 |
7 |
8 |
--------------------------------------------------------------------------------
/tests/Stb.Native/Stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // Stb.Native.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/AnimatedFrameResult.cs:
--------------------------------------------------------------------------------
1 | namespace StbImageSharp
2 | {
3 | #if !STBSHARP_INTERNAL
4 | public
5 | #else
6 | internal
7 | #endif
8 | class AnimatedFrameResult : ImageResult
9 | {
10 | public int Delay
11 | {
12 | get; set;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/ColorComponents.cs:
--------------------------------------------------------------------------------
1 | namespace StbImageSharp
2 | {
3 | #if !STBSHARP_INTERNAL
4 | public
5 | #else
6 | internal
7 | #endif
8 | enum ColorComponents
9 | {
10 | Grey = 1,
11 | GreyAlpha = 2,
12 | RedGreenBlue = 3,
13 | RedGreenBlueAlpha = 4
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace StbSharp.WinForms.Test
5 | {
6 | static class Program
7 | {
8 | ///
9 | /// The main entry point for the application.
10 | ///
11 | [STAThread]
12 | static void Main()
13 | {
14 | Application.EnableVisualStyles();
15 | Application.SetCompatibleTextRenderingDefault(false);
16 | Application.Run(new Form1());
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.MonoGame/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StbImageSharp.Samples.MonoGame
4 | {
5 | ///
6 | /// The main class.
7 | ///
8 | public static class Program
9 | {
10 | ///
11 | /// The main entry point for the application.
12 | ///
13 | [STAThread]
14 | static void Main()
15 | {
16 | using (var game = new Game1())
17 | game.Run();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/StbImageSharp.Testing/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/SafeStbImageSharp.Tests/SafeStbImageSharp.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/SafeStbImageSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | SafeStbImageSharpTeam
4 | SafeStbImageSharp
5 | SafeStbImageSharp
6 | netstandard2.0;net45
7 | Safe C# port of the stb_image.h
8 | Public Domain
9 | https://github.com/StbSharp/SafeStbImageSharp
10 | 2.22.4
11 |
12 |
13 |
14 | true
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Utility/ArrayExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StbImageSharp.Utility
4 | {
5 | internal static class ArrayExtensions
6 | {
7 | public static void Clear(this Array array)
8 | {
9 | Array.Clear(array, 0, array.Length);
10 | }
11 |
12 | public static void Set(this T[] array, int index, int length, T value)
13 | {
14 | for(var i = index; i < index + length; ++i)
15 | {
16 | array[i] = value;
17 | }
18 | }
19 |
20 | public static void Set(this T[] array, T value)
21 | {
22 | array.Set(0, array.Length, value);
23 | }
24 |
25 | public static void memcpy(this T[] a, FakePtr b, int count) where T: new()
26 | {
27 | Array.Copy(b._array, b.Offset, a, 0, count);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/StbImageSharp.Testing/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-publish.yml:
--------------------------------------------------------------------------------
1 | name: Build & Publish
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | BuildAndPublish:
8 | runs-on: windows-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v2
12 | with:
13 | submodules: recursive
14 | - name: Setup .NET Core
15 | uses: actions/setup-dotnet@v1
16 | with:
17 | dotnet-version: '3.1.x'
18 | - name: Build SafeStbImageSharp
19 | run: dotnet build src\SafeStbImageSharp.csproj --configuration Release
20 | - name: Install NuGet
21 | uses: NuGet/setup-nuget@v1
22 | - name: Publish SafeStbImageSharp to NuGet
23 | run: nuget.exe push src\bin\Release\SafeStbImageSharp.*.nupkg ${{secrets.NUGET_APIKEY}} -Source https://api.nuget.org/v3/index.json
--------------------------------------------------------------------------------
/src/Utility/MathExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace StbImageSharp.Utility
2 | {
3 | internal static class MathExtensions
4 | {
5 | public static int stbi__bitreverse16(int n)
6 | {
7 | n = (int)(((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1));
8 | n = (int)(((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2));
9 | n = (int)(((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4));
10 | n = (int)(((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8));
11 | return (int)(n);
12 | }
13 |
14 | public static int stbi__bit_reverse(int v, int bits)
15 | {
16 | return (int)(stbi__bitreverse16((int)(v)) >> (16 - bits));
17 | }
18 |
19 | public static uint _lrotl(uint x, int y)
20 | {
21 | return (x << y) | (x >> (32 - y));
22 | }
23 |
24 | public static int ToReqComp(this ColorComponents? requiredComponents)
25 | {
26 | return requiredComponents != null ? (int)requiredComponents.Value : 0;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.MonoGame/SafeStbImageSharp.Samples.MonoGame.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 |
5 |
6 | StbImageLib.Samples.MonoGame
7 | StbImageLib.Samples.MonoGame
8 | net45
9 | bin\MonoGame\$(Configuration)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | PreserveNewest
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/ImageInfo.cs:
--------------------------------------------------------------------------------
1 | using StbImageSharp.Decoding;
2 | using System.IO;
3 |
4 | namespace StbImageSharp
5 | {
6 | #if !STBSHARP_INTERNAL
7 | public
8 | #else
9 | internal
10 | #endif
11 | struct ImageInfo
12 | {
13 | public int Width;
14 | public int Height;
15 | public ColorComponents ColorComponents;
16 | public int BitsPerChannel;
17 |
18 | public static ImageInfo? FromStream(Stream stream)
19 | {
20 | ImageInfo? info = null;
21 |
22 | if (JpgDecoder.Test(stream))
23 | {
24 | info = JpgDecoder.Info(stream);
25 | }
26 | else if (PngDecoder.Test(stream))
27 | {
28 | info = PngDecoder.Info(stream);
29 | }
30 | else if (BmpDecoder.Test(stream))
31 | {
32 | info = BmpDecoder.Info(stream);
33 | }
34 | else if (GifDecoder.Test(stream))
35 | {
36 | info = GifDecoder.Info(stream);
37 | }
38 | else if (PsdDecoder.Test(stream))
39 | {
40 | info = PsdDecoder.Info(stream);
41 | }
42 | else if (TgaDecoder.Test(stream))
43 | {
44 | info = TgaDecoder.Info(stream);
45 | }
46 |
47 | return info;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace StbSharp.WinForms.Test.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Utility/IOUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace StbImageSharp.Utility
5 | {
6 | internal static class IOUtils
7 | {
8 | public static void Rewind(this Stream stream)
9 | {
10 | stream.Seek(0, SeekOrigin.Begin);
11 | }
12 |
13 | public static byte stbi__get8(this Stream s)
14 | {
15 | int b = s.ReadByte();
16 | if (b == -1)
17 | {
18 | throw new Exception("EOF");
19 | }
20 |
21 | return (byte)b;
22 | }
23 |
24 | public static int stbi__get16be(this Stream s)
25 | {
26 | int z = s.stbi__get8();
27 | return (z << 8) + s.stbi__get8();
28 | }
29 |
30 | public static uint stbi__get32be(this Stream s)
31 | {
32 | uint z = (uint)stbi__get16be(s);
33 | return (uint)((z << 16) + stbi__get16be(s));
34 | }
35 |
36 | public static int stbi__get16le(this Stream s)
37 | {
38 | int z = s.stbi__get8();
39 | return z + (s.stbi__get8() << 8);
40 | }
41 |
42 | public static uint stbi__get32le(this Stream s)
43 | {
44 | uint z = (uint)(stbi__get16le(s));
45 | return (uint)(z + (stbi__get16le(s) << 16));
46 | }
47 |
48 | public static void stbi__skip(this Stream s, int skip)
49 | {
50 | s.Seek(skip, SeekOrigin.Current);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tests/Stb.Native/AssemblyInfo.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | using namespace System;
4 | using namespace System::Reflection;
5 | using namespace System::Runtime::CompilerServices;
6 | using namespace System::Runtime::InteropServices;
7 | using namespace System::Security::Permissions;
8 |
9 | //
10 | // General Information about an assembly is controlled through the following
11 | // set of attributes. Change these attribute values to modify the information
12 | // associated with an assembly.
13 | //
14 | [assembly:AssemblyTitleAttribute(L"StbNative")];
15 | [assembly:AssemblyDescriptionAttribute(L"")];
16 | [assembly:AssemblyConfigurationAttribute(L"")];
17 | [assembly:AssemblyCompanyAttribute(L"")];
18 | [assembly:AssemblyProductAttribute(L"StbNative")];
19 | [assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2017")];
20 | [assembly:AssemblyTrademarkAttribute(L"")];
21 | [assembly:AssemblyCultureAttribute(L"")];
22 |
23 | //
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the value or you can default the Revision and Build Numbers
32 | // by using the '*' as shown below:
33 |
34 | [assembly:AssemblyVersionAttribute("1.0.*")];
35 |
36 | [assembly:ComVisible(false)];
37 |
38 | [assembly:CLSCompliantAttribute(true)];
--------------------------------------------------------------------------------
/tests/StbImageSharp.Testing/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("StbImageSharp.Testing")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("StbImageSharp.Testing")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("1cba18d9-3b9b-4f6a-8729-3e88abc98c33")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("StbSharp.WinForms.Test")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("StbSharp.WinForms.Test")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("69f55f52-5cab-4604-b6c3-3ed1180bf387")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Decoding/Decoder.cs:
--------------------------------------------------------------------------------
1 | using StbImageSharp.Utility;
2 | using System;
3 | using System.IO;
4 |
5 | namespace StbImageSharp.Decoding
6 | {
7 | #if !STBSHARP_INTERNAL
8 | public
9 | #else
10 | internal
11 | #endif
12 | class Decoder
13 | {
14 | public const int STBI__SCAN_load = 0;
15 | public const int STBI__SCAN_type = 1;
16 | public const int STBI__SCAN_header = 2;
17 | protected int img_x = 0;
18 | protected int img_y = 0;
19 | protected int img_n = 0;
20 |
21 | public Stream Stream { get; private set; }
22 |
23 | protected Decoder(Stream stream)
24 | {
25 | Stream = stream ?? throw new ArgumentNullException(nameof(stream));
26 | }
27 |
28 | protected uint stbi__get32be()
29 | {
30 | return Stream.stbi__get32be();
31 | }
32 |
33 | protected int stbi__get16be()
34 | {
35 | return Stream.stbi__get16be();
36 | }
37 |
38 | protected uint stbi__get32le()
39 | {
40 | return Stream.stbi__get32le();
41 | }
42 |
43 | protected int stbi__get16le()
44 | {
45 | return Stream.stbi__get16le();
46 | }
47 |
48 | protected byte stbi__get8()
49 | {
50 | return Stream.stbi__get8();
51 | }
52 |
53 | protected bool stbi__getn(byte[] buffer, int offset, int count)
54 | {
55 | var read = Stream.Read(buffer, offset, count);
56 |
57 | return read == count;
58 | }
59 |
60 | protected void stbi__skip(int count)
61 | {
62 | Stream.stbi__skip(count);
63 | }
64 |
65 | protected bool stbi__at_eof()
66 | {
67 | return Stream.Position == Stream.Length;
68 | }
69 |
70 | internal static void stbi__err(string message)
71 | {
72 | throw new Exception(message);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/tests/Stb.Native/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | DYNAMIC LINK LIBRARY : Stb.Native Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this Stb.Native DLL for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your Stb.Native application.
9 |
10 | Stb.Native.vcxproj
11 | This is the main project file for VC++ projects generated using an Application Wizard.
12 | It contains information about the version of Visual C++ that generated the file, and
13 | information about the platforms, configurations, and project features selected with the
14 | Application Wizard.
15 |
16 | Stb.Native.vcxproj.filters
17 | This is the filters file for VC++ projects generated using an Application Wizard.
18 | It contains information about the association between the files in your project
19 | and the filters. This association is used in the IDE to show grouping of files with
20 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
21 | "Source Files" filter).
22 |
23 | Stb.Native.cpp
24 | This is the main DLL source file.
25 |
26 | Stb.Native.h
27 | This file contains a class declaration.
28 |
29 | AssemblyInfo.cpp
30 | Contains custom attributes for modifying assembly metadata.
31 |
32 | /////////////////////////////////////////////////////////////////////////////
33 | Other notes:
34 |
35 | AppWizard uses "TODO:" to indicate parts of the source code you
36 | should add to or customize.
37 |
38 | /////////////////////////////////////////////////////////////////////////////
39 |
--------------------------------------------------------------------------------
/tests/SafeStbImageSharp.Tests/Utility/Res.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Reflection;
3 |
4 | namespace StbImageSharp.Tests.Utility
5 | {
6 | ///
7 | /// Resource utility
8 | ///
9 | public static class Res
10 | {
11 | ///
12 | /// Open assembly resource stream by relative name
13 | ///
14 | ///
15 | ///
16 | ///
17 | public static Stream OpenResourceStream(this Assembly assembly, string assetName)
18 | {
19 | var path = assembly.GetName().Name + ".Resources." + assetName;
20 |
21 | // Once you figure out the name, pass it in as the argument here.
22 | var stream = assembly.GetManifestResourceStream(path);
23 |
24 | return stream;
25 | }
26 |
27 | ///
28 | /// Reads assembly resource as byte array by relative name
29 | ///
30 | ///
31 | ///
32 | ///
33 | public static byte[] ReadResourceAsBytes(this Assembly assembly, string assetName)
34 | {
35 | var ms = new MemoryStream();
36 | using (var input = assembly.OpenResourceStream(assetName))
37 | {
38 | input.CopyTo(ms);
39 |
40 | return ms.ToArray();
41 | }
42 | }
43 |
44 | ///
45 | /// Reads assembly resource as string by relative name
46 | ///
47 | ///
48 | ///
49 | ///
50 | public static string ReadResourceAsString(this Assembly assembly, string assetName)
51 | {
52 | string result;
53 | using (var input = assembly.OpenResourceStream(assetName))
54 | {
55 | using (var textReader = new StreamReader(input))
56 | {
57 | result = textReader.ReadToEnd();
58 | }
59 | }
60 |
61 | return result;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/ImageResult.cs:
--------------------------------------------------------------------------------
1 | using StbImageSharp.Decoding;
2 | using System.IO;
3 |
4 | namespace StbImageSharp
5 | {
6 | #if !STBSHARP_INTERNAL
7 | public
8 | #else
9 | internal
10 | #endif
11 | class ImageResult
12 | {
13 | public int Width { get; set; }
14 | public int Height { get; set; }
15 | public ColorComponents ColorComponents { get; set; }
16 | public ColorComponents SourceComponents { get; set; }
17 |
18 | ///
19 | /// Either 8 or 16
20 | ///
21 | public int BitsPerChannel { get; set; }
22 | public byte[] Data { get; set; }
23 |
24 | public static ImageResult FromMemory(byte[] data, ColorComponents? requiredComponents = null, bool use8BitsPerChannel = true)
25 | {
26 | using (var stream = new MemoryStream(data))
27 | {
28 | return FromStream(stream, requiredComponents, use8BitsPerChannel);
29 | }
30 | }
31 |
32 | public static ImageResult FromStream(Stream stream, ColorComponents? requiredComponents = null, bool use8BitsPerChannel = true)
33 | {
34 | ImageResult result = null;
35 | if (JpgDecoder.Test(stream))
36 | {
37 | result = JpgDecoder.Decode(stream, requiredComponents);
38 | }
39 | else if (PngDecoder.Test(stream))
40 | {
41 | result = PngDecoder.Decode(stream, requiredComponents);
42 | }
43 | else if (BmpDecoder.Test(stream))
44 | {
45 | result = BmpDecoder.Decode(stream, requiredComponents);
46 | }
47 | else if (GifDecoder.Test(stream))
48 | {
49 | result = GifDecoder.Decode(stream, requiredComponents);
50 | }
51 | else if (PsdDecoder.Test(stream))
52 | {
53 | result = PsdDecoder.Decode(stream, requiredComponents);
54 | }
55 | else if (TgaDecoder.Test(stream))
56 | {
57 | result = TgaDecoder.Decode(stream, requiredComponents);
58 | }
59 |
60 | if (result == null)
61 | {
62 | Decoder.stbi__err("unknown image type");
63 | }
64 |
65 | if (use8BitsPerChannel && result.BitsPerChannel != 8)
66 | {
67 | result.Data = Conversion.stbi__convert_16_to_8(result.Data, result.Width, result.Height, (int)result.ColorComponents);
68 | }
69 |
70 | return result;
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/tests/SafeStbImageSharp.Tests/Tests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using StbImageSharp.Tests.Utility;
3 | using System.IO;
4 | using System.Reflection;
5 |
6 | namespace StbImageSharp.Tests
7 | {
8 | [TestFixture]
9 | public class Tests
10 | {
11 | private static readonly Assembly _assembly = typeof(Tests).Assembly;
12 |
13 | [TestCase("DockPanes.jpg", 2000, 609, 406, ColorComponents.RedGreenBlue, false)]
14 | [TestCase("J7dAdPl.png", 1000, 182, 169, ColorComponents.RedGreenBlueAlpha, false)]
15 | public void Info(string filename, int headerSize, int width, int height, ColorComponents colorComponents, bool is16bit)
16 | {
17 | ImageInfo? result;
18 |
19 | var data = new byte[headerSize];
20 | using (var stream = _assembly.OpenResourceStream(filename))
21 | {
22 | stream.Read(data, 0, data.Length);
23 | }
24 |
25 | using (var stream = new MemoryStream(data))
26 | {
27 | result = ImageInfo.FromStream(stream);
28 | }
29 |
30 | Assert.IsNotNull(result);
31 |
32 | var info = result.Value;
33 | Assert.AreEqual(info.Width, width);
34 | Assert.AreEqual(info.Height, height);
35 | Assert.AreEqual(info.ColorComponents, colorComponents);
36 | Assert.AreEqual(info.BitsPerChannel, is16bit ? 16 : 8);
37 | }
38 |
39 | [TestCase("DockPanes.jpg", 609, 406, ColorComponents.RedGreenBlue, false)]
40 | [TestCase("J7dAdPl.png", 182, 169, ColorComponents.RedGreenBlueAlpha, false)]
41 | public void Load(string filename, int width, int height, ColorComponents colorComponents, bool is16bit)
42 | {
43 | ImageResult result;
44 |
45 | using (var stream = _assembly.OpenResourceStream(filename))
46 | {
47 | result = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
48 | }
49 |
50 | Assert.IsNotNull(result);
51 |
52 | Assert.AreEqual(result.Width, width);
53 | Assert.AreEqual(result.Height, height);
54 | Assert.AreEqual(result.SourceComponents, colorComponents);
55 | Assert.AreEqual(result.BitsPerChannel, is16bit ? 16 : 8);
56 | Assert.IsNotNull(result.Data);
57 | Assert.AreEqual(result.Data.Length, result.Width * result.Height * (int)result.ColorComponents);
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.MonoGame/Game1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 |
6 | namespace StbImageSharp.Samples.MonoGame
7 | {
8 | ///
9 | /// This is the main type for your game.
10 | ///
11 | public class Game1 : Game
12 | {
13 | private const int FontBitmapWidth = 1024;
14 | private const int FontBitmapHeight = 1024;
15 |
16 | GraphicsDeviceManager _graphics;
17 | SpriteBatch _spriteBatch;
18 |
19 | private Texture2D _image;
20 |
21 | public Game1()
22 | {
23 | _graphics = new GraphicsDeviceManager(this)
24 | {
25 | PreferredBackBufferWidth = 1400,
26 | PreferredBackBufferHeight = 960
27 | };
28 |
29 | Content.RootDirectory = "Content";
30 | IsMouseVisible = true;
31 | Window.AllowUserResizing = true;
32 | }
33 |
34 | ///
35 | /// LoadContent will be called once per game and is the place to load
36 | /// all of your content.
37 | ///
38 | protected override void LoadContent()
39 | {
40 | // Create a new SpriteBatch, which can be used to draw textures.
41 | _spriteBatch = new SpriteBatch(GraphicsDevice);
42 |
43 | // TODO: use this.Content to load your game content here
44 |
45 | // Load image data into memory
46 | var path = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
47 | path = Path.Combine(path, "image.jpg");
48 |
49 | using (var stream = File.OpenRead(path))
50 | {
51 | var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
52 | _image = new Texture2D(GraphicsDevice, image.Width, image.Height, false, SurfaceFormat.Color);
53 | _image.SetData(image.Data);
54 | }
55 |
56 | GC.Collect();
57 | }
58 |
59 | ///
60 | /// This is called when the game should draw itself.
61 | ///
62 | /// Provides a snapshot of timing values.
63 | protected override void Draw(GameTime gameTime)
64 | {
65 | GraphicsDevice.Clear(Color.CornflowerBlue);
66 |
67 | // TODO: Add your drawing code here
68 | _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
69 |
70 | _spriteBatch.Draw(_image, Vector2.Zero);
71 |
72 | _spriteBatch.End();
73 |
74 | base.Draw(gameTime);
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Form1.cs:
--------------------------------------------------------------------------------
1 | using StbImageSharp;
2 | using System;
3 | using System.Drawing;
4 | using System.Drawing.Imaging;
5 | using System.IO;
6 | using System.Runtime.InteropServices;
7 | using System.Windows.Forms;
8 |
9 | namespace StbSharp.WinForms.Test
10 | {
11 | public partial class Form1 : Form
12 | {
13 | private string _fileName;
14 | private ImageResult _loadedImage;
15 |
16 | public Form1()
17 | {
18 | InitializeComponent();
19 | }
20 |
21 | private void button1_Click(object sender, EventArgs e)
22 | {
23 | try
24 | {
25 | using (var dlg = new OpenFileDialog())
26 | {
27 | dlg.Filter =
28 | "PNG Files (*.png)|*.png|JPEG Files (*.jpg)|*.jpg|BMP Files (*.bmp)|*.bmp|PSD Files (*.psd)|*.psd|TGA Files (*.tga)|*.tga|GIF Files (*.gif)|*.gif|All Files (*.*)|*.*";
29 | if (dlg.ShowDialog() != DialogResult.OK)
30 | {
31 | return;
32 | }
33 |
34 | _fileName = dlg.FileName;
35 |
36 | var bytes = File.ReadAllBytes(_fileName);
37 |
38 | using (var stream = File.OpenRead(_fileName))
39 | {
40 | _loadedImage = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
41 | }
42 | SetImage();
43 | }
44 | }
45 | catch (Exception ex)
46 | {
47 | MessageBox.Show("Error", ex.Message);
48 | }
49 | }
50 |
51 | private void SetImage()
52 | {
53 | // Convert to bgra
54 | var data = new byte[_loadedImage.Data.Length];
55 | Array.Copy(_loadedImage.Data, data, data.Length);
56 |
57 | for (var i = 0; i < _loadedImage.Width*_loadedImage.Height; ++i)
58 | {
59 | var r = data[i*4];
60 | var g = data[i*4 + 1];
61 | var b = data[i*4 + 2];
62 | var a = data[i*4 + 3];
63 |
64 |
65 | data[i*4] = b;
66 | data[i*4 + 1] = g;
67 | data[i*4 + 2] = r;
68 | data[i*4 + 3] = a;
69 | }
70 |
71 | // Convert to Bitmap
72 | var bmp = new Bitmap(_loadedImage.Width, _loadedImage.Height, PixelFormat.Format32bppArgb);
73 | var bmpData = bmp.LockBits(new Rectangle(0, 0, _loadedImage.Width, _loadedImage.Height), ImageLockMode.WriteOnly,
74 | bmp.PixelFormat);
75 |
76 | Marshal.Copy(data, 0, bmpData.Scan0, bmpData.Stride*bmp.Height);
77 | bmp.UnlockBits(bmpData);
78 |
79 | pictureBox1.Image = bmp;
80 | _numericWidth.Value = _loadedImage.Width;
81 | _numericHeight.Value = _loadedImage.Height;
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace StbSharp.WinForms.Test.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StbSharp.WinForms.Test.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Utility/FakePtr.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StbImageSharp.Utility
4 | {
5 | internal struct FakePtr where T: new()
6 | {
7 | public static FakePtr Null = new FakePtr(null);
8 |
9 | public readonly T[] _array;
10 |
11 | public int Offset;
12 |
13 | public bool IsNull
14 | {
15 | get
16 | {
17 | return _array == null;
18 | }
19 | }
20 |
21 | public T this[int index]
22 | {
23 | get
24 | {
25 | return _array[Offset + index];
26 | }
27 |
28 | set
29 | {
30 | _array[Offset + index] = value;
31 | }
32 | }
33 |
34 | public T this[long index]
35 | {
36 | get
37 | {
38 | return _array[Offset + index];
39 | }
40 |
41 | set
42 | {
43 | _array[Offset + index] = value;
44 | }
45 | }
46 |
47 | public T Value
48 | {
49 | get
50 | {
51 | return this[0];
52 | }
53 |
54 | set
55 | {
56 | this[0] = value;
57 | }
58 | }
59 |
60 | public FakePtr(FakePtr ptr, int offset)
61 | {
62 | Offset = ptr.Offset + offset;
63 | _array = ptr._array;
64 | }
65 |
66 | public FakePtr(T[] data, int offset)
67 | {
68 | Offset = offset;
69 | _array = data;
70 | }
71 |
72 | public FakePtr(T[] data): this(data, 0)
73 | {
74 | }
75 |
76 | public FakePtr(T value)
77 | {
78 | Offset = 0;
79 | _array = new T[1];
80 | _array[0] = value;
81 | }
82 |
83 | public void Clear(int count)
84 | {
85 | Array.Clear(_array, Offset, count);
86 | }
87 |
88 | public T GetAndIncrease()
89 | {
90 | var result = _array[Offset];
91 | ++Offset;
92 |
93 | return result;
94 | }
95 |
96 | public void SetAndIncrease(T value)
97 | {
98 | _array[Offset] = value;
99 | ++Offset;
100 | }
101 |
102 | public void Set(T value)
103 | {
104 | _array[Offset] = value;
105 | }
106 |
107 | public static FakePtr operator +(FakePtr p, int offset)
108 | {
109 | return new FakePtr(p._array) { Offset = p.Offset + offset };
110 | }
111 |
112 | public static FakePtr operator -(FakePtr p, int offset)
113 | {
114 | return p + -offset;
115 | }
116 |
117 | public static FakePtr operator +(FakePtr p, uint offset)
118 | {
119 | return p + (int)offset;
120 | }
121 |
122 | public static FakePtr operator -(FakePtr p, uint offset)
123 | {
124 | return p - (int)offset;
125 | }
126 |
127 | public static FakePtr operator +(FakePtr p, long offset)
128 | {
129 | return p + (int)offset;
130 | }
131 |
132 | public static FakePtr operator -(FakePtr p, long offset)
133 | {
134 | return p - (int)offset;
135 | }
136 |
137 | public static FakePtr operator ++(FakePtr p)
138 | {
139 | return p + 1;
140 | }
141 |
142 | public static FakePtr CreateWithSize(int size)
143 | {
144 | var result = new FakePtr(new T[size]);
145 |
146 | for (int i = 0; i < size; ++i)
147 | {
148 | result[i] = new T();
149 | }
150 |
151 | return result;
152 | }
153 |
154 | public static FakePtr CreateWithSize(long size)
155 | {
156 | return CreateWithSize((int)size);
157 | }
158 |
159 | public static FakePtr Create()
160 | {
161 | return CreateWithSize(1);
162 | }
163 |
164 | public void memset(T value, int count)
165 | {
166 | _array.Set(Offset, count, value);
167 | }
168 |
169 | public void memcpy(FakePtr b, int count)
170 | {
171 | Array.Copy(b._array, b.Offset, _array, Offset, count);
172 | }
173 |
174 | public void memcpy(T[] b, int count)
175 | {
176 | Array.Copy(b, 0, _array, Offset, count);
177 | }
178 | }
179 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SafeStbImageSharp
2 | [](https://www.nuget.org/packages/SafeStbImageSharp/)
3 | 
4 | [](https://discord.gg/ZeHxhCY)
5 |
6 | SafeStbImageSharp is safe and refactored version of [StbImageSharp](https://github.com/StbSharp/StbImageSharp).
7 |
8 | # Adding Reference
9 | There are two ways of referencing SafeStbImageSharp in the project:
10 | 1. Through nuget: https://www.nuget.org/packages/SafeStbImageSharp/
11 | 2. As submodule:
12 |
13 | a. `git submodule add https://github.com/StbSharp/SafeStbImageSharp.git`
14 |
15 | b. Now there are two options:
16 |
17 | * Add SafeStbImageSharp/src/SafeStbImageSharp/SafeStbImageSharp.csproj to the solution
18 |
19 | * Include *.cs from SafeStbImageSharp/src/SafeStbImageSharp directly in the project. In this case, it might make sense to add STBSHARP_INTERNAL build compilation symbol to the project, so SafeStbImageSharp classes would become internal.
20 |
21 | # Usage
22 | Following code loads image from stream and converts it to 32-bit RGBA:
23 | ```c#
24 | ImageResult image;
25 | using (var stream = File.OpenRead(path))
26 | {
27 | image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
28 | }
29 | ```
30 |
31 | If you are writing MonoGame application and would like to convert that data to the Texture2D. It could be done following way:
32 | ```c#
33 | Texture2D texture = new Texture2D(GraphicsDevice, image.Width, image.Height, false, SurfaceFormat.Color);
34 | texture.SetData(image.Data);
35 | ```
36 |
37 | Or if you are writing WinForms app and would like StbSharp resulting bytes to be converted to the Bitmap. The sample code is:
38 | ```c#
39 | byte[] data = image.Data;
40 | // Convert rgba to bgra
41 | for (int i = 0; i < x*y; ++i)
42 | {
43 | byte r = data[i*4];
44 | byte g = data[i*4 + 1];
45 | byte b = data[i*4 + 2];
46 | byte a = data[i*4 + 3];
47 |
48 |
49 | data[i*4] = b;
50 | data[i*4 + 1] = g;
51 | data[i*4 + 2] = r;
52 | data[i*4 + 3] = a;
53 | }
54 |
55 | // Create Bitmap
56 | Bitmap bmp = new Bitmap(_loadedImage.Width, _loadedImage.Height, PixelFormat.Format32bppArgb);
57 | BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, _loadedImage.Width, _loadedImage.Height), ImageLockMode.WriteOnly,
58 | bmp.PixelFormat);
59 |
60 | Marshal.Copy(data, 0, bmpData.Scan0, bmpData.Stride*bmp.Height);
61 | bmp.UnlockBits(bmpData);
62 | ```
63 |
64 | # Reliability & Performance
65 | There is special app to measure reliability & performance of SafeStbImageSharp in comparison to the original stb_image.h: https://github.com/StbSharp/SafeStbImageSharp/tree/master/tests/StbImageSharp.Testing
66 |
67 | It goes through every image file in the specified folder and tries to load it 10 times with SafeStbImageSharp, then 10 times with C++/CLI wrapper over the original stb_image.h(Stb.Native). Then it compares whether the results are byte-wise similar and also calculates loading times. Also it sums up and reports loading times for each method.
68 |
69 | Moreover SixLabor ImageSharp is included in the testing too.
70 |
71 | I've used it over following set of images: https://github.com/StbSharp/TestImages
72 |
73 | The byte-wise comprarison results are similar for StbImageSharp and Stb.Native.
74 |
75 | And performance comparison results are(times are total loading times):
76 | ```
77 | 10 -- SafeStbImageSharp - jpg: 16139 ms, tga: 4075 ms, bmp: 370 ms, psd: 2 ms, png: 73274 ms, Total: 93860 ms
78 | 10 -- Stb.Native - jpg: 6437 ms, tga: 2140 ms, bmp: 132 ms, psd: 0 ms, png: 52758 ms, Total: 61467 ms
79 | 10 -- ImageSharp - jpg: 101309 ms, bmp: 63 ms, png: 44211 ms, Total: 145583 ms
80 | 10 -- Total files processed - jpg: 170, tga: 41, bmp: 7, psd: 1, png: 564, Total: 783
81 | 10 -- StbImageSharp/Stb.Native matches/processed - 783/787
82 | ```
83 |
84 | # License
85 | Public Domain
86 |
87 | # Credits
88 | * [stb](https://github.com/nothings/stb)
89 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/SafeStbImageSharp.Samples.WinForms.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}
8 | WinExe
9 | Properties
10 | StbImageLib.Samples.WinForms
11 | StbImageLib.Samples.WinForms
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | false
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Form
51 |
52 |
53 | Form1.cs
54 |
55 |
56 |
57 |
58 | Form1.cs
59 |
60 |
61 | ResXFileCodeGenerator
62 | Resources.Designer.cs
63 | Designer
64 |
65 |
66 | True
67 | Resources.resx
68 | True
69 |
70 |
71 | SettingsSingleFileGenerator
72 | Settings.Designer.cs
73 |
74 |
75 | True
76 | Settings.settings
77 | True
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | {750e8dc6-0af8-4772-8931-1623d0ea49cc}
86 | SafeStbImageSharp
87 |
88 |
89 |
90 |
97 |
--------------------------------------------------------------------------------
/tests/Stb.Native/Stb.Native.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 |
14 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}
15 | v4.5
16 | ManagedCProj
17 | StbNative
18 | 10.0
19 |
20 |
21 |
22 | DynamicLibrary
23 | true
24 | v142
25 | true
26 | Unicode
27 |
28 |
29 | DynamicLibrary
30 | false
31 | v142
32 | true
33 | Unicode
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | true
47 |
48 |
49 | false
50 |
51 |
52 |
53 | Level3
54 | Disabled
55 | WIN32;_DEBUG;%(PreprocessorDefinitions)
56 | Use
57 |
58 |
59 | true
60 |
61 |
62 |
63 |
64 |
65 | Level3
66 | WIN32;NDEBUG;%(PreprocessorDefinitions)
67 | Use
68 |
69 |
70 | true
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | Create
89 | Create
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/tests/Stb.Native/Stb.Native.h:
--------------------------------------------------------------------------------
1 | // Stb.Native.h
2 |
3 | #pragma once
4 |
5 | using namespace System;
6 | using namespace System::IO;
7 | using namespace System::Collections::Generic;
8 | using namespace System::Runtime::InteropServices;
9 | using namespace System::Threading;
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #define STBI_NO_STDIO
16 | #define STB_IMAGE_IMPLEMENTATION
17 | #include "stb_image.h"
18 |
19 | namespace StbNative {
20 | int read_callback(void *user, char *data, int size);
21 | void skip_callback(void *user, int size);
22 | int eof_callback(void *user);
23 | void write_func(void *context, void *data, int size);
24 |
25 | public ref class ReadInfo
26 | {
27 | public:
28 | Stream ^stream;
29 | array ^buffer;
30 |
31 | ReadInfo(Stream ^s, array ^b)
32 | {
33 | stream = s;
34 | buffer = b;
35 | }
36 | };
37 |
38 | public ref class Native
39 | {
40 | public:
41 | static Dictionary ^readInfo = gcnew Dictionary();
42 | static Dictionary ^writeInfo = gcnew Dictionary();
43 | static int _id = 0;
44 |
45 | static int GenerateId()
46 | {
47 | int %trackRefCounter = _id;
48 | return System::Threading::Interlocked::Increment(trackRefCounter);
49 | }
50 |
51 | // TODO: Add your methods for this class here.
52 | static array ^ load_from_memory(array ^bytes, [Out] int %x, [Out] int %y, [Out] int %comp, int req_comp)
53 | {
54 | pin_ptr p = &bytes[0];
55 |
56 | int xx, yy, ccomp;
57 | const unsigned char *ptr = (const unsigned char *)p;
58 | void *res = stbi_load_from_memory(ptr, bytes->Length, &xx, &yy, &ccomp, req_comp);
59 |
60 | x = xx;
61 | y = yy;
62 | comp = ccomp;
63 |
64 | int c = req_comp != 0 ? req_comp : comp;
65 | array ^result = gcnew array(x * y * c);
66 |
67 | Marshal::Copy(IntPtr((void *)res), result, 0, result->Length);
68 | free(res);
69 |
70 | return result;
71 | }
72 |
73 | static array ^ load_from_stream(Stream ^input, [Out] int %x, [Out] int %y, [Out] int %comp, int req_comp)
74 | {
75 | array ^buffer = gcnew array(32768);
76 |
77 | Monitor::Enter(readInfo);
78 | int id;
79 | try {
80 | id = GenerateId();
81 |
82 | ReadInfo ^newInfo = gcnew ReadInfo(input, buffer);
83 | readInfo->Add(id, newInfo);
84 | }
85 | finally
86 | {
87 | Monitor::Exit(readInfo);
88 | }
89 |
90 | stbi_io_callbacks callbacks;
91 | callbacks.read = read_callback;
92 | callbacks.skip = skip_callback;
93 | callbacks.eof = eof_callback;
94 |
95 | int xx, yy, ccomp;
96 |
97 | void *res = stbi_load_from_callbacks(&callbacks, (void *)id, &xx, &yy, &ccomp, req_comp);
98 |
99 | x = xx;
100 | y = yy;
101 | comp = ccomp;
102 |
103 | int c = req_comp != 0 ? req_comp : comp;
104 | array ^result = gcnew array(x * y * c);
105 |
106 | Marshal::Copy(IntPtr((void *)res), result, 0, result->Length);
107 | free(res);
108 |
109 | buffer = nullptr;
110 |
111 | Monitor::Enter(readInfo);
112 | try {
113 | readInfo->Remove(id);
114 | }
115 | finally
116 | {
117 | Monitor::Exit(readInfo);
118 | }
119 |
120 | return result;
121 | }
122 | };
123 |
124 | int read_callback(void *user, char *data, int size)
125 | {
126 | ReadInfo ^info;
127 | Monitor::Enter(Native::readInfo);
128 | int id = (int)user;
129 | try {
130 | info = Native::readInfo[id];
131 | }
132 | finally
133 | {
134 | Monitor::Exit(Native::readInfo);
135 | }
136 |
137 | if (size > info->buffer->Length) {
138 | info->buffer = gcnew array(size * 2);
139 | }
140 |
141 | int res = info->stream->Read(info->buffer, 0, size);
142 |
143 | Marshal::Copy(info->buffer, 0, IntPtr(data), res);
144 |
145 | return res;
146 | }
147 |
148 | void skip_callback(void *user, int size)
149 | {
150 | ReadInfo ^info;
151 | Monitor::Enter(Native::readInfo);
152 | int id = (int)user;
153 | try {
154 | info = Native::readInfo[id];
155 | }
156 | finally
157 | {
158 | Monitor::Exit(Native::readInfo);
159 | }
160 |
161 | info->stream->Seek(size, SeekOrigin::Current);
162 | }
163 |
164 | int eof_callback(void *user)
165 | {
166 | ReadInfo ^info;
167 | Monitor::Enter(Native::readInfo);
168 | int id = (int)user;
169 | try {
170 | info = Native::readInfo[id];
171 | }
172 | finally
173 | {
174 | Monitor::Exit(Native::readInfo);
175 | }
176 |
177 | return info->stream->CanRead ? 1 : 0;
178 | }
179 |
180 | void write_func(void *context, void *data, int size)
181 | {
182 | Stream ^ info;
183 | Monitor::Enter(Native::writeInfo);
184 | int id = (int)context;
185 | try {
186 | info = Native::writeInfo[id];
187 | }
188 | finally
189 | {
190 | Monitor::Exit(Native::writeInfo);
191 | }
192 |
193 | unsigned char *bptr = (unsigned char *)data;
194 | for (int i = 0; i < size; ++i)
195 | {
196 | info->WriteByte(*bptr);
197 | ++bptr;
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Form1.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace StbSharp.WinForms.Test
2 | {
3 | partial class Form1
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.button1 = new System.Windows.Forms.Button();
32 | this.pictureBox1 = new System.Windows.Forms.PictureBox();
33 | this._numericWidth = new System.Windows.Forms.NumericUpDown();
34 | this.label1 = new System.Windows.Forms.Label();
35 | this.label2 = new System.Windows.Forms.Label();
36 | this._numericHeight = new System.Windows.Forms.NumericUpDown();
37 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
38 | ((System.ComponentModel.ISupportInitialize)(this._numericWidth)).BeginInit();
39 | ((System.ComponentModel.ISupportInitialize)(this._numericHeight)).BeginInit();
40 | this.SuspendLayout();
41 | //
42 | // button1
43 | //
44 | this.button1.Location = new System.Drawing.Point(13, 13);
45 | this.button1.Name = "button1";
46 | this.button1.Size = new System.Drawing.Size(75, 23);
47 | this.button1.TabIndex = 0;
48 | this.button1.Text = "Load...";
49 | this.button1.UseVisualStyleBackColor = true;
50 | this.button1.Click += new System.EventHandler(this.button1_Click);
51 | //
52 | // pictureBox1
53 | //
54 | this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
55 | | System.Windows.Forms.AnchorStyles.Left)
56 | | System.Windows.Forms.AnchorStyles.Right)));
57 | this.pictureBox1.Location = new System.Drawing.Point(12, 42);
58 | this.pictureBox1.Name = "pictureBox1";
59 | this.pictureBox1.Size = new System.Drawing.Size(707, 491);
60 | this.pictureBox1.TabIndex = 1;
61 | this.pictureBox1.TabStop = false;
62 | //
63 | // _numericWidth
64 | //
65 | this._numericWidth.Location = new System.Drawing.Point(429, 13);
66 | this._numericWidth.Maximum = new decimal(new int[] {
67 | 10000,
68 | 0,
69 | 0,
70 | 0});
71 | this._numericWidth.Name = "_numericWidth";
72 | this._numericWidth.Size = new System.Drawing.Size(120, 20);
73 | this._numericWidth.TabIndex = 7;
74 | //
75 | // label1
76 | //
77 | this.label1.AutoSize = true;
78 | this.label1.Location = new System.Drawing.Point(385, 15);
79 | this.label1.Name = "label1";
80 | this.label1.Size = new System.Drawing.Size(38, 13);
81 | this.label1.TabIndex = 8;
82 | this.label1.Text = "Width:";
83 | //
84 | // label2
85 | //
86 | this.label2.AutoSize = true;
87 | this.label2.Location = new System.Drawing.Point(555, 15);
88 | this.label2.Name = "label2";
89 | this.label2.Size = new System.Drawing.Size(41, 13);
90 | this.label2.TabIndex = 10;
91 | this.label2.Text = "Height:";
92 | //
93 | // _numericHeight
94 | //
95 | this._numericHeight.Location = new System.Drawing.Point(599, 13);
96 | this._numericHeight.Maximum = new decimal(new int[] {
97 | 10000,
98 | 0,
99 | 0,
100 | 0});
101 | this._numericHeight.Name = "_numericHeight";
102 | this._numericHeight.Size = new System.Drawing.Size(120, 20);
103 | this._numericHeight.TabIndex = 9;
104 | //
105 | // Form1
106 | //
107 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
108 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
109 | this.ClientSize = new System.Drawing.Size(731, 545);
110 | this.Controls.Add(this.label2);
111 | this.Controls.Add(this._numericHeight);
112 | this.Controls.Add(this.label1);
113 | this.Controls.Add(this._numericWidth);
114 | this.Controls.Add(this.pictureBox1);
115 | this.Controls.Add(this.button1);
116 | this.Name = "Form1";
117 | this.Text = "Form1";
118 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
119 | ((System.ComponentModel.ISupportInitialize)(this._numericWidth)).EndInit();
120 | ((System.ComponentModel.ISupportInitialize)(this._numericHeight)).EndInit();
121 | this.ResumeLayout(false);
122 | this.PerformLayout();
123 |
124 | }
125 |
126 | #endregion
127 |
128 | private System.Windows.Forms.Button button1;
129 | private System.Windows.Forms.PictureBox pictureBox1;
130 | private System.Windows.Forms.NumericUpDown _numericWidth;
131 | private System.Windows.Forms.Label label1;
132 | private System.Windows.Forms.Label label2;
133 | private System.Windows.Forms.NumericUpDown _numericHeight;
134 | }
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/tests/StbImageSharp.Testing/StbImageSharp.Testing.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | AnyCPU
8 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}
9 | Exe
10 | StbImageSharp.Testing
11 | StbImageSharp.Testing
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 |
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 | ..\..\packages\SixLabors.Core.1.0.0-beta0008\lib\netstandard2.0\SixLabors.Core.dll
41 |
42 |
43 | ..\..\packages\SixLabors.ImageSharp.1.0.0-beta0007\lib\net472\SixLabors.ImageSharp.dll
44 |
45 |
46 |
47 | ..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
48 |
49 |
50 |
51 | ..\..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll
52 |
53 |
54 |
55 | ..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
56 |
57 |
58 |
59 | ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {750e8dc6-0af8-4772-8931-1623d0ea49cc}
77 | SafeStbImageSharp
78 |
79 |
80 | {ea7b8121-942a-437d-85d5-e4d55b94e88a}
81 | Stb.Native
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Form1.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/samples/SafeStbImageSharp.Samples.WinForms/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/SafeStbImageSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30804.86
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeStbImageSharp", "src\SafeStbImageSharp.csproj", "{750E8DC6-0AF8-4772-8931-1623D0EA49CC}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{56C50AF4-B951-44C2-962F-89DB441ACEBD}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeStbImageSharp.Samples.MonoGame", "samples\SafeStbImageSharp.Samples.MonoGame\SafeStbImageSharp.Samples.MonoGame.csproj", "{4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeStbImageSharp.Samples.WinForms", "samples\SafeStbImageSharp.Samples.WinForms\SafeStbImageSharp.Samples.WinForms.csproj", "{87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{4DF85107-02EF-46F2-A399-D69461537899}"
15 | EndProject
16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stb.Native", "tests\Stb.Native\Stb.Native.vcxproj", "{EA7B8121-942A-437D-85D5-E4D55B94E88A}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeStbImageSharp.Tests", "tests\SafeStbImageSharp.Tests\SafeStbImageSharp.Tests.csproj", "{EC85117B-2ABE-43BD-950F-D26C00669F12}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StbImageSharp.Testing", "tests\StbImageSharp.Testing\StbImageSharp.Testing.csproj", "{4295DB99-F5C5-4D33-84DA-02AA2CA141B6}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Debug|x86 = Debug|x86
26 | Release|Any CPU = Release|Any CPU
27 | Release|x86 = Release|x86
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Debug|x86.ActiveCfg = Debug|Any CPU
33 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Debug|x86.Build.0 = Debug|Any CPU
34 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Release|x86.ActiveCfg = Release|Any CPU
37 | {750E8DC6-0AF8-4772-8931-1623D0EA49CC}.Release|x86.Build.0 = Release|Any CPU
38 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Debug|x86.ActiveCfg = Debug|Any CPU
41 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Debug|x86.Build.0 = Debug|Any CPU
42 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Release|x86.ActiveCfg = Release|Any CPU
45 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF}.Release|x86.Build.0 = Release|Any CPU
46 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Debug|x86.ActiveCfg = Debug|Any CPU
49 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Debug|x86.Build.0 = Debug|Any CPU
50 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Release|x86.ActiveCfg = Release|Any CPU
53 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B}.Release|x86.Build.0 = Release|Any CPU
54 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Debug|Any CPU.ActiveCfg = Debug|Win32
55 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Debug|Any CPU.Build.0 = Debug|Win32
56 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Debug|x86.ActiveCfg = Debug|Win32
57 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Debug|x86.Build.0 = Debug|Win32
58 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Release|Any CPU.ActiveCfg = Release|Win32
59 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Release|Any CPU.Build.0 = Release|Win32
60 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Release|x86.ActiveCfg = Release|Win32
61 | {EA7B8121-942A-437D-85D5-E4D55B94E88A}.Release|x86.Build.0 = Release|Win32
62 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Debug|x86.ActiveCfg = Debug|Any CPU
65 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Debug|x86.Build.0 = Debug|Any CPU
66 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Release|Any CPU.ActiveCfg = Release|Any CPU
67 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Release|Any CPU.Build.0 = Release|Any CPU
68 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Release|x86.ActiveCfg = Release|Any CPU
69 | {EC85117B-2ABE-43BD-950F-D26C00669F12}.Release|x86.Build.0 = Release|Any CPU
70 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Debug|x86.ActiveCfg = Debug|Any CPU
73 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Debug|x86.Build.0 = Debug|Any CPU
74 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
75 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Release|Any CPU.Build.0 = Release|Any CPU
76 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Release|x86.ActiveCfg = Release|Any CPU
77 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6}.Release|x86.Build.0 = Release|Any CPU
78 | EndGlobalSection
79 | GlobalSection(SolutionProperties) = preSolution
80 | HideSolutionNode = FALSE
81 | EndGlobalSection
82 | GlobalSection(NestedProjects) = preSolution
83 | {4E1D18DA-4594-408F-AC3A-2C3D7357C9DF} = {56C50AF4-B951-44C2-962F-89DB441ACEBD}
84 | {87A1E8BA-4F87-4BE7-84DD-BECD47E9944B} = {56C50AF4-B951-44C2-962F-89DB441ACEBD}
85 | {EA7B8121-942A-437D-85D5-E4D55B94E88A} = {4DF85107-02EF-46F2-A399-D69461537899}
86 | {EC85117B-2ABE-43BD-950F-D26C00669F12} = {4DF85107-02EF-46F2-A399-D69461537899}
87 | {4295DB99-F5C5-4D33-84DA-02AA2CA141B6} = {4DF85107-02EF-46F2-A399-D69461537899}
88 | EndGlobalSection
89 | GlobalSection(ExtensibilityGlobals) = postSolution
90 | SolutionGuid = {C9C812E7-F89A-4B6E-8F9D-981D5F8BBAB3}
91 | EndGlobalSection
92 | EndGlobal
93 |
--------------------------------------------------------------------------------
/src/Decoding/PsdDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using StbImageSharp.Utility;
4 |
5 | namespace StbImageSharp.Decoding
6 | {
7 | #if !STBSHARP_INTERNAL
8 | public
9 | #else
10 | internal
11 | #endif
12 | class PsdDecoder : Decoder
13 | {
14 | private PsdDecoder(Stream stream) : base(stream)
15 | {
16 | }
17 |
18 | private int stbi__psd_decode_rle(FakePtr p, int pixelCount)
19 | {
20 | var count = 0;
21 | var nleft = 0;
22 | var len = 0;
23 | count = 0;
24 | while ((nleft = pixelCount - count) > 0)
25 | {
26 | len = stbi__get8();
27 | if (len == 128)
28 | {
29 | }
30 | else if (len < 128)
31 | {
32 | len++;
33 | if (len > nleft)
34 | return 0;
35 | count += len;
36 | while (len != 0)
37 | {
38 | p.Value = stbi__get8();
39 | p += 4;
40 | len--;
41 | }
42 | }
43 | else if (len > 128)
44 | {
45 | byte val = 0;
46 | len = 257 - len;
47 | if (len > nleft)
48 | return 0;
49 | val = stbi__get8();
50 | count += len;
51 | while (len != 0)
52 | {
53 | p.Value = val;
54 | p += 4;
55 | len--;
56 | }
57 | }
58 | }
59 |
60 | return 1;
61 | }
62 |
63 | private ImageResult InternalDecode(ColorComponents? requiredComponents, int bpc)
64 | {
65 | var pixelCount = 0;
66 | var channelCount = 0;
67 | var compression = 0;
68 | var channel = 0;
69 | var i = 0;
70 | var bitdepth = 0;
71 | var w = 0;
72 | var h = 0;
73 | byte[] _out_;
74 | if (stbi__get32be() != 0x38425053)
75 | stbi__err("not PSD");
76 | if (stbi__get16be() != 1)
77 | stbi__err("wrong version");
78 | stbi__skip(6);
79 | channelCount = stbi__get16be();
80 | if (channelCount < 0 || channelCount > 16)
81 | stbi__err("wrong channel count");
82 | h = (int)stbi__get32be();
83 | w = (int)stbi__get32be();
84 | bitdepth = stbi__get16be();
85 | if (bitdepth != 8 && bitdepth != 16)
86 | stbi__err("unsupported bit depth");
87 | if (stbi__get16be() != 3)
88 | stbi__err("wrong color format");
89 | stbi__skip((int)stbi__get32be());
90 | stbi__skip((int)stbi__get32be());
91 | stbi__skip((int)stbi__get32be());
92 | compression = stbi__get16be();
93 | if (compression > 1)
94 | stbi__err("bad compression");
95 |
96 | var bits_per_channel = 8;
97 | if (compression == 0 && bitdepth == 16 && bpc == 16)
98 | {
99 | _out_ = new byte[8 * w * h];
100 | bits_per_channel = 16;
101 | }
102 | else
103 | {
104 | _out_ = new byte[4 * w * h];
105 | }
106 |
107 | pixelCount = w * h;
108 |
109 | var ptr = new FakePtr(_out_);
110 | if (compression != 0)
111 | {
112 | stbi__skip(h * channelCount * 2);
113 | for (channel = 0; channel < 4; channel++)
114 | {
115 | FakePtr p;
116 | p = ptr + channel;
117 | if (channel >= channelCount)
118 | {
119 | for (i = 0; i < pixelCount; i++, p += 4) p.Set((byte)(channel == 3 ? 255 : 0));
120 | }
121 | else
122 | {
123 | if (stbi__psd_decode_rle(p, pixelCount) == 0) stbi__err("corrupt");
124 | }
125 | }
126 | }
127 | else
128 | {
129 | for (channel = 0; channel < 4; channel++)
130 | if (channel >= channelCount)
131 | {
132 | if (bitdepth == 16 && bpc == 16)
133 | throw new NotImplementedException();
134 | /* ushort* q = ((ushort*)(ptr)) + channel;
135 | ushort val = (ushort)((channel) == (3) ? 65535 : 0);
136 | for (i = (int)(0); (i) < (pixelCount); i++, q += 4)
137 | {
138 | *q = (ushort)(val);
139 | }*/
140 |
141 | var p = ptr + channel;
142 | var val = (byte)(channel == 3 ? 255 : 0);
143 | for (i = 0; i < pixelCount; i++, p += 4) p.Set(val);
144 | }
145 | else
146 | {
147 | if (bits_per_channel == 16)
148 | throw new NotImplementedException();
149 | /* ushort* q = ((ushort*)(ptr)) + channel;
150 | for (i = (int)(0); (i) < (pixelCount); i++, q += 4)
151 | {
152 | *q = ((ushort)(stbi__get16be()));
153 | }*/
154 |
155 | var p = ptr + channel;
156 | if (bitdepth == 16)
157 | for (i = 0; i < pixelCount; i++, p += 4)
158 | p.Set((byte)(stbi__get16be() >> 8));
159 | else
160 | for (i = 0; i < pixelCount; i++, p += 4)
161 | p.Set(stbi__get8());
162 | }
163 | }
164 |
165 | if (channelCount >= 4)
166 | {
167 | if (bits_per_channel == 16)
168 | throw new NotImplementedException();
169 | /* for (i = (int)(0); (i) < (w * h); ++i)
170 | {
171 | ushort* pixel = (ushort*)(ptr) + 4 * i;
172 | if ((pixel[3] != 0) && (pixel[3] != 65535))
173 | {
174 | float a = (float)(pixel[3] / 65535.0f);
175 | float ra = (float)(1.0f / a);
176 | float inv_a = (float)(65535.0f * (1 - ra));
177 | pixel[0] = ((ushort)(pixel[0] * ra + inv_a));
178 | pixel[1] = ((ushort)(pixel[1] * ra + inv_a));
179 | pixel[2] = ((ushort)(pixel[2] * ra + inv_a));
180 | }
181 | }*/
182 | for (i = 0; i < w * h; ++i)
183 | {
184 | var pixel = ptr + 4 * i;
185 | if (pixel[3] != 0 && pixel[3] != 255)
186 | {
187 | var a = pixel[3] / 255.0f;
188 | var ra = 1.0f / a;
189 | var inv_a = 255.0f * (1 - ra);
190 | pixel[0] = (byte)(pixel[0] * ra + inv_a);
191 | pixel[1] = (byte)(pixel[1] * ra + inv_a);
192 | pixel[2] = (byte)(pixel[2] * ra + inv_a);
193 | }
194 | }
195 | }
196 |
197 | var req_comp = requiredComponents.ToReqComp();
198 | if (req_comp != 0 && req_comp != 4)
199 | {
200 | if (bits_per_channel == 16)
201 | _out_ = Conversion.stbi__convert_format16(_out_, 4, req_comp, (uint)w, (uint)h);
202 | else
203 | _out_ = Conversion.stbi__convert_format(_out_, 4, req_comp, (uint)w, (uint)h);
204 | }
205 |
206 | return new ImageResult
207 | {
208 | Width = w,
209 | Height = h,
210 | SourceComponents = ColorComponents.RedGreenBlueAlpha,
211 | ColorComponents = requiredComponents != null
212 | ? requiredComponents.Value
213 | : ColorComponents.RedGreenBlueAlpha,
214 | BitsPerChannel = bits_per_channel,
215 | Data = _out_
216 | };
217 | }
218 |
219 | public static bool Test(Stream stream)
220 | {
221 | var r = stream.stbi__get32be() == 0x38425053;
222 | stream.Rewind();
223 |
224 | return r;
225 | }
226 |
227 | public static ImageInfo? Info(Stream stream)
228 | {
229 | try
230 | {
231 | if (stream.stbi__get32be() != 0x38425053) return null;
232 |
233 | if (stream.stbi__get16be() != 1) return null;
234 |
235 | stream.stbi__skip(6);
236 | var channelCount = stream.stbi__get16be();
237 | if (channelCount < 0 || channelCount > 16) return null;
238 |
239 | var height = (int)stream.stbi__get32be();
240 | var width = (int)stream.stbi__get32be();
241 | var depth = stream.stbi__get16be();
242 | if (depth != 8 && depth != 16) return null;
243 |
244 | if (stream.stbi__get16be() != 3) return null;
245 |
246 | return new ImageInfo
247 | {
248 | Width = width,
249 | Height = height,
250 | ColorComponents = ColorComponents.RedGreenBlueAlpha,
251 | BitsPerChannel = depth
252 | };
253 | }
254 | finally
255 | {
256 | stream.Rewind();
257 | }
258 | }
259 |
260 | public static ImageResult Decode(Stream stream, ColorComponents? requiredComponents = null, int bpc = 8)
261 | {
262 | var decoder = new PsdDecoder(stream);
263 | return decoder.InternalDecode(requiredComponents, bpc);
264 | }
265 | }
266 | }
--------------------------------------------------------------------------------
/tests/StbImageSharp.Testing/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using SixLabors.ImageSharp;
11 | using SixLabors.ImageSharp.Advanced;
12 | using SixLabors.ImageSharp.PixelFormats;
13 | using StbNative;
14 |
15 | namespace StbImageSharp.Testing
16 | {
17 | internal static class Program
18 | {
19 | private class LoadResult
20 | {
21 | public int Width;
22 | public int Height;
23 | public ColorComponents? Components;
24 | public byte[] Data;
25 | public int TimeInMs;
26 | }
27 |
28 | private class LoadingTimes
29 | {
30 | private readonly ConcurrentDictionary _byExtension = new ConcurrentDictionary();
31 | private readonly ConcurrentDictionary _byExtensionCount = new ConcurrentDictionary();
32 | private int _total, _totalCount;
33 |
34 | public void Add(string extension, int value)
35 | {
36 | if (!_byExtension.ContainsKey(extension))
37 | {
38 | _byExtension[extension] = 0;
39 | _byExtensionCount[extension] = 0;
40 | }
41 |
42 | _byExtension[extension] += value;
43 | ++_byExtensionCount[extension];
44 | _total += value;
45 | ++_totalCount;
46 | }
47 |
48 | public string BuildString()
49 | {
50 | var sb = new StringBuilder();
51 | foreach (var pair in _byExtension)
52 | {
53 | sb.AppendFormat("{0}: {1} ms, ", pair.Key, pair.Value);
54 | }
55 |
56 | sb.AppendFormat("Total: {0} ms", _total);
57 |
58 | return sb.ToString();
59 | }
60 |
61 | public string BuildStringCount()
62 | {
63 | var sb = new StringBuilder();
64 | foreach (var pair in _byExtensionCount)
65 | {
66 | sb.AppendFormat("{0}: {1}, ", pair.Key, pair.Value);
67 | }
68 |
69 | sb.AppendFormat("Total: {0}", _totalCount);
70 |
71 | return sb.ToString();
72 | }
73 | }
74 |
75 | private const int LoadTries = 10;
76 | private static int tasksStarted;
77 | private static int filesProcessed, filesMatches;
78 | private static LoadingTimes stbImageSharpTotal = new LoadingTimes();
79 | private static LoadingTimes stbNativeTotal = new LoadingTimes();
80 | private static LoadingTimes imageSharpTotal = new LoadingTimes();
81 |
82 | public static void Log(string message)
83 | {
84 | Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " -- " + message);
85 | }
86 |
87 | public static void Log(string format, params object[] args)
88 | {
89 | Log(string.Format(format, args));
90 | }
91 |
92 | private static void BeginWatch(Stopwatch sw)
93 | {
94 | sw.Restart();
95 | }
96 |
97 | private static int EndWatch(Stopwatch sw)
98 | {
99 | sw.Stop();
100 | return (int)sw.ElapsedMilliseconds;
101 | }
102 |
103 | private static LoadResult ParseTest(string name, LoadDelegate load)
104 | {
105 | var sw = new Stopwatch();
106 |
107 | Log("With " + name);
108 | int x = 0, y = 0;
109 | ColorComponents? comp = null;
110 | var parsed = new byte[0];
111 | BeginWatch(sw);
112 |
113 | for (var i = 0; i < LoadTries; ++i)
114 | parsed = load(out x, out y, out comp);
115 |
116 | Log("x: {0}, y: {1}, comp: {2}, size: {3}", x, y, comp != null ? comp.Value.ToString() : "default", parsed.Length);
117 | var passed = EndWatch(sw) / LoadTries;
118 | Log("Span: {0} ms", passed);
119 |
120 | return new LoadResult
121 | {
122 | Width = x,
123 | Height = y,
124 | Components = comp,
125 | Data = parsed,
126 | TimeInMs = passed
127 | };
128 | }
129 |
130 | public static bool RunTests(string imagesPath)
131 | {
132 | var files = Directory.EnumerateFiles(imagesPath, "*.*", SearchOption.AllDirectories).ToArray();
133 |
134 | Log("Files count: {0}", files.Length);
135 |
136 | foreach (var file in files)
137 | {
138 | Task.Factory.StartNew(() => { ThreadProc(file); });
139 | Interlocked.Increment(ref tasksStarted);
140 | }
141 |
142 | while (true)
143 | {
144 | Thread.Sleep(1000);
145 |
146 | if (tasksStarted == 0)
147 | break;
148 | }
149 |
150 | return true;
151 | }
152 |
153 | private static void ThreadProc(string f)
154 | {
155 | if (!f.EndsWith(".bmp") && !f.EndsWith(".jpg") && !f.EndsWith(".png") &&
156 | !f.EndsWith(".jpg") && !f.EndsWith(".psd") && !f.EndsWith(".pic") &&
157 | !f.EndsWith(".tga"))
158 | {
159 | Interlocked.Decrement(ref tasksStarted);
160 | return;
161 | }
162 |
163 | bool match = false;
164 | try
165 | {
166 | Log(string.Empty);
167 | Log("{0}: Loading {1} into memory", DateTime.Now.ToLongTimeString(), f);
168 | var data = File.ReadAllBytes(f);
169 | var extension = Path.GetExtension(f).ToLower();
170 | if (extension.StartsWith("."))
171 | {
172 | extension = extension.Substring(1);
173 | }
174 |
175 | Log("----------------------------");
176 |
177 | var stbImageSharpResult = ParseTest(
178 | "StbImageSharp",
179 | (out int x, out int y, out ColorComponents? ccomp) =>
180 | {
181 | var img = ImageResult.FromMemory(data, ColorComponents.RedGreenBlueAlpha);
182 |
183 | x = img.Width;
184 | y = img.Height;
185 | ccomp = img.SourceComponents;
186 |
187 | return img.Data;
188 | });
189 |
190 | var stbNativeResult = ParseTest(
191 | "Stb.Native",
192 | (out int x, out int y, out ColorComponents? ccomp) =>
193 | {
194 | var result = Native.load_from_memory(data, out x, out y, out var icomp,
195 | (int)ColorComponents.RedGreenBlueAlpha);
196 | ccomp = (ColorComponents)icomp;
197 | return result;
198 | });
199 |
200 |
201 | if (stbImageSharpResult.Width != stbNativeResult.Width)
202 | throw new Exception(string.Format("Inconsistent x: StbSharp={0}, Stb.Native={1}", stbImageSharpResult.Width, stbNativeResult.Width));
203 |
204 | if (stbImageSharpResult.Height != stbNativeResult.Height)
205 | throw new Exception(string.Format("Inconsistent y: StbSharp={0}, Stb.Native={1}", stbImageSharpResult.Height, stbNativeResult.Height));
206 |
207 | if (stbImageSharpResult.Components != stbNativeResult.Components)
208 | throw new Exception(string.Format("Inconsistent comp: StbSharp={0}, Stb.Native={1}", stbImageSharpResult.Components, stbNativeResult.Components));
209 |
210 | if (stbImageSharpResult.Data.Length != stbNativeResult.Data.Length)
211 | throw new Exception(string.Format("Inconsistent parsed length: StbSharp={0}, Stb.Native={1}",
212 | stbImageSharpResult.Data.Length,
213 | stbNativeResult.Data.Length));
214 |
215 | for (var i = 0; i < stbImageSharpResult.Data.Length; ++i)
216 | if (stbImageSharpResult.Data[i] != stbNativeResult.Data[i])
217 | throw new Exception(string.Format("Inconsistent data: index={0}, StbSharp={1}, Stb.Native={2}",
218 | i,
219 | (int)stbImageSharpResult.Data[i],
220 | (int)stbNativeResult.Data[i]));
221 |
222 | match = true;
223 |
224 | if (extension != "tga" && extension != "psd" && extension != "pic")
225 | {
226 | var imageSharpResult = ParseTest(
227 | "ImageSharp",
228 | (out int x, out int y, out ColorComponents? ccomp) =>
229 | {
230 | using (Image image = Image.Load(data))
231 | {
232 | x = image.Width;
233 | y = image.Height;
234 | ccomp = null;
235 |
236 | return MemoryMarshal.AsBytes(image.GetPixelSpan()).ToArray();
237 | }
238 | }
239 | );
240 | imageSharpTotal.Add(extension, imageSharpResult.TimeInMs);
241 | }
242 |
243 | stbImageSharpTotal.Add(extension, stbImageSharpResult.TimeInMs);
244 | stbNativeTotal.Add(extension, stbNativeResult.TimeInMs);
245 | }
246 | catch (Exception ex)
247 | {
248 | Log("Error: " + ex.Message);
249 | }
250 | finally
251 | {
252 | if (match)
253 | {
254 | Interlocked.Increment(ref filesMatches);
255 | }
256 |
257 | Interlocked.Increment(ref filesProcessed);
258 | Interlocked.Decrement(ref tasksStarted);
259 |
260 | Log("StbImageSharp - {0}", stbImageSharpTotal.BuildString());
261 | Log("Stb.Native - {0}", stbNativeTotal.BuildString());
262 | Log("ImageSharp - {0}", imageSharpTotal.BuildString());
263 | Log("Total files processed - {0}", stbImageSharpTotal.BuildStringCount());
264 | Log("StbImageSharp/Stb.Native matches/processed - {0}/{1}", filesMatches, filesProcessed);
265 | Log("Tasks left - {0}", tasksStarted);
266 | Log("GC Memory - {0}", GC.GetTotalMemory(true));
267 | }
268 | }
269 |
270 | public static int Main(string[] args)
271 | {
272 | try
273 | {
274 | if (args == null || args.Length < 1)
275 | {
276 | Console.WriteLine("Usage: StbImageSharp.Testing ");
277 | return 1;
278 | }
279 |
280 | var start = DateTime.Now;
281 |
282 | var res = RunTests(args[0]);
283 | var passed = DateTime.Now - start;
284 | Log("Span: {0} ms", passed.TotalMilliseconds);
285 | Log(DateTime.Now.ToLongTimeString() + " -- " + (res ? "Success" : "Failure"));
286 |
287 | return res ? 1 : 0;
288 | }
289 | catch (Exception ex)
290 | {
291 | Console.WriteLine(ex);
292 | return 0;
293 | }
294 | }
295 |
296 | private delegate void WriteDelegate(ImageResult image, Stream stream);
297 |
298 | private delegate byte[] LoadDelegate(out int x, out int y, out ColorComponents? comp);
299 | }
300 | }
--------------------------------------------------------------------------------
/src/Utility/Conversion.cs:
--------------------------------------------------------------------------------
1 | using StbImageSharp.Decoding;
2 | using StbImageSharp.Utility;
3 | using System;
4 |
5 | namespace StbImageSharp
6 | {
7 | internal static class Conversion
8 | {
9 | public static byte stbi__compute_y(int r, int g, int b)
10 | {
11 | return (byte)(((r * 77) + (g * 150) + (29 * b)) >> 8);
12 | }
13 |
14 | public static ushort stbi__compute_y_16(int r, int g, int b)
15 | {
16 | return (ushort)(((r * 77) + (g * 150) + (29 * b)) >> 8);
17 | }
18 |
19 | public static byte[] stbi__convert_format16(byte[] data, int img_n, int req_comp, uint x, uint y)
20 | {
21 | throw new NotImplementedException();
22 | /* int i = 0;
23 | int j = 0;
24 | if ((req_comp) == (img_n))
25 | return data;
26 |
27 | var good = new byte[req_comp * x * y * 2];
28 | FakePtr dataPtr = new FakePtr(data);
29 | FakePtr goodPtr = new FakePtr(good);
30 | for (j = (int)(0); (j) < ((int)(y)); ++j)
31 | {
32 | ushort* src = (ushort*)dataPtr + j * x * img_n;
33 | ushort* dest = (ushort*)goodPtr + j * x * req_comp;
34 | switch (((img_n) * 8 + (req_comp)))
35 | {
36 | case ((1) * 8 + (2)):
37 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 2)
38 | {
39 | dest[0] = (ushort)(src[0]);
40 | dest[1] = (ushort)(0xffff);
41 | }
42 | break;
43 | case ((1) * 8 + (3)):
44 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 3)
45 | {
46 | dest[0] = (ushort)(dest[1] = (ushort)(dest[2] = (ushort)(src[0])));
47 | }
48 | break;
49 | case ((1) * 8 + (4)):
50 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 4)
51 | {
52 | dest[0] = (ushort)(dest[1] = (ushort)(dest[2] = (ushort)(src[0])));
53 | dest[3] = (ushort)(0xffff);
54 | }
55 | break;
56 | case ((2) * 8 + (1)):
57 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 1)
58 | {
59 | dest[0] = (ushort)(src[0]);
60 | }
61 | break;
62 | case ((2) * 8 + (3)):
63 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 3)
64 | {
65 | dest[0] = (ushort)(dest[1] = (ushort)(dest[2] = (ushort)(src[0])));
66 | }
67 | break;
68 | case ((2) * 8 + (4)):
69 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 4)
70 | {
71 | dest[0] = (ushort)(dest[1] = (ushort)(dest[2] = (ushort)(src[0])));
72 | dest[3] = (ushort)(src[1]);
73 | }
74 | break;
75 | case ((3) * 8 + (4)):
76 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 4)
77 | {
78 | dest[0] = (ushort)(src[0]);
79 | dest[1] = (ushort)(src[1]);
80 | dest[2] = (ushort)(src[2]);
81 | dest[3] = (ushort)(0xffff);
82 | }
83 | break;
84 | case ((3) * 8 + (1)):
85 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 1)
86 | {
87 | dest[0] = (ushort)(stbi__compute_y_16((int)(src[0]), (int)(src[1]), (int)(src[2])));
88 | }
89 | break;
90 | case ((3) * 8 + (2)):
91 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 2)
92 | {
93 | dest[0] = (ushort)(stbi__compute_y_16((int)(src[0]), (int)(src[1]), (int)(src[2])));
94 | dest[1] = (ushort)(0xffff);
95 | }
96 | break;
97 | case ((4) * 8 + (1)):
98 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 1)
99 | {
100 | dest[0] = (ushort)(stbi__compute_y_16((int)(src[0]), (int)(src[1]), (int)(src[2])));
101 | }
102 | break;
103 | case ((4) * 8 + (2)):
104 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 2)
105 | {
106 | dest[0] = (ushort)(stbi__compute_y_16((int)(src[0]), (int)(src[1]), (int)(src[2])));
107 | dest[1] = (ushort)(src[3]);
108 | }
109 | break;
110 | case ((4) * 8 + (3)):
111 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 3)
112 | {
113 | dest[0] = (ushort)(src[0]);
114 | dest[1] = (ushort)(src[1]);
115 | dest[2] = (ushort)(src[2]);
116 | }
117 | break;
118 | default:
119 | Decoder.stbi__err("0");
120 | break;
121 | }
122 | }
123 |
124 | return good;*/
125 | }
126 |
127 | public static byte[] stbi__convert_format(byte[] data, int img_n, int req_comp, uint x, uint y)
128 | {
129 | int i = 0;
130 | int j = 0;
131 | if ((req_comp) == (img_n))
132 | return data;
133 |
134 | var good = new byte[req_comp * x * y];
135 | for (j = (int)(0); (j) < ((int)(y)); ++j)
136 | {
137 | FakePtr src = new FakePtr(data, (int)(j * x * img_n));
138 | FakePtr dest = new FakePtr(good, (int)(j * x * req_comp));
139 | switch (((img_n) * 8 + (req_comp)))
140 | {
141 | case ((1) * 8 + (2)):
142 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 2)
143 | {
144 | dest[0] = (byte)(src[0]);
145 | dest[1] = (byte)(255);
146 | }
147 | break;
148 | case ((1) * 8 + (3)):
149 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 3)
150 | {
151 | dest[0] = (byte)(dest[1] = (byte)(dest[2] = (byte)(src[0])));
152 | }
153 | break;
154 | case ((1) * 8 + (4)):
155 | for (i = (int)(x - 1); (i) >= (0); --i, src += 1, dest += 4)
156 | {
157 | dest[0] = (byte)(dest[1] = (byte)(dest[2] = (byte)(src[0])));
158 | dest[3] = (byte)(255);
159 | }
160 | break;
161 | case ((2) * 8 + (1)):
162 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 1)
163 | {
164 | dest[0] = (byte)(src[0]);
165 | }
166 | break;
167 | case ((2) * 8 + (3)):
168 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 3)
169 | {
170 | dest[0] = (byte)(dest[1] = (byte)(dest[2] = (byte)(src[0])));
171 | }
172 | break;
173 | case ((2) * 8 + (4)):
174 | for (i = (int)(x - 1); (i) >= (0); --i, src += 2, dest += 4)
175 | {
176 | dest[0] = (byte)(dest[1] = (byte)(dest[2] = (byte)(src[0])));
177 | dest[3] = (byte)(src[1]);
178 | }
179 | break;
180 | case ((3) * 8 + (4)):
181 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 4)
182 | {
183 | dest[0] = (byte)(src[0]);
184 | dest[1] = (byte)(src[1]);
185 | dest[2] = (byte)(src[2]);
186 | dest[3] = (byte)(255);
187 | }
188 | break;
189 | case ((3) * 8 + (1)):
190 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 1)
191 | {
192 | dest[0] = (byte)(stbi__compute_y((int)(src[0]), (int)(src[1]), (int)(src[2])));
193 | }
194 | break;
195 | case ((3) * 8 + (2)):
196 | for (i = (int)(x - 1); (i) >= (0); --i, src += 3, dest += 2)
197 | {
198 | dest[0] = (byte)(stbi__compute_y((int)(src[0]), (int)(src[1]), (int)(src[2])));
199 | dest[1] = (byte)(255);
200 | }
201 | break;
202 | case ((4) * 8 + (1)):
203 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 1)
204 | {
205 | dest[0] = (byte)(stbi__compute_y((int)(src[0]), (int)(src[1]), (int)(src[2])));
206 | }
207 | break;
208 | case ((4) * 8 + (2)):
209 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 2)
210 | {
211 | dest[0] = (byte)(stbi__compute_y((int)(src[0]), (int)(src[1]), (int)(src[2])));
212 | dest[1] = (byte)(src[3]);
213 | }
214 | break;
215 | case ((4) * 8 + (3)):
216 | for (i = (int)(x - 1); (i) >= (0); --i, src += 4, dest += 3)
217 | {
218 | dest[0] = (byte)(src[0]);
219 | dest[1] = (byte)(src[1]);
220 | dest[2] = (byte)(src[2]);
221 | }
222 | break;
223 | default:
224 | Decoder.stbi__err("0");
225 | break;
226 | }
227 | }
228 |
229 | return good;
230 | }
231 |
232 | public static byte[] stbi__convert_16_to_8(byte[] orig, int w, int h, int channels)
233 | {
234 | throw new NotImplementedException();
235 |
236 | /* int i = 0;
237 | int img_len = (int)(w * h * channels);
238 | var reduced = new byte[img_len];
239 |
240 | fixed (byte* ptr2 = &orig[0])
241 | {
242 | ushort* ptr = (ushort*)ptr2;
243 | for (i = (int)(0); (i) < (img_len); ++i)
244 | {
245 | reduced[i] = ((byte)((ptr[i] >> 8) & 0xFF));
246 | }
247 | }
248 | return reduced;*/
249 | }
250 |
251 | public static ushort[] stbi__convert_8_to_16(byte[] orig, int w, int h, int channels)
252 | {
253 | int i = 0;
254 | int img_len = (int)(w * h * channels);
255 | var enlarged = new ushort[img_len];
256 | for (i = (int)(0); (i) < (img_len); ++i)
257 | {
258 | enlarged[i] = ((ushort)((orig[i] << 8) + orig[i]));
259 | }
260 |
261 | return enlarged;
262 | }
263 |
264 | public static void stbi__vertical_flip(byte[] image, int w, int h, int bytes_per_pixel)
265 | {
266 | int row = 0;
267 | int bytes_per_row = w * bytes_per_pixel;
268 | byte[] temp = new byte[2048];
269 | for (row = (int)(0); (row) < (h >> 1); row++)
270 | {
271 | FakePtr row0 = new FakePtr(image, (int)(row * bytes_per_row));
272 | FakePtr row1 = new FakePtr(image, (int)((h - row - 1) * bytes_per_row));
273 | int bytes_left = bytes_per_row;
274 | while ((bytes_left) != 0)
275 | {
276 | int bytes_copy = (((bytes_left) < (2048)) ? bytes_left : 2048);
277 | temp.memcpy(row0, bytes_copy);
278 | row0.memcpy(row1, bytes_copy);
279 | row1.memcpy(temp, bytes_copy);
280 | row0 += bytes_copy;
281 | row1 += bytes_copy;
282 | bytes_left -= bytes_copy;
283 | }
284 | }
285 | }
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/src/Decoding/TgaDecoder.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using StbImageSharp.Utility;
3 |
4 | namespace StbImageSharp.Decoding
5 | {
6 | #if !STBSHARP_INTERNAL
7 | public
8 | #else
9 | internal
10 | #endif
11 | class TgaDecoder : Decoder
12 | {
13 | private TgaDecoder(Stream stream) : base(stream)
14 | {
15 | }
16 |
17 | private static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, out int is_rgb16)
18 | {
19 | is_rgb16 = 0;
20 | switch (bits_per_pixel)
21 | {
22 | case 8:
23 | return 1;
24 | case 15:
25 | case 16:
26 | if (bits_per_pixel == 16 && is_grey != 0)
27 | return 2;
28 | is_rgb16 = 1;
29 | return 3;
30 | case 24:
31 | case 32:
32 | return bits_per_pixel / 8;
33 | default:
34 | return 0;
35 | }
36 | }
37 |
38 | private void stbi__tga_read_rgb16(FakePtr _out_)
39 | {
40 | var px = (ushort)stbi__get16le();
41 | var fiveBitMask = (ushort)31;
42 | var r = (px >> 10) & fiveBitMask;
43 | var g = (px >> 5) & fiveBitMask;
44 | var b = px & fiveBitMask;
45 | _out_[0] = (byte)(r * 255 / 31);
46 | _out_[1] = (byte)(g * 255 / 31);
47 | _out_[2] = (byte)(b * 255 / 31);
48 | }
49 |
50 | private ImageResult InternalDecode(ColorComponents? requiredComponents)
51 | {
52 | var tga_offset = (int)stbi__get8();
53 | var tga_indexed = (int)stbi__get8();
54 | var tga_image_type = (int)stbi__get8();
55 | var tga_is_RLE = 0;
56 | var tga_palette_start = stbi__get16le();
57 | var tga_palette_len = stbi__get16le();
58 | var tga_palette_bits = (int)stbi__get8();
59 | var tga_x_origin = stbi__get16le();
60 | var tga_y_origin = stbi__get16le();
61 | var tga_width = stbi__get16le();
62 | var tga_height = stbi__get16le();
63 | var tga_bits_per_pixel = (int)stbi__get8();
64 | var tga_comp = 0;
65 | var tga_rgb16 = 0;
66 | var tga_inverted = (int)stbi__get8();
67 | byte[] tga_data;
68 | byte[] tga_palette = null;
69 | var i = 0;
70 | var j = 0;
71 | var raw_data = new byte[4];
72 | raw_data[0] = 0;
73 |
74 | var RLE_count = 0;
75 | var RLE_repeating = 0;
76 | var read_next_pixel = 1;
77 | if (tga_image_type >= 8)
78 | {
79 | tga_image_type -= 8;
80 | tga_is_RLE = 1;
81 | }
82 |
83 | tga_inverted = 1 - ((tga_inverted >> 5) & 1);
84 | if (tga_indexed != 0)
85 | tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, out tga_rgb16);
86 | else
87 | tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, tga_image_type == 3 ? 1 : 0, out tga_rgb16);
88 | if (tga_comp == 0)
89 | stbi__err("bad format");
90 |
91 | tga_data = new byte[tga_width * tga_height * tga_comp];
92 | stbi__skip(tga_offset);
93 | if (tga_indexed == 0 && tga_is_RLE == 0 && tga_rgb16 == 0)
94 | {
95 | for (i = 0; i < tga_height; ++i)
96 | {
97 | var row = tga_inverted != 0 ? tga_height - i - 1 : i;
98 | stbi__getn(tga_data, row * tga_width * tga_comp, tga_width * tga_comp);
99 | }
100 | }
101 | else
102 | {
103 | if (tga_indexed != 0)
104 | {
105 | stbi__skip(tga_palette_start);
106 | tga_palette = new byte[tga_palette_len * tga_comp];
107 | if (tga_rgb16 != 0)
108 | {
109 | var pal_entry = new FakePtr(tga_palette);
110 | for (i = 0; i < tga_palette_len; ++i)
111 | {
112 | stbi__tga_read_rgb16(pal_entry);
113 | pal_entry += tga_comp;
114 | }
115 | }
116 | else if (!stbi__getn(tga_palette, 0, tga_palette_len * tga_comp))
117 | {
118 | stbi__err("bad palette");
119 | }
120 | }
121 |
122 | for (i = 0; i < tga_width * tga_height; ++i)
123 | {
124 | if (tga_is_RLE != 0)
125 | {
126 | if (RLE_count == 0)
127 | {
128 | var RLE_cmd = (int)stbi__get8();
129 | RLE_count = 1 + (RLE_cmd & 127);
130 | RLE_repeating = RLE_cmd >> 7;
131 | read_next_pixel = 1;
132 | }
133 | else if (RLE_repeating == 0)
134 | {
135 | read_next_pixel = 1;
136 | }
137 | }
138 | else
139 | {
140 | read_next_pixel = 1;
141 | }
142 |
143 | if (read_next_pixel != 0)
144 | {
145 | if (tga_indexed != 0)
146 | {
147 | var pal_idx = tga_bits_per_pixel == 8 ? stbi__get8() : stbi__get16le();
148 | if (pal_idx >= tga_palette_len) pal_idx = 0;
149 | pal_idx *= tga_comp;
150 | for (j = 0; j < tga_comp; ++j) raw_data[j] = tga_palette[pal_idx + j];
151 | }
152 | else if (tga_rgb16 != 0)
153 | {
154 | stbi__tga_read_rgb16(new FakePtr(raw_data));
155 | }
156 | else
157 | {
158 | for (j = 0; j < tga_comp; ++j) raw_data[j] = stbi__get8();
159 | }
160 |
161 | read_next_pixel = 0;
162 | }
163 |
164 | for (j = 0; j < tga_comp; ++j) tga_data[i * tga_comp + j] = raw_data[j];
165 | --RLE_count;
166 | }
167 |
168 | if (tga_inverted != 0)
169 | for (j = 0; j * 2 < tga_height; ++j)
170 | {
171 | var index1 = j * tga_width * tga_comp;
172 | var index2 = (tga_height - 1 - j) * tga_width * tga_comp;
173 | for (i = tga_width * tga_comp; i > 0; --i)
174 | {
175 | var temp = tga_data[index1];
176 | tga_data[index1] = tga_data[index2];
177 | tga_data[index2] = temp;
178 | ++index1;
179 | ++index2;
180 | }
181 | }
182 | }
183 |
184 | if (tga_comp >= 3 && tga_rgb16 == 0)
185 | {
186 | var tga_pixel = new FakePtr(tga_data);
187 | for (i = 0; i < tga_width * tga_height; ++i)
188 | {
189 | var temp = tga_pixel[0];
190 | tga_pixel[0] = tga_pixel[2];
191 | tga_pixel[2] = temp;
192 | tga_pixel += tga_comp;
193 | }
194 | }
195 |
196 | var req_comp = requiredComponents.ToReqComp();
197 | if (req_comp != 0 && req_comp != tga_comp)
198 | tga_data = Conversion.stbi__convert_format(tga_data, tga_comp, req_comp, (uint)tga_width,
199 | (uint)tga_height);
200 | tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0;
201 |
202 | return new ImageResult
203 | {
204 | Width = tga_width,
205 | Height = tga_height,
206 | SourceComponents = (ColorComponents)tga_comp,
207 | ColorComponents = requiredComponents != null ? requiredComponents.Value : (ColorComponents)tga_comp,
208 | BitsPerChannel = 8,
209 | Data = tga_data
210 | };
211 | }
212 |
213 | public static bool Test(Stream stream)
214 | {
215 | try
216 | {
217 | stream.stbi__get8();
218 | var tga_color_type = (int)stream.stbi__get8();
219 | if (tga_color_type > 1)
220 | return false;
221 | var sz = (int)stream.stbi__get8();
222 | if (tga_color_type == 1)
223 | {
224 | if (sz != 1 && sz != 9)
225 | return false;
226 | stream.stbi__skip(4);
227 | sz = stream.stbi__get8();
228 | if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
229 | return false;
230 | stream.stbi__skip(4);
231 | }
232 | else
233 | {
234 | if (sz != 2 && sz != 3 && sz != 10 && sz != 11)
235 | return false;
236 | stream.stbi__skip(9);
237 | }
238 |
239 | if (stream.stbi__get16le() < 1)
240 | return false;
241 | if (stream.stbi__get16le() < 1)
242 | return false;
243 | sz = stream.stbi__get8();
244 | if (tga_color_type == 1 && sz != 8 && sz != 16)
245 | return false;
246 | if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
247 | return false;
248 |
249 | return true;
250 | }
251 | finally
252 | {
253 | stream.Rewind();
254 | }
255 | }
256 |
257 | public static ImageInfo? Info(Stream stream)
258 | {
259 | try
260 | {
261 | var tga_w = 0;
262 | var tga_h = 0;
263 | var tga_comp = 0;
264 | var tga_image_type = 0;
265 | var tga_bits_per_pixel = 0;
266 | var tga_colormap_bpp = 0;
267 | var sz = 0;
268 | var tga_colormap_type = 0;
269 | stream.stbi__get8();
270 | tga_colormap_type = stream.stbi__get8();
271 | if (tga_colormap_type > 1) return null;
272 |
273 | tga_image_type = stream.stbi__get8();
274 | if (tga_colormap_type == 1)
275 | {
276 | if (tga_image_type != 1 && tga_image_type != 9) return null;
277 | stream.stbi__skip(4);
278 | sz = stream.stbi__get8();
279 | if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32) return null;
280 | stream.stbi__skip(4);
281 | tga_colormap_bpp = sz;
282 | }
283 | else
284 | {
285 | if (tga_image_type != 2 && tga_image_type != 3 && tga_image_type != 10 && tga_image_type != 11)
286 | return null;
287 | stream.stbi__skip(9);
288 | tga_colormap_bpp = 0;
289 | }
290 |
291 | tga_w = stream.stbi__get16le();
292 | if (tga_w < 1) return null;
293 |
294 | tga_h = stream.stbi__get16le();
295 | if (tga_h < 1) return null;
296 |
297 | tga_bits_per_pixel = stream.stbi__get8();
298 | stream.stbi__get8();
299 | int is_rgb16;
300 | if (tga_colormap_bpp != 0)
301 | {
302 | if (tga_bits_per_pixel != 8 && tga_bits_per_pixel != 16) return null;
303 | tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, out is_rgb16);
304 | }
305 | else
306 | {
307 | tga_comp = stbi__tga_get_comp(tga_bits_per_pixel,
308 | tga_image_type == 3 || tga_image_type == 11 ? 1 : 0, out is_rgb16);
309 | }
310 |
311 | if (tga_comp == 0) return null;
312 |
313 | return new ImageInfo
314 | {
315 | Width = tga_w,
316 | Height = tga_h,
317 | ColorComponents = (ColorComponents)tga_comp,
318 | BitsPerChannel = tga_bits_per_pixel
319 | };
320 | }
321 | finally
322 | {
323 | stream.Rewind();
324 | }
325 | }
326 |
327 | public static ImageResult Decode(Stream stream, ColorComponents? requiredComponents = null)
328 | {
329 | var decoder = new TgaDecoder(stream);
330 | return decoder.InternalDecode(requiredComponents);
331 | }
332 | }
333 | }
--------------------------------------------------------------------------------
/src/Decoding/BmpDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using StbImageSharp.Utility;
5 |
6 | namespace StbImageSharp.Decoding
7 | {
8 | #if !STBSHARP_INTERNAL
9 | public
10 | #else
11 | internal
12 | #endif
13 | class BmpDecoder : Decoder
14 | {
15 | [StructLayout(LayoutKind.Sequential)]
16 | public struct stbi__bmp_data
17 | {
18 | public int bpp;
19 | public int offset;
20 | public int hsz;
21 | public uint mr;
22 | public uint mg;
23 | public uint mb;
24 | public uint ma;
25 | public uint all_a;
26 | }
27 |
28 | private static readonly uint[] mul_table = { 0, 0xff, 0x55, 0x49, 0x11, 0x21, 0x41, 0x81, 0x01 };
29 | private static readonly uint[] shift_table = { 0, 0, 0, 1, 0, 2, 4, 6, 0 };
30 |
31 | private BmpDecoder(Stream stream) : base(stream)
32 | {
33 | }
34 |
35 | private static int stbi__high_bit(uint z)
36 | {
37 | var n = 0;
38 | if (z == 0)
39 | return -1;
40 | if (z >= 0x10000)
41 | {
42 | n += 16;
43 | z >>= 16;
44 | }
45 |
46 | if (z >= 0x00100)
47 | {
48 | n += 8;
49 | z >>= 8;
50 | }
51 |
52 | if (z >= 0x00010)
53 | {
54 | n += 4;
55 | z >>= 4;
56 | }
57 |
58 | if (z >= 0x00004)
59 | {
60 | n += 2;
61 | z >>= 2;
62 | }
63 |
64 | if (z >= 0x00002)
65 | {
66 | n += 1;
67 | z >>= 1;
68 | }
69 |
70 | return n;
71 | }
72 |
73 | private static int stbi__bitcount(uint a)
74 | {
75 | a = (a & 0x55555555) + ((a >> 1) & 0x55555555);
76 | a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
77 | a = (a + (a >> 4)) & 0x0f0f0f0f;
78 | a = a + (a >> 8);
79 | a = a + (a >> 16);
80 | return (int)(a & 0xff);
81 | }
82 |
83 | private static int stbi__shiftsigned(uint v, int shift, int bits)
84 | {
85 | if (shift < 0)
86 | v <<= -shift;
87 | else
88 | v >>= shift;
89 | v >>= 8 - bits;
90 | return (int)(v * (int)mul_table[bits]) >> (int)shift_table[bits];
91 | }
92 |
93 | private void stbi__bmp_parse_header(ref stbi__bmp_data info)
94 | {
95 | var hsz = 0;
96 | if (stbi__get8() != 'B' || stbi__get8() != 'M')
97 | stbi__err("not BMP");
98 | stbi__get32le();
99 | stbi__get16le();
100 | stbi__get16le();
101 | info.offset = (int)stbi__get32le();
102 | info.hsz = hsz = (int)stbi__get32le();
103 | info.mr = info.mg = info.mb = info.ma = 0;
104 | if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
105 | stbi__err("unknown BMP");
106 | if (hsz == 12)
107 | {
108 | img_x = stbi__get16le();
109 | img_y = stbi__get16le();
110 | }
111 | else
112 | {
113 | img_x = (int)stbi__get32le();
114 | img_y = (int)stbi__get32le();
115 | }
116 |
117 | if (stbi__get16le() != 1)
118 | stbi__err("bad BMP");
119 | info.bpp = stbi__get16le();
120 | if (hsz != 12)
121 | {
122 | var compress = (int)stbi__get32le();
123 | if (compress == 1 || compress == 2)
124 | stbi__err("BMP RLE");
125 | stbi__get32le();
126 | stbi__get32le();
127 | stbi__get32le();
128 | stbi__get32le();
129 | stbi__get32le();
130 | if (hsz == 40 || hsz == 56)
131 | {
132 | if (hsz == 56)
133 | {
134 | stbi__get32le();
135 | stbi__get32le();
136 | stbi__get32le();
137 | stbi__get32le();
138 | }
139 |
140 | if (info.bpp == 16 || info.bpp == 32)
141 | {
142 | if (compress == 0)
143 | {
144 | if (info.bpp == 32)
145 | {
146 | info.mr = 0xffu << 16;
147 | info.mg = 0xffu << 8;
148 | info.mb = 0xffu << 0;
149 | info.ma = 0xffu << 24;
150 | info.all_a = 0;
151 | }
152 | else
153 | {
154 | info.mr = 31u << 10;
155 | info.mg = 31u << 5;
156 | info.mb = 31u << 0;
157 | }
158 | }
159 | else if (compress == 3)
160 | {
161 | info.mr = stbi__get32le();
162 | info.mg = stbi__get32le();
163 | info.mb = stbi__get32le();
164 | if (info.mr == info.mg && info.mg == info.mb) stbi__err("bad BMP");
165 | }
166 | else
167 | {
168 | stbi__err("bad BMP");
169 | }
170 | }
171 | }
172 | else
173 | {
174 | var i = 0;
175 | if (hsz != 108 && hsz != 124)
176 | stbi__err("bad BMP");
177 | info.mr = stbi__get32le();
178 | info.mg = stbi__get32le();
179 | info.mb = stbi__get32le();
180 | info.ma = stbi__get32le();
181 | stbi__get32le();
182 | for (i = 0; i < 12; ++i) stbi__get32le();
183 | if (hsz == 124)
184 | {
185 | stbi__get32le();
186 | stbi__get32le();
187 | stbi__get32le();
188 | stbi__get32le();
189 | }
190 | }
191 | }
192 | }
193 |
194 | private ImageResult InternalDecode(ColorComponents? requiredComponents)
195 | {
196 | byte[] _out_;
197 | var mr = (uint)0;
198 | var mg = (uint)0;
199 | var mb = (uint)0;
200 | var ma = (uint)0;
201 | uint all_a = 0;
202 | var pal = new byte[256 * 4];
203 | var psize = 0;
204 | var i = 0;
205 | var j = 0;
206 | var width = 0;
207 | var flip_vertically = 0;
208 | var pad = 0;
209 | var target = 0;
210 | var info = new stbi__bmp_data();
211 | info.all_a = 255;
212 | stbi__bmp_parse_header(ref info);
213 | flip_vertically = img_y > 0 ? 1 : 0;
214 | img_y = Math.Abs(img_y);
215 | mr = info.mr;
216 | mg = info.mg;
217 | mb = info.mb;
218 | ma = info.ma;
219 | all_a = info.all_a;
220 | if (info.hsz == 12)
221 | {
222 | if (info.bpp < 24)
223 | psize = (info.offset - 14 - 24) / 3;
224 | }
225 | else
226 | {
227 | if (info.bpp < 16)
228 | psize = (info.offset - 14 - info.hsz) >> 2;
229 | }
230 |
231 | img_n = ma != 0 ? 4 : 3;
232 | if (requiredComponents != null && (int)requiredComponents.Value >= 3)
233 | target = (int)requiredComponents.Value;
234 | else
235 | target = img_n;
236 | _out_ = new byte[target * img_x * img_y];
237 | if (info.bpp < 16)
238 | {
239 | var z = 0;
240 | if (psize == 0 || psize > 256) stbi__err("invalid");
241 | for (i = 0; i < psize; ++i)
242 | {
243 | pal[i * 4 + 2] = stbi__get8();
244 | pal[i * 4 + 1] = stbi__get8();
245 | pal[i * 4 + 0] = stbi__get8();
246 | if (info.hsz != 12)
247 | stbi__get8();
248 | pal[i * 4 + 3] = 255;
249 | }
250 |
251 | stbi__skip(info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
252 | if (info.bpp == 1)
253 | width = (img_x + 7) >> 3;
254 | else if (info.bpp == 4)
255 | width = (img_x + 1) >> 1;
256 | else if (info.bpp == 8)
257 | width = img_x;
258 | else
259 | stbi__err("bad bpp");
260 | pad = -width & 3;
261 | if (info.bpp == 1)
262 | for (j = 0; j < img_y; ++j)
263 | {
264 | var bit_offset = 7;
265 | var v = (int)stbi__get8();
266 | for (i = 0; i < img_x; ++i)
267 | {
268 | var color = (v >> bit_offset) & 0x1;
269 | _out_[z++] = pal[color * 4 + 0];
270 | _out_[z++] = pal[color * 4 + 1];
271 | _out_[z++] = pal[color * 4 + 2];
272 | if (target == 4)
273 | _out_[z++] = 255;
274 | if (i + 1 == img_x)
275 | break;
276 | if (--bit_offset < 0)
277 | {
278 | bit_offset = 7;
279 | v = stbi__get8();
280 | }
281 | }
282 |
283 | stbi__skip(pad);
284 | }
285 | else
286 | for (j = 0; j < img_y; ++j)
287 | {
288 | for (i = 0; i < img_x; i += 2)
289 | {
290 | var v = (int)stbi__get8();
291 | var v2 = 0;
292 | if (info.bpp == 4)
293 | {
294 | v2 = v & 15;
295 | v >>= 4;
296 | }
297 |
298 | _out_[z++] = pal[v * 4 + 0];
299 | _out_[z++] = pal[v * 4 + 1];
300 | _out_[z++] = pal[v * 4 + 2];
301 | if (target == 4)
302 | _out_[z++] = 255;
303 | if (i + 1 == img_x)
304 | break;
305 | v = info.bpp == 8 ? stbi__get8() : v2;
306 | _out_[z++] = pal[v * 4 + 0];
307 | _out_[z++] = pal[v * 4 + 1];
308 | _out_[z++] = pal[v * 4 + 2];
309 | if (target == 4)
310 | _out_[z++] = 255;
311 | }
312 |
313 | stbi__skip(pad);
314 | }
315 | }
316 | else
317 | {
318 | var rshift = 0;
319 | var gshift = 0;
320 | var bshift = 0;
321 | var ashift = 0;
322 | var rcount = 0;
323 | var gcount = 0;
324 | var bcount = 0;
325 | var acount = 0;
326 | var z = 0;
327 | var easy = 0;
328 | stbi__skip(info.offset - 14 - info.hsz);
329 | if (info.bpp == 24)
330 | width = 3 * img_x;
331 | else if (info.bpp == 16)
332 | width = 2 * img_x;
333 | else
334 | width = 0;
335 | pad = -width & 3;
336 | if (info.bpp == 24)
337 | easy = 1;
338 | else if (info.bpp == 32)
339 | if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
340 | easy = 2;
341 | if (easy == 0)
342 | {
343 | if (mr == 0 || mg == 0 || mb == 0) stbi__err("bad masks");
344 | rshift = stbi__high_bit(mr) - 7;
345 | rcount = stbi__bitcount(mr);
346 | gshift = stbi__high_bit(mg) - 7;
347 | gcount = stbi__bitcount(mg);
348 | bshift = stbi__high_bit(mb) - 7;
349 | bcount = stbi__bitcount(mb);
350 | ashift = stbi__high_bit(ma) - 7;
351 | acount = stbi__bitcount(ma);
352 | }
353 |
354 | for (j = 0; j < img_y; ++j)
355 | {
356 | if (easy != 0)
357 | {
358 | for (i = 0; i < img_x; ++i)
359 | {
360 | byte a = 0;
361 | _out_[z + 2] = stbi__get8();
362 | _out_[z + 1] = stbi__get8();
363 | _out_[z + 0] = stbi__get8();
364 | z += 3;
365 | a = (byte)(easy == 2 ? stbi__get8() : 255);
366 | all_a |= a;
367 | if (target == 4)
368 | _out_[z++] = a;
369 | }
370 | }
371 | else
372 | {
373 | var bpp = info.bpp;
374 | for (i = 0; i < img_x; ++i)
375 | {
376 | var v = bpp == 16 ? (uint)stbi__get16le() : stbi__get32le();
377 | uint a = 0;
378 | _out_[z++] = (byte)(stbi__shiftsigned(v & mr, rshift, rcount) & 255);
379 | _out_[z++] = (byte)(stbi__shiftsigned(v & mg, gshift, gcount) & 255);
380 | _out_[z++] = (byte)(stbi__shiftsigned(v & mb, bshift, bcount) & 255);
381 | a = (uint)(ma != 0 ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
382 | all_a |= a;
383 | if (target == 4)
384 | _out_[z++] = (byte)(a & 255);
385 | }
386 | }
387 |
388 | stbi__skip(pad);
389 | }
390 | }
391 |
392 | if (target == 4 && all_a == 0)
393 | for (i = 4 * img_x * img_y - 1; i >= 0; i -= 4)
394 | _out_[i] = 255;
395 | if (flip_vertically != 0)
396 | {
397 | byte t = 0;
398 | var ptr = new FakePtr(_out_);
399 | for (j = 0; j < img_y >> 1; ++j)
400 | {
401 | var p1 = ptr + j * img_x * target;
402 | var p2 = ptr + (img_y - 1 - j) * img_x * target;
403 | for (i = 0; i < img_x * target; ++i)
404 | {
405 | t = p1[i];
406 | p1[i] = p2[i];
407 | p2[i] = t;
408 | }
409 | }
410 | }
411 |
412 | if (requiredComponents != null && (int)requiredComponents.Value != target)
413 | _out_ = Conversion.stbi__convert_format(_out_, target, (int)requiredComponents.Value, (uint)img_x,
414 | (uint)img_y);
415 |
416 | return new ImageResult
417 | {
418 | Width = img_x,
419 | Height = img_y,
420 | SourceComponents = (ColorComponents)img_n,
421 | ColorComponents = requiredComponents != null ? requiredComponents.Value : (ColorComponents)img_n,
422 | BitsPerChannel = 8,
423 | Data = _out_
424 | };
425 | }
426 |
427 | private static bool TestInternal(Stream stream)
428 | {
429 | var sz = 0;
430 | if (stream.ReadByte() != 'B')
431 | return false;
432 | if (stream.ReadByte() != 'M')
433 | return false;
434 |
435 | stream.stbi__get32le();
436 | stream.stbi__get16le();
437 | stream.stbi__get16le();
438 | stream.stbi__get32le();
439 | sz = (int)stream.stbi__get32le();
440 | var r = sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124;
441 | return r;
442 | }
443 |
444 | public static bool Test(Stream stream)
445 | {
446 | var r = TestInternal(stream);
447 | stream.Rewind();
448 | return r;
449 | }
450 |
451 | public static ImageInfo? Info(Stream stream)
452 | {
453 | var info = new stbi__bmp_data
454 | {
455 | all_a = 255
456 | };
457 |
458 | var decoder = new BmpDecoder(stream);
459 | try
460 | {
461 | decoder.stbi__bmp_parse_header(ref info);
462 | }
463 | catch (Exception)
464 | {
465 | return null;
466 | }
467 | finally
468 | {
469 | stream.Rewind();
470 | }
471 |
472 | return new ImageInfo
473 | {
474 | Width = decoder.img_x,
475 | Height = decoder.img_y,
476 | ColorComponents = info.ma != 0 ? ColorComponents.RedGreenBlueAlpha : ColorComponents.RedGreenBlue,
477 | BitsPerChannel = 8
478 | };
479 | }
480 |
481 | public static ImageResult Decode(Stream stream, ColorComponents? requiredComponents = null)
482 | {
483 | var decoder = new BmpDecoder(stream);
484 | return decoder.InternalDecode(requiredComponents);
485 | }
486 | }
487 | }
--------------------------------------------------------------------------------
/src/Decoding/ZLib.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using StbImageSharp.Utility;
3 |
4 | namespace StbImageSharp.Decoding
5 | {
6 | internal class ZLib
7 | {
8 | private class stbi__zhuffman
9 | {
10 | public readonly ushort[] fast = new ushort[1 << 9];
11 | public readonly ushort[] firstcode = new ushort[16];
12 | public readonly ushort[] firstsymbol = new ushort[16];
13 | public readonly int[] maxcode = new int[17];
14 | public readonly byte[] size = new byte[288];
15 | public readonly ushort[] value = new ushort[288];
16 | }
17 |
18 | private static readonly int[] stbi__zlength_base =
19 | {
20 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195,
21 | 227, 258, 0, 0
22 | };
23 |
24 | private static readonly int[] stbi__zlength_extra =
25 | {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0};
26 |
27 | private static readonly int[] stbi__zdist_base =
28 | {
29 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097,
30 | 6145, 8193, 12289, 16385, 24577, 0, 0
31 | };
32 |
33 | private static readonly int[] stbi__zdist_extra =
34 | {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
35 |
36 | private static readonly byte[] stbi__zdefault_length =
37 | {
38 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
39 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
40 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
41 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
42 | 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
43 | 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
44 | 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
45 | 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8
46 | };
47 |
48 | private static readonly byte[] stbi__zdefault_distance =
49 | {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
50 |
51 | private static readonly byte[] length_dezigzag =
52 | {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
53 |
54 | private uint code_buffer;
55 | private int num_bits;
56 | private readonly stbi__zhuffman z_distance = new stbi__zhuffman();
57 | private int z_expandable;
58 | private readonly stbi__zhuffman z_length = new stbi__zhuffman();
59 |
60 | private FakePtr zbuffer;
61 | private FakePtr zbuffer_end;
62 | private FakePtr zout;
63 | private FakePtr zout_end;
64 | private byte[] zout_start;
65 |
66 | private byte stbi__zget8()
67 | {
68 | if (zbuffer.Offset >= zbuffer_end.Offset)
69 | return 0;
70 | return zbuffer.GetAndIncrease();
71 | }
72 |
73 | private void stbi__fill_bits()
74 | {
75 | do
76 | {
77 | code_buffer |= (uint)stbi__zget8() << num_bits;
78 | num_bits += 8;
79 | } while (num_bits <= 24);
80 | }
81 |
82 | private uint stbi__zreceive(int n)
83 | {
84 | uint k = 0;
85 | if (num_bits < n)
86 | stbi__fill_bits();
87 | k = (uint)(code_buffer & ((1 << n) - 1));
88 | code_buffer >>= n;
89 | num_bits -= n;
90 | return k;
91 | }
92 |
93 | private int stbi__zhuffman_decode_slowpath(stbi__zhuffman z)
94 | {
95 | var b = 0;
96 | var s = 0;
97 | var k = 0;
98 | k = MathExtensions.stbi__bit_reverse((int)code_buffer, 16);
99 | for (s = 9 + 1; ; ++s)
100 | if (k < z.maxcode[s])
101 | break;
102 | if (s == 16)
103 | return -1;
104 | b = (k >> (16 - s)) - z.firstcode[s] + z.firstsymbol[s];
105 | code_buffer >>= s;
106 | num_bits -= s;
107 | return z.value[b];
108 | }
109 |
110 | private int stbi__zhuffman_decode(stbi__zhuffman z)
111 | {
112 | var b = 0;
113 | var s = 0;
114 | if (num_bits < 16)
115 | stbi__fill_bits();
116 | b = z.fast[code_buffer & ((1 << 9) - 1)];
117 | if (b != 0)
118 | {
119 | s = b >> 9;
120 | code_buffer >>= s;
121 | num_bits -= s;
122 | return b & 511;
123 | }
124 |
125 | return stbi__zhuffman_decode_slowpath(z);
126 | }
127 |
128 | private int stbi__zexpand(FakePtr zout, int n)
129 | {
130 | var cur = 0;
131 | var limit = 0;
132 | var old_limit = 0;
133 | this.zout = zout;
134 | if (z_expandable == 0)
135 | Decoder.stbi__err("output buffer limit");
136 | cur = this.zout.Offset;
137 | limit = old_limit = zout_end.Offset;
138 | while (cur + n > limit) limit *= 2;
139 |
140 | Array.Resize(ref zout_start, limit);
141 | this.zout = new FakePtr(zout_start, cur);
142 | zout_end = new FakePtr(zout_start, limit);
143 | return 1;
144 | }
145 |
146 | private int stbi__parse_huffman_block()
147 | {
148 | var zout = this.zout;
149 | for (; ; )
150 | {
151 | var z = stbi__zhuffman_decode(z_length);
152 | if (z < 256)
153 | {
154 | if (z < 0)
155 | Decoder.stbi__err("bad huffman code");
156 | if (zout.Offset >= zout_end.Offset)
157 | {
158 | if (stbi__zexpand(zout, 1) == 0)
159 | return 0;
160 | zout = this.zout;
161 | }
162 |
163 | zout.SetAndIncrease((byte)z);
164 | }
165 | else
166 | {
167 | var len = 0;
168 | var dist = 0;
169 | if (z == 256)
170 | {
171 | this.zout = zout;
172 | return 1;
173 | }
174 |
175 | z -= 257;
176 | len = stbi__zlength_base[z];
177 | if (stbi__zlength_extra[z] != 0)
178 | len += (int)stbi__zreceive(stbi__zlength_extra[z]);
179 | z = stbi__zhuffman_decode(z_distance);
180 | if (z < 0)
181 | Decoder.stbi__err("bad huffman code");
182 | dist = stbi__zdist_base[z];
183 | if (stbi__zdist_extra[z] != 0)
184 | dist += (int)stbi__zreceive(stbi__zdist_extra[z]);
185 | if (zout.Offset < dist)
186 | Decoder.stbi__err("bad dist");
187 | if (zout.Offset + len > zout_end.Offset)
188 | {
189 | if (stbi__zexpand(zout, len) == 0)
190 | return 0;
191 | zout = this.zout;
192 | }
193 |
194 | var p = new FakePtr(zout, -dist);
195 | if (dist == 1)
196 | {
197 | var v = p.Value;
198 | if (len > 0)
199 | {
200 | zout.memset(v, len);
201 | zout += len;
202 | }
203 | }
204 | else
205 | {
206 | if (len != 0)
207 | do
208 | {
209 | zout.SetAndIncrease(p.GetAndIncrease());
210 | } while (--len != 0);
211 | }
212 | }
213 | }
214 | }
215 |
216 | private static int stbi__zbuild_huffman(stbi__zhuffman z, FakePtr sizelist, int num)
217 | {
218 | var i = 0;
219 | var k = 0;
220 | var code = 0;
221 | var next_code = new int[16];
222 | var sizes = new int[17];
223 | sizes.Clear();
224 | z.fast.Clear();
225 | for (i = 0; i < num; ++i) ++sizes[sizelist[i]];
226 | sizes[0] = 0;
227 | for (i = 1; i < 16; ++i)
228 | if (sizes[i] > 1 << i)
229 | Decoder.stbi__err("bad sizes");
230 | code = 0;
231 | for (i = 1; i < 16; ++i)
232 | {
233 | next_code[i] = code;
234 | z.firstcode[i] = (ushort)code;
235 | z.firstsymbol[i] = (ushort)k;
236 | code = code + sizes[i];
237 | if (sizes[i] != 0)
238 | if (code - 1 >= 1 << i)
239 | Decoder.stbi__err("bad codelengths");
240 | z.maxcode[i] = code << (16 - i);
241 | code <<= 1;
242 | k += sizes[i];
243 | }
244 |
245 | z.maxcode[16] = 0x10000;
246 | for (i = 0; i < num; ++i)
247 | {
248 | var s = (int)sizelist[i];
249 | if (s != 0)
250 | {
251 | var c = next_code[s] - z.firstcode[s] + z.firstsymbol[s];
252 | var fastv = (ushort)((s << 9) | i);
253 | z.size[c] = (byte)s;
254 | z.value[c] = (ushort)i;
255 | if (s <= 9)
256 | {
257 | var j = MathExtensions.stbi__bit_reverse(next_code[s], s);
258 | while (j < 1 << 9)
259 | {
260 | z.fast[j] = fastv;
261 | j += 1 << s;
262 | }
263 | }
264 |
265 | ++next_code[s];
266 | }
267 | }
268 |
269 | return 1;
270 | }
271 |
272 | private int stbi__compute_huffman_codes()
273 | {
274 | var z_codelength = new stbi__zhuffman();
275 | var lencodes = new byte[286 + 32 + 137];
276 | var codelength_sizes = new byte[19];
277 | var i = 0;
278 | var n = 0;
279 | var hlit = (int)(stbi__zreceive(5) + 257);
280 | var hdist = (int)(stbi__zreceive(5) + 1);
281 | var hclen = (int)(stbi__zreceive(4) + 4);
282 | var ntot = hlit + hdist;
283 | codelength_sizes.Clear();
284 | for (i = 0; i < hclen; ++i)
285 | {
286 | var s = (int)stbi__zreceive(3);
287 | codelength_sizes[length_dezigzag[i]] = (byte)s;
288 | }
289 |
290 | if (stbi__zbuild_huffman(z_codelength, new FakePtr(codelength_sizes), 19) == 0)
291 | return 0;
292 | n = 0;
293 | while (n < ntot)
294 | {
295 | var c = stbi__zhuffman_decode(z_codelength);
296 | if (c < 0 || c >= 19)
297 | Decoder.stbi__err("bad codelengths");
298 | if (c < 16)
299 | {
300 | lencodes[n++] = (byte)c;
301 | }
302 | else
303 | {
304 | var fill = (byte)0;
305 | if (c == 16)
306 | {
307 | c = (int)(stbi__zreceive(2) + 3);
308 | if (n == 0)
309 | Decoder.stbi__err("bad codelengths");
310 | fill = lencodes[n - 1];
311 | }
312 | else if (c == 17)
313 | {
314 | c = (int)(stbi__zreceive(3) + 3);
315 | }
316 | else
317 | {
318 | c = (int)(stbi__zreceive(7) + 11);
319 | }
320 |
321 | if (ntot - n < c)
322 | Decoder.stbi__err("bad codelengths");
323 | lencodes.Set(n, c, fill);
324 | n += c;
325 | }
326 | }
327 |
328 | if (n != ntot)
329 | Decoder.stbi__err("bad codelengths");
330 | if (stbi__zbuild_huffman(z_length, new FakePtr(lencodes), hlit) == 0)
331 | return 0;
332 | if (stbi__zbuild_huffman(z_distance, new FakePtr(lencodes, hlit), hdist) == 0)
333 | return 0;
334 | return 1;
335 | }
336 |
337 | private int stbi__parse_uncompressed_block()
338 | {
339 | var header = new byte[4];
340 | var len = 0;
341 | var nlen = 0;
342 | var k = 0;
343 | if ((num_bits & 7) != 0)
344 | stbi__zreceive(num_bits & 7);
345 | k = 0;
346 | while (num_bits > 0)
347 | {
348 | header[k++] = (byte)(code_buffer & 255);
349 | code_buffer >>= 8;
350 | num_bits -= 8;
351 | }
352 |
353 | while (k < 4) header[k++] = stbi__zget8();
354 | len = header[1] * 256 + header[0];
355 | nlen = header[3] * 256 + header[2];
356 | if (nlen != (len ^ 0xffff))
357 | Decoder.stbi__err("zlib corrupt");
358 | if (zbuffer.Offset + len > zbuffer_end.Offset)
359 | Decoder.stbi__err("read past buffer");
360 | if (zout.Offset + len > zout_end.Offset)
361 | if (stbi__zexpand(zout, len) == 0)
362 | return 0;
363 | for (var i = 0; i < len; i++) zout[i] = zbuffer[i];
364 | zbuffer += len;
365 | zout += len;
366 | return 1;
367 | }
368 |
369 | private int stbi__parse_zlib_header()
370 | {
371 | var cmf = (int)stbi__zget8();
372 | var cm = cmf & 15;
373 | var flg = (int)stbi__zget8();
374 | if ((cmf * 256 + flg) % 31 != 0)
375 | Decoder.stbi__err("bad zlib header");
376 | if ((flg & 32) != 0)
377 | Decoder.stbi__err("no preset dict");
378 | if (cm != 8)
379 | Decoder.stbi__err("bad compression");
380 | return 1;
381 | }
382 |
383 | private int stbi__parse_zlib(int parse_header)
384 | {
385 | var final = 0;
386 | var type = 0;
387 | if (parse_header != 0)
388 | if (stbi__parse_zlib_header() == 0)
389 | return 0;
390 | num_bits = 0;
391 | code_buffer = 0;
392 | do
393 | {
394 | final = (int)stbi__zreceive(1);
395 | type = (int)stbi__zreceive(2);
396 | if (type == 0)
397 | {
398 | if (stbi__parse_uncompressed_block() == 0)
399 | return 0;
400 | }
401 | else if (type == 3)
402 | {
403 | return 0;
404 | }
405 | else
406 | {
407 | if (type == 1)
408 | {
409 | if (stbi__zbuild_huffman(z_length, new FakePtr(stbi__zdefault_length), 288) == 0)
410 | return 0;
411 | if (stbi__zbuild_huffman(z_distance, new FakePtr(stbi__zdefault_distance), 32) == 0)
412 | return 0;
413 | }
414 | else
415 | {
416 | if (stbi__compute_huffman_codes() == 0)
417 | return 0;
418 | }
419 |
420 | if (stbi__parse_huffman_block() == 0)
421 | return 0;
422 | }
423 | } while (final == 0);
424 |
425 | return 1;
426 | }
427 |
428 | private int stbi__do_zlib(byte[] obuf, int olen, int exp, int parse_header)
429 | {
430 | zout_start = obuf;
431 | zout = new FakePtr(obuf);
432 | zout_end = new FakePtr(obuf, olen);
433 | z_expandable = exp;
434 | return stbi__parse_zlib(parse_header);
435 | }
436 |
437 | public static byte[] stbi_zlib_decode_malloc_guesssize_headerflag(byte[] buffer, int len, int initial_size,
438 | out int outlen, int parse_header)
439 | {
440 | outlen = 0;
441 | var a = new ZLib();
442 | var p = new byte[initial_size];
443 | a.zbuffer = new FakePtr(buffer);
444 | a.zbuffer_end = new FakePtr(buffer, +len);
445 | if (a.stbi__do_zlib(p, initial_size, 1, parse_header) != 0)
446 | {
447 | outlen = a.zout.Offset;
448 | return a.zout_start;
449 | }
450 |
451 | return null;
452 | }
453 | }
454 | }
--------------------------------------------------------------------------------
/src/Decoding/GifDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using StbImageSharp.Utility;
5 |
6 | namespace StbImageSharp.Decoding
7 | {
8 | #if !STBSHARP_INTERNAL
9 | public
10 | #else
11 | internal
12 | #endif
13 | class GifDecoder : Decoder
14 | {
15 | [StructLayout(LayoutKind.Sequential)]
16 | private struct stbi__gif_lzw
17 | {
18 | public short prefix;
19 | public byte first;
20 | public byte suffix;
21 | }
22 |
23 | private int w;
24 | private int h;
25 | private byte[] _out_;
26 | private byte[] background;
27 | private byte[] history;
28 | private int flags;
29 | private int bgindex;
30 | private int ratio;
31 | private int transparent;
32 | private int eflags;
33 | private int delay;
34 | private readonly byte[] pal;
35 | private readonly byte[] lpal;
36 | private readonly stbi__gif_lzw[] codes = new stbi__gif_lzw[8192];
37 | private byte[] color_table;
38 | private int parse;
39 | private int step;
40 | private int lflags;
41 | private int start_x;
42 | private int start_y;
43 | private int max_x;
44 | private int max_y;
45 | private int cur_x;
46 | private int cur_y;
47 | private int line_size;
48 |
49 | private GifDecoder(Stream stream) : base(stream)
50 | {
51 | pal = new byte[256 * 4];
52 | lpal = new byte[256 * 4];
53 | }
54 |
55 | private void stbi__gif_parse_colortable(byte[] pal, int num_entries, int transp)
56 | {
57 | int i;
58 | for (i = 0; i < num_entries; ++i)
59 | {
60 | pal[i * 4 + 2] = stbi__get8();
61 | pal[i * 4 + 1] = stbi__get8();
62 | pal[i * 4] = stbi__get8();
63 | pal[i * 4 + 3] = (byte)(transp == i ? 0 : 255);
64 | }
65 | }
66 |
67 | private int stbi__gif_header(out int comp, int is_info)
68 | {
69 | byte version = 0;
70 | if (stbi__get8() != 'G' || stbi__get8() != 'I' || stbi__get8() != 'F' || stbi__get8() != '8')
71 | stbi__err("not GIF");
72 | version = stbi__get8();
73 | if (version != '7' && version != '9')
74 | stbi__err("not GIF");
75 | if (stbi__get8() != 'a')
76 | stbi__err("not GIF");
77 | w = stbi__get16le();
78 | h = stbi__get16le();
79 | flags = stbi__get8();
80 | bgindex = stbi__get8();
81 | ratio = stbi__get8();
82 | transparent = -1;
83 |
84 | comp = 4;
85 | if (is_info != 0)
86 | return 1;
87 | if ((flags & 0x80) != 0)
88 | stbi__gif_parse_colortable(pal, 2 << (flags & 7), -1);
89 | return 1;
90 | }
91 |
92 | private void stbi__out_gif_code(ushort code)
93 | {
94 | var idx = 0;
95 | if (codes[code].prefix >= 0)
96 | stbi__out_gif_code((ushort)codes[code].prefix);
97 | if (cur_y >= max_y)
98 | return;
99 | idx = cur_x + cur_y;
100 | history[idx / 4] = 1;
101 | var c = new FakePtr(color_table, codes[code].suffix * 4);
102 | if (c[3] > 128)
103 | {
104 | var p = new FakePtr(_out_, idx);
105 | p[0] = c[2];
106 | p[1] = c[1];
107 | p[2] = c[0];
108 | p[3] = c[3];
109 | }
110 |
111 | cur_x += 4;
112 | if (cur_x >= max_x)
113 | {
114 | cur_x = start_x;
115 | cur_y += step;
116 | while (cur_y >= max_y && parse > 0)
117 | {
118 | step = (1 << parse) * line_size;
119 | cur_y = start_y + (step >> 1);
120 | --parse;
121 | }
122 | }
123 | }
124 |
125 | private byte[] stbi__process_gif_raster()
126 | {
127 | byte lzw_cs = 0;
128 | var len = 0;
129 | var init_code = 0;
130 | uint first = 0;
131 | var codesize = 0;
132 | var codemask = 0;
133 | var avail = 0;
134 | var oldcode = 0;
135 | var bits = 0;
136 | var valid_bits = 0;
137 | var clear = 0;
138 | lzw_cs = stbi__get8();
139 | if (lzw_cs > 12)
140 | return null;
141 | clear = 1 << lzw_cs;
142 | first = 1;
143 | codesize = lzw_cs + 1;
144 | codemask = (1 << codesize) - 1;
145 | bits = 0;
146 | valid_bits = 0;
147 | for (init_code = 0; init_code < clear; init_code++)
148 | {
149 | codes[init_code].prefix = -1;
150 | codes[init_code].first = (byte)init_code;
151 | codes[init_code].suffix = (byte)init_code;
152 | }
153 |
154 | avail = clear + 2;
155 | oldcode = -1;
156 | len = 0;
157 | for (; ; )
158 | if (valid_bits < codesize)
159 | {
160 | if (len == 0)
161 | {
162 | len = stbi__get8();
163 | if (len == 0)
164 | return _out_;
165 | }
166 |
167 | --len;
168 | bits |= stbi__get8() << valid_bits;
169 | valid_bits += 8;
170 | }
171 | else
172 | {
173 | var code = bits & codemask;
174 | bits >>= codesize;
175 | valid_bits -= codesize;
176 | if (code == clear)
177 | {
178 | codesize = lzw_cs + 1;
179 | codemask = (1 << codesize) - 1;
180 | avail = clear + 2;
181 | oldcode = -1;
182 | first = 0;
183 | }
184 | else if (code == clear + 1)
185 | {
186 | stbi__skip(len);
187 | while ((len = stbi__get8()) > 0) stbi__skip(len);
188 | return _out_;
189 | }
190 | else if (code <= avail)
191 | {
192 | if (first != 0) stbi__err("no clear code");
193 | if (oldcode >= 0)
194 | {
195 | var idx = avail++;
196 | if (avail > 8192) stbi__err("too many codes");
197 | codes[idx].prefix = (short)oldcode;
198 | codes[idx].first = codes[oldcode].first;
199 | codes[idx].suffix = code == avail ? codes[idx].first : codes[code].first;
200 | }
201 | else if (code == avail)
202 | {
203 | stbi__err("illegal code in raster");
204 | }
205 |
206 | stbi__out_gif_code((ushort)code);
207 | if ((avail & codemask) == 0 && avail <= 0x0FFF)
208 | {
209 | codesize++;
210 | codemask = (1 << codesize) - 1;
211 | }
212 |
213 | oldcode = code;
214 | }
215 | else
216 | {
217 | stbi__err("illegal code in raster");
218 | }
219 | }
220 | }
221 |
222 | private byte[] stbi__gif_load_next(out int comp, FakePtr? two_back)
223 | {
224 | comp = 0;
225 |
226 | var dispose = 0;
227 | var first_frame = 0;
228 | var pi = 0;
229 | var pcount = 0;
230 | first_frame = 0;
231 | if (_out_ == null)
232 | {
233 | if (stbi__gif_header(out comp, 0) == 0)
234 | return null;
235 | pcount = w * h;
236 | _out_ = new byte[4 * pcount];
237 | Array.Clear(_out_, 0, _out_.Length);
238 | background = new byte[4 * pcount];
239 | Array.Clear(background, 0, background.Length);
240 | history = new byte[pcount];
241 | Array.Clear(history, 0, history.Length);
242 | first_frame = 1;
243 | }
244 | else
245 | {
246 | var ptr = new FakePtr(_out_);
247 | dispose = (eflags & 0x1C) >> 2;
248 | pcount = w * h;
249 | if (dispose == 3 && two_back == null) dispose = 2;
250 | if (dispose == 3)
251 | {
252 | for (pi = 0; pi < pcount; ++pi)
253 | if (history[pi] != 0)
254 | new FakePtr(ptr, pi * 4).memcpy(new FakePtr(two_back.Value, pi * 4), 4);
255 | }
256 | else if (dispose == 2)
257 | {
258 | for (pi = 0; pi < pcount; ++pi)
259 | if (history[pi] != 0)
260 | new FakePtr(ptr, pi * 4).memcpy(new FakePtr(background, pi * 4), 4);
261 | }
262 |
263 | new FakePtr(background).memcpy(ptr, 4 * w * h);
264 | }
265 |
266 | Array.Clear(history, 0, w * h);
267 | for (; ; )
268 | {
269 | var tag = (int)stbi__get8();
270 | switch (tag)
271 | {
272 | case 0x2C:
273 | {
274 | var x = 0;
275 | var y = 0;
276 | var w = 0;
277 | var h = 0;
278 | byte[] o;
279 | x = stbi__get16le();
280 | y = stbi__get16le();
281 | w = stbi__get16le();
282 | h = stbi__get16le();
283 | if (x + w > w || y + h > h)
284 | stbi__err("bad Image Descriptor");
285 | line_size = w * 4;
286 | start_x = x * 4;
287 | start_y = y * line_size;
288 | max_x = start_x + w * 4;
289 | max_y = start_y + h * line_size;
290 | cur_x = start_x;
291 | cur_y = start_y;
292 | if (w == 0)
293 | cur_y = max_y;
294 | lflags = stbi__get8();
295 | if ((lflags & 0x40) != 0)
296 | {
297 | step = 8 * line_size;
298 | parse = 3;
299 | }
300 | else
301 | {
302 | step = line_size;
303 | parse = 0;
304 | }
305 |
306 | if ((lflags & 0x80) != 0)
307 | {
308 | stbi__gif_parse_colortable(lpal, 2 << (lflags & 7),
309 | (eflags & 0x01) != 0 ? transparent : -1);
310 | color_table = lpal;
311 | }
312 | else if ((flags & 0x80) != 0)
313 | {
314 | color_table = pal;
315 | }
316 | else
317 | {
318 | stbi__err("missing color table");
319 | }
320 |
321 | o = stbi__process_gif_raster();
322 | if (o == null)
323 | return null;
324 | pcount = w * h;
325 | if (first_frame != 0 && bgindex > 0)
326 | for (pi = 0; pi < pcount; ++pi)
327 | if (history[pi] == 0)
328 | {
329 | pal[bgindex * 4 + 3] = 255;
330 | new FakePtr(_out_, pi * 4).memcpy(new FakePtr(pal, bgindex), 4);
331 | }
332 |
333 | return o;
334 | }
335 | case 0x21:
336 | {
337 | var len = 0;
338 | var ext = (int)stbi__get8();
339 | if (ext == 0xF9)
340 | {
341 | len = stbi__get8();
342 | if (len == 4)
343 | {
344 | eflags = stbi__get8();
345 | delay = 10 * stbi__get16le();
346 | if (transparent >= 0) pal[transparent * 4 + 3] = 255;
347 | if ((eflags & 0x01) != 0)
348 | {
349 | transparent = stbi__get8();
350 | if (transparent >= 0) pal[transparent * 4 + 3] = 0;
351 | }
352 | else
353 | {
354 | stbi__skip(1);
355 | transparent = -1;
356 | }
357 | }
358 | else
359 | {
360 | stbi__skip(len);
361 | break;
362 | }
363 | }
364 |
365 | while ((len = stbi__get8()) != 0) stbi__skip(len);
366 | break;
367 | }
368 | case 0x3B:
369 | return null;
370 | default:
371 | stbi__err("unknown code");
372 | break;
373 | }
374 | }
375 | }
376 |
377 | /* private void* stbi__load_gif_main(int** delays, int* x, int* y, int* z, int* comp, int req_comp)
378 | {
379 | if ((IsGif(Stream)))
380 | {
381 | int layers = (int)(0);
382 | byte* u = null;
383 | byte* _out_ = null;
384 | byte* two_back = null;
385 | int stride = 0;
386 | if ((delays) != null)
387 | {
388 | *delays = null;
389 | }
390 | do
391 | {
392 | u = stbi__gif_load_next(comp, (int)(req_comp), two_back);
393 | if ((u) != null)
394 | {
395 | *x = (int)(w);
396 | *y = (int)(h);
397 | ++layers;
398 | stride = (int)(w * h * 4);
399 | if ((_out_) != null)
400 | {
401 | _out_ = (byte*)(CRuntime.realloc(_out_, (ulong)(layers * stride)));
402 | if ((delays) != null)
403 | {
404 | *delays = (int*)(CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers)));
405 | }
406 | }
407 | else
408 | {
409 | _out_ = (byte*)(Utility.stbi__malloc((ulong)(layers * stride)));
410 | if ((delays) != null)
411 | {
412 | *delays = (int*)(Utility.stbi__malloc((ulong)(layers * sizeof(int))));
413 | }
414 | }
415 | CRuntime.memcpy(_out_ + ((layers - 1) * stride), u, (ulong)(stride));
416 | if ((layers) >= (2))
417 | {
418 | two_back = _out_ - 2 * stride;
419 | }
420 | if ((delays) != null)
421 | {
422 | (*delays)[layers - 1U] = (int)(delay);
423 | }
424 | }
425 | }
426 | while (u != null);
427 | CRuntime.free(_out_);
428 | CRuntime.free(history);
429 | CRuntime.free(background);
430 | if (((req_comp) != 0) && (req_comp != 4))
431 | _out_ = stbi__convert_format(_out_, (int)(4), (int)(req_comp), (uint)(layers * w), (uint)(h));
432 | *z = (int)(layers);
433 | return _out_;
434 | }
435 | else
436 | {
437 | stbi__err("not GIF");
438 | }
439 |
440 | }*/
441 |
442 | private ImageResult InternalDecode(ColorComponents? requiredComponents)
443 | {
444 | int comp;
445 | var u = stbi__gif_load_next(out comp, null);
446 | if (u == null) throw new Exception("could not decode gif");
447 |
448 | if (requiredComponents != null && requiredComponents.Value != ColorComponents.RedGreenBlueAlpha)
449 | u = Conversion.stbi__convert_format(u, 4, (int)requiredComponents.Value, (uint)w, (uint)h);
450 |
451 | return new ImageResult
452 | {
453 | Width = w,
454 | Height = h,
455 | SourceComponents = (ColorComponents)comp,
456 | ColorComponents = requiredComponents != null ? requiredComponents.Value : (ColorComponents)comp,
457 | BitsPerChannel = 8,
458 | Data = u
459 | };
460 | }
461 |
462 | private static bool InternalTest(Stream stream)
463 | {
464 | var sz = 0;
465 | if (stream.stbi__get8() != 'G' || stream.stbi__get8() != 'I' || stream.stbi__get8() != 'F' ||
466 | stream.stbi__get8() != '8')
467 | return false;
468 | sz = stream.stbi__get8();
469 | if (sz != '9' && sz != '7')
470 | return false;
471 | if (stream.stbi__get8() != 'a')
472 | return false;
473 | return true;
474 | }
475 |
476 | public static bool Test(Stream stream)
477 | {
478 | var result = InternalTest(stream);
479 | stream.Rewind();
480 | return result;
481 | }
482 |
483 | public static ImageInfo? Info(Stream stream)
484 | {
485 | var decoder = new GifDecoder(stream);
486 |
487 | int comp;
488 | var r = decoder.stbi__gif_header(out comp, 1);
489 | stream.Rewind();
490 | if (r == 0) return null;
491 |
492 | return new ImageInfo
493 | {
494 | Width = decoder.w,
495 | Height = decoder.h,
496 | ColorComponents = (ColorComponents)comp,
497 | BitsPerChannel = 8
498 | };
499 | }
500 |
501 | public static ImageResult Decode(Stream stream, ColorComponents? requiredComponents = null)
502 | {
503 | var decoder = new GifDecoder(stream);
504 | return decoder.InternalDecode(requiredComponents);
505 | }
506 | }
507 | }
--------------------------------------------------------------------------------
/src/Decoding/PngDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using StbImageSharp.Utility;
5 |
6 | namespace StbImageSharp.Decoding
7 | {
8 | #if !STBSHARP_INTERNAL
9 | public
10 | #else
11 | internal
12 | #endif
13 | class PngDecoder : Decoder
14 | {
15 | [StructLayout(LayoutKind.Sequential)]
16 | public struct stbi__pngchunk
17 | {
18 | public uint length;
19 | public uint type;
20 | }
21 |
22 | private const int STBI__F_none = 0;
23 | private const int STBI__F_sub = 1;
24 | private const int STBI__F_up = 2;
25 | private const int STBI__F_avg = 3;
26 | private const int STBI__F_paeth = 4;
27 | private const int STBI__F_avg_first = 5;
28 | private const int STBI__F_paeth_first = 6;
29 |
30 | private static readonly byte[] first_row_filter =
31 | {STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_paeth_first};
32 |
33 | private static readonly byte[] stbi__depth_scale_table = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
34 | private static readonly byte[] png_sig = { 137, 80, 78, 71, 13, 10, 26, 10 };
35 |
36 | protected int img_out_n;
37 |
38 | private int stbi__unpremultiply_on_load;
39 |
40 | private int stbi__de_iphone_flag;
41 |
42 | private byte[] idata;
43 | private byte[] expanded;
44 | private byte[] _out_;
45 | private int depth;
46 |
47 | private PngDecoder(Stream stream) : base(stream)
48 | {
49 | }
50 |
51 | private stbi__pngchunk stbi__get_chunk_header()
52 | {
53 | var c = new stbi__pngchunk();
54 | c.length = stbi__get32be();
55 | c.type = stbi__get32be();
56 | return c;
57 | }
58 |
59 | private static bool stbi__check_png_header(Stream input)
60 | {
61 | var i = 0;
62 | for (i = 0; i < 8; ++i)
63 | if (input.ReadByte() != png_sig[i])
64 | return false;
65 |
66 | return true;
67 | }
68 |
69 | private static int stbi__paeth(int a, int b, int c)
70 | {
71 | var p = a + b - c;
72 | var pa = Math.Abs(p - a);
73 | var pb = Math.Abs(p - b);
74 | var pc = Math.Abs(p - c);
75 | if (pa <= pb && pa <= pc)
76 | return a;
77 | if (pb <= pc)
78 | return b;
79 | return c;
80 | }
81 |
82 | private int stbi__create_png_image_raw(FakePtr raw, uint raw_len, int out_n, uint x, uint y, int depth,
83 | int color)
84 | {
85 | var bytes = depth == 16 ? 2 : 1;
86 | uint i = 0;
87 | uint j = 0;
88 | var stride = (uint)(x * out_n * bytes);
89 | uint img_len = 0;
90 | uint img_width_bytes = 0;
91 | var k = 0;
92 | var output_bytes = out_n * bytes;
93 | var filter_bytes = img_n * bytes;
94 | var width = (int)x;
95 | _out_ = new byte[x * y * output_bytes];
96 | img_width_bytes = (uint)((img_n * x * depth + 7) >> 3);
97 | img_len = (img_width_bytes + 1) * y;
98 | if (raw_len < img_len)
99 | stbi__err("not enough pixels");
100 | var ptr = new FakePtr(_out_);
101 | for (j = (uint)0; j < y; ++j)
102 | {
103 | var cur = ptr + stride * j;
104 | FakePtr prior;
105 | var filter = (int)raw.Value;
106 | raw++;
107 | if (filter > 4)
108 | stbi__err("invalid filter");
109 | if (depth < 8)
110 | {
111 | cur += x * out_n - img_width_bytes;
112 | filter_bytes = 1;
113 | width = (int)img_width_bytes;
114 | }
115 |
116 | prior = cur - stride;
117 | if (j == 0)
118 | filter = first_row_filter[filter];
119 | for (k = 0; k < filter_bytes; ++k)
120 | switch (filter)
121 | {
122 | case STBI__F_none:
123 | cur[k] = raw[k];
124 | break;
125 | case STBI__F_sub:
126 | cur[k] = raw[k];
127 | break;
128 | case STBI__F_up:
129 | cur[k] = (byte)((raw[k] + prior[k]) & 255);
130 | break;
131 | case STBI__F_avg:
132 | cur[k] = (byte)((raw[k] + (prior[k] >> 1)) & 255);
133 | break;
134 | case STBI__F_paeth:
135 | cur[k] = (byte)((raw[k] + stbi__paeth(0, prior[k], 0)) & 255);
136 | break;
137 | case STBI__F_avg_first:
138 | cur[k] = raw[k];
139 | break;
140 | case STBI__F_paeth_first:
141 | cur[k] = raw[k];
142 | break;
143 | }
144 |
145 | if (depth == 8)
146 | {
147 | if (img_n != out_n)
148 | cur[img_n] = 255;
149 | raw += img_n;
150 | cur += out_n;
151 | prior += out_n;
152 | }
153 | else if (depth == 16)
154 | {
155 | if (img_n != out_n)
156 | {
157 | cur[filter_bytes] = 255;
158 | cur[filter_bytes + 1] = 255;
159 | }
160 |
161 | raw += filter_bytes;
162 | cur += output_bytes;
163 | prior += output_bytes;
164 | }
165 | else
166 | {
167 | raw += 1;
168 | cur += 1;
169 | prior += 1;
170 | }
171 |
172 | if (depth < 8 || img_n == out_n)
173 | {
174 | var nk = (width - 1) * filter_bytes;
175 | switch (filter)
176 | {
177 | case STBI__F_none:
178 | cur.memcpy(raw, nk);
179 | break;
180 | case STBI__F_sub:
181 | for (k = 0; k < nk; ++k) cur[k] = (byte)((raw[k] + cur[k - filter_bytes]) & 255);
182 | break;
183 | case STBI__F_up:
184 | for (k = 0; k < nk; ++k) cur[k] = (byte)((raw[k] + prior[k]) & 255);
185 | break;
186 | case STBI__F_avg:
187 | for (k = 0; k < nk; ++k)
188 | cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)) & 255);
189 | break;
190 | case STBI__F_paeth:
191 | for (k = 0; k < nk; ++k)
192 | cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k],
193 | prior[k - filter_bytes])) & 255);
194 | break;
195 | case STBI__F_avg_first:
196 | for (k = 0; k < nk; ++k) cur[k] = (byte)((raw[k] + (cur[k - filter_bytes] >> 1)) & 255);
197 | break;
198 | case STBI__F_paeth_first:
199 | for (k = 0; k < nk; ++k)
200 | cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)) & 255);
201 | break;
202 | }
203 |
204 | raw += nk;
205 | }
206 | else
207 | {
208 | switch (filter)
209 | {
210 | case STBI__F_none:
211 | for (i = x - 1;
212 | i >= 1;
213 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
214 | output_bytes)
215 | for (k = 0; k < filter_bytes; ++k)
216 | cur[k] = raw[k];
217 | break;
218 | case STBI__F_sub:
219 | for (i = x - 1;
220 | i >= 1;
221 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
222 | output_bytes)
223 | for (k = 0; k < filter_bytes; ++k)
224 | cur[k] = (byte)((raw[k] + cur[k - output_bytes]) & 255);
225 | break;
226 | case STBI__F_up:
227 | for (i = x - 1;
228 | i >= 1;
229 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
230 | output_bytes)
231 | for (k = 0; k < filter_bytes; ++k)
232 | cur[k] = (byte)((raw[k] + prior[k]) & 255);
233 | break;
234 | case STBI__F_avg:
235 | for (i = x - 1;
236 | i >= 1;
237 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
238 | output_bytes)
239 | for (k = 0; k < filter_bytes; ++k)
240 | cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - output_bytes]) >> 1)) & 255);
241 | break;
242 | case STBI__F_paeth:
243 | for (i = x - 1;
244 | i >= 1;
245 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
246 | output_bytes)
247 | for (k = 0; k < filter_bytes; ++k)
248 | cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - output_bytes], prior[k],
249 | prior[k - output_bytes])) & 255);
250 | break;
251 | case STBI__F_avg_first:
252 | for (i = x - 1;
253 | i >= 1;
254 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
255 | output_bytes)
256 | for (k = 0; k < filter_bytes; ++k)
257 | cur[k] = (byte)((raw[k] + (cur[k - output_bytes] >> 1)) & 255);
258 | break;
259 | case STBI__F_paeth_first:
260 | for (i = x - 1;
261 | i >= 1;
262 | --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
263 | output_bytes)
264 | for (k = 0; k < filter_bytes; ++k)
265 | cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - output_bytes], 0, 0)) & 255);
266 | break;
267 | }
268 |
269 | if (depth == 16)
270 | {
271 | cur = ptr + stride * j;
272 | for (i = (uint)0; i < x; ++i, cur += output_bytes) cur[filter_bytes + 1] = 255;
273 | }
274 | }
275 | }
276 |
277 | if (depth < 8)
278 | for (j = (uint)0; j < y; ++j)
279 | {
280 | var cur = ptr + stride * j;
281 | var _in_ = ptr + stride * j + x * out_n - img_width_bytes;
282 | var scale = (byte)(color == 0 ? stbi__depth_scale_table[depth] : 1);
283 | if (depth == 4)
284 | {
285 | for (k = (int)(x * img_n); k >= 2; k -= 2, ++_in_)
286 | {
287 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 4)));
288 | cur.SetAndIncrease((byte)(scale * (_in_.Value & 0x0f)));
289 | }
290 |
291 | if (k > 0)
292 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 4)));
293 | }
294 | else if (depth == 2)
295 | {
296 | for (k = (int)(x * img_n); k >= 4; k -= 4, ++_in_)
297 | {
298 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 6)));
299 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 4) & 0x03)));
300 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 2) & 0x03)));
301 | cur.SetAndIncrease((byte)(scale * (_in_.Value & 0x03)));
302 | }
303 |
304 | if (k > 0)
305 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 6)));
306 | if (k > 1)
307 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 4) & 0x03)));
308 | if (k > 2)
309 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 2) & 0x03)));
310 | }
311 | else if (depth == 1)
312 | {
313 | for (k = (int)(x * img_n); k >= 8; k -= 8, ++_in_)
314 | {
315 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 7)));
316 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 6) & 0x01)));
317 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 5) & 0x01)));
318 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 4) & 0x01)));
319 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 3) & 0x01)));
320 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 2) & 0x01)));
321 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 1) & 0x01)));
322 | cur.SetAndIncrease((byte)(scale * (_in_.Value & 0x01)));
323 | }
324 |
325 | if (k > 0)
326 | cur.SetAndIncrease((byte)(scale * (_in_.Value >> 7)));
327 | if (k > 1)
328 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 6) & 0x01)));
329 | if (k > 2)
330 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 5) & 0x01)));
331 | if (k > 3)
332 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 4) & 0x01)));
333 | if (k > 4)
334 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 3) & 0x01)));
335 | if (k > 5)
336 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 2) & 0x01)));
337 | if (k > 6)
338 | cur.SetAndIncrease((byte)(scale * ((_in_.Value >> 1) & 0x01)));
339 | }
340 |
341 | if (img_n != out_n)
342 | {
343 | var q = 0;
344 | cur = ptr + stride * j;
345 | if (img_n == 1)
346 | for (q = (int)(x - 1); q >= 0; --q)
347 | {
348 | cur[q * 2 + 1] = 255;
349 | cur[q * 2 + 0] = cur[q];
350 | }
351 | else
352 | for (q = (int)(x - 1); q >= 0; --q)
353 | {
354 | cur[q * 4 + 3] = 255;
355 | cur[q * 4 + 2] = cur[q * 3 + 2];
356 | cur[q * 4 + 1] = cur[q * 3 + 1];
357 | cur[q * 4 + 0] = cur[q * 3 + 0];
358 | }
359 | }
360 | }
361 | else if (depth == 16)
362 | throw new NotImplementedException();
363 | /* FakePtr cur = ptr;
364 | ushort* cur16 = (ushort*)(cur);
365 | for (i = (uint)(0); (i) < (x * y * out_n); ++i, cur16++, cur += 2)
366 | {
367 | *cur16 = (ushort)((cur[0] << 8) | cur[1]);
368 | }*/
369 |
370 | return 1;
371 | }
372 |
373 | private int stbi__create_png_image(FakePtr image_data, uint image_data_len, int out_n, int depth,
374 | int color, int interlaced)
375 | {
376 | var bytes = depth == 16 ? 2 : 1;
377 | var out_bytes = out_n * bytes;
378 | var p = 0;
379 | if (interlaced == 0)
380 | return stbi__create_png_image_raw(image_data, image_data_len, out_n, (uint)img_x, (uint)img_y, depth,
381 | color);
382 | var final = new byte[img_x * img_y * out_bytes];
383 | var xorig = new int[7];
384 | var yorig = new int[7];
385 | var xspc = new int[7];
386 | var yspc = new int[7];
387 |
388 | for (p = 0; p < 7; ++p)
389 | {
390 | xorig[0] = 0;
391 | xorig[1] = 4;
392 | xorig[2] = 0;
393 | xorig[3] = 2;
394 | xorig[4] = 0;
395 | xorig[5] = 1;
396 | xorig[6] = 0;
397 |
398 | yorig[0] = 0;
399 | yorig[1] = 0;
400 | yorig[2] = 4;
401 | yorig[3] = 0;
402 | yorig[4] = 2;
403 | yorig[5] = 0;
404 | yorig[6] = 1;
405 |
406 | xspc[0] = 8;
407 | xspc[1] = 8;
408 | xspc[2] = 4;
409 | xspc[3] = 4;
410 | xspc[4] = 2;
411 | xspc[5] = 2;
412 | xspc[6] = 1;
413 |
414 | yspc[0] = 8;
415 | yspc[1] = 8;
416 | yspc[2] = 8;
417 | yspc[3] = 4;
418 | yspc[4] = 4;
419 | yspc[5] = 2;
420 | yspc[6] = 2;
421 | var i = 0;
422 | var j = 0;
423 | var x = 0;
424 | var y = 0;
425 | x = (img_x - xorig[p] + xspc[p] - 1) / xspc[p];
426 | y = (img_y - yorig[p] + yspc[p] - 1) / yspc[p];
427 | if (x != 0 && y != 0)
428 | {
429 | var img_len = (uint)((((img_n * x * depth + 7) >> 3) + 1) * y);
430 | if (stbi__create_png_image_raw(image_data, image_data_len, out_n, (uint)x, (uint)y, depth,
431 | color) == 0) return 0;
432 |
433 | var finalPtr = new FakePtr(final);
434 | var outPtr = new FakePtr(_out_);
435 | for (j = 0; j < y; ++j)
436 | for (i = 0; i < x; ++i)
437 | {
438 | var out_y = j * yspc[p] + yorig[p];
439 | var out_x = i * xspc[p] + xorig[p];
440 | (finalPtr + out_y * img_x * out_bytes + out_x * out_bytes).memcpy(
441 | outPtr + (j * x + i) * out_bytes,
442 | out_bytes);
443 | }
444 |
445 | image_data += img_len;
446 | image_data_len -= img_len;
447 | }
448 | }
449 |
450 | _out_ = final;
451 | return 1;
452 | }
453 |
454 | private int stbi__compute_transparency(byte[] tc, int out_n)
455 | {
456 | uint i = 0;
457 | var pixel_count = (uint)(img_x * img_y);
458 | var p = new FakePtr(_out_);
459 | if (out_n == 2)
460 | for (i = (uint)0; i < pixel_count; ++i)
461 | {
462 | p[1] = (byte)(p[0] == tc[0] ? 0 : 255);
463 | p += 2;
464 | }
465 | else
466 | for (i = (uint)0; i < pixel_count; ++i)
467 | {
468 | if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
469 | p[3] = 0;
470 | p += 4;
471 | }
472 |
473 | return 1;
474 | }
475 |
476 | private int stbi__compute_transparency16(ushort[] tc, int out_n)
477 | {
478 | throw new NotImplementedException();
479 |
480 | /* uint i = 0;
481 | uint pixel_count = (uint)(img_x * img_y);
482 | FakePtr p = new FakePtr(_out_);
483 | if ((out_n) == (2))
484 | {
485 | for (i = (uint)(0); (i) < (pixel_count); ++i)
486 | {
487 | p[1] = (ushort)((p[0]) == (tc[0]) ? 0 : 65535);
488 | p += 2;
489 | }
490 | }
491 | else
492 | {
493 | for (i = (uint)(0); (i) < (pixel_count); ++i)
494 | {
495 | if ((((p[0]) == (tc[0])) && ((p[1]) == (tc[1]))) && ((p[2]) == (tc[2])))
496 | p[3] = (ushort)(0);
497 | p += 4;
498 | }
499 | }
500 |
501 | return (int)(1);*/
502 | }
503 |
504 | private int stbi__expand_png_palette(byte[] palette, int len, int pal_img_n)
505 | {
506 | uint i = 0;
507 | var pixel_count = (uint)(img_x * img_y);
508 | var orig = _out_;
509 | _out_ = new byte[pixel_count * pal_img_n];
510 | var p = new FakePtr(_out_);
511 | if (pal_img_n == 3)
512 | for (i = (uint)0; i < pixel_count; ++i)
513 | {
514 | var n = orig[i] * 4;
515 | p[0] = palette[n];
516 | p[1] = palette[n + 1];
517 | p[2] = palette[n + 2];
518 | p += 3;
519 | }
520 | else
521 | for (i = (uint)0; i < pixel_count; ++i)
522 | {
523 | var n = orig[i] * 4;
524 | p[0] = palette[n];
525 | p[1] = palette[n + 1];
526 | p[2] = palette[n + 2];
527 | p[3] = palette[n + 3];
528 | p += 4;
529 | }
530 |
531 | return 1;
532 | }
533 |
534 | private void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
535 | {
536 | stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
537 | }
538 |
539 | private void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
540 | {
541 | stbi__de_iphone_flag = flag_true_if_should_convert;
542 | }
543 |
544 | private void stbi__de_iphone()
545 | {
546 | uint i = 0;
547 | var pixel_count = (uint)(img_x * img_y);
548 | var p = new FakePtr(_out_);
549 | if (img_out_n == 3)
550 | {
551 | for (i = (uint)0; i < pixel_count; ++i)
552 | {
553 | var t = p[0];
554 | p[0] = p[2];
555 | p[2] = t;
556 | p += 3;
557 | }
558 | }
559 | else
560 | {
561 | if (stbi__unpremultiply_on_load != 0)
562 | for (i = (uint)0; i < pixel_count; ++i)
563 | {
564 | var a = p[3];
565 | var t = p[0];
566 | if (a != 0)
567 | {
568 | var half = (byte)(a / 2);
569 | p[0] = (byte)((p[2] * 255 + half) / a);
570 | p[1] = (byte)((p[1] * 255 + half) / a);
571 | p[2] = (byte)((t * 255 + half) / a);
572 | }
573 | else
574 | {
575 | p[0] = p[2];
576 | p[2] = t;
577 | }
578 |
579 | p += 4;
580 | }
581 | else
582 | for (i = (uint)0; i < pixel_count; ++i)
583 | {
584 | var t = p[0];
585 | p[0] = p[2];
586 | p[2] = t;
587 | p += 4;
588 | }
589 | }
590 | }
591 |
592 | private int stbi__parse_png_file(int scan, int req_comp)
593 | {
594 | var palette = new byte[1024];
595 | var pal_img_n = (byte)0;
596 | var has_trans = (byte)0;
597 | var tc = new byte[3];
598 | tc[0] = 0;
599 |
600 | var tc16 = new ushort[3];
601 | var ioff = 0;
602 | var idata_limit = 0;
603 | uint i = 0;
604 | var pal_len = (uint)0;
605 | var first = 1;
606 | var k = 0;
607 | var interlace = 0;
608 | var color = 0;
609 | var is_iphone = 0;
610 | expanded = null;
611 | idata = null;
612 | _out_ = null;
613 | if (!stbi__check_png_header(Stream))
614 | return 0;
615 | if (scan == STBI__SCAN_type)
616 | return 1;
617 | for (; ; )
618 | {
619 | var c = stbi__get_chunk_header();
620 | switch (c.type)
621 | {
622 | case ((uint)'C' << 24) + ((uint)'g' << 16) + ((uint)'B' << 8) + 'I':
623 | is_iphone = 1;
624 | stbi__skip((int)c.length);
625 | break;
626 | case ((uint)'I' << 24) + ((uint)'H' << 16) + ((uint)'D' << 8) + 'R':
627 | {
628 | var comp = 0;
629 | var filter = 0;
630 | if (first == 0)
631 | stbi__err("multiple IHDR");
632 | first = 0;
633 | if (c.length != 13)
634 | stbi__err("bad IHDR len");
635 | img_x = (int)stbi__get32be();
636 | if (img_x > 1 << 24)
637 | stbi__err("too large");
638 | img_y = (int)stbi__get32be();
639 | if (img_y > 1 << 24)
640 | stbi__err("too large");
641 | depth = stbi__get8();
642 | if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 16)
643 | stbi__err("1/2/4/8/16-bit only");
644 | color = stbi__get8();
645 | if (color > 6)
646 | stbi__err("bad ctype");
647 | if (color == 3 && depth == 16)
648 | stbi__err("bad ctype");
649 | if (color == 3)
650 | pal_img_n = 3;
651 | else if ((color & 1) != 0)
652 | stbi__err("bad ctype");
653 | comp = stbi__get8();
654 | if (comp != 0)
655 | stbi__err("bad comp method");
656 | filter = stbi__get8();
657 | if (filter != 0)
658 | stbi__err("bad filter method");
659 | interlace = stbi__get8();
660 | if (interlace > 1)
661 | stbi__err("bad interlace method");
662 | if (img_x == 0 || img_y == 0)
663 | stbi__err("0-pixel image");
664 | if (pal_img_n == 0)
665 | {
666 | img_n = ((color & 2) != 0 ? 3 : 1) + ((color & 4) != 0 ? 1 : 0);
667 | if ((1 << 30) / img_x / img_n < img_y)
668 | stbi__err("too large");
669 | if (scan == STBI__SCAN_header)
670 | return 1;
671 | }
672 | else
673 | {
674 | img_n = 1;
675 | if ((1 << 30) / img_x / 4 < img_y)
676 | stbi__err("too large");
677 | }
678 |
679 | break;
680 | }
681 | case ((uint)'P' << 24) + ((uint)'L' << 16) + ((uint)'T' << 8) + 'E':
682 | {
683 | if (first != 0)
684 | stbi__err("first not IHDR");
685 | if (c.length > 256 * 3)
686 | stbi__err("invalid PLTE");
687 | pal_len = c.length / 3;
688 | if (pal_len * 3 != c.length)
689 | stbi__err("invalid PLTE");
690 | for (i = (uint)0; i < pal_len; ++i)
691 | {
692 | palette[i * 4 + 0] = stbi__get8();
693 | palette[i * 4 + 1] = stbi__get8();
694 | palette[i * 4 + 2] = stbi__get8();
695 | palette[i * 4 + 3] = 255;
696 | }
697 |
698 | break;
699 | }
700 | case ((uint)'t' << 24) + ((uint)'R' << 16) + ((uint)'N' << 8) + 'S':
701 | {
702 | if (first != 0)
703 | stbi__err("first not IHDR");
704 | if (idata != null)
705 | stbi__err("tRNS after IDAT");
706 | if (pal_img_n != 0)
707 | {
708 | if (scan == STBI__SCAN_header)
709 | {
710 | img_n = 4;
711 | return 1;
712 | }
713 |
714 | if (pal_len == 0)
715 | stbi__err("tRNS before PLTE");
716 | if (c.length > pal_len)
717 | stbi__err("bad tRNS len");
718 | pal_img_n = 4;
719 | for (i = (uint)0; i < c.length; ++i) palette[i * 4 + 3] = stbi__get8();
720 | }
721 | else
722 | {
723 | if ((img_n & 1) == 0)
724 | stbi__err("tRNS with alpha");
725 | if (c.length != (uint)img_n * 2)
726 | stbi__err("bad tRNS len");
727 | has_trans = 1;
728 | if (depth == 16)
729 | for (k = 0; k < img_n; ++k)
730 | tc16[k] = (ushort)stbi__get16be();
731 | else
732 | for (k = 0; k < img_n; ++k)
733 | tc[k] = (byte)((byte)(stbi__get16be() & 255) * stbi__depth_scale_table[depth]);
734 | }
735 |
736 | break;
737 | }
738 | case ((uint)'I' << 24) + ((uint)'D' << 16) + ((uint)'A' << 8) + 'T':
739 | {
740 | if (first != 0)
741 | stbi__err("first not IHDR");
742 | if (pal_img_n != 0 && pal_len == 0)
743 | stbi__err("no PLTE");
744 | if (scan == STBI__SCAN_header)
745 | {
746 | img_n = pal_img_n;
747 | return 1;
748 | }
749 |
750 | if ((int)(ioff + c.length) < ioff)
751 | return 0;
752 | if (ioff + c.length > idata_limit)
753 | {
754 | var idata_limit_old = (uint)idata_limit;
755 | if (idata_limit == 0)
756 | idata_limit = (int)(c.length > 4096 ? c.length : 4096);
757 | while (ioff + c.length > idata_limit) idata_limit *= 2;
758 |
759 | Array.Resize(ref idata, idata_limit);
760 | }
761 |
762 | if (!stbi__getn(idata, ioff, (int)c.length))
763 | stbi__err("outofdata");
764 | ioff += (int)c.length;
765 | break;
766 | }
767 | case ((uint)'I' << 24) + ((uint)'E' << 16) + ((uint)'N' << 8) + 'D':
768 | {
769 | var raw_len = 0;
770 | uint bpl = 0;
771 | if (first != 0)
772 | stbi__err("first not IHDR");
773 | if (scan != STBI__SCAN_load)
774 | return 1;
775 | if (idata == null)
776 | stbi__err("no IDAT");
777 | bpl = (uint)((img_x * depth + 7) / 8);
778 | raw_len = (int)(bpl * img_y * img_n + img_y);
779 | expanded = ZLib.stbi_zlib_decode_malloc_guesssize_headerflag(idata, ioff, raw_len, out raw_len,
780 | is_iphone != 0 ? 0 : 1);
781 | if (expanded == null)
782 | return 0;
783 | idata = null;
784 | if (req_comp == img_n + 1 && req_comp != 3 && pal_img_n == 0 || has_trans != 0)
785 | img_out_n = img_n + 1;
786 | else
787 | img_out_n = img_n;
788 | if (stbi__create_png_image(new FakePtr(expanded), (uint)raw_len, img_out_n, depth, color,
789 | interlace) == 0)
790 | return 0;
791 | if (has_trans != 0)
792 | {
793 | if (depth == 16)
794 | {
795 | if (stbi__compute_transparency16(tc16, img_out_n) == 0)
796 | return 0;
797 | }
798 | else
799 | {
800 | if (stbi__compute_transparency(tc, img_out_n) == 0)
801 | return 0;
802 | }
803 | }
804 |
805 | if (is_iphone != 0 && stbi__de_iphone_flag != 0 && img_out_n > 2)
806 | stbi__de_iphone();
807 | if (pal_img_n != 0)
808 | {
809 | img_n = pal_img_n;
810 | img_out_n = pal_img_n;
811 | if (req_comp >= 3)
812 | img_out_n = req_comp;
813 | if (stbi__expand_png_palette(palette, (int)pal_len, img_out_n) == 0)
814 | return 0;
815 | }
816 | else if (has_trans != 0)
817 | {
818 | ++img_n;
819 | }
820 |
821 | expanded = null;
822 | return 1;
823 | }
824 | default:
825 | if (first != 0)
826 | stbi__err("first not IHDR");
827 | if ((c.type & (1 << 29)) == 0)
828 | {
829 | var invalid_chunk = c.type + " PNG chunk not known";
830 | stbi__err(invalid_chunk);
831 | }
832 |
833 | stbi__skip((int)c.length);
834 | break;
835 | }
836 |
837 | stbi__get32be();
838 | }
839 | }
840 |
841 | private ImageResult InternalDecode(ColorComponents? requiredComponents)
842 | {
843 | var req_comp = requiredComponents.ToReqComp();
844 | if (req_comp < 0 || req_comp > 4)
845 | stbi__err("bad req_comp");
846 |
847 | try
848 | {
849 | if (stbi__parse_png_file(STBI__SCAN_load, req_comp) == 0) stbi__err("could not parse png");
850 |
851 | var bits_per_channel = 8;
852 | if (depth < 8)
853 | bits_per_channel = 8;
854 | else
855 | bits_per_channel = depth;
856 | var result = _out_;
857 | _out_ = null;
858 | if (req_comp != 0 && req_comp != img_out_n)
859 | {
860 | if (bits_per_channel == 8)
861 | result = Conversion.stbi__convert_format(result, img_out_n, req_comp, (uint)img_x,
862 | (uint)img_y);
863 | else
864 | result = Conversion.stbi__convert_format16(result, img_out_n, req_comp, (uint)img_x,
865 | (uint)img_y);
866 | img_out_n = req_comp;
867 | }
868 |
869 | return new ImageResult
870 | {
871 | Width = img_x,
872 | Height = img_y,
873 | SourceComponents = (ColorComponents)img_n,
874 | ColorComponents = requiredComponents != null ? requiredComponents.Value : (ColorComponents)img_n,
875 | BitsPerChannel = bits_per_channel,
876 | Data = result
877 | };
878 | }
879 | finally
880 | {
881 | _out_ = null;
882 | expanded = null;
883 | idata = null;
884 | }
885 | }
886 |
887 | public static bool Test(Stream stream)
888 | {
889 | var r = stbi__check_png_header(stream);
890 | stream.Rewind();
891 |
892 | return r;
893 | }
894 |
895 | public static ImageInfo? Info(Stream stream)
896 | {
897 | var decoder = new PngDecoder(stream);
898 | var r = decoder.stbi__parse_png_file(STBI__SCAN_header, 0);
899 | stream.Rewind();
900 |
901 | if (r == 0) return null;
902 |
903 | return new ImageInfo
904 | {
905 | Width = decoder.img_x,
906 | Height = decoder.img_y,
907 | ColorComponents = (ColorComponents)decoder.img_n,
908 | BitsPerChannel = decoder.depth
909 | };
910 | }
911 |
912 | public static ImageResult Decode(Stream stream, ColorComponents? requiredComponents = null)
913 | {
914 | var decoder = new PngDecoder(stream);
915 | return decoder.InternalDecode(requiredComponents);
916 | }
917 | }
918 | }
--------------------------------------------------------------------------------