//----------------------------------------------------------------------------- // Demonstracni priklad k serialu "Graficke formaty" // http://www.root.cz/ // // Autor: Pavel Tisnovsky // // Tento program predvadi zpusob redukce barvonosnych slozek v barvovem modelu // YCbCr. //----------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <math.h> // pripony souboru, se kterymi se pracuje #define EXTENSION_SRC ".tga" #define EXTENSION_DEST "_red.tga" #define EXTENSION_SUB "_sub.tga" // datova struktura popisujici pixmapu typedef struct { unsigned int width; unsigned int height; unsigned char *pixels; } pixmap; // jmena vstupniho souboru a souboru vystupnich char *src_name; char *dest_name; char *dest_name_sub; // pracovni pixmapy pixmap *src; pixmap *dest; //----------------------------------------------------------------------------- // vytvoreni plnobarevne (truecolor) pixmapy //----------------------------------------------------------------------------- pixmap * createPixmapTruecolor(unsigned int width, unsigned int height) { pixmap *px; unsigned int size; assert(width>0); assert(height>0); // alokace pameti pro hlavicku pixmapy px=(pixmap*)malloc(sizeof(pixmap)); // kontrola alokace pameti assert(px); px->width=width; px->height=height; size=width*height*3; // alokace pameti pro pixely px->pixels=(unsigned char *)malloc(sizeof(unsigned char)*size); // kontrola alokace pameti assert(px->pixels); return px; } //----------------------------------------------------------------------------- // ulozeni pixmapy (truecolor) do externiho souboru //----------------------------------------------------------------------------- void saveTrueColorPixmap(const pixmap *p, const char *filename) { FILE *fout; unsigned int i, j; unsigned char tgaHeader[18]={ // hlavicka formatu typu TGA 0x00, // typ hlavicky TGA 0x00, // nepouzivame paletu 0x02, // typ obrazku je grayscale 0x00, 0x00, // delka palety je nulova 0x00, 0x00, 0x00, // pozice v palete nas nezajima 0x00, 0x00, 0x00, 0x00, // obrazek je umisteny na pozici [0, 0] 0x00, 0x00, 0x00, 0x00, // sirka a vyska obrazku (dva byty na polozku) 0x18, // format je 24 bitu na pixel 0x20 // orientace bitmapy v obrazku }; assert(p); // je pixmapa v poradku? assert(p->pixels); printf("pixmap info:\n\tname:\t%s\n\twidth:\t%d\n\theight:\t%d\n\tbpp:\t%d\n", filename, p->width, p->height, 24); memcpy(tgaHeader+12, &(p->width), 2); // do hlavicky TGA zapsat velikost obrazku memcpy(tgaHeader+14, &(p->height), 2); fout=fopen(filename, "wb"); if (fout) { fwrite(tgaHeader, 18, 1, fout); // zapsat hlavicku TGA do souboru for (i=p->height; i; i--) { // radky zapisovat v opacnem poradi unsigned int yoff=3*(i-1)*p->width; // y-ovy offset v poli unsigned char *p1=p->pixels+yoff; for (j=0; j<p->width; j++) { // prohozeni BGR na RGB a ulozeni radku do souboru int result; result=fputc(*(p1+2), fout); assert(result!=EOF); result=fputc(*(p1+1), fout); assert(result!=EOF); result=fputc(*(p1), fout); assert(result!=EOF); p1+=3; } } fclose(fout); } puts("pixmap saved"); } //----------------------------------------------------------------------------- // nacteni pixmapy (truecolor) z obrazku typu TGA //----------------------------------------------------------------------------- pixmap * loadTruecolorPixmap(const char *filename) { FILE *fin; int width=0, height=0, bpp=0; int pallength=0; int i, j; int count; pixmap *p; unsigned char *p1, *p2; unsigned char tgaHeader[18]={ // hlavicka formatu typu TGA 0x00, // typ hlavicky TGA 0x00, // nepouzivame paletu 0x02, // typ obrazku je RGB TrueColor 0x00, 0x00, // delka palety je nulova 0x00, 0x00, 0x00, // pozice v palete nas nezajima 0x00, 0x00, 0x00, 0x00, // obrazek je umisteny na pozici [0, 0] 0x00, 0x00, 0x00, 0x00, // sirka a vyska obrazku (dva byty na polozku) 0x18, // format je 24 bitu na pixel 0x20 // orientace bitmapy v obrazku }; assert(filename); fin=fopen(filename, "rb"); assert(fin); count=fread(tgaHeader, 18, 1, fin); // nacteni hlavicky assert(count==1); memcpy(&width, tgaHeader+12, 2); // naplneni hlavicky memcpy(&height, tgaHeader+14, 2); memcpy(&bpp, tgaHeader+16, 1); memcpy(&pallength, tgaHeader+5, 2); printf("pixmap info:\n\tname:\t%s\n\twidth:\t%d\n\theight:\t%d\n\tbpp:\t%d\n", filename, width, height, bpp); assert(bpp==24); p=createPixmapTruecolor(width, height); for (i=0; i<height; i++) { // nacitani dat do pixmapy int offset=i*3*p->width; count=fread(p->pixels+offset, 3*p->width, 1, fin); assert(count==1); p1=p->pixels+offset; p2=p1+2; for (j=0; j<width; j++, p1+=3, p2+=3) { // prohozeni BGR na RGB unsigned char k=*p1; *p1=*p2; *p2=k; } } fclose(fin); puts("pixmap loaded"); return p; } //----------------------------------------------------------------------------- // priprava jmen vstupniho souboru a souboru vystupnich //----------------------------------------------------------------------------- void createFileNames(char *full_name) { int name_size; char *p; // delka zadaneho jmena souboru name_size=strlen(full_name); // alokace pameti pro dalsi jmena src_name= (char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_SRC))); dest_name= (char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_DEST))); dest_name_sub=(char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_SUB))); // oddelit koncovku od jmena p=strrchr(full_name, '.'); assert(p>full_name); *p=0; // naplnit konkretni jmena souboru strcpy(src_name, full_name); strcat(src_name, EXTENSION_SRC); strcpy(dest_name, full_name); strcat(dest_name, EXTENSION_DEST); strcpy(dest_name_sub, full_name); strcat(dest_name_sub, EXTENSION_SUB); // kontrolni vypis printf("source pixmap: %s\ndestination pixmap: %s\nsubtract pixmap: %s\n", src_name, dest_name, dest_name_sub); } //----------------------------------------------------------------------------- // vytvoreni vystupniho obrazku //----------------------------------------------------------------------------- void createDestinationPixmap(void) { dest=createPixmapTruecolor(src->width, src->height); } //----------------------------------------------------------------------------- // ulozeni vystupniho obrazku //----------------------------------------------------------------------------- void saveDestinationPixmap(void) { saveTrueColorPixmap(dest, dest_name); } //----------------------------------------------------------------------------- // ulozeni rozdiloveho obrazku //----------------------------------------------------------------------------- void saveSubBitmap(void) { saveTrueColorPixmap(dest, dest_name_sub); } //----------------------------------------------------------------------------- // nacteni barvove slozky R //----------------------------------------------------------------------------- unsigned char getR(int x, int y) { if (x>=src->width) x=src->width-1; if (y>=src->height) y=src->height-1; return *(src->pixels+3*(y*src->width+x)); } //----------------------------------------------------------------------------- // nacteni barvove slozky B //----------------------------------------------------------------------------- unsigned char getG(int x, int y) { if (x>=src->width) x=src->width-1; if (y>=src->height) y=src->height-1; return *(src->pixels+3*(y*src->width+x)+1); } //----------------------------------------------------------------------------- // nacteni barvove slozky B //----------------------------------------------------------------------------- unsigned char getB(int x, int y) { if (x>=src->width) x=src->width-1; if (y>=src->height) y=src->height-1; return *(src->pixels+3*(y*src->width+x)+2); } //----------------------------------------------------------------------------- // provedeni transformace z barvoveho prostoru RGB do barvoveho prostoru YCbCr //----------------------------------------------------------------------------- void reduce_colors(void) { #define BLOCK 1 //memcpy(dest->pixels, src->pixels, src->width*src->height*3); int i, j; for (j=0; j<src->height; j++) { // pro vsechny radky zdrojove pixmapy unsigned char *p_dest=dest->pixels+(3*j*dest->width); for (i=0; i<src->width; i++) { // pro vsechny pixely na radku float r, g, b, rr, gg, bb; float y, cb, cr; // souradnice zarovnane na zacatek bloku int ii=i & (~BLOCK); int jj=j & (~BLOCK); // barvove slozky pro kazdy pixel r=getR(i, j); g=getG(i, j); b=getB(i, j); // barvove slozky platne pro cely blok rr=getR(ii, jj); gg=getG(ii, jj); bb=getB(ii, jj); // provest prepocet z prostoru RGB y = 0.299 *r+0.587 *g+0.114 *b; cb=-0.1687*rr-0.3313*gg+0.5 *bb+128; cr= 0.5 *rr-0.4187*gg-0.0813*bb+128; // zpetny prepocet do prostoru RGB r=y +1.402 *(cr-128); g=y-0.34414*(cb-128)-0.71414*(cr-128); b=y+1.772 *(cb-128); // zkontrolovat meze if (r>255) r=255; if (g>255) g=255; if (b>255) b=255; if (r<0) r=0; if (g<0) g=0; if (b<0) b=0; *p_dest++=(unsigned char)r; // prevod na byty a ulozeni *p_dest++=(unsigned char)g; *p_dest++=(unsigned char)b; } } } //----------------------------------------------------------------------------- // vypocet rozdiloveho obrazku //----------------------------------------------------------------------------- void calculate_subs(void) { int i, j; for (j=0; j<src->height; j++) { // pro vsechny radky zdrojove pixmapy unsigned char *p_src=src->pixels+(3*j*src->width); unsigned char *p_dest=dest->pixels+(3*j*dest->width); for (i=0; i<src->width; i++) { // pro vsechny pixely na radku unsigned char rs, gs, bs; unsigned char rd, gd, bd; rs=*p_src++; // ziskat barvove slozky RGB zdrojove pixmapy gs=*p_src++; bs=*p_src++; rd=*p_dest++; // ziskat barvove slozky RGB cilove pixmapy gd=*p_dest++; bd=*p_dest++; p_dest-=3; // vypocet a zvyrazneni rozdilu *p_dest++=10.0*fabs(rs-rd); *p_dest++=10.0*fabs(gs-gd); *p_dest++=10.0*fabs(bs-bd); } } } //----------------------------------------------------------------------------- // hlavni funkce konzolove aplikace //----------------------------------------------------------------------------- int main(int argc, char **argv) { char *full_name; full_name=argv[1]; createFileNames(full_name); src=loadTruecolorPixmap(src_name); createDestinationPixmap(); reduce_colors(); saveDestinationPixmap(); calculate_subs(); saveSubBitmap(); printf("\ndone!\n"); return 0; } //----------------------------------------------------------------------------- // finito //-----------------------------------------------------------------------------