//=======================================================================================
//
// template for RGB bitmap image processing
//
// templ_bmp.h
//
// developer: Henry Guennadi Levkin
//
//=======================================================================================

#include <stdio.h>
#include <stdlib.h>

//=======================================================================================
typedef unsigned char byte;

//=======================================================================================
// Get width and height of bmp file from its memory buffer
// Works in Windows and Unix
//=======================================================================================
int BmpWidthHeight(byte* pBmpFile, int* pnWidth, int* pnHeight)
{
  *pnWidth  = *((int*) (pBmpFile + 14 + 4 ));
  *pnHeight = *((int*) (pBmpFile + 14 + 4 + 4));

  return 0;
}

//=======================================================================================
// reading of file with bmp
// Works in Windows and Unix
//=======================================================================================
int ReadBmpFile(char* pFileName, byte* pBmpFile)
{
  FILE* fp;
  int fSize;
  int count;

  fp=fopen(pFileName,"rb");

  if(fp==NULL) return 1;

  fseek(fp,2,SEEK_SET);
  fread(&fSize,4,1,fp);

  // back to the beginning of the file
  fseek(fp,0,SEEK_SET);
  count=fread((void*)pBmpFile,1,fSize,fp);

  fclose(fp);

  if(count!=fSize) return 2;

  return 0;
}

//=======================================================================================
// pBmp - buffer with all bmp file, including headers
// Works in Windows and Unix
//=======================================================================================
int GetColorComponentFromBmp(byte* pBmp, byte* pRed, byte* pGreen, byte* pBlue)
{
  int nWidth, nHeight;
  byte* pBmpMat= pBmp + 14 + 40;
  int bWidth;

  int i,j;

  nWidth = *((int*) (pBmp+14+4));
  nHeight= *((int*) (pBmp+14+4+4));
  bWidth=( (nWidth*24+31)/32 )*4; // byte width of one line

  for(i=0; i<nHeight; i++)
    for(j=0; j<nWidth; j++)
    {
      pBlue[i*nWidth+j]   = pBmpMat[i*bWidth+3*j+0]; //blue 
      pGreen[i*nWidth+j] = pBmpMat[i*bWidth+3*j+1];  //green
      pRed[i*nWidth+j]  = pBmpMat[i*bWidth+3*j+2];   //red
    }

  return 0;
}

//=======================================================================================
// make (r,g,b) image from R,G,B components
void MakeRGBfromComponents(byte* pRGB, byte* pRed, byte* pGreen, byte* pBlue,
                           int nWidth, int nHeight)
{
 int i,ii;
 int nn = nWidth*nHeight;

 for(i=0; i<nn; i++)
 {
   ii = i*3;
   pRGB[ii+0]=pBlue[i];
   pRGB[ii+1]=pGreen[i];
   pRGB[ii+2]=pRed[i];
 }
}


//=======================================================================================
// Luma, ChromaB, ChromaR,     4:4:4
void TransformRGBtoLuCbCr(byte* pRed,  byte* pGreen,   byte* pBlue,
                          byte* pLuma, byte* pChromaB, byte* pChromaR,
                          int nWidth, int nHeight)
{
  int i;
  int size = nWidth * nHeight;
  int acc;

  for(i=0; i<size; i++)
  {
    acc = 0.299*pRed[i] + 0.587*pGreen[i] + 0.114* pBlue[i];
    pLuma[i] = acc;

    acc = 0.564*pBlue[i] - 0.564*pLuma[i] + 128.;
    if(acc<0) acc = 0;
    else if(acc>255) acc = 255;
    pChromaB[i] = acc;

    acc = 0.713*pRed[i] - 0.713*pLuma[i] + 128.;
    if(acc<0) acc = 0;
    else if(acc>255) acc = 255;
    pChromaR[i] = acc;
  }
}

//=======================================================================================
// Luma, ChromaB, ChromaR,     4:4:4
void TransformLuCbCrToRGB(byte* pLuma, byte* pChromaB, byte* pChromaR,
                          byte* pRed,  byte* pGreen,   byte* pBlue,
                          int nWidth, int nHeight)
{
  int i;
  int size = nWidth * nHeight;
  int acc;

  for(i=0; i<size; i++)
  {
    acc = (double) pLuma[i] + 1.402*((double)pChromaR[i]-128.);
//printf("%d ",pLuma[i]);
    if(acc<0) acc = 0; 	
    else if(acc>255) acc = 255;
    pRed[i] = acc;

    acc = (double) pLuma[i] - 0.344*(pChromaB[i]-128.) - 0.714*(pChromaR[i]-128.);
    if(acc<0) acc = 0; 	
    else if(acc>255) acc = 255;
    pGreen[i] = acc;

    acc = (double) pLuma[i] + 1.772*(pChromaB[i]-128.);
    if(acc<0) acc = 0; 	
    else if(acc>255) acc = 255;
    pBlue[i] = acc;
  }
}

//=======================================================================================
void BitmapImageFileWrite(char* pFilename, byte* pBmpFile, int nWidth, int nHeight)
{
  FILE* fp;

  int fSize = 14 + 40 + 3*nWidth*nHeight;

  fp = fopen(pFilename,"wb");

  fwrite((void*)pBmpFile, 1, fSize, fp);

  fclose(fp);
}
