コード例 #1
0
void IDCT<preshift,T,deadzone,optimize>::InverseTransformBlock(LONG *target,const LONG *source,
                                                               LONG dcoffset)
{
  LONG *dptr,*dend;
  
  const LONG *qnt = m_plQuant;

  dcoffset <<= preshift + 3;

  if (source) {
    for(dptr = target,dend = target + (8 << 3);dptr < dend;dptr +=8,source += 8,qnt += 8) {
      // Even part.
      T  tz2       = source[2] * qnt[2];
      T  tz3       = source[6] * qnt[6];
      FIXED z1     = (tz2 + tz3) *  TO_FIX(0.541196100);
      FIXED tmp2   = z1 + tz3    * -TO_FIX(1.847759065);
      FIXED tmp3   = z1 + tz2    *  TO_FIX(0.765366865);
      
      tz2          = source[0] * qnt[0] + dcoffset;
      tz3          = source[4] * qnt[4];
      
      FIXED tmp0   = (tz2 + tz3) << FIX_BITS;
      FIXED tmp1   = (tz2 - tz3) << FIX_BITS;
      FIXED tmp10  = tmp0 + tmp3;
      FIXED tmp13  = tmp0 - tmp3;
      FIXED tmp11  = tmp1 + tmp2;
      FIXED tmp12  = tmp1 - tmp2;
      
      // Odd part.
      T ttmp0      = source[7] * qnt[7];
      T ttmp1      = source[5] * qnt[5];
      T ttmp2      = source[3] * qnt[3];
      T ttmp3      = source[1] * qnt[1];
      
      T tz1        = ttmp0 + ttmp3;
      tz2          = ttmp1 + ttmp2;
      tz3          = ttmp0 + ttmp2;
      T tz4        = ttmp1 + ttmp3;
      FIXED z5     = (tz3 + tz4) * TO_FIX(1.175875602);
      
      tmp0         = ttmp0 * TO_FIX(0.298631336);
      tmp1         = ttmp1 * TO_FIX(2.053119869);
      tmp2         = ttmp2 * TO_FIX(3.072711026);
      tmp3         = ttmp3 * TO_FIX(1.501321110);
      z1           = tz1   *-TO_FIX(0.899976223);
      FIXED z2     = tz2   *-TO_FIX(2.562915447);
      FIXED z3     = tz3   *-TO_FIX(1.961570560) + z5;
      FIXED z4     = tz4   *-TO_FIX(0.390180644) + z5;
      
      tmp0        += z1 + z3;
      tmp1        += z2 + z4;
      tmp2        += z2 + z3;
      tmp3        += z1 + z4;
      
      dptr[0]      = FIXED_TO_INTERMEDIATE(tmp10 + tmp3);
      dptr[7]      = FIXED_TO_INTERMEDIATE(tmp10 - tmp3);
      dptr[1]      = FIXED_TO_INTERMEDIATE(tmp11 + tmp2);
      dptr[6]      = FIXED_TO_INTERMEDIATE(tmp11 - tmp2);
      dptr[2]      = FIXED_TO_INTERMEDIATE(tmp12 + tmp1);
      dptr[5]      = FIXED_TO_INTERMEDIATE(tmp12 - tmp1);
      dptr[3]      = FIXED_TO_INTERMEDIATE(tmp13 + tmp0);
      dptr[4]      = FIXED_TO_INTERMEDIATE(tmp13 - tmp0);
      dcoffset     = 0;
    }
    
    // After transforming over the columns, now transform over the rows.
    for(dptr = target,dend = target + 8;dptr < dend;dptr++) {
      INTER tz2         = dptr[2 << 3];
      INTER tz3         = dptr[6 << 3];
      INTER_FIXED z1    = (tz2 + tz3) *  TO_FIX(0.541196100);
      INTER_FIXED tmp2  = z1 +   tz3  * -TO_FIX(1.847759065);
      INTER_FIXED tmp3  = z1 +   tz2  *  TO_FIX(0.765366865);
      INTER_FIXED tmp0  = (dptr[0 << 3] + dptr[4 << 3]) << FIX_BITS;
      INTER_FIXED tmp1  = (dptr[0 << 3] - dptr[4 << 3]) << FIX_BITS;
      INTER_FIXED tmp10 = tmp0 + tmp3;
      INTER_FIXED tmp13 = tmp0 - tmp3;
      INTER_FIXED tmp11 = tmp1 + tmp2;
      INTER_FIXED tmp12 = tmp1 - tmp2;
      // Odd parts.
      INTER ttmp0       = dptr[7 << 3];
      INTER ttmp1       = dptr[5 << 3];
      INTER ttmp2       = dptr[3 << 3];
      INTER ttmp3       = dptr[1 << 3];
      INTER tz1         = ttmp0 + ttmp3;
      tz2               = ttmp1 + ttmp2;
      tz3               = ttmp0 + ttmp2;
      INTER tz4         = ttmp1 + ttmp3;
      INTER_FIXED z5    = (tz3 + tz4) * TO_FIX(1.175875602);
      tmp0              = ttmp0 * TO_FIX(0.298631336);
      tmp1              = ttmp1 * TO_FIX(2.053119869);
      tmp2              = ttmp2 * TO_FIX(3.072711026);
      tmp3              = ttmp3 * TO_FIX(1.501321110);
      z1                = tz1   *-TO_FIX(0.899976223);
      INTER_FIXED z2    = tz2   *-TO_FIX(2.562915447);
      INTER_FIXED z3    = tz3   *-TO_FIX(1.961570560) + z5;
      INTER_FIXED z4    = tz4   *-TO_FIX(0.390180644) + z5;
      tmp0             += z1 + z3;
      tmp1             += z2 + z4;
      tmp2             += z2 + z3;
      tmp3             += z1 + z4;
      
      dptr[0 << 3]      = INTER_FIXED_TO_INT(tmp10 + tmp3);
      dptr[7 << 3]      = INTER_FIXED_TO_INT(tmp10 - tmp3);
      dptr[1 << 3]      = INTER_FIXED_TO_INT(tmp11 + tmp2);
      dptr[6 << 3]      = INTER_FIXED_TO_INT(tmp11 - tmp2);
      dptr[2 << 3]      = INTER_FIXED_TO_INT(tmp12 + tmp1);
      dptr[5 << 3]      = INTER_FIXED_TO_INT(tmp12 - tmp1);
      dptr[3 << 3]      = INTER_FIXED_TO_INT(tmp13 + tmp0);
      dptr[4 << 3]      = INTER_FIXED_TO_INT(tmp13 - tmp0);
    }
  } else {
    memset(target,0,sizeof(LONG) * 64);
  }
}
コード例 #2
0
void IDCT<preshift,T,deadzone,optimize>::TransformBlock(const LONG *source,LONG *target,LONG dcoffset)
{ 
  LONG *dpend,*dp;
  const LONG *qp = m_plInvQuant; 
  int band = 0;
  //
  // Adjust the DC offset to the number of fractional bits.
  dcoffset <<= preshift + 3 + 3 + INTERMEDIATE_BITS; 
  // three additional bits because we still need to divide by 8.
  //
  // Pass over columns.
  for(dp = target,dpend = target + 8;dp < dpend;dp++,source++) {
    T tmp0    = source[0 << 3] + source[7 << 3];
    T tmp1    = source[1 << 3] + source[6 << 3];
    T tmp2    = source[2 << 3] + source[5 << 3];
    T tmp3    = source[3 << 3] + source[4 << 3];
    T tmp10   = tmp0      + tmp3;
    T tmp12   = tmp0      - tmp3;
    T tmp11   = tmp1      + tmp2;
    T tmp13   = tmp1      - tmp2;
    
    tmp0      = source[0 << 3] - source[7 << 3];
    tmp1      = source[1 << 3] - source[6 << 3];
    tmp2      = source[2 << 3] - source[5 << 3];
    tmp3      = source[3 << 3] - source[4 << 3];

    // complete DC and middle band.
    dp[0 << 3] = (tmp10 + tmp11) << INTERMEDIATE_BITS;
    dp[4 << 3] = (tmp10 - tmp11) << INTERMEDIATE_BITS;

    FIXED   z1 = (tmp12 + tmp13) * TO_FIX(0.541196100);

    // complete bands 2 and 6
    dp[2 << 3] = FIXED_TO_INTERMEDIATE(z1 + tmp12 * TO_FIX(0.765366865));
    dp[6 << 3] = FIXED_TO_INTERMEDIATE(z1 + tmp13 *-TO_FIX(1.847759065));

    
    tmp10      = tmp0 + tmp3;
    tmp11      = tmp1 + tmp2;
    tmp12      = tmp0 + tmp2;
    tmp13      = tmp1 + tmp3;
    z1         = (tmp12 + tmp13) * TO_FIX(1.175875602);

    FIXED ttmp0  = tmp0  * TO_FIX(1.501321110);
    FIXED ttmp1  = tmp1  * TO_FIX(3.072711026);
    FIXED ttmp2  = tmp2  * TO_FIX(2.053119869);
    FIXED ttmp3  = tmp3  * TO_FIX(0.298631336);
    FIXED ttmp10 = tmp10 *-TO_FIX(0.899976223);
    FIXED ttmp11 = tmp11 *-TO_FIX(2.562915447);
    FIXED ttmp12 = tmp12 *-TO_FIX(0.390180644) + z1;
    FIXED ttmp13 = tmp13 *-TO_FIX(1.961570560) + z1;

    dp[1 << 3]   = FIXED_TO_INTERMEDIATE(ttmp0 + ttmp10 + ttmp12);
    dp[3 << 3]   = FIXED_TO_INTERMEDIATE(ttmp1 + ttmp11 + ttmp13);
    dp[5 << 3]   = FIXED_TO_INTERMEDIATE(ttmp2 + ttmp11 + ttmp12);
    dp[7 << 3]   = FIXED_TO_INTERMEDIATE(ttmp3 + ttmp10 + ttmp13);
  }
  //
  // Pass over rows and quantize.
  for(dp = target,dpend = target + (8 << 3);dp < dpend;dp += 8,qp += 8) { 
    INTER tmp0         = dp[0] + dp[7];
    INTER tmp1         = dp[1] + dp[6];
    INTER tmp2         = dp[2] + dp[5];
    INTER tmp3         = dp[3] + dp[4];
    INTER tmp10        = tmp0  + tmp3;
    INTER tmp12        = tmp0  - tmp3;
    INTER tmp11        = tmp1  + tmp2;
    INTER tmp13        = tmp1  - tmp2;
    
    tmp0               = dp[0] - dp[7];
    tmp1               = dp[1] - dp[6];
    tmp2               = dp[2] - dp[5];
    tmp3               = dp[3] - dp[4];

    // complete DC and middle band.
    dp[0]              = Quantize((tmp10 + tmp11 - dcoffset) << FIX_BITS,qp[0],band);
    dp[4]              = Quantize((tmp10 - tmp11) << FIX_BITS           ,qp[4],band+4);
    
    INTER_FIXED z1     = (tmp12 + tmp13) * TO_FIX(0.541196100);

    // complete bands 2 and 6
    dp[2]              = Quantize(z1 + tmp12 * TO_FIX(0.765366865),qp[2],band+2);
    dp[6]              = Quantize(z1 + tmp13 *-TO_FIX(1.847759065),qp[6],band+6);

    tmp10              = tmp0 + tmp3;
    tmp11              = tmp1 + tmp2;
    tmp12              = tmp0 + tmp2;
    tmp13              = tmp1 + tmp3;
    z1                 = (tmp12 + tmp13) * TO_FIX(1.175875602);

    INTER_FIXED ttmp0  = tmp0  * TO_FIX(1.501321110);
    INTER_FIXED ttmp1  = tmp1  * TO_FIX(3.072711026);
    INTER_FIXED ttmp2  = tmp2  * TO_FIX(2.053119869);
    INTER_FIXED ttmp3  = tmp3  * TO_FIX(0.298631336);
    INTER_FIXED ttmp10 = tmp10 *-TO_FIX(0.899976223);
    INTER_FIXED ttmp11 = tmp11 *-TO_FIX(2.562915447);
    INTER_FIXED ttmp12 = tmp12 *-TO_FIX(0.390180644) + z1;
    INTER_FIXED ttmp13 = tmp13 *-TO_FIX(1.961570560) + z1;

    dp[1]              = Quantize(ttmp0 + ttmp10 + ttmp12,qp[1],band+1);
    dp[3]              = Quantize(ttmp1 + ttmp11 + ttmp13,qp[3],band+3);
    dp[5]              = Quantize(ttmp2 + ttmp11 + ttmp12,qp[5],band+5);
    dp[7]              = Quantize(ttmp3 + ttmp10 + ttmp13,qp[7],band+7);
    dcoffset           = 0;
    band              += 8;
  }
}
コード例 #3
0
/// EncodeC
void EncodeC(const char *source,const char *ldrsource,const char *target,const char *ltable,
             int quality,int hdrquality,
             int tabletype,int residualtt,int maxerror,
             int colortrafo,bool lossless,bool progressive,
             bool residual,bool optimize,bool accoding,
             bool rsequential,bool rprogressive,bool raccoding,
             bool qscan,UBYTE levels,bool pyramidal,bool writednl,UWORD restart,double gamma,
             int lsmode,bool noiseshaping,bool serms,bool losslessdct,
             bool openloop,bool deadzone,bool lagrangian,bool dering,
             bool xyz,bool cxyz,
             int hiddenbits,int riddenbits,int resprec,bool separate,
             bool median,bool noclamp,int smooth,
             bool dctbypass,
             const char *sub,const char *ressub,
             const char *alpha,int alphamode,int matte_r,int matte_g,int matte_b,
             bool alpharesiduals,int alphaquality,int alphahdrquality,
             int alphatt,int residualalphatt,
             int ahiddenbits,int ariddenbits,int aresprec,
             bool aopenloop,bool adeadzone,bool alagrangian,bool adering,
             bool aserms,bool abypass)
{ 
  struct JPG_TagItem pscan1[] = { // standard progressive scan, first scan.
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,0),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,1),
    JPG_EndTag
  };
  struct JPG_TagItem pscan2[] = {
    JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,1),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,5),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,2), 
    JPG_EndTag
  };
  struct JPG_TagItem pscan3[] = {
    JPG_ValueTag(JPGTAG_SCAN_COMPONENTS_CHROMA,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,1),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,63),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,1),
    JPG_EndTag
  };
  struct JPG_TagItem pscan4[] = {
    JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0), 
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,6),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,63),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,2),
    JPG_EndTag
  }; 
  struct JPG_TagItem pscan5[] = {
    JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0), 
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,1),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,63),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,1),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,2),
    JPG_EndTag
  };  
  struct JPG_TagItem pscan6[] = {
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,0),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,0),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,1),
    JPG_EndTag
  };
  struct JPG_TagItem pscan7[] = {
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,1),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,63),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,0),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,1),
    JPG_EndTag
  };

  struct JPG_TagItem qscan1[] = { // quick progresssive scan, separates only DC from AC
    JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0), 
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,0),
    JPG_EndTag
  };
  struct JPG_TagItem qscan2[] = { // quick progresssive scan, separates only DC from AC
    JPG_ValueTag(JPGTAG_SCAN_COMPONENTS_CHROMA,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,0),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,0),
    JPG_EndTag
  };
  struct JPG_TagItem qscan3[] = {
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_START,1),
    JPG_ValueTag(JPGTAG_SCAN_SPECTRUM_STOP,63),
    JPG_EndTag
  };

  struct JPG_TagItem rscan1[] = { // residual progressive scan, first scan.
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,6),
    JPG_EndTag
  };
  struct JPG_TagItem rscan2[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,5),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,6),
    JPG_EndTag
  }; 
  struct JPG_TagItem rscan3[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,4),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,5),
    JPG_EndTag
  }; 
  struct JPG_TagItem rscan4[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,3),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,4),
    JPG_EndTag
  }; 
  struct JPG_TagItem rscan5[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,2),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,3),
    JPG_EndTag
  }; 
  struct JPG_TagItem rscan6[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,1),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,2),
    JPG_EndTag
  }; 
  struct JPG_TagItem rscan7[] = {
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_LO,0),
    JPG_ValueTag(JPGTAG_SCAN_APPROXIMATION_HI,1),
    JPG_EndTag
  }; 
  //
  //
  //
  UWORD ldrtohdr[65536]; // The tone mapping curve. Currently, only one.
  UWORD red[65536],green[65536],blue[65536];
  UWORD hdrtoldr[65536]; // Its inverse. This table is used to construct the legacy image.
  UWORD alphaldrtohdr[65536]; // the TMO for alpha (if required)
  const UWORD *tonemapping = NULL; // points to the above if used.
  UBYTE subx[4],suby[4];
  UBYTE ressubx[4],ressuby[4];
  memset(subx,1,sizeof(subx));
  memset(suby,1,sizeof(suby));
  memset(ressubx,1,sizeof(ressubx));
  memset(ressuby,1,sizeof(ressuby));

  if (sub) {
    ParseSubsamplingFactors(subx,suby,sub,4);
  }
  if (ressub) {
    ParseSubsamplingFactors(ressubx,ressuby,ressub,4);
  }

  {
    int width,height,depth,prec;
    int alphaprec   = 0;
    bool flt       = false;
    bool alphaflt  = false;
    bool big       = false;
    bool alphabig  = false;
    bool fullrange = false;
    FILE *ldrin    = NULL;
    FILE *alphain  = NULL;
    FILE *in       = OpenPNMFile(source,width,height,depth,prec,flt,big);
    if (in) {
      if (ldrsource) {
        int ldrdepth  = 0;
        int ldrwidth  = 0;
        int ldrheight = 0;      
        int ldrprec;
        bool ldrflt;
        bool ldrbig;
        ldrin = OpenPNMFile(ldrsource,ldrwidth,ldrheight,ldrdepth,ldrprec,ldrflt,ldrbig);
        //
        if (ldrin) {
          if (ldrflt) {
            fprintf(stderr,"%s is a floating point image, but the LDR image must be 8 bits/sample\n",
                    ldrsource);
            ldrdepth = 0;
          }
          if (ldrdepth != depth) {
            fprintf(stderr,"The number of components of %s and %s do not match\n",
                    source,ldrsource);
            ldrdepth = 0;
          }
          if (ldrprec != 8) {
            fprintf(stderr,"unsuitable format for LDR images, must be binary PPM with eight bits/component.\n");
            ldrdepth = 0;
          }
          if (ldrwidth != width || ldrheight != height) {
            fprintf(stderr,"The image dimensions of %s and %s do not match\n",
                    source,ldrsource);
            ldrdepth = 0;
          }
          if (ldrdepth == 0) {
            fprintf(stderr,"LDR image unsuitable, will not be used.\n");
            if (ldrin) 
              fclose(ldrin);
            ldrin = NULL;
          }
        }
      }
      //
      // Create the tone mapping curve if gamma != 1.0
      if ((gamma != 1.0 && residual && prec != 8) || hiddenbits || ltable || ldrin) {
        if (ltable != NULL) {
          LoadLTable(ltable,ldrtohdr,flt,(1L << prec) - 1,hiddenbits);
          if (separate)
            printf("Warning: -sp switch ignored, only one TMO will be used");
          separate = false;
        } else {
          if (gamma <= 0.0) {
            if (ldrin != NULL) {
              if (separate) {
                BuildRGBToneMappingFromLDR(in,ldrin,width,height,prec,depth,
                                           red,green,blue,flt,big,xyz || cxyz,hiddenbits,
                                           median,fullrange,smooth);
              } else {
                BuildToneMappingFromLDR(in,ldrin,width,height,prec,depth,
                                        ldrtohdr,flt,big,xyz || cxyz,hiddenbits,
                                        median,fullrange,smooth);
              }
              if (hiddenbits)
                printf("\n"
                       "Warning: If refinement coding is used, the LDR image will only\n"
                       "be used to create a tone mapping function, but the LDR image\n"
                       "itself will not be stored in the legacy codestream.\n\n");
            } else {
              if (separate)
                printf("Warning: -sp switch ignored, only one TMO will be used");
              separate = false; // Still to be done.
              BuildToneMapping_C(in,width,height,prec,depth,ldrtohdr,flt,big,xyz || cxyz,hiddenbits);
            }
          } else {
            BuildGammaMapping(gamma,1.0,ldrtohdr,flt,(1L << prec) - 1,hiddenbits);
            if (separate)
              printf("Warning: -sp switch ignored, only one TMO will be used");
            separate = false; // Still to be done.
          }
        }
        tonemapping = ldrtohdr;
      }
      //
      if (fullrange) {
        if (lossless || hdrquality >= 100 || dctbypass) {
          fullrange = false;
        } else {
          printf("Found overly large differentials, adding additional scaling step.\n");
        }
      }
      //
      // Automatically disable clamping.
      if (lossless || hdrquality >= 100)
        noclamp = true;
      //
      // Check for the alpha channel.
      if (alpha) { 
        alphain = PrepareAlphaForRead(alpha,width,height,alphaprec,alphaflt,alphabig,
                                      alpharesiduals,ahiddenbits,alphaldrtohdr);
      }
      // Construct the forwards tonemapping curve from inverting the
      // inverse. (-: But first check whether there is an inverse table.
      // If not, build one.
      if (residual || hiddenbits || ltable || ldrin) {
        if (tonemapping == NULL) {
          if (hiddenbits)
            fprintf(stderr,
                    "Warning: Suggested to use automatic tone mapping (-g 0)\n"
                    "instead of a gamma=1.0 value\n");
          BuildGammaMapping(1.0,1.0,ldrtohdr,flt,(1L << prec) - 1,hiddenbits);
          if (separate)
            printf("Warning: -sp switch ignored, only one TMO will be used");
          separate = false; 
        }
        // Now build the inverse.
        InvertTable(ldrtohdr,hdrtoldr,8 + hiddenbits,prec);
      }
      //
      FILE *out = fopen(target,"wb");
      if (out) { 
        int frametype = JPGFLAG_SEQUENTIAL;
        int residualtype = JPGFLAG_RESIDUAL;
        int aframetype;
        int arestype;
        if (lossless) {
          frametype = JPGFLAG_LOSSLESS;
        } else if (progressive) {
          frametype = JPGFLAG_PROGRESSIVE;
        } else if (lsmode >=0) {
          frametype = JPGFLAG_JPEG_LS;
        }
        if (residual)
          frametype |= JPGFLAG_RESIDUAL_CODING;
        if (optimize)
          frametype |= JPGFLAG_OPTIMIZE_HUFFMAN;
        if (accoding)
          frametype |= JPGFLAG_ARITHMETIC;
        if (pyramidal)
          frametype |= JPGFLAG_PYRAMIDAL;
        if (losslessdct)
          residualtype  = JPGFLAG_RESIDUALDCT;
        if (!lossless && !losslessdct && hdrquality < 100)
          residualtype  = JPGFLAG_SEQUENTIAL;
        if (rsequential && !lossless && hdrquality < 100)
          residualtype  = JPGFLAG_SEQUENTIAL;
        if (rprogressive && !lossless && hdrquality < 100)
          residualtype  = JPGFLAG_PROGRESSIVE;
        if (dctbypass)
          residualtype  = JPGFLAG_RESIDUAL;
        if (residualtype == JPGFLAG_RESIDUAL && rprogressive)
          residualtype  = JPGFLAG_RESIDUALPROGRESSIVE;
        if (raccoding)
          residualtype |= JPGFLAG_ARITHMETIC;
        if (depth == 1)
          colortrafo = JPGFLAG_MATRIX_COLORTRANSFORMATION_NONE;

        aframetype = frametype & (~JPGFLAG_RESIDUAL_CODING);
        if (alpharesiduals)
          aframetype |= JPGFLAG_RESIDUAL_CODING;
        
        arestype = residualtype;
        
        if (alphahdrquality >= 100) {
          if (rprogressive) {
            arestype = JPGFLAG_RESIDUALPROGRESSIVE;
          } else {
            arestype = JPGFLAG_RESIDUAL;
          }
        } else if (abypass) {
          arestype = JPGFLAG_RESIDUAL;
        }
        if (raccoding)
          arestype |= JPGFLAG_ARITHMETIC;
        
        {                 
          int ok = 1;
          struct BitmapMemory bmm;
          struct JPG_Hook bmhook(BitmapHook,&bmm);
          struct JPG_Hook ldrhook(LDRBitmapHook,&bmm);
          struct JPG_Hook alphahook(AlphaHook,&bmm);
          //
          // Generate the taglist for alpa, even if we don't need it.
          struct JPG_TagItem alphatags[] = {
            JPG_ValueTag(JPGTAG_IMAGE_PRECISION,alphaprec),
            // currently, make the frame types the same as the image
            // can be changed later.
            JPG_ValueTag(JPGTAG_IMAGE_FRAMETYPE,aframetype), 
            JPG_ValueTag(JPGTAG_RESIDUAL_FRAMETYPE,arestype),
            JPG_ValueTag((alphaquality >= 0)?JPGTAG_IMAGE_QUALITY:JPGTAG_TAG_IGNORE,alphaquality),
            JPG_ValueTag((alphahdrquality >= 0)?JPGTAG_RESIDUAL_QUALITY:JPGTAG_TAG_IGNORE,
                         alphahdrquality),
            JPG_ValueTag(JPGTAG_QUANTIZATION_MATRIX,alphatt),
            JPG_ValueTag(JPGTAG_RESIDUALQUANT_MATRIX,residualalphatt),
            JPG_ValueTag(JPGTAG_IMAGE_RESOLUTIONLEVELS,levels),
            JPG_ValueTag(JPGTAG_IMAGE_WRITE_DNL,writednl),
            JPG_ValueTag(JPGTAG_IMAGE_RESTART_INTERVAL,restart),
            JPG_ValueTag(JPGTAG_IMAGE_ENABLE_NOISESHAPING,noiseshaping),
            JPG_ValueTag(JPGTAG_IMAGE_HIDDEN_DCTBITS,ahiddenbits),
            JPG_ValueTag(JPGTAG_RESIDUAL_HIDDEN_DCTBITS,ariddenbits),
            JPG_ValueTag(JPGTAG_IMAGE_LOSSLESSDCT,aserms),
            JPG_ValueTag((alphahdrquality >= 100)?JPGTAG_RESIDUAL_DCT:JPGTAG_TAG_IGNORE,losslessdct),
            JPG_ValueTag(JPGTAG_OPENLOOP_ENCODER,aopenloop),
            JPG_ValueTag(JPGTAG_DEADZONE_QUANTIZER,adeadzone),
            JPG_ValueTag(JPGTAG_OPTIMIZE_QUANTIZER,alagrangian),
            JPG_ValueTag(JPGTAG_IMAGE_DERINGING,adering),
            JPG_ValueTag(JPGTAG_ALPHA_MODE,alphamode),
            JPG_ValueTag(JPGTAG_ALPHA_MATTE(0),matte_r),
            JPG_ValueTag(JPGTAG_ALPHA_MATTE(1),matte_g),
            JPG_ValueTag(JPGTAG_ALPHA_MATTE(2),matte_b),
            JPG_ValueTag(JPGTAG_RESIDUAL_PRECISION,aresprec),
            // Use a LUT in case we must be lossless.
            JPG_PointerTag((alpharesiduals && (residualtype == JPGFLAG_RESIDUALDCT ||
                                               residualtype == JPGFLAG_RESIDUAL    ||
                                               residualtype == JPGFLAG_RESIDUALPROGRESSIVE))?
                           JPGTAG_TONEMAPPING_L_LUT(0):JPGTAG_TAG_IGNORE,alphaldrtohdr),
            // Ditto. Use linear scaling otherwise.
            JPG_ValueTag(alpharesiduals?JPGTAG_TONEMAPPING_L_TYPE(0):JPGTAG_TAG_IGNORE,
                         (residualtype == JPGFLAG_RESIDUALDCT ||
                          residualtype == JPGFLAG_RESIDUAL    ||
                          residualtype == JPGFLAG_RESIDUALPROGRESSIVE)?
                         JPGFLAG_TONEMAPPING_LUT:JPGFLAG_TONEMAPPING_IDENTITY),
            // Define the scan parameters for progressive.
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan1):(pscan1)),
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan2):(pscan2)),
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan3):(pscan3)),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan4),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan5),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan6),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan7),
            
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan1:pscan1),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan2:pscan2),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan3:pscan3),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan4:pscan4),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan5:pscan5),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan6:pscan6),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan7:pscan7),
            JPG_ValueTag(JPGTAG_IMAGE_IS_FLOAT,alphaflt),
            JPG_ValueTag(JPGTAG_IMAGE_OUTPUT_CONVERSION,alphaflt),
            JPG_EndTag
          };
          //
          struct JPG_TagItem tags[] = {
            JPG_PointerTag(JPGTAG_BIH_HOOK,&bmhook),
            JPG_PointerTag((alpha)?JPGTAG_BIH_ALPHAHOOK:JPGTAG_TAG_IGNORE,&alphahook),
            JPG_PointerTag((residual && hiddenbits == 0 && ldrin)?JPGTAG_BIH_LDRHOOK:JPGTAG_TAG_IGNORE,&ldrhook),
            JPG_ValueTag(JPGTAG_ENCODER_LOOP_ON_INCOMPLETE,true),
            JPG_ValueTag(JPGTAG_IMAGE_WIDTH,width), 
            JPG_ValueTag(JPGTAG_IMAGE_HEIGHT,height), 
            JPG_ValueTag(JPGTAG_IMAGE_DEPTH,depth),      
            JPG_ValueTag(JPGTAG_IMAGE_PRECISION,prec),
            JPG_ValueTag(JPGTAG_IMAGE_FRAMETYPE,frametype),
            JPG_ValueTag(JPGTAG_RESIDUAL_FRAMETYPE,residualtype),
            JPG_ValueTag((quality >= 0)?JPGTAG_IMAGE_QUALITY:JPGTAG_TAG_IGNORE,quality),
            JPG_ValueTag((hdrquality >= 0)?JPGTAG_RESIDUAL_QUALITY:JPGTAG_TAG_IGNORE,
                         hdrquality),
            JPG_ValueTag(JPGTAG_QUANTIZATION_MATRIX,tabletype),
            JPG_ValueTag(JPGTAG_RESIDUALQUANT_MATRIX,residualtt),
            JPG_ValueTag(JPGTAG_IMAGE_ERRORBOUND,maxerror),
            JPG_ValueTag(JPGTAG_IMAGE_RESOLUTIONLEVELS,levels),
            JPG_ValueTag(JPGTAG_MATRIX_LTRAFO,xyz?JPGFLAG_MATRIX_COLORTRANSFORMATION_FREEFORM:colortrafo),
            JPG_ValueTag((xyz && hdrquality < 100)?JPGTAG_MATRIX_RTRAFO:JPGTAG_TAG_IGNORE,
                         JPGFLAG_MATRIX_COLORTRANSFORMATION_FREEFORM),
            JPG_ValueTag(JPGTAG_IMAGE_WRITE_DNL,writednl),
            JPG_ValueTag(JPGTAG_IMAGE_RESTART_INTERVAL,restart),
            JPG_ValueTag(JPGTAG_IMAGE_ENABLE_NOISESHAPING,noiseshaping),
            JPG_ValueTag(JPGTAG_IMAGE_HIDDEN_DCTBITS,hiddenbits),
            JPG_ValueTag(JPGTAG_RESIDUAL_HIDDEN_DCTBITS,riddenbits),
            JPG_ValueTag(JPGTAG_IMAGE_LOSSLESSDCT,serms),
            JPG_ValueTag((hdrquality >= 100)?JPGTAG_RESIDUAL_DCT:JPGTAG_TAG_IGNORE,losslessdct),
            JPG_PointerTag(JPGTAG_IMAGE_SUBX,subx),
            JPG_PointerTag(JPGTAG_IMAGE_SUBY,suby),
            JPG_PointerTag(JPGTAG_RESIDUAL_SUBX,ressubx),
            JPG_PointerTag(JPGTAG_RESIDUAL_SUBY,ressuby),
            JPG_ValueTag(JPGTAG_OPENLOOP_ENCODER,openloop),
            JPG_ValueTag(JPGTAG_DEADZONE_QUANTIZER,deadzone),
            JPG_ValueTag(JPGTAG_OPTIMIZE_QUANTIZER,lagrangian),
            JPG_ValueTag(JPGTAG_IMAGE_DERINGING,dering),
            JPG_ValueTag(JPGTAG_RESIDUAL_PRECISION,resprec),
            // The RGB2XYZ transformation matrix, used as L-transformation if the xyz flag is true.
            // this is the product of the 601->RGB and RGB->XYZ matrix
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(0,0),TO_FIX(0.95047000)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(1,0),TO_FIX(0.1966803389)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(2,0),TO_FIX(0.3229058048)),
            
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(0,1),TO_FIX(1.00000010)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(1,1),TO_FIX(-0.1182157221)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(2,1),TO_FIX(-0.2125487302)),
            
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(0,2),TO_FIX(1.08883000)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(1,2),TO_FIX(1.642920573)),
            JPG_ValueTag(JPGTAG_MATRIX_LMATRIX(2,2),TO_FIX(-0.05801320439)),    
            //
            // Same for R, potentially ignored.
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(0,0),TO_FIX(0.95047000)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(1,0),TO_FIX(0.1966803389)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(2,0),TO_FIX(0.3229058048)),
            
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(0,1),TO_FIX(1.00000010)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(1,1),TO_FIX(-0.1182157221)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(2,1),TO_FIX(-0.2125487302)),
            
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(0,2),TO_FIX(1.08883000)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(1,2),TO_FIX(1.642920573)),
            JPG_ValueTag(JPGTAG_MATRIX_RMATRIX(2,2),TO_FIX(-0.05801320439)),
            //
            // If XYZ encoding is done by the C-transformation, enter the transformation matrix from
            // RGB to XYZ here.
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(0,0)):JPGTAG_TAG_IGNORE,TO_FIX(0.4124564)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(1,0)):JPGTAG_TAG_IGNORE,TO_FIX(0.3575761)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(2,0)):JPGTAG_TAG_IGNORE,TO_FIX(0.1804375)),
            
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(0,1)):JPGTAG_TAG_IGNORE,TO_FIX(0.2126729)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(1,1)):JPGTAG_TAG_IGNORE,TO_FIX(0.7151522)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(2,1)):JPGTAG_TAG_IGNORE,TO_FIX(0.0721750)),
            
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(0,2)):JPGTAG_TAG_IGNORE,TO_FIX(0.0193339)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(1,2)):JPGTAG_TAG_IGNORE,TO_FIX(0.1191920)),
            JPG_ValueTag((cxyz)?(JPGTAG_MATRIX_CMATRIX(2,2)):JPGTAG_TAG_IGNORE,TO_FIX(0.9503041)),
            
            JPG_PointerTag((tonemapping)?(JPGTAG_TONEMAPPING_L_LUT(0)):JPGTAG_TAG_IGNORE,
                           const_cast<UWORD *>(separate?red:tonemapping)),
            JPG_PointerTag((tonemapping && depth > 1)?(JPGTAG_TONEMAPPING_L_LUT(1)):JPGTAG_TAG_IGNORE,
                           const_cast<UWORD *>(separate?green:tonemapping)),
            JPG_PointerTag((tonemapping && depth > 2)?(JPGTAG_TONEMAPPING_L_LUT(2)):JPGTAG_TAG_IGNORE,
                           const_cast<UWORD *>(separate?blue:tonemapping)),
            JPG_ValueTag((tonemapping)?(JPGTAG_TONEMAPPING_L_TYPE(0)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LUT),
            JPG_ValueTag((tonemapping && depth > 1)?(JPGTAG_TONEMAPPING_L_TYPE(1)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LUT),
            JPG_ValueTag((tonemapping && depth > 2)?(JPGTAG_TONEMAPPING_L_TYPE(2)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LUT),
            JPG_ValueTag((fullrange)?(JPGTAG_TONEMAPPING_R2_TYPE(0)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LINEAR),
            JPG_ValueTag((fullrange)?(JPGTAG_TONEMAPPING_R2_TYPE(1)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LINEAR),
            JPG_ValueTag((fullrange)?(JPGTAG_TONEMAPPING_R2_TYPE(2)):JPGTAG_TAG_IGNORE,
                         JPGFLAG_TONEMAPPING_LINEAR), 
            // The default settings for R2 in profile C are quite ok.
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan1):(pscan1)),
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan2):(pscan2)),
            JPG_PointerTag((progressive)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,(qscan)?(qscan3):(pscan3)),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan4),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan5),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan6),
            JPG_PointerTag((progressive && !qscan)?JPGTAG_IMAGE_SCAN:JPGTAG_TAG_IGNORE,pscan7),
            
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan1:pscan1),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan2:pscan2),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan3:pscan3),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan4:pscan4),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan5:pscan5),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan6:pscan6),
            JPG_PointerTag((rprogressive)?JPGTAG_RESIDUAL_SCAN:JPGTAG_TAG_IGNORE,
                           ((residualtype & 7) == JPGFLAG_RESIDUALPROGRESSIVE)?rscan7:pscan7),
            JPG_ValueTag((lsmode >= 0)?JPGTAG_SCAN_LS_INTERLEAVING:JPGTAG_TAG_IGNORE,lsmode),
            JPG_ValueTag(JPGTAG_IMAGE_IS_FLOAT,flt),
            JPG_ValueTag(JPGTAG_IMAGE_OUTPUT_CONVERSION,flt),
            JPG_PointerTag(alphain?JPGTAG_ALPHA_TAGLIST:JPGTAG_TAG_IGNORE,alphatags),
            JPG_EndTag
          };
          
          class JPEG *jpeg = JPEG::Construct(NULL);
          if (jpeg) {
            UBYTE bytesperpixel = sizeof(UBYTE);
            UBYTE pixeltype     = CTYP_UBYTE;
            if (prec > 8) {
              bytesperpixel = sizeof(UWORD);
              pixeltype     = CTYP_UWORD;
            }
            
            UBYTE *mem      = (UBYTE *)malloc(width * 8 * depth * bytesperpixel + width * 8 * depth);
            UBYTE *alphamem = NULL;
            if (mem) {
              bmm.bmm_pMemPtr      = mem + width * 8 * depth;
              bmm.bmm_pLDRMemPtr   = ldrin?mem:NULL;
              bmm.bmm_ulWidth      = width;
              bmm.bmm_ulHeight     = height;
              bmm.bmm_usDepth      = depth;
              bmm.bmm_ucPixelType  = pixeltype;
              bmm.bmm_pTarget      = NULL;
              bmm.bmm_pAlphaPtr    = NULL;
              bmm.bmm_pAlphaTarget = NULL;
              bmm.bmm_pAlphaSource = NULL;
              bmm.bmm_pSource      = in;
              bmm.bmm_pAlphaSource = NULL;
              bmm.bmm_pAlphaTarget = NULL;
              bmm.bmm_pLDRSource   = ldrin;
              bmm.bmm_bFloat       = flt;
              bmm.bmm_bBigEndian   = big;
              bmm.bmm_HDR2LDR      = hdrtoldr;
              bmm.bmm_bNoOutputConversion = false;
              bmm.bmm_bClamp       = !noclamp;
              //
              // Create the buffer for the alpha channel.
              if (alphain) {
                UBYTE alphabytesperpixel = sizeof(UBYTE);
                UBYTE alphapixeltype     = CTYP_UBYTE;
                if (alphaprec > 8) {
                  alphabytesperpixel = sizeof(UWORD);
                  alphapixeltype     = CTYP_UWORD;
                }
                alphamem = (UBYTE *)malloc(width * 8 * alphabytesperpixel + width * 8);
                if (alphamem) {
                  bmm.bmm_pAlphaPtr    = alphamem + width * 8;
                  bmm.bmm_ucAlphaType  = alphapixeltype;
                  bmm.bmm_pAlphaSource = alphain;
                  bmm.bmm_bAlphaFloat  = alphaflt;
                  bmm.bmm_bAlphaBigEndian          = alphabig;
                  bmm.bmm_bNoAlphaOutputConversion = false;
                  bmm.bmm_bAlphaClamp      = !noclamp;
                }
              }
              //
              // Ready to go?
              if (alphain == NULL || alphamem) {
                // Push the image into the frame. We could
                // get away with writing the image as it is
                // pushed into the image, but then only a single
                // scan is allowed. 
                ok = jpeg->ProvideImage(tags);
                
                if (ok) {
                  struct JPG_Hook filehook(FileHook,out);
                  struct JPG_TagItem iotags[] = {
                    JPG_PointerTag(JPGTAG_HOOK_IOHOOK,&filehook),
                    JPG_PointerTag(JPGTAG_HOOK_IOSTREAM,out),
                    JPG_EndTag
                  };
                  
                  //
                  // Write in one go, could interrupt this on each frame,scan,line or MCU.
                  ok = jpeg->Write(iotags);
                }
                if (!ok) {
                  const char *error;
                  int code = jpeg->LastError(error);
                  fprintf(stderr,"writing a JPEG file failed - error %d - %s\n",code,error);
                }
                if (alphamem)
                  free(alphamem);
              } else {
                fprintf(stderr,"failed allocating a buffer for the alpha channel\n");
              }
              free(mem);
            } else {
              fprintf(stderr,"failed allocating a buffer for the image\n");
            }
            JPEG::Destruct(jpeg);
          } else {
            fprintf(stderr,"failed to create a JPEG object\n");
          }
        }
        fclose(out);
      } else {
        perror("unable to open the output file");
      }
      if (alphain)
        fclose(alphain);
      if (ldrin)
        fclose(ldrin);
      fclose(in);
    }
  }
}