Ejemplo n.º 1
0
/// Frame::InstallDefaultParameters
// Define default scan parameters. Returns the scan for further refinement if required.
class Scan *Frame::InstallDefaultParameters(ULONG width,ULONG height,UBYTE depth,UBYTE prec,
					    bool writednl,const UBYTE *psubx,const UBYTE *psuby,
					    const struct JPG_TagItem *tags)
{
  int i;
  
  if (m_pScan || m_ucDepth != 0 || m_ucPrecision != 0)
    JPG_THROW(OBJECT_EXISTS,"Frame::InstallDefaultScanParameters","the scan has already been installed");

  if (width > MAX_UWORD)
    JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultScanParameters","image dimensions must be < 65536");
  m_ulWidth = width;

  if (height > MAX_UWORD)
    JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultScanParameters","image dimensions must be < 65535");
  m_ulHeight = height;

  if (depth < 1 || depth > 4)
    JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultScanParameters","image depth must be between 1 and 4");
  m_ucDepth     = depth;
  //
  // Potentially clamp the precision to be in range. Only for the DCT operations.
  m_ucPrecision = prec;
  //
  // Check the validity of the precision.
  switch(m_Type) {
  case Baseline:
  case Sequential:
  case Progressive:
  case DifferentialSequential:
  case DifferentialProgressive:
  case ACSequential:
  case ACProgressive:
  case ACDifferentialSequential:
  case ACDifferentialProgressive:
    //
    if (m_ucPrecision != 8 && m_ucPrecision != 12)
      JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultScanParameters","image precision must be 8 or 12");
    break;
  default: // lossless
    if (m_ucPrecision < 2 || m_ucPrecision > 16)
      JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultScanParameters","image precision must be between 2 and 16");
    break;
  }
  m_bWriteDNL   = writednl;
  //
  //
  // Define the components. This call here does not support subsampling.
  for(i = 0;i < m_ucDepth;i++) {
    // Get subsampling parameters
    UBYTE sx = (psubx)?(*psubx++):(1);
    UBYTE sy = (psuby)?(*psuby++):(1);
    //
    // End of the array - fall back to one.
    if (sx == 0) {
      sx = 1;psubx = NULL;
    }
    if (sy == 0) {
      sy = 1;psuby = NULL;
    }
    //
    class Component *comp = DefineComponent(i,sx,sy);
    comp->SetComponentID(i);        // simple 1-1 mapping.
    if (m_pTables->UseColortrafo()) {
      comp->SetQuantizer(i == 0?0:1); // one lume and one chroma quantizer
    } else {
      comp->SetQuantizer(0);          // only one quantizer
    }
  }

  ComputeMCUSizes();

  assert(m_pScan == NULL);

  // If this is only the DHP marker segment, do not create a scan.
  if (m_Type == Dimensions)
    return NULL;
  
  if (m_Type == Progressive             || 
      m_Type == ACProgressive           ||
      m_Type == DifferentialProgressive || 
      m_Type == ACDifferentialProgressive) {
    if (m_ucDepth > 4)
      JPG_THROW(OVERFLOW_PARAMETER,"Frame::InstallDefaultParameters",
		"progressive mode allows only up to four components");
    //
    while(tags && (tags = tags->FindTagItem(JPGTAG_IMAGE_SCAN))) {
      const struct JPG_TagItem *scantags = (struct JPG_TagItem *)(tags->ti_Data.ti_pPtr);
      if (scantags) {
	if (scantags->FindTagItem(JPGTAG_SCAN_COMPONENTS_CHROMA)) {
	  // This actually creates a group of tags if the spectral selection contains
	  // AC bands.
	  if (m_ucDepth > 1) {
	    if (scantags->GetTagData(JPGTAG_SCAN_SPECTRUM_START) > 0) {
	      UBYTE i;
	      struct JPG_TagItem ctags[] = {
		JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0),
		JPG_Continue(scantags)
	      };
	      for(i = 1; i < m_ucDepth;i++) {
		class Scan *scan = new(m_pEnviron) class Scan(this);
		if (m_pScan == NULL) {
		  m_pScan = scan;
		} else {
		  m_pLast->TagOn(scan);
		}
		m_pLast = scan;
		ctags[0].ti_Data.ti_lData = i;
		scan->InstallDefaults(1,ctags);
	      }
	    } else {
	      struct JPG_TagItem ctags[] = {
		JPG_ValueTag((m_ucDepth > 1)?JPGTAG_SCAN_COMPONENT0:JPGTAG_TAG_IGNORE,1),
		JPG_ValueTag((m_ucDepth > 2)?JPGTAG_SCAN_COMPONENT1:JPGTAG_TAG_IGNORE,2),
		JPG_ValueTag((m_ucDepth > 3)?JPGTAG_SCAN_COMPONENT2:JPGTAG_TAG_IGNORE,3),
		JPG_Continue(scantags)
	      };
	      class Scan *scan = new(m_pEnviron) class Scan(this);
	      if (m_pScan == NULL) {
		m_pScan = scan;
	      } else {
		m_pLast->TagOn(scan);
	      }
	      m_pLast = scan;
	      scan->InstallDefaults(m_ucDepth - 1,ctags);
	    }
	  } // Nothing to do if chroma channels are not present.
	} else { 
	  UBYTE depth = m_ucDepth;
	  if (scantags->FindTagItem(JPGTAG_SCAN_COMPONENT0)) depth = 1;
	  if (scantags->FindTagItem(JPGTAG_SCAN_COMPONENT1)) depth = 2;
	  if (scantags->FindTagItem(JPGTAG_SCAN_COMPONENT2)) depth = 3;
	  if (scantags->FindTagItem(JPGTAG_SCAN_COMPONENT3)) depth = 4;
	  //
	  // If this is an AC scan, and there is more than one component, separate
	  // into several scans.
	  if (depth > 1 && scantags->GetTagData(JPGTAG_SCAN_SPECTRUM_START) > 0) {
	    UBYTE i;
	    struct JPG_TagItem ctags[] = {
	      JPG_ValueTag(JPGTAG_SCAN_COMPONENT0,0),
	      JPG_ValueTag(JPGTAG_SCAN_COMPONENT1,0),
	      JPG_ValueTag(JPGTAG_SCAN_COMPONENT2,0),
	      JPG_ValueTag(JPGTAG_SCAN_COMPONENT3,0),
	      JPG_Continue(scantags)
	    };
	    for(i = 0;i < depth;i++) {
	      const struct JPG_TagItem *comp = scantags->FindTagItem(JPGTAG_SCAN_COMPONENT0 + i);
	      ctags[0].ti_Data.ti_lData = (comp)?(comp->ti_Data.ti_lData):(i);
	      class Scan *scan = new(m_pEnviron) class Scan(this);
	      if (m_pScan == NULL) {
		m_pScan = scan;
	      } else {
		m_pLast->TagOn(scan);
	      }
	      m_pLast = scan;
	      scan->InstallDefaults(1,ctags);
	    }
	  } else {
	    class Scan *scan = new(m_pEnviron) class Scan(this);
	    if (m_pScan == NULL) {
	      m_pScan = scan;
	    } else {
	      m_pLast->TagOn(scan);
	    }
	    m_pLast = scan;
	    scan->InstallDefaults(depth,scantags);
	  }
	}
      }
      tags = tags->NextTagItem();
    }
  } else {
    UBYTE maxdepth    = 4;
    if (m_Type == JPEG_LS) {
      if (tags->GetTagData(JPGTAG_SCAN_LS_INTERLEAVING,JPGFLAG_SCAN_LS_INTERLEAVING_NONE) == 
	  JPGFLAG_SCAN_LS_INTERLEAVING_NONE)
	maxdepth = 1;
    }
    UBYTE depth       = m_ucDepth;
    UBYTE comp        = 0;
    //
    // Create multiple scans for more than maxdepth components.
    while(depth) {
      class Scan *scan;
      UBYTE curdepth = (depth > maxdepth)?(maxdepth):(depth);
      struct JPG_TagItem ctags[] = {
	JPG_ValueTag((curdepth > 0)?JPGTAG_SCAN_COMPONENT0:JPGTAG_TAG_IGNORE,comp + 0),
	JPG_ValueTag((curdepth > 1)?JPGTAG_SCAN_COMPONENT1:JPGTAG_TAG_IGNORE,comp + 1),
	JPG_ValueTag((curdepth > 2)?JPGTAG_SCAN_COMPONENT2:JPGTAG_TAG_IGNORE,comp + 2),
	JPG_ValueTag((curdepth > 3)?JPGTAG_SCAN_COMPONENT3:JPGTAG_TAG_IGNORE,comp + 3),
	JPG_Continue(tags)
      };
      
      scan = new(m_pEnviron) class Scan(this);
      if (m_pScan == NULL) {
	assert(m_pScan == NULL && m_pLast == NULL);
	m_pScan = scan;
      } else {
	assert(m_pScan && m_pLast);
	m_pLast->TagOn(scan);
      }
      m_pLast = scan;
      scan->InstallDefaults(curdepth,ctags);
      comp += maxdepth;
      depth-= curdepth;
    }
  }
  //
  // Create a residual scan?
  if (m_pTables->UseResiduals()) {
    switch(m_Type) {
    case Lossless:
    case ACLossless:
    case JPEG_LS:
      JPG_THROW(INVALID_PARAMETER,"Frame::InstallDefaultScanParameters",
		"the lossless scans do not create residuals, no need to code them");
      break;
    case DifferentialSequential:
    case DifferentialProgressive:
    case DifferentialLossless:
    case ACDifferentialSequential:
    case ACDifferentialProgressive:
    case ACDifferentialLossless:
      // Hmm. At this time, simply disallow. There is probably a way how to fit this into
      // the highest hierarchical level, but not now.
      JPG_THROW(NOT_IMPLEMENTED,"Frame::InstallDefaultScanParameters",
		"the hierarchical mode does not yet allow residual coding");
      break;
    default:
      // Make the first scan a residual scan.
      { 
	UBYTE component = m_ucDepth;
	class Scan *scan;
	do {
	  component--;
	  scan = new(m_pEnviron) class Scan(this);
	  scan->TagOn(m_pScan);
	  m_pScan = scan;
	  scan->MakeResidualScan(ComponentOf(component));
	} while(component);
      }
      break;
    }
  }
  if (m_pTables->UseRefinements()) {
    switch(m_Type) {
    case Lossless:
    case ACLossless:
    case JPEG_LS:
      JPG_THROW(INVALID_PARAMETER,"Frame::InstallDefaultScanParameters",
		"the lossless scans do not support hidden refinement scans");
      break;
    case DifferentialSequential:
    case DifferentialProgressive:
    case DifferentialLossless:
    case ACDifferentialSequential:
    case ACDifferentialProgressive:
    case ACDifferentialLossless:
      // Hmm. At this time, simply disallow. There is probably a way how to fit this into
      // the highest hierarchical level, but not now.
      JPG_THROW(NOT_IMPLEMENTED,"Frame::InstallDefaultScanParameters",
		"the hierarchical mode does not yet allow hidden refinement coding");
      break;
    default:
      // Create hidden refinement scans.
      {
	UBYTE hiddenbits;
	UBYTE component;
	class Scan *scan;
	for(hiddenbits = 0;hiddenbits < m_pTables->HiddenDCTBitsOf();hiddenbits++) {
	  component = m_ucDepth;
	  do {
	    component--;
	    scan = new(m_pEnviron) class Scan(this);
	    scan->TagOn(m_pScan);
	    m_pScan = scan;
	    scan->MakeHiddenRefinementACScan(hiddenbits,ComponentOf(component));
	  } while(component);
	  scan = new(m_pEnviron) class Scan(this);
	  scan->TagOn(m_pScan);
	  m_pScan = scan;
	  scan->MakeHiddenRefinementDCScan(hiddenbits);
	}
      }
      break;
    }
  }
  m_pCurrent = m_pScan;
  return m_pScan;
}
Ejemplo n.º 2
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);
    }
  }
}