Отправляет email-рассылки с помощью сервиса Sendsay

Одинокий программист

  Все выпуски  

Одинокий программист


Информационный Канал Subscribe.Ru


Одинокий программист

Thanks, www.subscribe.ru

Создаем свой формат графических файлов #5(часть 2)

Как я говорил, примемся уже конкретно создавать свой гр. файл. Будем писать простой конвертер для BMP(8;24) и TGA(8;24). 8=256 оттенков цветов, 24=16 млн. оттенков цветов. Наш формат будет содержать 16 млн. оттенков цветов. В 8 битном(256 оттенков цветов) режиме каждый пиксел есть индекс-значение в палитре цветов, размером в 768=256*3 байт. В 15 битном режиме(32 тыс.) цвет представлен следующим образом:

 rrrrr ggggg bbbbb

где r-бит красного цвета(Red), g-бит зеленого цвета(Green), b-бит синего цвета (Blue). В 16 битном режиме(65 тыс.) к пяти битам зеленого добавляется еще один бит:

 rrrrr gggggg bbbbb

В режиме 24 бита(16 млн.), каждый цвет задан восьмью битами:

 rrrrrrrr gggggggg bbbbbbbb

Может ко всем режимам добавляться еще Alpha канал или канал прозрачности. Размером обычно в 8 бит, хотя некто не ограничивает этим значением. 256 оттенков обычно хватает. Например, для 24 бит, правда, нужно называть уже 32 битным режимом:

 rrrrrrrr gggggggg bbbbbbbb aaaaaaaa

на один пиксел 32 бита, картинка размером 800x600 будет иметь размер 800*600*32= 15 360 000 байт. 15 мигов неправда ли много? Можно, конечно сжать. Ну да ладно! Приложение будет консольным(пример тупой, много памяти надо, но на то он и пример, на основе сделайте гораздо лучше).
 Один глоб. указатель на всю картинку, где каждые три элемента RGB. Два файла bmp.h и tga.h. Соответственно читать из bmp и tga. Для 24 бит все просто, грузим его прямо в указатель:

 data=new char[w*h*3];
 for(cx=0;cx< w*h*3;cx++)
  data[cx]=fgetc(fp);

где w-размер по горизонтали, h-размер по вертикали.
Для 8 бит, т.е. с индекснопалитровыми значениями, дела обстоят чуть сложнее:

// Грузим палитру
 char pal[768];
 for(cx=0;cx< 256;cx++)
 {
  pal[cx*3]=fgetc(fp);
  pal[cx*3+1]=fgetc(fp);
   pal[cx*3+2]=fgetc(fp);
  }
// Преобразуем в 24 бита
  for(cx=0;cx< w*h;cx++)
  {
   col=fgetc(fp);
   data[cx*3]=pal[col*3+2];
   data[cx*3+1]=pal[col*3+1];
   data[cx*3+2]=pal[col*3];
  }

 Функции типа isBmp(in) и isTga(in) проверяют, является ли in нужным нам форматом. ConvertFromBmp(in) и ConvertFromTga(in)-загружают из файла в наш буфер-указатель. Теперь есть размер картинки и буфер содержащий RGB последовательность, т.е.

 R=data[0];
 G=data[1];
 B=data[2];

 R=data[3];
 G=data[4];
 B=data[5];
  .
  .
  .
 R=data[n*3];
 G=data[n*3+1];
 B=data[n*3+2];

где n-нужный нам пиксел.
Имея таким образом готовый, разложенный пиксел можно превратить его в 8,15,16 бит.
Например в 16 бит:

 R=data[n*3]
 G=data[n*3+1]
 B=data[n*3+2]

 colorPixel=(R>>3)<<11 | (G>>2)<<5 | (B>>3)

// или

 #define RGB24TO16(r,g,b) (((r>>3)<<11)|((g>>2)<<5)|(b>>3))

Для 8 бит сложнее.
Сейчас сохраним заголовок.
struct MGFHeader{ char id[3]; // Заголовок long version; // Версия long width,height; // Размеры: горизонталь, вертикаль. long options; // Конфигурации файла. Например: упаковка. }mgf;
где mgf.id[0]='M' mgf.id[1]='G' mgf.id[2]='F' , mgf.version=0x100 mgf.width=размеру по X
mgf.height=размеру по Y, mgf.options=0 - не используем(while).

//Сохраним заголовок:
 fwrite(&mgf,sizeof(MGFHeader),1,f_out);
//сохраним пикселы как есть:
 fwrite(data,mgf.width*mgf.height*3,1,f_out);

Все, теперь мы имеем простой, но зато свой гр. файл.
//////////////////////////////////// bmp.h //////////////////////////////

int isBmp(char *fn)
{
 FILE *fp=fopen(fn,"rb");
 if((fgetc(fp)!='B')||
    (fgetc(fp)!='M'))
     return 0;
 fclose(fp);
 return 1;
}

void ConvertFromBmp(char *in)
{
 int bpp=0,cx,col;
 char pal[768];
 FILE *fp=fopen(in,"rb");
 if(fp==NULL)
 {
  perror(in);
  exit(1);
 }
 fseek(fp,0x12,0);
 fread(&w,4,1,fp);
 fread(&h,4,1,fp);
 fseek(fp,0x1c,0);
 fread(&bpp,2,1,fp);
 printf("%s - %dx%dx%d\n",in,w,h,bpp);
 data=new char[w*h*3];
 if(!data)
 {
  puts("Sorry, memory!");
  exit(1);
 }
 if(bpp==24)
 {
  fseek(fp,0x36,0);
  for(cx=0;cx< w*h*3;cx++)
   data[cx]=fgetc(fp);
 }
 else
 if(bpp==8)
 {
  fseek(fp,0x36,0);
  for(cx=0;cx< 256;cx++)
  {
   pal[cx*3]=fgetc(fp);
   pal[cx*3+1]=fgetc(fp);
   pal[cx*3+2]=fgetc(fp);
   fgetc(fp);
  }
  for(cx=0;cx< w*h;cx++)
  {
   col=fgetc(fp);
   data[cx*3]=pal[col*3+2];
   data[cx*3+1]=pal[col*3+1];
   data[cx*3+2]=pal[col*3];
  }
 }
 else
 {
  puts("What BMP bpp?");
  exit(1);
 }
 fcloseall();
}

/////////////////////////// tga.h /////////////////////////////////

int isTga(char *fn)
{
 int a,b,c;
 FILE *fp=fopen(fn,"rb");
 a=fgetc(fp); b=fgetc(fp); c=fgetc(fp);

 if(a==0&&b==0&&c==2)
  a=1;
 if(a==0&&b==1&&c==1)
  a=1;
 if(!a)
  return 0;
 fclose(fp);
 return 1;
}

void ConvertFromTga(char *in)
{
 int bpp=0,cx,col;
 char pal[768];
 FILE *fp=fopen(in,"rb");
 if(fp==NULL)
 {
  perror(in);
  exit(1);
 }
 fseek(fp,0xC,0);
 fread(&w,2,1,fp);
 fread(&h,2,1,fp);
 fseek(fp,0x10,0);
 fread(&bpp,1,1,fp);


 printf("%s - %dx%dx%d\n",in,w,h,bpp);
 data=new char[w*h*3];
 if(!data)
 {
  puts("Sorry, memory!");
  exit(1);
 }
 if(bpp==24)
 {
  fseek(fp,0x12,0);
  for(cx=0;cx< w*h*3;cx++)
   data[cx]=fgetc(fp);
  FlipAndMiror();
 }
 else
 if(bpp==8)
 {
  fseek(fp,0x12,0);
  for(cx=0;cx< 256;cx++)
  {
   pal[cx*3]=fgetc(fp);
   pal[cx*3+1]=fgetc(fp);
   pal[cx*3+2]=fgetc(fp);
  }
  for(cx=0;cx< w*h;cx++)
  {
   col=fgetc(fp);
   data[cx*3]=pal[col*3+2];
   data[cx*3+1]=pal[col*3+1];
   data[cx*3+2]=pal[col*3];
  }
  FlipAndMiror();
 }
 else
 {
  puts("What BMP bpp?");
  exit(1);
 }
 fcloseall();
}

/////////////////////////// img2mgf.h /////////////////////////////

#include< stdio.h>
#include< string.h>
#include< stdlib.h>
#include< conio.h>
//
// может еще что.
//

int  w=0,h=0;
char *data;

#include"tga.h"
#include"bmp.h"

void main(int argc,char **argv)
{
 char in[80];
 char out[80];
 int  cx;
 if(argc!=2)
 {
  puts("Usage: EXE  (BMP_or_TGA)(s)");
  exit(1);
 }
 strcpy(in,argv[1]);
 strcpy(out,in);

 for(cx=0;cx< strlen(out)&&out[cx]!='.';cx++);

 out[cx]=0;
 strcat(out,".mgf");

 if(isBmp(in))
  ConvertFromBmp(in);
 else
  if(isTga(in))
   ConvertFromTga(in);
 else
 {
  puts("What formats?");
  exit(1);
 }
 FILE *fp2=fopen(out,"wb");
 if(fp2==NULL)
 {
  perror(out);
  exit(1);
 }
 fprintf(fp2,"MGF%c%c",0x00,0x01);
 fwrite(&w,4,1,fp2);
 fwrite(&h,4,1,fp2);
 int col=0;
 for(cx=0;cx< w*h;cx++)
 {
  fwrite(&data[cx*3+2],1,1,fp2);
  fwrite(&data[cx*3+1],1,1,fp2);
  fwrite(&data[cx*3],1,1,fp2);
 }
 delete data;
 puts("Ok!");
}


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное