Example #1
0
static void WriteImageEXR(const std::string &name, const Float *pixels,
                          int xRes, int yRes, int totalXRes, int totalYRes,
                          int xOffset, int yOffset) {
    EXRImage image;
    InitEXRImage(&image);
    image.num_channels = 3;
    const char *channel_names[] = {"B", "G", "R"};
    image.channel_names = channel_names;
    int pixel_types[3] = {TINYEXR_PIXELTYPE_FLOAT, TINYEXR_PIXELTYPE_FLOAT,
                          TINYEXR_PIXELTYPE_FLOAT};
    image.pixel_types = pixel_types;
    int requestedPixelTypes[] = {TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF,
                                 TINYEXR_PIXELTYPE_HALF};
    image.requested_pixel_types = requestedPixelTypes;
    image.width = xRes;
    image.height = yRes;
    image.images = new unsigned char *[3];
    float *bgr = new float[3 * xRes * yRes];
    image.images[0] = (unsigned char *)bgr;
    image.images[1] = (unsigned char *)(bgr + 1 * xRes * yRes);
    image.images[2] = (unsigned char *)(bgr + 2 * xRes * yRes);
    image.pixel_aspect_ratio = 1.;
    // Work around bug in OpenEXR 1.1.
    // See https://github.com/mmp/pbrt-v3/issues/43.
    image.compression = (xRes < 64 || yRes < 64) ? TINYEXR_COMPRESSIONTYPE_NONE :
                                                   TINYEXR_COMPRESSIONTYPE_ZIP;

    int offset = 0;
    for (int y = 0; y < yRes; ++y) {
        for (int x = 0; x < xRes; ++x, ++offset) {
            ((float *)image.images[0])[offset] = pixels[3 * offset + 2];  // B
            ((float *)image.images[1])[offset] = pixels[3 * offset + 1];  // G
            ((float *)image.images[2])[offset] = pixels[3 * offset + 0];  // R
        }
    }

    const char *err;
    if (SaveMultiChannelEXRToFile(&image, name.c_str(), &err)) {
        Error("Error writing \"%s\": %s", name.c_str(), err);
    }

    delete[] bgr;
    delete[] image.images;
}
Example #2
0
void ImageTargetFileTinyExr::finalize()
{
	unique_ptr<EXRImage> exrImage( new EXRImage );
	InitEXRImage( exrImage.get() ); // we intentionally do not call FreeEXRImage on this

	const char *channelNames[4];
	
	// turn interleaved data into a series of planar channels
	std::vector<Channel32f> channels;
	float *srcData = mData.data();
	for( int c = 0; c < mNumComponents; ++c ) {
		channels.emplace_back( getWidth(), getHeight() );
		Channel32f srcChannel( getWidth(), getHeight(), mNumComponents * getWidth() * sizeof(float), mNumComponents, srcData + c );
		channels.back().copyFrom( srcChannel, srcChannel.getBounds() );
	}

	exrImage->num_channels = mNumComponents;
	exrImage->width = mWidth;
	exrImage->height = mHeight;

	float* imagePtr[4];
	int pixelTypes[4], requested_pixel_types[4];
	for( int i = 0; i < exrImage->num_channels; i++ ) {
		pixelTypes[i] = TINYEXR_PIXELTYPE_FLOAT;
		requested_pixel_types[i] = pixelTypes[i];
		channelNames[i] = mChannelNames[i].c_str();

		imagePtr[i] = channels[i].getData();
	}

	exrImage->channel_names = channelNames;
	exrImage->images = (unsigned char **)imagePtr;
	exrImage->pixel_types = pixelTypes;
	exrImage->requested_pixel_types = requested_pixel_types;

	const char *error;
	int status = SaveMultiChannelEXRToFile( exrImage.get(), mFilePath.string().c_str(), &error );
	if( status != 0 )
		throw ImageIoExceptionFailedWriteTinyExr( string( "TinyExr: failed to write. Error: " ) + error );
}
Example #3
0
void ImageViewer::RefreshFile()
{
  FILE *f = NULL;

  for(int attempt = 0; attempt < 10 && f == NULL; attempt++)
  {
    f = FileIO::fopen(m_Filename.c_str(), "rb");
    if(f)
      break;
    Threading::Sleep(40);
  }

  if(!f)
  {
    RDCERR("Couldn't open %s! Exclusive lock elsewhere?", m_Filename.c_str());
    return;
  }

  FetchTexture texDetails;

  ResourceFormat rgba8_unorm;
  rgba8_unorm.compByteWidth = 1;
  rgba8_unorm.compCount = 4;
  rgba8_unorm.compType = eCompType_UNorm;
  rgba8_unorm.special = false;

  ResourceFormat rgba32_float = rgba8_unorm;
  rgba32_float.compByteWidth = 4;
  rgba32_float.compType = eCompType_Float;

  texDetails.creationFlags = eTextureCreate_SwapBuffer | eTextureCreate_RTV;
  texDetails.cubemap = false;
  texDetails.customName = true;
  texDetails.name = m_Filename;
  texDetails.ID = m_TextureID;
  texDetails.byteSize = 0;
  texDetails.msQual = 0;
  texDetails.msSamp = 1;
  texDetails.format = rgba8_unorm;

  // reasonable defaults
  texDetails.numSubresources = 1;
  texDetails.dimension = 2;
  texDetails.arraysize = 1;
  texDetails.width = 1;
  texDetails.height = 1;
  texDetails.depth = 1;
  texDetails.mips = 1;

  byte *data = NULL;
  size_t datasize = 0;

  bool dds = false;

  if(is_exr_file(f))
  {
    texDetails.format = rgba32_float;

    FileIO::fseek64(f, 0, SEEK_END);
    uint64_t size = FileIO::ftell64(f);
    FileIO::fseek64(f, 0, SEEK_SET);

    std::vector<byte> buffer;
    buffer.resize((size_t)size);

    FileIO::fread(&buffer[0], 1, buffer.size(), f);

    FileIO::fclose(f);

    EXRImage exrImage;
    InitEXRImage(&exrImage);

    const char *err = NULL;

    int ret = ParseMultiChannelEXRHeaderFromMemory(&exrImage, &buffer[0], &err);

    if(ret != 0)
    {
      RDCERR(
          "EXR file detected, but couldn't load with ParseMultiChannelEXRHeaderFromMemory %d: '%s'",
          ret, err);
      return;
    }

    texDetails.width = exrImage.width;
    texDetails.height = exrImage.height;

    datasize = texDetails.width * texDetails.height * 4 * sizeof(float);
    data = (byte *)malloc(datasize);

    for(int i = 0; i < exrImage.num_channels; i++)
      exrImage.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;

    ret = LoadMultiChannelEXRFromMemory(&exrImage, &buffer[0], &err);

    int channels[4] = {-1, -1, -1, -1};
    for(int i = 0; i < exrImage.num_channels; i++)
    {
      switch(exrImage.channel_names[i][0])
      {
        case 'R': channels[0] = i; break;
        case 'G': channels[1] = i; break;
        case 'B': channels[2] = i; break;
        case 'A': channels[3] = i; break;
      }
    }

    float *rgba = (float *)data;
    float **src = (float **)exrImage.images;

    for(uint32_t i = 0; i < texDetails.width * texDetails.height; i++)
    {
      for(int c = 0; c < 4; c++)
      {
        if(channels[c] >= 0)
          rgba[i * 4 + c] = src[channels[c]][i];
        else if(c < 3)    // RGB channels default to 0
          rgba[i * 4 + c] = 0.0f;
        else    // alpha defaults to 1
          rgba[i * 4 + c] = 1.0f;
      }
    }

    FreeEXRImage(&exrImage);

    // shouldn't get here but let's be safe
    if(ret != 0)
    {
      free(data);
      RDCERR("EXR file detected, but couldn't load with LoadEXRFromMemory %d: '%s'", ret, err);
      return;
    }
  }
  else if(stbi_is_hdr_from_file(f))
  {
    texDetails.format = rgba32_float;

    FileIO::fseek64(f, 0, SEEK_SET);

    int ignore = 0;
    data = (byte *)stbi_loadf_from_file(f, (int *)&texDetails.width, (int *)&texDetails.height,
                                        &ignore, 4);
    datasize = texDetails.width * texDetails.height * 4 * sizeof(float);
  }
  else if(is_dds_file(f))
  {
    dds = true;
  }
  else
  {
    int ignore = 0;
    int ret = stbi_info_from_file(f, (int *)&texDetails.width, (int *)&texDetails.height, &ignore);

    // just in case (we shouldn't have come in here if this weren't true), make sure
    // the format is supported
    if(ret == 0 || texDetails.width == 0 || texDetails.width == ~0U || texDetails.height == 0 ||
       texDetails.height == ~0U)
    {
      FileIO::fclose(f);
      return;
    }

    texDetails.format = rgba8_unorm;

    data = stbi_load_from_file(f, (int *)&texDetails.width, (int *)&texDetails.height, &ignore, 4);
    datasize = texDetails.width * texDetails.height * 4 * sizeof(byte);
  }

  // if we don't have data at this point (and we're not a dds file) then the
  // file was corrupted and we failed to load it
  if(!dds && data == NULL)
  {
    FileIO::fclose(f);
    return;
  }

  m_FrameRecord.frameInfo.initDataSize = 0;
  m_FrameRecord.frameInfo.persistentSize = 0;
  m_FrameRecord.frameInfo.fileSize = datasize;

  dds_data read_data = {0};

  if(dds)
  {
    FileIO::fseek64(f, 0, SEEK_SET);
    read_data = load_dds_from_file(f);

    if(read_data.subdata == NULL)
    {
      FileIO::fclose(f);
      return;
    }

    texDetails.cubemap = read_data.cubemap;
    texDetails.arraysize = read_data.slices;
    texDetails.width = read_data.width;
    texDetails.height = read_data.height;
    texDetails.depth = read_data.depth;
    texDetails.mips = read_data.mips;
    texDetails.numSubresources = texDetails.arraysize * texDetails.mips;
    texDetails.format = read_data.format;
    texDetails.dimension = 1;
    if(texDetails.width > 1)
      texDetails.dimension = 2;
    if(texDetails.depth > 1)
      texDetails.dimension = 3;

    m_FrameRecord.frameInfo.fileSize = 0;
    for(uint32_t i = 0; i < texDetails.numSubresources; i++)
      m_FrameRecord.frameInfo.fileSize += read_data.subsizes[i];
  }

  // recreate proxy texture if necessary.
  // we rewrite the texture IDs so that the
  // outside world doesn't need to know about this
  // (we only ever have one texture in the image
  // viewer so we can just set all texture IDs
  // used to that).
  if(m_TextureID != ResourceId())
  {
    if(m_TexDetails.width != texDetails.width || m_TexDetails.height != texDetails.height ||
       m_TexDetails.depth != texDetails.depth || m_TexDetails.cubemap != texDetails.cubemap ||
       m_TexDetails.mips != texDetails.mips || m_TexDetails.arraysize != texDetails.arraysize ||
       m_TexDetails.width != texDetails.width || m_TexDetails.format != texDetails.format)
    {
      m_TextureID = ResourceId();
    }
  }

  if(m_TextureID == ResourceId())
    m_TextureID = m_Proxy->CreateProxyTexture(texDetails);

  if(!dds)
  {
    m_Proxy->SetProxyTextureData(m_TextureID, 0, 0, data, datasize);
    free(data);
  }
  else
  {
    for(uint32_t i = 0; i < texDetails.numSubresources; i++)
    {
      m_Proxy->SetProxyTextureData(m_TextureID, i / texDetails.mips, i % texDetails.mips,
                                   read_data.subdata[i], (size_t)read_data.subsizes[i]);

      delete[] read_data.subdata[i];
    }

    delete[] read_data.subdata;
    delete[] read_data.subsizes;
  }

  FileIO::fclose(f);
}
Example #4
0
ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
  FILE *f = FileIO::fopen(logfile, "rb");

  if(!f)
    return eReplayCreate_FileIOFailed;

  // make sure the file is a type we recognise before going further
  if(is_exr_file(f))
  {
    const char *err = NULL;

    FileIO::fseek64(f, 0, SEEK_END);
    uint64_t size = FileIO::ftell64(f);
    FileIO::fseek64(f, 0, SEEK_SET);

    std::vector<byte> buffer;
    buffer.resize((size_t)size);

    FileIO::fread(&buffer[0], 1, buffer.size(), f);

    EXRImage exrImage;
    InitEXRImage(&exrImage);

    int ret = ParseMultiChannelEXRHeaderFromMemory(&exrImage, &buffer[0], &err);

    FreeEXRImage(&exrImage);

    // could be an unsupported form of EXR, like deep image or other
    if(ret != 0)
    {
      FileIO::fclose(f);

      RDCERR(
          "EXR file detected, but couldn't load with ParseMultiChannelEXRHeaderFromMemory %d: '%s'",
          ret, err);
      return eReplayCreate_APIUnsupported;
    }
  }
  else if(stbi_is_hdr_from_file(f))
  {
    FileIO::fseek64(f, 0, SEEK_SET);

    int ignore = 0;
    float *data = stbi_loadf_from_file(f, &ignore, &ignore, &ignore, 4);

    if(!data)
    {
      FileIO::fclose(f);
      RDCERR("HDR file recognised, but couldn't load with stbi_loadf_from_file");
      return eReplayCreate_FileCorrupted;
    }

    free(data);
  }
  else if(is_dds_file(f))
  {
    FileIO::fseek64(f, 0, SEEK_SET);
    dds_data read_data = load_dds_from_file(f);

    if(read_data.subdata == NULL)
    {
      FileIO::fclose(f);
      RDCERR("DDS file recognised, but couldn't load");
      return eReplayCreate_FileCorrupted;
    }

    for(int i = 0; i < read_data.slices * read_data.mips; i++)
      delete[] read_data.subdata[i];

    delete[] read_data.subdata;
    delete[] read_data.subsizes;
  }
  else
  {
    int width = 0, height = 0;
    int ignore = 0;
    int ret = stbi_info_from_file(f, &width, &height, &ignore);

    // just in case (we shouldn't have come in here if this weren't true), make sure
    // the format is supported
    if(ret == 0 || width == 0 || width == ~0U || height == 0 || height == ~0U)
    {
      FileIO::fclose(f);
      return eReplayCreate_APIUnsupported;
    }

    byte *data = stbi_load_from_file(f, &ignore, &ignore, &ignore, 4);

    if(!data)
    {
      FileIO::fclose(f);
      RDCERR("File recognised, but couldn't load with stbi_load_from_file");
      return eReplayCreate_FileCorrupted;
    }

    free(data);
  }

  FileIO::fclose(f);

  IReplayDriver *proxy = NULL;
  auto status = RenderDoc::Inst().CreateReplayDriver(RDC_Unknown, NULL, &proxy);

  if(status != eReplayCreate_Success || !proxy)
  {
    if(proxy)
      proxy->Shutdown();
    return status;
  }

  *driver = new ImageViewer(proxy, logfile);

  return eReplayCreate_Success;
}
Example #5
0
ImageSourceFileTinyExr::ImageSourceFileTinyExr( DataSourceRef dataSource, ImageSource::Options /*options*/ )
{
	mExrImage.reset( new EXRImage );
	const char *error;

	InitEXRImage( mExrImage.get() );

	int status = 0;
	if( dataSource->isFilePath() ) {
		status = ParseMultiChannelEXRHeaderFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error );
		if( status != 0 )
			throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error );
		status = LoadMultiChannelEXRFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error );
		if( status != 0 )
			throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error );
	}
	else {
		BufferRef buffer = dataSource->getBuffer();
		
		status = ParseMultiChannelEXRHeaderFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error );
		if( status != 0 )
			throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error );
		status = LoadMultiChannelEXRFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error );
		if( status != 0 )
			throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error );
	}

	// verify that the channels are all the same size; currently we don't support variably sized channels
	int pixelType = mExrImage->pixel_types[0];
	for( int c = 1; c < mExrImage->num_channels; ++c ) {
		if( pixelType != mExrImage->pixel_types[c] )
			throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: heterogneous channel data types not supported" );
	}

	switch( pixelType ) {
		case TINYEXR_PIXELTYPE_HALF:
			setDataType( ImageIo::FLOAT16 );
		break;
		case TINYEXR_PIXELTYPE_FLOAT:
			setDataType( ImageIo::FLOAT32 );
		break;
		default:
			throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unknown data type" );
		break;
	}

	setSize( mExrImage->width, mExrImage->height );

	switch( mExrImage->num_channels ) {
		case 3:
			setColorModel( ImageIo::CM_RGB );
			setChannelOrder( ImageIo::ChannelOrder::RGB );
		break;
		case 4:
			setColorModel( ImageIo::CM_RGB );
			setChannelOrder( ImageIo::ChannelOrder::RGBA );
		break;
		default:
			throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unsupported number of channels (" + to_string( mExrImage->num_channels ) + ")" );
	}
}
Example #6
0
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
    /* check for proper number of arguments */
    if(nrhs != 1) {
        mexErrMsgIdAndTxt("HDRToolbox:write_exr:nrhs", "One input is required.");
    }
    
    char *nameFile;
    mwSize buflen;
    int status;    
    buflen = mxGetN(prhs[0])*sizeof(mxChar)+1;
    nameFile = (char*) mxMalloc(buflen);
    
    /* Copy the string data into buf. */ 
    status = mxGetString(prhs[0], nameFile, buflen);
    
    /* call the computational routine */
    EXRImage image;
    InitEXRImage(&image);

    const char* err;
    int ret = ParseMultiChannelEXRHeaderFromFile(&image, nameFile, &err);
    if (ret != 0) {
        printf("Parse EXR error: %s\n", err);
        return;
    }

    int width = image.width;
    int height = image.height;
    int channels = image.num_channels;

    //Allocate into memory

    mwSize dims[3];
    dims[0] = height;
    dims[1] = width;
    dims[2] = channels;

    plhs[0] = mxCreateNumericArray(channels, dims, mxDOUBLE_CLASS, mxREAL);
    double *outMatrix = mxGetPr(plhs[0]);

    for (int i = 0; i < image.num_channels; i++) {
        if (image.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
            image.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
        }
    }
    
    ret = LoadMultiChannelEXRFromFile(&image, nameFile, &err);
    
    if (ret != 0) {
        printf("Load EXR error: %s\n", err);
        return;
    }
    
    float **images = (float**) image.images;
    int nPixels = width * height;
    int nPixels2 = nPixels * 2;
    if(channels == 1) {
        nPixels = 0;
        nPixels2 = 0;
    }
    
    if(channels == 2) {
        nPixels2 = 0;
    }
    
    for (int i = 0; i < width; i++){
        for (int j = 0; j < height; j++){
            int index = i * height + j;
            int indexOut = j * width + i;
            
            outMatrix[index    ]        = images[2][indexOut];
            outMatrix[index + nPixels]  = images[1][indexOut];
            outMatrix[index + nPixels2] = images[0][indexOut];
        }
    }
    
    FreeEXRImage(&image);
}