Giter Club home page Giter Club logo

bcnencoder.net's Introduction

Nuget Tests

BCnEncoder.NET

A Cross-platform BCn / DXT encoding libary for .NET

What is it?

BCnEncoder.NET is a library for compressing rgba images to different block-compressed formats. It has no native dependencies and is .NET Standard 2.1 compatible.

Supported formats are:

  • Raw unsigned byte R, RG, RGB and RGBA formats
  • BC1 (S3TC DXT1)
  • BC2 (S3TC DXT3)
  • BC3 (S3TC DXT5)
  • BC4 (RGTC1)
  • BC5 (RGTC2)
  • BC6 (BPTC_FLOAT)
  • BC7 (BPTC)

Current state

The current state of this library is in development but quite usable. I'm planning on implementing support for more codecs and different algorithms. The current version is capable of encoding and decoding BC1-BC7 images in both KTX or DDS formats.

Please note, that the API might change between versions.

Dependencies

Current dependencies are:

Image library extensions

This library has extension packages available for the following image libraries:

ImageSharp

The extension packages provide extension methods for ease of use with the image library.

Upgrading to 2.0

If you're upgrading from 1.X.X to version 2, expect some of your exsting code to be broken. ImageSharp was removed as a core dependency in version 2.0, so the code will no longer work with ImageSharp's Image types by default. You can install the extension package for ImageSharp to continue using this library easily with ImageSharp apis.

API

The below examples are using the ImageSharp extension package. For more detailed usage examples, you can go look at the unit tests.

Remember add the following usings to the top of the file:

using BCnEncoder.Encoder;
using BCnEncoder.Decoder;
using BCnEncoder.Shared;
using BCnEncoder.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

Here's an example on how to encode a png image to BC1 without alpha, and save it to a file.

using Image<Rgba32> image = Image.Load<Rgba32>("example.png");

BcEncoder encoder = new BcEncoder();

encoder.OutputOptions.GenerateMipMaps = true;
encoder.OutputOptions.Quality = CompressionQuality.Balanced;
encoder.OutputOptions.Format = CompressionFormat.Bc1;
encoder.OutputOptions.FileFormat = OutputFileFormat.Ktx; //Change to Dds for a dds file.

using FileStream fs = File.OpenWrite("example.ktx");
encoder.EncodeToStream(image, fs);

And how to decode a compressed image from a KTX file and save it to png format.

using FileStream fs = File.OpenRead("compressed_bc1.ktx");

BcDecoder decoder = new BcDecoder();
using Image<Rgba32> image = decoder.DecodeToImageRgba32(fs);

using FileStream outFs = File.OpenWrite("decoding_test_bc1.png");
image.SaveAsPng(outFs);

How to encode an HDR image with BC6H. (HdrImage class reads and writes Radiance HDR files. This class is experimental and subject to be removed)

HdrImage image = HdrImage.Read("example.hdr");
			
BcEncoder encoder = new BcEncoder();

encoder.OutputOptions.GenerateMipMaps = true;
encoder.OutputOptions.Quality = CompressionQuality.Balanced;
encoder.OutputOptions.Format = CompressionFormat.Bc6U;
encoder.OutputOptions.FileFormat = OutputFileFormat.Ktx; //Change to Dds for a dds file.

using FileStream fs = File.OpenWrite("example.ktx");
encoder.EncodeToStreamHdr(image.PixelMemory, fs);

How to decode a BC6H encoded file.

using FileStream fs = File.OpenRead("compressed_bc6.ktx");

BcDecoder decoder = new BcDecoder();
Memory2D<ColorRgbFloat> pixels = decoder.DecodeHdr2D(fs);

HdrImage image = new HdrImage(pixels.Span);

using FileStream outFs = File.OpenWrite("decoded.hdr");
image.Write(outFs);

TO-DO

  • BC1 / DXT1 Encoding Without Alpha
  • BC1 / DXT1 Encoding With 1bit of alpha
  • BC2 / DXT3 Encoding
  • BC3 / DXT5 Encoding
  • BC4 Encoding
  • BC5 Encoding
  • BC7 / BPTC Encoding
  • DDS file support
  • Implement PCA to remove Accord.Statistics dependency
  • BC6H HDR Encoding
  • Performance improvements
  • ETC / ETC2 Encoding?

Contributing

All contributions are welcome. I'll try to respond to bug reports and feature requests as fast as possible, but you can also fix things yourself and submit a pull request. Please note, that by submitting a pull request you accept that your code will be dual licensed under MIT and public domain Unlicense.

License

This library is dual-licensed under the Unlicense and MIT licenses.

You may use this code under the terms of either license.

Please note, that any dependencies of this project are licensed under their own respective licenses.

bcnencoder.net's People

Contributors

nominom avatar onepiecefreak3 avatar ptasev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bcnencoder.net's Issues

SixLabors.ImageSharp dependency

Hi! Any chance of a nuget release that depends on the latest SharpLabors.ImageSharp version (1.0.1) rather than 1.0.0-beta0007 ?

Improve readme.md example

Hi,

I know I can be a bit dense, but it took me like 5 minutes to get the main page example working. I think it should include the "usings"

using BCnEncoder.ImageSharp; was specially hard, as for other usings you can right click and if you're lucky to have intellisense, it will help you, but with the BCnEncoder.ImageSharp one you have no idea what to search for... (I had to go check the tests to see what was different).

At least it works now, time for fun! :)

`DecodeAllMipMaps2D(DdsFile)` returns empty array if `dwMipMapCount` is 0 even when there is a face with mip maps

This issue arises from the fact that mip count is handled differently in DdsFile and in DecodeInternal.

These are the relevent lines:
https://github.com/Nominom/BCnEncoder.NET/blob/master/BCnEnc.Net/Decoder/BcDecoder.cs#L1161-L1164
https://github.com/Nominom/BCnEncoder.NET/blob/master/BCnEnc.Net/Shared/ImageFiles/DdsFile.cs#L57

I think the easiest way to fix this would to be assume that each file has at least 1 mipmap. Microsoft says that you shouldn't rely on the mipmap flag being set.

Make `DecodeRaw` accept `ReadOnlyMemory<byte>`

DecodeRaw is currently a wrapper for DecodeRawInternal which itself accepts ReadOnlyMemory<byte>.
There is no reason why the public function shouldn't also accept ReadOnlyMemory/ReadOnlySpan.

Figure out something to replace HdrImage

This project is mostly about block-compressed formats, so including the HdrImage-class was a band-aid fix to allow usage with any kind of a HDR-format. Ideally ImageSharp would implement HDRsupport or another Image library would have it, so I could make an extensions package for it.

Sort out dds file dwFourCC

Here is some dwFourCC's that might be found in a dds, but the DdsFile does not recognize them.

While encoding, always prefer the DX10 extended header by default. Also add an option for encoder to prefer dwFourCC over DX10 header for formats which can be written there (BC1 - BC5).

Add tests for encoding and decoding files with the dwFourCC preferred.

Endianess of the BcBlock structs

I'm currently working on implementing ATC and I noticed how the Blocks are actually cast and read now. The current approach of casting the memory containing the blocks to the struct type only works out if the executing architecture is Little Endian.
The current code only works since all Block Compressions are specified as being stored in Little Endian, so a LE architecture has no trouble with the code.

Is it a concern that the library should work independant from the architecture of the executing system?

Quality Problems with Mipmaps

I have a BC3 image that I decoded with my own decoders. I'm not sure how the original BC3 image was created (maybe with nvidia texture tools?). Once I decoded the main mip from the image, I encoded it again to BC3 using your library. Then I decoded the newly encoded image again (with my own decoder), and I noticed that there are issues/differences in how the smaller mip levels look.

I have attached the original images in the expected folder, and the new images using your encoder in the actual folder. I used the following code to encode the images:

BcEncoder encoder = new BcEncoder();
encoder.OutputOptions.generateMipMaps = true;
encoder.OutputOptions.quality = CompressionQuality.BestQuality;
encoder.OutputOptions.fileFormat = OutputFileFormat.Dds;
encoder.OutputOptions.format = CompressionFormat.BC3;
encoder.OutputOptions.ddsBc1WriteAlphaFlag = false;
encoder.OutputOptions.maxMipMapLevel = 5;

Image<Rgba32> faceImage = ...;
var encodedData = encoder.EncodeToRawBytes(faceImage);

mipmap.zip

Possible bug in BC2/3 decoding

I am not super sure on this one so please just correct me if I am wrong: every resource I read pointed towards Bc2/3 being exactly the same, the difference only being that Bc2 colors are premultiplied with alpha.

However in the current implementation Bc3Block uses Bc4ComponentBlock which produces very much different results.

Update MS High Performance Package to 7.0.0

Currently the high performance dependency uses a preview release. The package now has a stable version. Would be great to get a new nuget package with the latest stable version.

Possible corruption decoding BC6h uf16

I'm converting a decoded BC6h uf16 RgbFloat to Bgr24. Assuming I haven't made a mistake, it appears there may be corruption in the decoder.

Nuget: BcnEncoder.NET ImageSharp 1.1.1
Sample.zip

Here's my code:

var fileName = @"";
var outFileName = fileName + ".png";
var bcDds = DdsFile.Load(fileName);
var width = (int)bcDds.header.dwWidth;
var height = (int)bcDds.header.dwHeight;

var decoder = new BcDecoder();
var source = decoder.DecodeHdr2D(bcDds);

var pixels = new byte[width * height * 3];
var pixelsSpan = MemoryMarshal.Cast<byte, Bgr24>(pixels);
for (var r = 0; r < height; ++r)
{
    var destRow = pixelsSpan.Slice(r * width, width);
    var sorcRow = source.Span.GetRowSpan(r);
    for (var c = 0; c < destRow.Length; ++c)
    {
        ref var destPixel = ref destRow[c];
        ref var sorcPixel = ref sorcRow[c];

        var rgbVal = sorcPixel.ToVector3() * byte.MaxValue;
        var bgr24 = new Bgr24(
            Math.Clamp((byte)rgbVal.X, (byte)0, byte.MaxValue), 
            Math.Clamp((byte)rgbVal.Y, (byte)0, byte.MaxValue), 
            Math.Clamp((byte)rgbVal.Z, (byte)0, byte.MaxValue));
        destPixel = bgr24;
    }
}

unsafe
{
    fixed (void* wrap = pixelsSpan)
    {
        Image.WrapMemory<Bgr24>(wrap, width, height).Save(outFileName);
    }
}

Issues when encoding certain files to DDS

Hi, I've been working on a program that can create .YTD files from folders using images for Grand Theft Auto V.
Due to the game's nature, I need to convert the numerous image files to .DDS so I'm using BCnEncoder.NET for that, but I'm having serious issues with some images, one of my testers has some textures that was extracted from Assetto Corsa and some of those textures can't be encoded, I'm getting the following error:

image

I already tried resaving the image (maintaining the same format) using Photoshop and Paint.NET and I even save it as .TGA

From a folder that has 34 textures just 30 of them were successfully converted to .DDS.
So I will attach those four textures as well: crash.zip

And this is the code I'm using to export the .DDS

var amigo = bcEncoder.EncodeToDds(image); //Here's where the crash happens

MemoryStream ms = new();

amigo.Write(ms);

byte[] ddsbytes = ms.ToArray();


File.WriteAllBytes(Path.GetDirectoryName(filename) + "/" + GetImageName + ".dds", ddsbytes);
LbProgressLog.Dispatcher.Invoke(() => { LbProgressLog.AppendText($"\nDDS conversion of {Path.GetFileName(GetImageName)} was sucessful..."); });

Program details:

  • .NET 6
  • WPF
  • Targeted for Windows7+

Async API

As discussed in issue #15 an async api would benefit consuming programs of this library to design non-blocking UI's while decoding and encoding processes are running.
Currently all classes seem to be thread-safe already, so it would just suffice to offer Async methods that wrap starting the async operation. This needs further investigation though.

Avoid allocating all RawBlock4X4Rgba32 blocks to reduce memory overhead

It seems the code allocates all blocks necessary during decoding, but these blocks are only used temporarily. It would be ideal if instead of allocating separate blocks, the decoded data is written directly to the output instead of these temporary blocks.

An example could be that the blocks to process are divided up so that they are separated evenly on each thread. Each thread allocates a single RawBlock4X4Rgba32 and decodes each block serially using that temporary block. Then the contents of the raw block are written directly to the output image at the proper location.

Not sure if this is worth it, but interested to hear your thoughts.

Progress report

Would it be a desirable feature to add report progress for encoding and decoding processes? For longer running processes like best quality compression, this might be helpful if the library is used for GUI's.

There already are build-in types in .NET like IProgress<T>. And maybe the progress reporter can be part of the decoder/encoder options.

Support for Unity3D

Hi,

I currently use Unity which only supports .NET Standard 2.0 Dlls, is making the library compatible with .NET Standard 2.0 on the plans?

Thank you!

Support for ATC

ATC is a rather exotic derivation of DXT, but it exists. I first encountered it on my work for Dai Gyakuten Saiban Mobile. Depending on the phone, the engine chose a certain image from the internal image format. And those image formats contained an encoding similar to DXT, but with slight variations.

ATC is supported in hardware by Adreno mobile GPU's (and that's where probably the name comes from, Adreno Texture Compression) and as said above, is a derivation of DXT. Here's a document detailing the differences between ATC and DXT, and how to easily convert DXT to ATC and vice versa.
http://www.guildsoftware.com/papers/2012.Converting.DXTC.to.ATC.pdf

I think it would be a nice addition, even though ATC is not that widespread.
(I already have a working implementation of ATC, so I can probably provide that one within the next week)

Bc4 & Bc5 decoding

After PR #14 the issue #3 is now fixed in Bc1, 2 and 3. Bc4, Bc5 and the alpha block in Bc3 still seem to have some issues.

Currently investigating what's up.

Discussion: remove ImageSharp?

As briefly discussed in #27 and #9, removing imagesharp as a dependency is under consideration. This would require manual implememtation of a resizing algorithm. The main package api would be changed to use raw bytes or generics argument type. When supplied with a generic argument, the type would be blindly casted to an internal Rgba32 format. Here we cannot guarantee that the input data is in the right format. We could also implement Span2D support.

Current ImageSharp api could be extracted to an extension package, that would add the current ImageSharp.Image based api.This would mainly be for convenience. We could also add an extension package for different image libraries, so the user is not locked to a single one.

What are your thoughts on such a change? Would it be more beneficial or harmful overall?

The benefits in my view are:

  • Not locked in to a single Image library
  • User has a choice to not use any external image library
  • We can add support for older .net versions

BcStream class implementation

What do people think about adding a BcStream class? It would be a Stream-based implementation of BcEncoder/BcDecoder, that would only convert raw data between different formats (no file headers, no mipmaps). Like from Rgba to compressed Bc1. This popped up in discussion in issue #9. Feedback is wanted: how would this be best implemented and would this be useful?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.