//-----------------------------------------------------------------------------
// Demonstracni priklad k serialu "Graficke formaty"
// http://www.root.cz/
//
// Autor: Pavel Tisnovsky
//
// Tento program prevadi obrazek ulozeny v truecolor formatu TGA na trojici
// TGA obrazku s rozlozenymi barvovymi slozkami barvoveho modelu YCbCr.
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// pripony souboru, se kterymi se pracuje
#define EXTENSION_SRC ".tga"
#define EXTENSION_Y "_y.tga"
#define EXTENSION_CB "_cb.tga"
#define EXTENSION_CR "_cr.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_y_name;
char *dest_cb_name;
char *dest_cr_name;
// pracovni pixmapy
pixmap *src;
pixmap *dest_y;
pixmap *dest_cb;
pixmap *dest_cr;
//-----------------------------------------------------------------------------
// vytvoreni pixmapy ve stupnich sedi
//-----------------------------------------------------------------------------
pixmap * createPixmapGrayscale(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;
// alokace pameti pro pixely
px->pixels=(unsigned char *)malloc(sizeof(unsigned char)*size);
// kontrola alokace pameti
assert(px->pixels);
return px;
}
//-----------------------------------------------------------------------------
// 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 do externiho souboru
//-----------------------------------------------------------------------------
void saveGrayscalePixmap(const pixmap *p, const char *filename)
{
FILE *fout;
unsigned int i;
unsigned char tgaHeader[18]={ // hlavicka formatu typu TGA
0x00, // typ hlavicky TGA
0x00, // nepouzivame paletu
0x03, // 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)
0x08, // 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, 8);
memcpy(tgaHeader+12, &(p->width), 2); // do hlavicky TGA zapsat velikost obrazku
memcpy(tgaHeader+14, &(p->height), 2);
fout=fopen(filename, "wb");
assert(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=(i-1)*p->width; // y-ovy offset v poli
fwrite((const void *)(p->pixels+yoff), (size_t)p->width, (size_t)1, fout);// zapis celeho radku
}
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_y_name= (char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_Y)));
dest_cb_name=(char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_CB)));
dest_cr_name=(char *)malloc(sizeof(char)*(name_size+strlen(EXTENSION_CR)));
// 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_y_name, full_name);
strcat(dest_y_name, EXTENSION_Y);
strcpy(dest_cb_name, full_name);
strcat(dest_cb_name, EXTENSION_CB);
strcpy(dest_cr_name, full_name);
strcat(dest_cr_name, EXTENSION_CR);
// kontrolni vypis
printf("source pixmap: %s\ndest y: %s\ndest cb: %s\ndest cr: %s\n",
src_name,
dest_y_name,
dest_cb_name,
dest_cr_name);
}
//-----------------------------------------------------------------------------
// vytvoreni trojice vystupnich obrazku
//-----------------------------------------------------------------------------
void createDestinationPixmaps(void)
{
dest_y=createPixmapGrayscale(src->width, src->height);
dest_cb=createPixmapGrayscale(src->width, src->height);
dest_cr=createPixmapGrayscale(src->width, src->height);
}
//-----------------------------------------------------------------------------
// ulozeni trojice vystupnich obrazku
//-----------------------------------------------------------------------------
void saveDestinationPixmaps(void)
{
saveGrayscalePixmap(dest_y, dest_y_name);
saveGrayscalePixmap(dest_cb, dest_cb_name);
saveGrayscalePixmap(dest_cr, dest_cr_name);
}
//-----------------------------------------------------------------------------
// provedeni transformace z barvoveho prostoru RGB do barvoveho prostoru YCbCr
//-----------------------------------------------------------------------------
void rgb2ycbcr(void)
{
int i, j;
for (j=0; j<src->height; j++) { // pro vsechny radky zdrojove pixmapy
unsigned char *p_rgb=src->pixels+(3*j*src->width);
unsigned char *p_y=dest_y->pixels+(j*dest_y->width);
unsigned char *p_cb=dest_cb->pixels+(j*dest_cb->width);
unsigned char *p_cr=dest_cr->pixels+(j*dest_cr->width);
for (i=0; i<src->width; i++) { // pro vsechny pixely na radku
float r, g, b;
float y, cb, cr;
r=*p_rgb++; // ziskat barvove slozky RGB
g=*p_rgb++;
b=*p_rgb++;
y = 0.299 *r+0.587 *g+0.114 *b; // provest prepocet
cb=-0.1687*r-0.3313*g+0.5 *b+128;
cr= 0.5 *r-0.4187*g-0.0813*b+128;
*p_y++=(unsigned char)y; // prevod na byty a ulozeni
*p_cb++=(unsigned char)cb;
*p_cr++=(unsigned char)cr;
}
}
}
//-----------------------------------------------------------------------------
// hlavni funkce konzolove aplikace
//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
char *full_name;
if (argc<2) {
puts("Usage rgb2ycbcr file.tga");
return 1;
}
full_name=argv[1];
createFileNames(full_name);
src=loadTruecolorPixmap(src_name);
createDestinationPixmaps();
rgb2ycbcr();
saveDestinationPixmaps();
printf("\ndone!\n");
return 0;
}
//-----------------------------------------------------------------------------
// finito
//-----------------------------------------------------------------------------