reference/ocr-simple/BitMap.cc
author viric@llimona
Thu, 18 May 2006 23:12:51 +0200
changeset 0 6b8091ca909a
permissions -rw-r--r--
Init from working directory of svn repository.

 /* *****************************************************************
  * BitMap.cc - Member functions for a BitMap                      *
  *  because of the complexity of the many Bit functions, they are  *
  *  not all in this file.  In this file are only the following     *
  *  functions:
  *         
  *	BitMap() - Constructor
  *     ~BitMap() - Destructor
  *
  *	int imageLength();
  *	int imageWidth();
  *	MapStatus & status;
  *   	MapStatus readMap(char * filename) ;
  *	MapStatus writeMap(char * filename);
  *
  *	// Data Access and low level manipulation functions  
  *      uchar * row(int i) - Returns a pointer to row i    
  *	 MapStatus setBit(Point point, Color clr);
  *	 Color readBit(Point point);
  *
  *
   ***************************************************************/

#include "BitMap.h"
#include <iostream.h>
#include <stdio.h>
#include "status_message.h"

inline int set_pixel_value(uchar** new_data, int y, int x, int new_val)
{
  new_data[y][x/8] |= (uchar)(new_val << (7-(x%8)));
}

inline int get_pixel_value(uchar** data, int y, int x)
{
  if((data[y][x/8]) & (1 << (7 - (x%8))))
    return 1;
  else
    return 0;
}


BitMap::BitMap()
:fImageWidth(0), fImageLength(0), fStatus(EMPTY), fMapData(NULL)
/*--------------------------------------------------------------
Primary Function: Constructor
Return Value: pointer to new BitMap
Effects: Initialize status to empty other values to zero
Rev: 10/6/95  KM
---------------------------------------------------------------*/
{ };



 BitMap::~BitMap()
/*--------------------------------------------------------------
Primary Purpose: destructor
Effects: Deletes each row of BitPairs then the array of rows
Rev: 10/6/95   KM
---------------------------------------------------------------*/
{
  if (fMapData != NULL)
    {
      int i;

      // delete each row
      for (i=0; i< fImageLength; i++)
	delete fMapData[i];

      // delete array of rows
        delete fMapData;   
    }
};



uchar * BitMap::row(int i)
/*--------------------------------------------------------------
Primary Purpose:  Access a row of the BitMap
Arguments: i is the row to access
Constraints:  i < fImageLength
Rev:  KM 10/15
---------------------------------------------------------------*/
{
  return fMapData[i];

};



MapStatus BitMap::readMap(char * filename)
/*--------------------------------------------------------------
Primary Purpose: Read an BitMap from a TIFF file
Arguments: filename of TIFF file
Return Value: A MapStatus, either VALID or READERROR
Effects:
  *  BitMap::readMap(filename) will read a two level TIFF file
  *  and place it in an BitMap.  The private fields of the BitMap
  *  set are:
         fImageWidth - the pixel width of the image
	 fImageLength - the vertical pixel length of the image
	 fstat - the status after the Read VALID, OTHERERROR,READERROR
         fMapData - an array of pointers to uchar arrays/
Constraints: filename must be a two level TIFF file
Rev: 10/15/95  KM Portions Borrowed from Assignment 1
---------------------------------------------------------------*/
{
  TIFF *tif;
  short photometric;

  // Open File - Read length and width

  tif = TIFFOpen (filename, "r");
  if(tif == NULL)
    { fStatus= OPENERROR;
      return OPENERROR;
    }

  TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &fImageLength);
  TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &fImageWidth);
  TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric);
  
  fMapData = new (uchar *)[fImageLength];

  printf("open succeeded on file %s.  length = %d. width = %d\n",
	 filename, fImageLength, fImageWidth);
  /*  if(photometric == PHOTOMETRIC_MINISWHITE)
       printf("min-is-white format\n");
  else if(photometric == PHOTOMETRIC_MINISBLACK )
    printf("min-is-black format\n"); */

  if((photometric != PHOTOMETRIC_MINISWHITE) && 
     (photometric != PHOTOMETRIC_MINISBLACK))
    printf("with an unknown(!) photometric: %d\n", photometric);
  
  // Calculate number of chars in a row
  int numChars = (fImageWidth / 8 ) +1 ;
  if(ENABLE_USER_INTERFACE)
    set_status("Reading %s...", filename);
  last_status = 0.0;

  for (int row = 0; row < fImageLength; ++row)
    {
      if(ENABLE_USER_INTERFACE)
	set_read_status(row, fImageLength);
      fMapData[row] = new uchar[numChars];        
      fMapData[row][numChars - 1] = 0;
      TIFFReadScanline(tif,fMapData[row],row,0);
      if(photometric != PHOTOMETRIC_MINISWHITE)
	invertBitsInBuffer(fMapData[row], numChars);

    }
  last_status = 0.0;
  if(ENABLE_USER_INTERFACE)
    set_status("Done reading %s", filename);
  TIFFClose(tif);
  fStatus = VALID; 
  return VALID;

};


MapStatus BitMap::writeTclMap(char * filename, 
			      Point & ul, Point & lr, int scaledown)
{
  FILE *  outfile;
  int numChars= fImageWidth /8 + 1;
  outfile = fopen(filename, "w");

  if(!outfile)
    cout << " Could not open " << filename << endl;
   
  fprintf(outfile, "%s_width %d\n",filename,fImageWidth);
  fprintf(outfile, "%s_height %d\n",filename,fImageLength);
  fprintf(outfile, "static char %s_bits[] {\n",filename);

  
  for (int r = 0; r < fImageLength; r++)
      {
	for(int col=0; col < numChars; col++)
	    {
	      fprintf(outfile, "%4#x,", fMapData[r][col]);

	      if (!(r == fImageLength-1 && col == numChars-1))
		fprintf(outfile, " ,");

	      if (((r*numChars + col) % 15)==0)
		fprintf(outfile,"\n");
	    }

      }
  fprintf(outfile,"}\n");

  fclose(outfile);

}



short int BitMap::grayScale(Point & ul, Point & lr)
// Dummy function for now
{
   int numPixels = pixelsInRegion( ul, lr);
   int area = (lr.x() - ul.x()+1) * (lr.y() - ul.y()+1);
   if (area < numPixels) {
     printf("Uh oh! Area = %d and pixels = %d\n", area, numPixels);
     assert(area >= numPixels);
   }
   short int gscale =(short int)(((float)numPixels/area) * 255);
   
   return gscale;
 };



int BitMap::pixelsInRegion( Point  ul,  Point lr)
{
  assert (ul >= Point(0,0));  /* did someone overload these? */
  if (!(lr <= Point(fImageWidth, fImageLength))) 
       printf("problem\n");
  assert (lr <= Point(fImageWidth, fImageLength));

  if(ul > lr)return 0;

  int ulx = ul.x(); int uly = ul.y();
  int lrx = lr.x(); int lry = lr.y();
  uchar * curRow;
  int pixCount = 0;
  

  for(int r = uly; r <= lry; r++)
    {
      curRow = row(r);
      // Count middle (whole) characters
      pixCount += pixelsBetween(curRow, ulx, lrx);
//      cout << pixelsBetween(curRow,ulx,lrx) <<" ";
//      cout << pixCount << endl;

    }
  return pixCount;
};


void testBitMap(char * filename)
// Reads in BitMap and prints on screen
{
    BitMap * m = new BitMap;
    
    m->readMap(filename);
    int numChars = (m->imageWidth() / 8 )+ 1;

    for (int r = 0; r < m->imageLength(); r++){
      for (int c =0; c < numChars; c++) byteprint(m->row(r)[c]);
    printf( "\n");
  }

};


void byteprint(char d) // print bits in a byte, high bit on left
{
  for (int i= 7; i>=0; --i) {
    if ((d>>i)&1) printf("X");
    else printf(" ");
  } 
};

void bitprint(char d, int x)
{
  if ((d>>(7-x))&1) cout << "X";
  else cout << " ";
};


class Page;

void testPixelsInRegion(BitMap * bmap, RLEMap * rmap)
// Reads in file and compares pixelsInRegion to RLEVersion
{

  int bmapcnt, rmapcnt;

  cout << "Testing pixelsInRegion " << endl;
  
   bmapcnt = bmap->pixelsInRegion(Point(0,0), 
		Point(bmap->imageWidth()-1, bmap->imageLength()-1));

   rmapcnt = rmap->pixelsInRegion(Point(0,0), 
	 Point(rmap->imageWidth()-1, rmap->imageLength()-1));				     
				     
  cout << "For whole page:";
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

  cout << "Start on char edge end on edge (8,8) (16,21) ";  
   bmapcnt = bmap->pixelsInRegion(Point(8,8), Point(16,21));
   rmapcnt = rmap->pixelsInRegion(Point(8,8), Point(16,21));
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

  cout << "Start on char edge, end mid char (0,8) (50,21)";
   bmapcnt = bmap->pixelsInRegion(Point(0,8), Point(50,21));
   rmapcnt = rmap->pixelsInRegion(Point(0,8), Point(50,21));
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

  cout << "Start mid char, end on edge (2,8) (7,21)";
   bmapcnt = bmap->pixelsInRegion(Point(2,8), Point(7,21));
   rmapcnt = rmap->pixelsInRegion(Point(2,8), Point(7,21));
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

  cout << "Start mid char, end mid char (2,8) (9,21)";
   bmapcnt = bmap->pixelsInRegion(Point(2,8), Point(9,21));
   rmapcnt = rmap->pixelsInRegion(Point(2,8), Point(9,21));
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

  cout << "Start and, end same char (2,8) (4,21)";
   bmapcnt = bmap->pixelsInRegion(Point(2,4), Point(4,21));
   rmapcnt = rmap->pixelsInRegion(Point(2,4), Point(4,21));
  cout <<" Bitmap-" << bmapcnt << " RLEMap-" << rmapcnt << endl;

};

MapStatus BitMap::rotateMap(Angle angle) 
/* 
   Thanks to Clint Staley and S. Jacques @calpoly 
   for this bitmap rotation alg.

   copied and slightly modified since it wass a pain getting
   the RLE rotate to work and I think this might be decently
   fast -AR
*/
{
  int nx,ny,newheight,newwidth,oldheight,oldwidth,i,j,halfnewheight,halfnewwidth;
  int halfoldheight,halfoldwidth;
  double radians; 
  double cosval,sinval;
  uchar** newMapData;
  
  fprintf(stderr,"Rotating Image %lf Degrees\n",angle);
  radians =  -(angle) / ((180 / 3.142));
  cosval = cos(radians);
  sinval = sin(radians);

  oldheight = fImageLength;
  oldwidth = fImageWidth;
  
  newwidth = (int)abs((int)(oldwidth*cosval)) + (int)abs((int)(oldheight*sinval));
  newheight = (int)abs((int)(-oldwidth*sinval)) + (int)abs((int)(oldheight*cosval));

  halfnewheight = newheight / 2;
  halfnewwidth = newwidth / 2;
  halfoldwidth = oldwidth /2;
  halfoldheight = oldheight /2 ;
  
  newMapData = new (uchar*) [newheight];

  int num_chars = (newwidth / 8) + 1;
  
  for (int row = 0; row < newheight; ++row)
      {
	newMapData[row] = new uchar[num_chars];        
	for (int k = 0; k < num_chars; k++)
	  newMapData[row][k] = '\0';
      }

  last_status = 0.0;
  for(i=0;i < newheight;i++)
      {
	if(ENABLE_USER_INTERFACE)
	  set_rotation_status((int)i, (int)newheight);
	for(j=0;j < newwidth;j++)
	    {
	     
/*	      set_pixel_value(newMapData, i, j, 0); 
	      break;  */

	      nx =(int)( (j - halfnewwidth)*cosval + (i-halfnewheight)*sinval);
	      ny =(int)( -((j - halfnewwidth)*sinval) + (i - halfnewheight)*cosval);
	      nx = nx + halfoldwidth;
	      ny = ny + halfoldheight;
	      if ((nx < oldwidth) && (ny < oldheight) && (nx > 0) && (ny > 0))
		{
		  if(get_pixel_value(fMapData, ny, nx))
		    set_pixel_value(newMapData, i, j, 1);
		  else
		    set_pixel_value(newMapData, i, j, 0);
		}
	      else
		  {
		    set_pixel_value(newMapData, i, j, 0);		
		  }
	    }
      }
  if(ENABLE_USER_INTERFACE)
    set_status("Rotating Image: Done");
  last_status = 0.0;

/* free up the old storage */  
  for(i = 0; i < fImageLength; i++)
      {
	free(fMapData[i]);
      }
  free(fMapData);

/* assign pointer, etc to the new stuff */
  fMapData = newMapData;
  fImageLength = newheight;
  fImageWidth = newwidth;
}

/*
				
int set_pixel_value(uchar** new_data, int y, int x, int new_val)
{
  new_data[y][x/8] |= (uchar)(new_val << (7-(x%8)));
}

int get_pixel_value(uchar** data, int y, int x)
{
  if((data[y][x/8]) & (1 << (7 - (x%8))))
    return 1;
  else
    return 0;
}

*/