SkillAgentSearch skills...

PVRTexLib.NET

A PVRTexLib wrapper written by CSharp

Install / Use

/learn @YingFengTingYu/PVRTexLib.NET
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

PVRTexLib.NET

Introduction

PVRTexLib.NET is a wrapper for PVRTexLib supporting .NET Framework 3.5, .NET Standard 1.1 and upper. It contains all the API from PVRTexLib.
The documents can be found through installing PVRTexTool.

License

PVRTexLib.NET is licensed under the MIT license.
This product includes components of the PowerVR Tools Software from Imagination Technologies Limited.

Supported Platforms

PVRTexLib.NET try to support all the platforms which PVRTexLib is supporting.
For best compatibility, it is recommended that PVRTexTool is installed on machines running at least Windows 7, macOS 10.11 (El Capitan), or Ubuntu 16.04.

Windows

x86 and x64

macOS

x64 and arm64

Linux

x86, x64, arm, arm64 and riscv64

Quick Start

Create PVRTexture instance to handle your textures.

using PVRTexLib;

class TextureTranscoder
{
    static void Main(string[] args)
    {
        EncodeTexture("D:\\in.png", "D:\\out.bin", (ulong)PVRTexLibPixelFormat.PVRTLPF_PVRTCII_HDR_8bpp);
        DecodeTexture("D:\\out.bin", "D:\\in2.png");
    }
    
    public static unsafe void EncodeTexture(string inFile, string outFile, ulong outFormat)
    {
        using (Bitmap bitmap = new Bitmap(Image.FromFile(inFile)))
        {
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            using (PVRTextureHeader header = new PVRTextureHeader(PVRDefine.PVRTGENPIXELID4('b', 'g', 'r', 'a', 8, 8, 8, 8), (uint)bitmap.Width, (uint)bitmap.Height, 1, 1, 1, 1, PVRTexLibColourSpace.PVRTLCS_sRGB, PVRTexLibVariableType.PVRTLVT_UnsignedByteNorm, false))
            {
                using (PVRTexture tex = new PVRTexture(header, (void*)data.Scan0))
                {
                    if (tex.GetTextureDataSize() != 0)
                    {
                        if (tex.Transcode(outFormat, PVRTexLibVariableType.PVRTLVT_UnsignedByteNorm, PVRTexLibColourSpace.PVRTLCS_sRGB, 0, false))
                        {
                            using (Stream outStream = File.Create(outFile))
                            {
                                using (BinaryWriter bw = new BinaryWriter(outStream))
                                {
                                    bw.Write(bitmap.Width);
                                    bw.Write(bitmap.Height);
                                    bw.Write(outFormat);
                                    bw.Write(new ReadOnlySpan<byte>(tex.GetTextureDataPointer(0), (int)tex.GetTextureDataSize(0)));
                                }
                            }
                        }
                    }
                }
            }
            bitmap.UnlockBits(data);
        }
    }

    public static unsafe void DecodeTexture(string inFile, string outFile)
    {
        ulong size = 0ul;
        byte[] rawTexDataArray;
        int width, height;
        ulong inFormat;
        using (Stream inStream = File.OpenRead(inFile))
        {
            using (BinaryReader br = new BinaryReader(inStream))
            {
                width = br.ReadInt32();
                height = br.ReadInt32();
                inFormat = br.ReadUInt64();
                size = (ulong)(inStream.Length - 16);
                rawTexDataArray = new byte[size];
                br.Read(rawTexDataArray);
            }
        }
        using (Bitmap bitmap = new Bitmap(width, height))
        {
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            using (PVRTextureHeader header = new PVRTextureHeader(inFormat, (uint)width, (uint)height, 1, 1, 1, 1, PVRTexLibColourSpace.PVRTLCS_sRGB, PVRTexLibVariableType.PVRTLVT_UnsignedByteNorm, false))
            {
                fixed (byte* rawTexDataPtr = &rawTexDataArray[0])
                {
                    using (PVRTexture tex = new PVRTexture(header, rawTexDataPtr))
                    {
                        if (tex.GetTextureDataSize() != 0)
                        {
                            if (tex.Transcode(PVRDefine.PVRTGENPIXELID4('b', 'g', 'r', 'a', 8, 8, 8, 8), PVRTexLibVariableType.PVRTLVT_UnsignedByteNorm, PVRTexLibColourSpace.PVRTLCS_sRGB, 0, false))
                            {
                                NativeMemory.Copy(tex.GetTextureDataPointer(0), (void*)data.Scan0, (nuint)tex.GetTextureDataSize(0));
                            }
                        }
                    }
                }
            }
            bitmap.UnlockBits(data);
            bitmap.Save(outFile);
        }
    }
}

Examples of Using the PVRTexTool Library

This section demonstrates a few of examples of using the PVRTexTool library with the required code shown.

Reading and Transcoding an Image

In this example, an existing file is read from disk and then transcoded to RGBA8888. The resulting texture object can then be used for later processing.

public static PVRTexture? ReadAndTranscodeImage(string filePath)
{
    // Open and read a texture from the file location specified by filePath.
    // Accepted file formats are: PVR, KTX, KTX2, ASTC, DDS,
    // PNG, JPEG, BMP, TGA, GIF, HDR, PSD, PPM, PGM and PIC
    using PVRTexture texture = new PVRTexture(filePath);

    // Check that PVRTexLib loaded the file successfully
    if (texture.GetTextureDataSize() == 0)
    {
        return null;
    }

    // Decompress texture to the standard RGBA8888 format.
    ulong RGBA8888 = PVRDefine.PVRTGENPIXELID4('r', 'g', 'b', 'a', 8, 8, 8, 8);

    if (!texture.Transcode(RGBA8888, PVRTexLibVariableType.UnsignedByteNorm, PVRTexLibColourSpace.Linear))
    {
        return null;
    }

    // texture is now in the format RGBA8888,
    // with each channel being of type unsigned integer,
    // and in linear colour space (i.e. without gamma correction).
    return new PVRTexture(in texture);
}

Pre-processing a Texture

In this example, a file is loaded, the pixel format is checked to determine if it is compressed or packed and transcoded to a usable format if required. The texture is then converted into a normal map of the same dimensions and a full MIP map chain is generated. Finally the texture is encoded into PVRTC1 four bits per pixel and saved to an output file.
The memory backing the data pointer returned from GetTextureDataPointer(...) is tied to the lifetime of the PVRTexture object.

public static bool ApplySomeProcessing(string inFilePath, string outFilePath)
{
    // Open and read a texture from the file location specified by inFilePath.
    // Accepted file formats are: PVR, KTX, KTX2, ASTC, DDS,
    // PNG, JPEG, BMP, TGA, GIF, HDR, PSD, PPM, PGM and PIC
    using PVRTexture texture = new PVRTexture(inFilePath);

    // Check that PVRTexLib loaded the file successfully
    if (texture.GetTextureDataSize() == 0)
    {
        return false;
    }

    // Pre-processing functions will not with some formats so
    // check the input texture format to determine if the data is compressed
    // or the format is packed.
    if ((texture.GetTexturePixelFormat() & PVRDefine.PVRTEX_PFHIGHMASK) == 0 || texture.TextureHasPackedChannelData())
    {
        // Decompress texture to the standard RGBA8888 format.
        // Note: Any decompressed, non-packed pixel format would work here,
        // for example: R32G32B32A32 Signed float
        ulong RGBA8888 = PVRDefine.PVRTGENPIXELID4('r', 'g', 'b', 'a', 8, 8, 8, 8);

        if (!texture.Transcode(RGBA8888, PVRTexLibVariableType.UnsignedByteNorm, PVRTexLibColourSpace.Linear))
        {
            return false;
        }
    }

    // Convert the image to a Normal Map with a scale of 5.0, and y/z/x channel order
    if (!texture.GenerateNormalMap(5.0f, "yzx"))
    {
        return false;
    }

    // Generate MIP-map chain
    if (!texture.GenerateMIPMaps(PVRTexLibResizeMode.Linear))
    {
        return false;
    }

    // Compress to PVRTC 4bpp.
    // Note: A better compressor quality will improve image quality,
    // at the expensive of compression speed.
    if (!texture.Transcode((ulong)PVRTexLibPixelFormat.PVRTCI_4bpp_RGB, PVRTexLibVariableType.UnsignedByteNorm, PVRTexLibColourSpace.Linear, PVRTexLibCompressorQuality.PVRTCNormal))
    {
        return false;
    }

    // Save the texture to file location specified by outFilePath.
    // The file type will be determined by the extension present in the string.
    // Valid extensions are: PVR, KTX, KTX2, ASTC, DDS and h
    // If no extension is present the PVR format will be selected.
    return texture.SaveToFile(outFilePath);
}

Reading an Image and Resizing the Canvas

In this example, an existing file is opened, the pixel format is checked to determine if it is compressed or packed and transcoded to a usable format if required. The canvas is resized to 512x256, leaving the (original) canvas in the top left of the texture. A full MIP map chain is then generated and the texture is saved to a file.

public static bool ResizeCanvasAndGenMipChain(string inFilePath, string outFilePath)
{
    // Open and read a texture from the file location specified by inFilePath.
    // Accepted file formats are: PVR, KTX, KTX2, ASTC, DDS,
    // PNG, JPEG, BMP, TGA, GIF, HDR, PSD, PPM, PGM and PIC
    using PVRTexture texture = new PVRTexture(inFilePath);

    // Check that PVRTexLib loaded the file successfully
    if (texture.GetTextureDataSize() == 0)
    {
        return false;
    }

    // Pre-processing functions will not with some formats so
    // check the input texture format to determine if the data is compressed
    // or the format is packed.
    if ((texture.GetTexturePixelFormat() & PVRDefine.PVRTEX_PFHIGHMASK) == 0 || texture.TextureHasPackedChannelData())
    {
        // Decompress texture to the standard RGBA8888 format.
        // Note: Any decompressed, non-packed pixel format would w
View on GitHub
GitHub Stars7
CategoryDevelopment
Updated8mo ago
Forks1

Languages

C#

Security Score

77/100

Audited on Jul 30, 2025

No findings