bgfx/3rdparty/tinyexr/README.md
Branimir Karadžić c525059d18 Added tinyexr.
2015-12-22 20:31:46 -08:00

8.0 KiB

Tiny OpenEXR image library.

Example

AppVeyor build status

Travis build Status

Coverity Scan Build Status

tinyexr is a small, single header-only library to load and save OpenEXR(.exr) images. tinyexr is written in portable C++(no library dependency except for STL), thus tinyexr is good to embed into your application. To use tinyexr, simply copy tinyexr.h into your project.

tinyexr currently supports:

  • OpenEXR version 1.x.
  • Normal image
    • Scanline format.
    • Uncompress("compress" = 0), ZIPS("compress" = 2), ZIP compression("compress" = 3) and PIZ compression("compress" = 4).
    • Half/Uint/Float pixel type.
    • Custom attributes(up to 128)
  • Deep image
    • Scanline format.
    • ZIPS compression("compress" = 2).
    • Half, float pixel type.
  • Litte endian machine.
  • Limited support for big endian machine.
    • read/write normal image.
  • C interface.
    • You can easily write language bindings(e.g. golang)
  • EXR saving
    • with ZIP compression.
  • JavaScript library
    • Through emscripten.

Use case

Examples

Usage

NOTE: API is still subject to change. See the source code for details.

Include tinyexr.h with TINYEXR_IMPLEMENTATION flag(do this only for one .cc file).

#define TINYEXR_IMPLEMENTATION
#include "tinyexr.h"

Quickly reading RGB(A) EXR file.

  const char* input = "asakusa.exr";
  float* out; // width * height * RGBA
  int width;
  int height;
  const char* err;

  int ret = LoadEXR(&out, &width, &height, input, &err);

Loading EXR from a file.

  const char* input = "asakusa.exr";
  const char* err;

  EXRImage exrImage;
  InitEXRImage(&exrImage);

  int ret = ParseMultiChannelEXRHeaderFromFile(&exrImage, input, &err);
  if (ret != 0) {
    fprintf(stderr, "Parse EXR err: %s\n", err);
    return;
  }

  //// Uncomment if you want reading HALF image as FLOAT.
  //for (int i = 0; i < exrImage.num_channels; i++) {
  //  if (exrImage.pixel_types[i] = TINYEXR_PIXELTYPE_HALF) {
  //    exrImage.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
  //  }
  //}

  ret = LoadMultiChannelEXRFromFile(&exrImage, input, &err);
  if (ret != 0) {
    fprintf(stderr, "Load EXR err: %s\n", err);
    return;
  }

Saving EXR file.

  bool SaveEXR(const float* rgb, int width, int height, const char* outfilename) {

    float* channels[3];

    EXRImage image;
    InitEXRImage(&image);

    image.num_channels = 3;

    // Must be BGR(A) order, since most of EXR viewers expect this channel order.
    const char* channel_names[] = {"B", "G", "R"}; // "B", "G", "R", "A" for RGBA image

    std::vector<float> images[3];
    images[0].resize(width * height);
    images[1].resize(width * height);
    images[2].resize(width * height);

    for (int i = 0; i < width * height; i++) {
      images[0][i] = rgb[3*i+0];
      images[1][i] = rgb[3*i+1];
      images[2][i] = rgb[3*i+2];
    }

    float* image_ptr[3];
    image_ptr[0] = &(images[2].at(0)); // B
    image_ptr[1] = &(images[1].at(0)); // G
    image_ptr[2] = &(images[0].at(0)); // R

    image.channel_names = channel_names;
    image.images = (unsigned char**)image_ptr;
    image.width = width;
    image.height = height;
    image.compression = TINYEXR_COMPRESSIONTYPE_ZIP;

    image.pixel_types = (int *)malloc(sizeof(int) * image.num_channels);
    image.requested_pixel_types = (int *)malloc(sizeof(int) * image.num_channels);
    for (int i = 0; i < image.num_channels; i++) {
      image.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
      image.requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in .EXR
    }

    const char* err;
    int ret = SaveMultiChannelEXRToFile(&image, outfilename, &err);
    if (ret != 0) {
      fprintf(stderr, "Save EXR err: %s\n", err);
      return ret;
    }
    printf("Saved exr file. [ %s ] \n", outfilename);

    free(image.pixel_types);
    free(image.requested_pixel_types);

    return ret;

  }

Reading deep image EXR file. See example/deepview for actual usage.

  const char* input = "deepimage.exr";
  const char* err;
  DeepImage deepImage;

  int ret = LoadDeepEXR(&deepImage, input, &err);

  // acccess to each sample in the deep pixel.
  for (int y = 0; y < deepImage.height; y++) {
    int sampleNum = deepImage.offset_table[y][deepImage.width-1];
    for (int x = 0; x < deepImage.width-1; x++) {
      int s_start = deepImage.offset_table[y][x];
      int s_end   = deepImage.offset_table[y][x+1];
      if (s_start >= sampleNum) {
        continue;
      }
      s_end = (s_end < sampleNum) ? s_end : sampleNum;
      for (int s = s_start; s < s_end; s++) {
        float val = deepImage.image[depthChan][y][s];
        ...
      }
    }
  }

deepview

examples/deepview is simple deep image viewer in OpenGL.

DeepViewExample

TODO

Contribution is welcome!

  • Compression
    • NONE("compress" = 0, load)
    • RLE("compress" = 1, load)
    • ZIPS("compress" = 2, load)
    • ZIP("compress" = 3, load)
    • PIZ("compress" = 4, load)
    • NONE("compress" = 0, save)
    • RLE("compress" = 1, save)
    • ZIPS("compress" = 2, save)
    • ZIP("compress" = 3, save)
    • PIZ("compress" = 4, save)
  • Custom attributes
    • Normal image(EXR 1.x)
    • Deep image(EXR 2.x)
  • JavaScript library
    • LoadEXRFromMemory
    • SaveMultiChannelEXR
    • Deep image save/load
  • Write from/to memory buffer.
    • SaveMultiChannelEXR
    • LoadMultiChannelEXR
    • Deep image save/load
  • Tile format.
  • Support for various compression type.
    • zstd compression(Not in OpenEXR spec, though)
  • Multi-channel.
  • Multi-part(EXR2.0)
  • Line order.
    • Increasing, decreasing(load)
    • Random?
    • Increasing, decreasing(save)
  • Pixel format(UINT, FLOAT).
    • UINT, FLOAT(load)
    • UINT, FLOAT(deep load)
    • UINT, FLOAT(save)
    • UINT, FLOAT(deep save)
  • Full support for big endian machine.
    • Loading multi channel EXR
    • Saving multi channel EXR
    • Loading deep image
    • Saving deep image
  • Optimization
    • ISPC?
    • OpenMP multi-threading in EXR loading.
    • OpenMP multi-threading in EXR saving.
    • OpenMP multi-threading in deep image loading.
    • OpenMP multi-threading in deep image saving.

License

3-clause BSD

tinyexr uses miniz, which is developed by Rich Geldreich richgel99@gmail.com, and licensed under public domain.

tinyexr tools uses stb, which is licensed under public domain: https://github.com/nothings/stb tinyexr uses some code from OpenEXR, which is licensed under 3-clause BSD license.

Author(s)

Syoyo Fujita(syoyo@lighttransport.com)

Contributor(s)