/* Copyright (c) 2010 MJ Rutter 
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA  02110-1301, USA.
 */ 

/* Check 8 bit depth paletted images to ensure all entries used, and
 * that palette is not grey-scale */

#include<stdio.h>
#include<stdlib.h>

#include "bmp2eps.h"

void palette_check(struct bitmap *image){
  int i,debug;
  unsigned int size;
  unsigned char ncols;

  debug=image->flags&DEBUG_MASK;

  if (image->depth!=8) return;
  if (image->type!=PALETTE) return;

  /* Find highest used palette entry */

  ncols=0;
  size=image->data_len;

  for(i=0;i<size;i++) ncols=(ncols>image->data[i] ? ncols : image->data[i]);

  if (ncols<(image->pal_len-1)){
    if (debug>1) fprintf(stderr,"Palette length reduced from %d to %d.\n",
	    image->pal_len,1+ncols);
    image->pal_len=1+ncols;
  }
}

void grey_check(struct bitmap *image){
  int i,j,grey,debug,depth,magic,test;
  unsigned int size, ncols;

  debug=image->flags&DEBUG_MASK;

  if (image->type!=PALETTE) return;

  ncols=image->pal_len;
  size=image->data_len;

  /* See if palette is greyscale */

  grey=1;
  for(i=0;i<image->pal_len;i++){
    if((image->palette[3*i]!=image->palette[3*i+1])||
       (image->palette[3*i]!=image->palette[3*i+2])){
      grey=0;
      break;
    }
  }

  if (!grey) return;

  if (debug>1) fprintf(stderr,"Image is greyscale\n");

  if(ncols<=16){
    if (ncols==2){
      magic=255;
      depth=1;
    }
    else if (ncols<=4){
      magic=255/3;
      depth=2;
    }
    else{
      magic=255/15;
      depth=4;
    }
    test=1;
    for(i=0;i<ncols;i++){
      j=(image->palette[3*i]*magic)&255;
      if ((j!=0)&&(j!=1)&&(j!=255)){
	test=0;
	break;
      }
    }
    if (test){
      for(i=0;i<ncols;i++)image->palette[3*i]/=magic;
      image->depth=depth;
      if (debug>1) fprintf(stderr,"Greyscale depth is %d bit\n",depth);
    }else{    /* We have a <=4 bit image, but cannot use a 4 bit
	       * greyscale representation. Give up and use palette! */
      if (debug>1) fprintf(stderr,"ncols=%d, but not %d bit greyscale\n",
			 ncols,depth);
      return;
    }
  }

  /* See if palette is already ordered */

  for(i=0;i<image->pal_len;i++){
    if(image->palette[3*i]!=i){
      grey=0;
      break;
    }
  }

  if (!grey){  /* Need to order things */
    if (debug>2) fprintf(stderr,"Greyscale palette being reordered\n");
    for(i=0;i<size;i++) image->data[i]=image->palette[3*image->data[i]];
  }


  /* Worry about transparency */
  if (image->trans){
    /* To account for palette re-ordering */
    *image->trans=image->palette[*image->trans*3];
    /* To account for depth change */
    *image->trans=*image->trans&((1<<image->depth)-1);
  }

  /* Now we can ditch palette etc. */

  free(image->palette);
  image->palette=NULL;
  image->type=BMP;
  image->colour=GREY;
  image->pal_len=0;

  if (image->depth<=4){
      image->pal_len=1<<image->depth;
      compact(image);
      image->pal_len=0;
  }

  return;
}

int grey_bits(struct bitmap *image){
  int debug;
  unsigned size;
  unsigned char *p,*end;

  if ((image->type!=BMP)||(image->colour!=GREY)||(image->depth!=8))
    return -1;

  size=image->height*image->width;
  p=image->data;
  end=p+size;
  debug=image->flags&DEBUG_MASK;

  while((p<end)&&((*p==0)||(*p==0xff))) p++;

  if (p==end) return 1;

  while((p<end)&&((*p==0)||(*p==0x55)||(*p==0xaa)||(*p==0xff))) p++;

  if (p==end) return 2;

  while((p<end)&&(((*p)&0x0f)==(((*p)&0xf0)>>4))) p++;

  if (p==end) return 4;

  if (debug>2) fprintf(stderr,"Full 8 bit greyscale found %d offset %d\n",
     (int)(*p),(int)(p-image->data));

  return 8;
}

