Logo Search packages:      
Sourcecode: yafray version File versions

HDRimage.cc

//---------------------------------------------------------------------------
#include "HDRimage.h"
#include <math.h>
#include <string.h>

__BEGIN_YAFRAY
// Parts of the actual HDR loader & saver code came from this page:
// http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html
// describing the HDR format and code as used in Greg Ward's Radiance render package.

//---------------------------------------------------------------------------
// START OF HDR LOADER

// loads HDR, converts to float image or stores directly as RGBE image
bool HDRimage_t::LoadHDR(const char* filename, HDRFORMAT hf)
{
  file = fopen(filename,"rb");
  if (file==NULL) return false;
  if (!CheckHDR()) {
    fclose(file);
    return false;
  }
  bool ok;
  if (hf==HDR_FLOAT)
    ok = radiance2fp();
  else
    ok = radiance2rgbe();
  fclose(file);
  EXPadjust = 0;
  return ok;
}


// check header to see if this is really a HDR file
// if so get the resolution information
bool HDRimage_t::CheckHDR()
{
  char cs[256], st1[80], st2[80];
  bool resok = false, HDRok = false;
  while (!feof(file) && !resok) {
    fgets(cs, 255, file);
    if (strstr(cs, "32-bit_rle_rgbe")) HDRok = true;
    if (strcmp(cs, "\n") == 0) {
      // empty line found, next is resolution info, format: -Y N +X N
      // directly followed by data
      fgets(cs, 255, file);
      sscanf(cs, "%s %d %s %d", (char*)&st1, &ymax, (char*)&st2, &xmax);
      resok = true;
    }
  }
  return HDRok;
}

// free any allocated images/buffers before allocating new memory
void HDRimage_t::freeBuffers()
{
  if (fRGB) {
    delete[] fRGB;
    fRGB = NULL;
  }
  if (rgbe_scan) {
   delete[] rgbe_scan;
   rgbe_scan = NULL;
  }
  if (RGBE_img) {
    delete[] RGBE_img;
    RGBE_img = NULL;
  }
}

// convert radiance hdr to float image
bool HDRimage_t::radiance2fp()
{
  RGBE *sline;
  int x,y,yx;
  freeBuffers();
  sline = new RGBE[xmax];
  //ouch!, fRGB can be HUGE! (stpeters=1500x1500 fRGB = 25.75MB!)
  fRGB = new fCOLOR[xmax*ymax];
  for (y=ymax-1;y>=0;y--) {
    yx = y*xmax;
    if (!freadcolrs(sline)) return false;
    for (x=0;x<xmax;x++)
      RGBE2FLOAT(sline[x], fRGB[x+yx]);
  }
  delete[] sline;
  return true;
}


// directly reads in the image as RGBE, only decodes if RLE used
bool HDRimage_t::radiance2rgbe()
{
  freeBuffers();
  RGBE_img = new RGBE[xmax*ymax];
  for (int y=ymax-1;y>=0;y--) {
    if (!freadcolrs(&RGBE_img[y*xmax])) return false;
  }
  return true;
}


// read and possibly RLE decode a rgbe scanline
bool HDRimage_t::freadcolrs(RGBE *scan)
{
  int i,j,code,val;
  if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan);
  if ((i = getc(file)) == EOF) return false;
  if (i != 2) {
    ungetc(i, file);
    return oldreadcolrs(scan);
  }
  scan[0][GRN] = (unsigned char)getc(file);
  scan[0][BLU] = (unsigned char)getc(file);
  if ((i = getc(file)) == EOF) return false;
  if (((scan[0][BLU] << 8) | i) != xmax) return false;
  for (i=0;i<4;i++)
    for (j=0;j<xmax;) {
      if ((code = getc(file)) == EOF) return false;
      if (code > 128) {
        code &= 127;
        val = getc(file);
        while (code--)
          scan[j++][i] = (unsigned char)val;
      }
      else
        while (code--)
          scan[j++][i] = (unsigned char)getc(file);
    }
  return feof(file) ? false : true;
}


// old format
bool HDRimage_t::oldreadcolrs(RGBE *scan)
{
  int i, rshift = 0, len = xmax;
  while (len > 0) {
    scan[0][RED] = (unsigned char)getc(file);
    scan[0][GRN] = (unsigned char)getc(file);
    scan[0][BLU] = (unsigned char)getc(file);
    scan[0][EXP] = (unsigned char)getc(file);
    if (feof(file) || ferror(file)) return false;
    if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
      for (i=scan[0][EXP]<<rshift;i>0;i--) {
        copy_rgbe(scan[-1], scan[0]);
        scan++;
        len--;
      }
      rshift += 8;
    }
    else {
      scan++;
      len--;
      rshift = 0;
    }
  }
  return true;
}

// END OF HDR LOADER
//---------------------------------------------------------------------------
// START OF HDR SAVER

bool HDRimage_t::SaveHDR(const char* filename)
{
  file = fopen(filename, "wb");
  fprintf(file, "#?RADIANCE");
  fputc(10, file);
  fprintf(file, "# %s", "Written with YafRay");
  fputc(10, file);
  fprintf(file, "FORMAT=32-bit_rle_rgbe");
  fputc(10, file);
  fprintf(file, "EXPOSURE=%25.13f", 1.0);
  fputc(10, file);
  fputc(10, file);
  fprintf(file, "-Y %d +X %d", ymax, xmax);
  fputc(10, file);
  if (rgbe_scan != NULL) delete[] rgbe_scan;
  rgbe_scan = new RGBE[xmax];
  //upside down !!!
  for (int y=ymax-1;y>=0;y--) {
    if (fwritecolrs(&fRGB[y*xmax]) < 0) {        // error
      fclose(file);
      return false;
    }
  }
  fclose(file);
  return true;
}


int HDRimage_t::fwritecolrs(fCOLOR* scan)
{
  int i, j, beg, c2, cnt=0;
  // convert scanline
  for (i=0;i<xmax;i++) {
    FLOAT2RGBE(scan[0], rgbe_scan[i]);
    scan++;
  }
  if ((xmax < MINELEN) | (xmax > MAXELEN))      // OOBs, write out flat
          return (fwrite((char *)rgbe_scan, sizeof(RGBE), xmax, file) - xmax);
  // put magic header
  putc(2, file);
  putc(2, file);
  putc((unsigned char)(xmax>>8), file);
  putc((unsigned char)(xmax&255), file);
  // put components seperately
  for (i=0;i<4;i++) {
    for (j=0;j<xmax;j+=cnt) { // find next run
      for (beg=j;beg<xmax;beg+=cnt) {
        for (cnt=1;(cnt<127) && ((beg+cnt)<xmax) && (rgbe_scan[beg+cnt][i] == rgbe_scan[beg][i]); cnt++);
        if (cnt>=MINRUN) break;   // long enough
      }
      if (((beg-j)>1) && ((beg-j) < MINRUN)) {
        c2 = j+1;
        while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
          if (c2 == beg) {        // short run
            putc((unsigned char)(128+beg-j), file);
            putc((unsigned char)(rgbe_scan[j][i]), file);
            j = beg;
            break;
          }
      }
      while (j < beg) {     // write out non-run
        if ((c2 = beg-j) > 128) c2 = 128;
        putc((unsigned char)(c2), file);
        while (c2--) putc(rgbe_scan[j++][i], file);
      }
      if (cnt >= MINRUN) {      // write out run
        putc((unsigned char)(128+cnt), file);
        putc(rgbe_scan[beg][i], file);
      }
      else cnt = 0;
    }
  }
  return(ferror(file) ? -1 : 0);
}

// END OF HDR SAVER
//---------------------------------------------------------------------------
// MISC. FUNCTIONS

// Adjust exposure if necessary, rgbe image version, returns float color
inline void HDRimage_t::ExposureAdjust_rgbe2float(RGBE rgbe, fCOLOR acol)
{
  RGBE nrgbe;
  copy_rgbe(rgbe, nrgbe);
  if (EXPadjust) {
    int t = nrgbe[EXP] + EXPadjust;
    if (t<0) t=0; else if (t>255) t=255;
    nrgbe[EXP] = (unsigned char)t;
  }
  RGBE2FLOAT(nrgbe, acol);
}

// Adjust exposure if necessary, float image version
inline void HDRimage_t::ExposureAdjust_float(fCOLOR fcol, fCOLOR acol)
{
  RGBE itp;
  if (EXPadjust) {
    FLOAT2RGBE(fcol, itp);
    int t = itp[EXP] + EXPadjust;
    if (t<0) t=0; else if (t>255) t=255;
    itp[EXP] = (unsigned char)t;
    RGBE2FLOAT(itp, acol);
  }
  else copy_fcol(fcol, acol);
}


// bilinear interpolation of float HDR image at coords u,v
color_t HDRimage_t::BilerpSample(GFLOAT u, GFLOAT v)
{
  GFLOAT xf = u * GFLOAT(xmax-1);
  GFLOAT yf = v * GFLOAT(ymax-1);
  GFLOAT dx=xf-floor(xf), dy=yf-floor(yf);
  GFLOAT w0=(1-dx)*(1-dy), w1=(1-dx)*dy, w2=dx*(1-dy), w3=dx*dy;
  int x2, y2, x1 = int(xf), y1 = int(yf);
  // reject outside, return black
  if ((x1<0) || (x1>=xmax) || (y1<0) || (y1>=ymax)) return color_t(0.0);
  if ((x2 = x1+1) >= xmax) x2 = xmax-1;
  if ((y2 = y1+1) >= ymax) y2 = ymax-1;
  fCOLOR k1,k2,k3,k4;
  if (RGBE_img) {
    ExposureAdjust_rgbe2float(RGBE_img[x1 + y1*xmax], k1);
    ExposureAdjust_rgbe2float(RGBE_img[x2 + y1*xmax], k2);
    ExposureAdjust_rgbe2float(RGBE_img[x1 + y2*xmax], k3);
    ExposureAdjust_rgbe2float(RGBE_img[x2 + y2*xmax], k4);
  }
  else {
    ExposureAdjust_float(fRGB[x1 + y1*xmax], k1);
    ExposureAdjust_float(fRGB[x2 + y1*xmax], k2);
    ExposureAdjust_float(fRGB[x1 + y2*xmax], k3);
    ExposureAdjust_float(fRGB[x2 + y2*xmax], k4);
  }
  return color_t(w0*k1[RED] + w1*k3[RED] + w2*k2[RED] + w3*k4[RED],
                 w0*k1[GRN] + w1*k3[GRN] + w2*k2[GRN] + w3*k4[GRN],
                 w0*k1[BLU] + w1*k3[BLU] + w2*k2[BLU] + w3*k4[BLU]);
}

//---------------------------------------------------------------------------
// CONVERSION FUNCTIONS RGBE <-> FLOAT COLOR

//rgbe -> float color
inline void HDRimage_t::RGBE2FLOAT(RGBE rgbe, fCOLOR fcol)
{
  if (rgbe[EXP] == 0) {
    fcol[RED] = fcol[GRN] = fcol[BLU] = 0;
  }
  else {
    CFLOAT f = ldexp(1., rgbe[EXP]-(COLXS+8));
    fcol[RED] = (rgbe[RED]+.5)*f;
    fcol[GRN] = (rgbe[GRN]+.5)*f;
    fcol[BLU] = (rgbe[BLU]+.5)*f;
  }
}

//---------------------------------------------------------------------------

//float color -> rgbe
inline void HDRimage_t::FLOAT2RGBE(fCOLOR fcol, RGBE rgbe)
{
  CFLOAT d = (fcol[RED]>fcol[GRN])?fcol[RED]:fcol[GRN];
  if (fcol[BLU]>d) d = fcol[BLU];
  if (d <= 1e-32f)
    rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
  else {
    int e;
    d = frexp(d, &e) * 256.f / d;
    rgbe[RED] = (unsigned char)(fcol[RED] * d);
    rgbe[GRN] = (unsigned char)(fcol[GRN] * d);
    rgbe[BLU] = (unsigned char)(fcol[BLU] * d);
    rgbe[EXP] = (unsigned char)(e + COLXS);
  }
}

__END_YAFRAY

Generated by  Doxygen 1.6.0   Back to index