hurlbertvisionlab / LibRawWrapper

C++/CLI wrapper around the LibRaw library for reading RAW files in .NET
MIT License
2 stars 1 forks source link

# LibRaw Wrapper (C++/CLI LibRaw)

.NET and .NET Framework assembly for reading and processing RAW images

LibRawWrapper is a single-file C++/CLI assembly containing the LibRaw library for reading RAW files from digital photo cameras (CRW/CR2, NEF, RAF, DNG, MOS, KDC, DCR, etc, virtually all RAW formats are supported).

It pays special attention to correct retrieval of data required for subsequent RAW conversion.

The library is intended for embedding in RAW converters, data analyzers, and other programs using RAW files as the initial data.

Documentation for LibRaw can be found at libraw.org and it is included in the wrapper using XML documentation. (The original dcraw manual is available here.)

Usage

👉 If you are looking for a way to show RAW images to users for informational purposes, just get the LibRaw-based WIC codec in the form of Raw Image Extension by Microsoft. It is the same code outputting 8-bit images with default settings, enabling both RAW file thumbnails and previews in Windows Explorer as well as reading images in .NET using BitmapDecoder.Create.

This LibRaw Wrapper is aiming at image processing pipeline, giving access to 32-bit floating or 16-bit integer data. By default, it produces PixelFormats.Rgb128 bitmap with fixed white level and linear gamma, corresponding to -4 dcraw parameter.

⚠️ Since this is mixed native/managed assembly, you need to ensure your application architecture matches the architecture of the LibRaw Wrapper assembly. Most likely, if you are targeting 64-bit platforms and your project configuration is Any CPU, you might need to go to project settings > Build and uncheck Prefer 32-bit.

Higher-level API

The high level API is inspired by the BitmapDecoder API (the API currently allows extending only by writing a WIC codec):

This example converts raw files passed via command-line into JPEG files:

using System.IO;
using System.Windows.Media.Imaging;
using LibRawWrapper;

class Program
{
    static void Main(string[] args!!)
    {
        foreach (string filename in args)
        {
            LibRawBitmapDecoder raw = new LibRawBitmapDecoder(new Uri(Path.GetFullPath(filename)),
                                                              BitmapCreateOptions.PreservePixelFormat,
                                                              BitmapCacheOption.None);
            BitmapFrame rawFrame = raw.Frames[0];

            JpegBitmapEncoder jpeg = new JpegBitmapEncoder();
            jpeg.Frames.Add(rawFrame);
            using (FileStream stream = File.Create(Path.ChangeExtension(filename, ".jpg"))
                jpeg.Save(stream);
        }
    }
}

Currently the high-level API does not include metadata or color context in the bitmap frames. The resulting frames are as follows:

BitmapCreateOptions: None IgnoreColorProfile PreservePixelFormat
BitmapFrame.PixelFormat Rgb128Float Rgb128Float Rgb48
gamma linear linear sRGB
equivalent dcraw settings -4 -D -4 -6 -W -g 2.4 12.92

The BitmapFrame can be directly shown in the user interface or encoded into an image file as shown above. Technically IgnoreColorProfile and PreservePixelFormat can be combined to get access to the raw 16-bit data, however, the BitmapFrame would then hold data that should not be directly shown in the user interface, because it doesn't meet the expectations of the Rgb48 pixel format.

Lower-level API

The low level API directly corresponds to the native LibRaw API.

using LibRawWrapper.Native;

class Program
{
    static unsafe void Main()
    {
        // Let us create an image processor
        LibRawProcessor iProcessor = new LibRawProcessor();

        // Subscribe to processing notifications
        iProcessor.ProgressChanged += OnProgressChanged;

        // Open the file and read the metadata
        iProcessor.Open(@"C:\tmp\00_0011.CR2");

        // The metadata are accessible through data fields of the class
        Console.WriteLine($"Image size: {iProcessor.Sizes.Width} × {iProcessor.Sizes.Width}");

        // iProcessor.GetProcessedBitmap() calls unpack() and dcraw_process() if needed and
        // returns BitmapSource of either Gray8, Gray16, Gray32Float, Rgb24, Rgb48 or Rgb128Float
        // pixel format with the appropriate gamma (i.e. linear or sRGB).
        // To enforce your gamma regardless of pixel format contract, call DcrawProcess() manually first.

        // Alternatively, access the data manually:

        // Let us unpack the image
        iProcessor.Unpack();

        // Process the image using dcraw settings
        iProcessor.DcrawProcess();

        // Get processed image dimensions
        iProcessor.GetMemoryImageFormat(out int width, out int height, out int channels, out int bpp);

        // Get the processed image data
        byte[] data = new byte[width * height * channels];
        fixed (byte* pData = data)
            iProcessor.CopyMemoryImage(pData, width * channels, 0 /* RGB */);

        // And let us print its dump
        for (int i = 0; i < data.Length; i += channels)
            Console.WriteLine($"i={i}, R={data[i]}, G={data[i + 1]}, B={data[i + 2]}");

        // Finally, let us free the image processor for work with the next image
        iProcessor.Recycle();
    }

    static void OnProgressChanged(object sender, LibRawProgressEventArgs e)
    {
        Console.WriteLine($"{e.Description} ({e.Iteration + 1}/{e.Expected})");
    }
}

API coverage

Most of the LibRaw methods are available. The following APIs are NOT implemented:

Metadata

There is currently no way to access the makernote metadata. This is on the roadmap, subject to demand.

File output:

For saving decoded images into TIFF, use TiffBitmapEncoder.

To access image thumbnail, use LibRawProcessor.GetThumbnailBitmap and encode as desired.

Rendering:

Legacy LibRaw methods (raw2image and free_image) are not available. Access LibRawProcessor.RawData.Buffer directly.

For image thumbnail, use LibRawProcessor.GetThumbnailBitmap or access the LibRawProcessor.Thumbnail.ThumbnailBuffer directly.

dcraw_make_mem_image:

  1. calls get_mem_image_format,
  2. allocates memory,
  3. calls copy_mem_image,
  4. frees the allocated memory using dcraw_clear_mem.

It is expected that managed applications will want to allocate their own memory. The underlying APIs are still available if needed, see the lower-level API example above.

Events:

These are on the roadmap, subject to demand.

License

The LibRaw Wrapper statically links the LibRaw library (in the LibRaw submodule). The LibRaw library is Copyright © 2008-2021 LibRaw LLC (info@libraw.org) and includes source code from

dcraw.c, Dave Coffin's raw photo decoder
Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net

LibRaw is distributed for free under two different licenses:

Any changes to the LibRaw library in this repository follow the same licensing model as requested.

The C++/CLI wrapper code itself is released under MIT license.

Build

The solution builds in Visual Studio 2022. The required components are: