Logo Search packages:      
Sourcecode: kdc2tiff version File versions  Download package

KDCFile.cpp

/* Class used to read tags and image data from .kdc files.
 * 
 * Written by:  Chris Studholme
 * Last Update: 7-July-1999
 * Copyright:   GPL (http://www.fsf.org/copyleft/gpl.html)
 */

#include <config.h>
#include <tiffio.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

extern "C" {
#include <jpeglib.h>
}

#ifdef DECODE_KDCTAG
#include "xtiffio.h"
#else
#include "tiffio.h"
#endif

#include "KDCFile.h"

//#define _VERBOSE
//#define __COMPRESSED_PIXEL_STATS

/* KDC image dimensions:  
 *   848x976
 *
 * Bayer patter:
 *   GRGRGR (R is red, G is green, B is blue)
 *   BGBGBG
 *   GRGRGR
 *   BGBGBG
 */

/*
 * Data for decoding uncompressed .kdc files.  Kodak has gone
 * to a great deal of trouble to make it hard to reverse-engineer
 * this table, but I was able to compute it by calculating the
 * offset at which scan lines were correlated.  Ed Hamrick, 10/24/97
 */
static const short int kdcoff[] = {
    0,828,798,488,648,748,698,  8,448,668,598,376,248,588,498,744,
   48,508,398,264,696,428,298,632,496,348,198,152,296,268, 98,520,
   96,188,846, 40,744,108,746,408,544, 28,646,776,344,796,546,296,
  144,716,446,664,792,636,346,184,592,556,246,552,392,476,146, 72,
  192,396, 46,440,840,316,794,808,640,236,694,328,440,156,594,696,
  240, 76,494,216, 40,844,394,584,688,764,294,104,488,684,194,472,
  288,604, 94,840, 88,524,842,360,736,444,742,728,536,364,642,248,
  336,284,542,616,136,204,442,136,784,124,342,504,584, 44,242, 24,
  384,812,142,392,184,732, 42,760,832,652,790,280,632,572,690,648,
  432,492,590,168,232,412,490,536, 32,332,390, 56,680,252,290,424,
  480,172,190,792,280, 92, 90,312, 80, 12,838,680,728,780,738,200,
  528,700,638,568,328,620,538, 88,128,540,438,456,776,460,338,824,
  576,380,238,344,376,300,138,712,176,220, 38,232,824,140,786,600,
  624, 60,686,120,424,828,586,488,224,748,486,  8, 24,668,386,376,
  672,588,286,744,472,508,186,264,272,428, 86,632, 72,348,834,152,
  720,268,734,520,520,188,634, 40,320,108,534,408,120, 28,434,776,
  768,796,334,296,568,716,234,664,368,636,134,184,168,556, 34,552,
  816,476,782, 72,616,396,682,440,416,316,582,808,216,236,482,328,
   16,156,382,696,664, 76,282,216,464,844,182,584,264,764, 82,104,
   64,684,830,472,712,604,730,840,512,524,630,360,312,444,530,728,
  112,364,430,248,760,284,330,616,560,204,230,136,360,124,130,504,
  160, 44, 30, 24,808,812,778,392,608,732,678,760,408,652,578,280,
  208,572,478,648,  8,492,378,168,656,412,278,536,456,332,178, 56,
  256,252, 78,424, 56,172,826,792,704, 92,726,312,504, 12,626,680,
  304,780,526,200,104,700,426,568,752,620,326, 88,552,540,226,456,
  352,460,126,824,152,380, 26,344,800,300,774,712,600,220,674,232,
  400,140,574,600,200, 60,474,120,  0,828,374,488,648,748,274,  8,
  448,668,174,376,248,588, 74,744, 48,508,822,264,696,428,722,632,
  496,348,622,152,296,268,522,520, 96,188,422, 40,744,108,322,408,
  544, 28,222,776,344,796,122,296,144,716, 22,664,792,636,770,184,
  592,556,670,552,392,476,570, 72,192,396,470,440,840,316,370,808,
  640,236,270,328,440,156,170,696,240, 76, 70,216, 40,844,818,584,
  688,764,718,104,488,684,618,472,288,604,518,840, 88,524,418,360,
  736,444,318,728,536,364,218,248,336,284,118,616,136,204, 18,136,
  784,124,766,504,584, 44,666, 24,384,812,566,392,184,732,466,760,
  832,652,366,280,632,572,266,648,432,492,166,168,232,412, 66,536,
   32,332,814, 56,680,252,714,424,480,172,614,792,280, 92,514,312,
   80, 12,414,680,728,780,314,200,528,700,214,568,328,620,114, 88,
  128,540, 14,456,776,460,762,824,576,380,662,344,376,300,562,712,
  176,220,462,232,824,140,362,600,624, 60,262,120,424,828,162,488,
  224,748, 62,  8, 24,668,810,376,672,588,710,744,472,508,610,264,
  272,428,510,632, 72,348,410,152,720,268,310,520,520,188,210, 40,
  320,108,110,408,120, 28, 10,776,768,796,758,296,568,716,658,664,
  368,636,558,184,168,556,458,552,816,476,358, 72,616,396,258,440,
  416,316,158,808,216,236, 58,328, 16,156,806,696,664, 76,706,216,
  464,844,606,584,264,764,506,104, 64,684,406,472,712,604,306,840,
  512,524,206,360,312,444,106,728,112,364,  6,248,760,284,754,616,
  560,204,654,136,360,124,554,504,160, 44,454, 24,808,812,354,392,
  608,732,254,760,408,652,154,280,208,572, 54,648,  8,492,802,168,
  656,412,702,536,456,332,602, 56,256,252,502,424, 56,172,402,792,
  704, 92,302,312,504, 12,202,680,304,780,102,200,104,700,  2,568,
  752,620,750, 88,552,540,650,456,352,460,550,824,152,380,450,344,
  800,300,350,712,600,220,250,232,400,140,150,600,200, 60, 50,120,
    0,828,798,488,648,748,698,  8,448,668,598,376,248,588,498,744,
   48,508,398,264,696,428,298,632,496,348,198,152,296,268, 98,520,
   96,188,846, 40,744,108,746,408,544, 28,646,776,344,796,546,296,
  144,716,446,664,792,636,346,184,592,556,246,552,392,476,146, 72,
  192,396, 46,440,840,316,794,808,640,236,694,328,440,156,594,696,
  240, 76,494,216, 40,844,394,584,688,764,294,104,488,684,194,472,
  288,604, 94,840, 88,524,842,360,736,444,742,728,536,364,642,248,
  336,284,542,616,136,204,442,136,784,124,342,504,584, 44,242, 24,
};


static const unsigned char jpeghead[] = {
  0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,
  0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x64,
  0x00, 0x4B   // maybe this last number should be 0x64
};  


void KDCFile::FixScanline(unsigned char* dest, const unsigned char* src, 
                    int row) {
  for (unsigned int i=0; i<width; ++i)
    dest[i]=src[(i+kdcoff[row])%width];
}


KDCFile::KDCFile(const char* filename) {
  
  DateTime=0;
  ImageDescription=0;
  Make=0;
  Model=0;
  Software=0;
  Copyright=0;
  T33423=0;
  T36867=0;

#ifdef DECODE_KDCTAG
  kdcimage = XTIFFOpen(filename,"r");
#else
  // suppress tiff warning messages
  TIFFErrorHandler wh = TIFFSetWarningHandler(0);
  kdcimage = TIFFOpen(filename,"r");
#endif

  if (kdcimage==0) {
    fprintf(stderr,"KDCFile::KDCFile, cannot read file '%s'\n",filename);
    return;
  }

  char* s;
  if (TIFFGetField(kdcimage,TIFFTAG_DATETIME,&s)==1)
    DateTime=strdup(s);
  if (TIFFGetField(kdcimage,TIFFTAG_IMAGEDESCRIPTION,&s)==1)
    ImageDescription=strdup(s);
  if (TIFFGetField(kdcimage,TIFFTAG_MAKE,&s)==1)
    Make=strdup(s);
  if (TIFFGetField(kdcimage,TIFFTAG_MODEL,&s)==1)
    Model=strdup(s);
  if (TIFFGetField(kdcimage,TIFFTAG_SOFTWARE,&s)==1)
    Software=strdup(s);

  if (TIFFGetField(kdcimage,33432,&s)==1)
    Copyright=strdup(s);
  if (TIFFGetField(kdcimage,33423,&s)==1)
    T33423=strdup(s);
  if (TIFFGetField(kdcimage,36867,&s)==1)
    T36867=strdup(s);

//  TIFFPrintDirectory(kdcimage,stdout,0);

  uint16 count=0;
  uint32 *SubIFD=0;
  if (TIFFGetField(kdcimage,TIFFTAG_SUBIFD,&count,&SubIFD)!=1) {
    fprintf(stderr,"KDCFile::ReadKDCFile, no SubIFD found\n");
    TIFFClose(kdcimage);
    kdcimage=0;
    return;
  }

  if ((count!=1)||(SubIFD[0]!=0x288)) {
    fprintf(stderr,"KDCFile::ReadKDCFile, bad SubIFD found\n");
    TIFFClose(kdcimage);
    kdcimage=0;
    return;
  }

  if (!TIFFSetSubDirectory(kdcimage,SubIFD[0])) {
    fprintf(stderr,"KDCFile::ReadKDCFile, cannot read subdirectory\n");
    TIFFClose(kdcimage);
    kdcimage=0;
    return;
  }

#ifdef DECODE_KDCTAG
#else
  // restore tiff warning messages
  TIFFSetWarningHandler(wh);
#endif

//  TIFFPrintDirectory(kdcimage,stdout,0);
}


KDCFile::~KDCFile() {
  if (kdcimage!=0) 
#ifdef DECODE_KDCTAG
    XTIFFClose(kdcimage);
#else
    TIFFClose(kdcimage);
#endif
  free((char*)DateTime);
  free((char*)ImageDescription);
  free((char*)Make);
  free((char*)Model);
  free((char*)Software);
  free((char*)Copyright);
  free((char*)T33423);
  free((char*)T36867);
}


bool KDCFile::ReadKDCFile(unsigned char* dest) {

  if (kdcimage==0)
    return false;

  uint16 compression;

  if (TIFFGetField(kdcimage,TIFFTAG_COMPRESSION,&compression)!=1) {
    fprintf(stderr,"KDCFile::ReadKDCFile, cannot read compression type\n");
    return false;
  }

  switch (compression) {
  case COMPRESSION_NONE:
    return ReadUncompressedData(dest);
    
  case COMPRESSION_JPEG:
    return ReadCompressedData(dest);
  }

  fprintf(stderr,"KDCFile::ReadKDCFile, invalid compression type\n");
  return false;
}


bool KDCFile::ReadUncompressedData(unsigned char* dest) {
  
  unsigned char *rawdata = new unsigned char[width*height];
  unsigned int pos=0;
  int size=0;
  tstrip_t strip=0;

  while (pos<width*height) {
    size=TIFFReadRawStrip(kdcimage,strip++,rawdata+pos,width*height-pos);
    if (size<=0) {
      fprintf(stderr,"KDCFile::ReadUncompressedData, error reading image after %d bytes\n",pos);
      delete[] rawdata;
      TIFFClose(kdcimage);
      kdcimage=0;
      return false;
    }
    pos+=size;
  }
  
#ifdef _VERBOSE  
  fprintf(stderr,"KDCFile::ReadUncompressedData, %d bytes read, decrypting... ",pos);
#endif

  for (unsigned int i=0; i<height; ++i)
    FixScanline(dest+width*i,rawdata+width*i,i);

  delete[] rawdata;

  /*
  FILE* out=fopen("kdcraw.bin","w");
  fwrite(dest,width*height,1,out);
  fclose(out);
  */

#ifdef _VERBOSE  
  fprintf(stderr,"done.\n");
#endif
  return true;
}


bool KDCFile::ReadCompressedData(unsigned char* dest) {

  unsigned int bufsize = 512*1024;
  unsigned char *rawdata = new unsigned char[bufsize];
  unsigned int pos=0;
  int size=0;
  tstrip_t strip=0;

  memcpy(rawdata,jpeghead,sizeof(jpeghead));
  pos=sizeof(jpeghead);

  // suppress tiff error messages
  TIFFErrorHandler eh = TIFFSetErrorHandler(0);

  while ((size=TIFFReadRawStrip(kdcimage,strip++,rawdata+pos,bufsize-pos))>0)
    pos+=size;

  // restore tiff error messages
  TIFFSetErrorHandler(eh);

  if (pos==0) {
    fprintf(stderr,"KDCFile::ReadUncompressedData, error reading image after %d bytes\n",pos);
    delete[] rawdata;
    TIFFClose(kdcimage);
    kdcimage=0;
    return false;
  }

  if (pos>=bufsize) {
    fprintf(stderr,"KDCFile::ReadUncompressedData, compressed image too large\n");
    delete[] rawdata;
    TIFFClose(kdcimage);
    kdcimage=0;
    return false;
  }

  rawdata[sizeof(jpeghead)]=0;
  rawdata[sizeof(jpeghead)+1]=0;

  // order bytes correctly
  for (unsigned int i=sizeof(jpeghead)+2; i<pos; i+=2) {
    unsigned char c = rawdata[i];
    rawdata[i] = rawdata[i+1];
    rawdata[i+1] = c;
  }

  //  for(unsigned int i=0; i<sizeof(jpeghead)+4; ++i) 
  //    fprintf(stderr," %.02X", rawdata[i]);
  //  fprintf(stderr,"\n");
  
#ifdef _VERBOSE  
  fprintf(stderr,"KDCFile::ReadCompressedData, %d bytes read, uncompressing... ",pos);
#endif

  if (UncompressJPEG(dest,rawdata,pos)==false) {
#ifdef _VERBOSE  
    fprintf(stderr,"failed.\n");
#endif
    delete[] rawdata;
    return false;
  }

#ifdef _VERBOSE  
  fprintf(stderr,"done.\n");
#endif

  delete[] rawdata;
  return true;
}


void init_source(j_decompress_ptr cinfo) {}
boolean fill_input_buffer(j_decompress_ptr cinfo) {return FALSE;}
void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {}
void term_source(j_decompress_ptr cinfo) {}

bool KDCFile::UncompressJPEG(unsigned char* dest, const unsigned char* src, 
                       int srcsize) {

  /* This struct contains the JPEG decompression parameters and pointers to
   * working space (which is allocated as needed by the JPEG library).
   */
  struct jpeg_decompress_struct cinfo;
  /* This struct represents a JPEG error handler.  It is declared separately
   * because applications often want to supply a specialized error handler
   * (see the second half of this file for an example).  But here we just
   * take the easy way out and use the standard error handler, which will
   * print a message on stderr and call exit() if compression fails.
   * Note that this struct must live as long as the main JPEG parameter
   * struct, to avoid dangling-pointer problems.
   */
  struct jpeg_error_mgr jerr;

  JSAMPARRAY buffer;          /* Output row buffer */
  int row_stride;       /* physical row width in output buffer */

  /* Step 1: allocate and initialize JPEG decompression object */

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress(&cinfo);

  /* Step 2: specify data source (eg, memory) */
  struct jpeg_source_mgr smgr;
  smgr.next_input_byte = src;
  smgr.bytes_in_buffer = srcsize;
  smgr.init_source=init_source;
  smgr.fill_input_buffer=fill_input_buffer;
  smgr.skip_input_data=skip_input_data;
  smgr.resync_to_restart=jpeg_resync_to_restart;
  smgr.term_source=term_source;

  cinfo.src = &smgr;

  /* Step 3: read file parameters with jpeg_read_header() */

  jpeg_read_header(&cinfo, TRUE);
  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

  /* Step 4: set parameters for decompression */

  cinfo.dct_method = JDCT_FLOAT;

  /* Step 5: Start decompressor */

  jpeg_start_decompress(&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  if ((cinfo.output_width!=width)||
      (cinfo.output_height!=height/2)||
      (cinfo.output_components!=3)) {
    jpeg_destroy_decompress(&cinfo);
    fprintf(stderr,"KDCFile::UncompressJPEG, image has incorrect dimensions (%d,%d,%d)\n",
          cinfo.output_width,cinfo.output_height,cinfo.output_components);
    return false;
  }
    
  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   * In this example, we need to make an output work buffer of the right size.
   */ 
  /* JSAMPLEs per row in output buffer */
  row_stride = cinfo.output_width * cinfo.output_components;
  /* Make a one-row-high sample array that will go away when done with image */
  buffer = (*cinfo.mem->alloc_sarray)
    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

  //FILE* out=fopen("kdcraw.bin","w");

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */
  
  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */
  while (cinfo.output_scanline < cinfo.output_height) {
    /* jpeg_read_scanlines expects an array of pointers to scanlines.
     * Here the array is only one element long, but you could ask for
     * more than one scanline at a time if that's more convenient.
     */
    jpeg_read_scanlines(&cinfo, buffer, 1);

    // decode scanline to a pair of rows in the dest buffer
    for (unsigned int i=0; i<cinfo.output_width; i+=2) {
      /* I have verified that the camera simply copies red pixels one to the left and 
       * blue pixels one to the right before doing the JPEG encoding.  Hence the mean
       * calculation here.
       */
      dest[i] = buffer[0][3*i+1];
      dest[i+1] = ((unsigned int)buffer[0][3*i+0]+buffer[0][3*i+3])/2;
      dest[cinfo.output_width+i] = ((unsigned int)buffer[0][3*i+2]+buffer[0][3*i+5])/2;
      dest[cinfo.output_width+i+1] = buffer[0][3*i+4];
    }

    //fwrite(dest,cinfo.output_width*2,1,out);

    dest+=cinfo.output_width*2;

    //fwrite(buffer[0],cinfo.output_width*3,1,out);
  }

  //fclose(out);

  /* Step 7: Finish decompression */
  
  jpeg_finish_decompress(&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  /* Step 8: Release JPEG decompression object */
  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress(&cinfo);
  
  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */

  return true;
}

Generated by  Doxygen 1.6.0   Back to index