/* gc-a2ycbycr : converts an image of any type to a C/C++ array
 * (supports bmp, pnm, xpm, xcf, pcx, gif, jpg, tif, png, tga, lbm)
 * Copyright (C) 2003  Alexandre Boeglin <alex AT boeglin DOT org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <stdio.h>
#include <string.h>

#define OUTPUT_C 0
#define OUTPUT_BE 1
#define OUTPUT_LE 2

Uint32 getpixel(SDL_Surface *surface,int x,int y){
	int bpp=surface->format->BytesPerPixel;
	/* Here p is the address to the pixel we want to retrieve */
	Uint8 *p=(Uint8 *)surface->pixels+y*surface->pitch+x*bpp;

	switch(bpp){
		case 1:
			return *p;
		case 2:
			return *(Uint16 *)p;
		case 3:
			if(SDL_BYTEORDER==SDL_BIG_ENDIAN)
				return p[0]<<16|p[1]<<8|p[2];
			else
				return p[0]|p[1]<<8|p[2]<<16;
		case 4:
			return *(Uint32 *)p;
		default:
			return 0;       /* shouldn't happen, but avoids warnings */
	}
}

int main(int argc,char **argv){
	char *imagefile;
	FILE *f_out;
	SDL_Surface *image;
	int i,j,w,h,bpp,output=OUTPUT_C;
	Uint32 pix1,pix2;
	Uint8 r1,g1,b1,r2,g2,b2;
	int y1,cb1,cr1,y2,cb2,cr2,cb,cr;
	
	/* check arguments */
	if(argc<2||argc>4){
		fprintf(stderr,"\tUsage : %s [-be|-le] <imagefile> [<outputfile>]\n",argv[0]);
		fprintf(stderr,"\t\t-be : output is raw, big endian\n");
		fprintf(stderr,"\t\t-le : output is raw, little endian\n");
		return 1;
	}
	/* check optional parameters and wanted output */
	else if(argc==2)
		imagefile=argv[1];
	else if(argc>2&&!strcmp(argv[1],"-be")){
		output=OUTPUT_BE;
		imagefile=argv[2];
	}
	else if(argc>2&&!strcmp(argv[1],"-le")){
		output=OUTPUT_LE;
		imagefile=argv[2];
	}
	else
		imagefile=argv[1];

	/* stdout redirected to outputfile */
	if((output==OUTPUT_C&&argc==3)||argc==4)
		if((f_out=freopen(argv[argc-1],"w",stdout))==NULL){
			perror("Opening outputfile");
			return 1;
		}

	/* startup SDL */
	if(SDL_Init(0)==-1){
		fprintf(stderr,"SDL_Init: %s\n",SDL_GetError());
		return 1;
	}

	/* load the image */
	image=IMG_Load(imagefile);
	if(!image){
		/* image failed to load */
		fprintf(stderr,"IMG_Load: %s\n",IMG_GetError());
		SDL_Quit();
		return 1;
	}

	/* print some info about the image */
	w=image->w;
	h=image->h;
	bpp=image->format->BitsPerPixel;
	fprintf(stderr,"loaded %s: %dx%d %dbpp, ",imagefile,w,h,bpp);
	switch(output){
		case OUTPUT_BE:
			fprintf(stderr,"output as big endian raw data\n");
			break;
		case OUTPUT_LE:
			fprintf(stderr,"output as little endian raw data\n");
			break;
		default:
			fprintf(stderr,"output as C/C++ array\n");
	}

	/* transform the image to YCbYCr */
	if(output==OUTPUT_C)
		printf("// created with a2ycbycr\n// using %s: %dx%d %dbpp\n\n",imagefile,w,h,bpp);

	/* remove last column if width is odd */
	w&=0xFFFFFFFE;

	if(output==OUTPUT_C){
		printf("#define IMAGE_WIDTH\t(%d)\n#define IMAGE_HEIGHT\t(%d)\n#define IMAGE_SIZE\t(%d)\n\n",w/2,h,w/2*h);
		printf("const unsigned long IMAGE_BITMAP[%d][%d]={\n",h,w/2);
	}

	for(j=0;j<h;j++){
		if(output==OUTPUT_C)
			printf("{");
		for(i=0;i<w;i+=2){
			pix1=getpixel(image,i,j);
			pix2=getpixel(image,i+1,j);

			SDL_GetRGB(pix1,image->format,&r1,&g1,&b1);
			SDL_GetRGB(pix2,image->format,&r2,&g2,&b2);

			y1=(299*r1+587*g1+114*b1)/1000;
			cb1=(-16874*r1-33126*g1+50000*b1+12800000)/100000;
			cr1=(50000*r1-41869*g1-8131*b1+12800000)/100000;

			y2=(299*r2+587*g2+114*b2)/1000;
			cb2=(-16874*r2-33126*g2+50000*b2+12800000)/100000;
			cr2=(50000*r2-41869*g2-8131*b2+12800000)/100000;

			cb=(cb1+cb2)/2;
			cr=(cr1+cr2)/2;

			switch(output){
				case OUTPUT_BE:
					printf("%c%c%c%c",y1,cb,y2,cr);
					break;
				case OUTPUT_LE:
					printf("%c%c%c%c",cr,y2,cb,y1);
					break;
				default:
					if(i+2!=w){
						printf("0x%02X%02X%02X%02X,",y1,cb,y2,cr);

					/* keep it readable*/
						if(!((i+2)%16))
							printf("\n");
					}
					else
						printf("0x%02X%02X%02X%02X",y1,cb,y2,cr);
				}
		}
		if(output==OUTPUT_C){
			if(j+1!=h)
				printf("},\n");
			else
				printf("}\n");
		}
	}

	if(output==OUTPUT_C)
		printf("};\n");

	/* free the loaded image */
	SDL_FreeSurface(image);

	/* shutdown SDL */
	SDL_Quit();

	/* close file */
	fclose(f_out);

	return 0;
}
