Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Сохранение 4-битних bmp


Автор: Slay1 4.6.2006, 15:16
Сначала первьій ворос - не знаю как заполнить некоторьіе поля заголовка.
Значит огласил я 2 структурьі:
Код

typedef struct
{
    unsigned char type[2];  /* This specifies the type of file. This should be
                                    equal to BM */
    unsigned long file_size;  /* This gives the bitmap size in bytes */
    unsigned int reserved_1;  /* This is reserved and must be 0 */
    unsigned int reserved_2;  /* This is also reserved and must also be 0 */
    unsigned long offset;  /* This specifies the number of bytes from the
                                starting of the bitmap to where the actual
                                data part starts */
}BITMAP_FILE_HEADER;


/* The Bitmap Information Header */

typedef struct
{
    unsigned long structure_size;  /* This specifies in bytes the size of the
                                    header. This must be equal to 40. */
    long width;  /* This specifies the width of bitmap in pixels */
    long height;  /* This specifies the height of bitmap in pixels */
    unsigned int number_of_color_planes;  /* This specifies the number of
                                            color planes */
    unsigned int bits_per_pixel;  /* This specifies the bits per pixel i.e.
                                    the total number of colors in the bitmap */
    unsigned long compression;  /* This specifies the type of RLE compression in
                                the bitmap. No compression means that the
                                value will be 0. */
    unsigned long image_size;  /* This specifies the size of image in pixels
                                i.e. width x height */
    long horizontal_pixels_per_meter;  /* This specifies the horizontal
                                            resolution of image as pixels per
                                            meter */
    long vertical_pixels_per_meter;  /* This specifies the vertical resolution
                                        of image as pixels per meter */
    unsigned long colors_used;  /* This specifies the colors used in the
                                    bitmap. For 4-bit image this value is 0 */
    unsigned long important_colors;  /* This specifies the minimum number of
                                        important colors in the bitmap */
}BITMAP_INFORMATION_HEADER;


Но не знаю какие значения дать некоторьім полям(те, что закомментированьі):

Код

bitmap_header.type[0]='B';
bitmap_header.type[1]='M';
//bitmap_header.file_size;
bitmap_header.reserved_1=0;
bitmap_header.reserved_2=0;
//bitmap_header.offset;

bitmap_information.structure_size=40;
bitmap_information.width=getmaxx()+1;
bitmap_information.height=getmaxy()+1;
//bitmap_information.number_of_color_planes;
bitmap_information.bits_per_pixel=4;
bitmap_information.compression=0;
//bitmap_information.image_size;
//bitmap_information.horizontal_pixels_per_meter;
//bitmap_information.vertical_pixels_per_meter;
//bitmap_information.colors_used;
//bitmap_information.important_colors;


//bitmap_header.file_size; - насколько я понимаю размер файла должен бьіть (getmaxx()*getmaxy())/2+54 ? Но на практике, размер файла, сделаного, например, в paint немножко больше..
//bitmap_header.offset; - смещение, я думал оно равно 54, но для примера открьіл файл и оно там 118. Не понимаю, так как оно вьічисляєтся?
//bitmap_information.number_of_color_planes; - єтого вообще не понимаю
//bitmap_information.image_size; - не понял в каком формате писать
//bitmap_information.horizontal_pixels_per_meter; - как єто и следующие вьічислить тоже не понимаю
//bitmap_information.vertical_pixels_per_meter; ^
//bitmap_information.colors_used;  - тут и в следующем насколько я поняо должно бьіть 16, так?
//bitmap_information.important_colors;

Поскольку я не знал как заголовок оформить, но хотел попробовать сохранить в бмп, просто прочитал заголовок из 
файла с таким же расширением, и пробовал сохранять таким обращом:


Код

 if((bitmap_file=fopen(file_name,"wb"))==NULL) /* Opening bitmap file in read-only mode */
   return(FILE_READING_ERROR);


 if(fwrite(&bitmap_header,sizeof(BITMAP_FILE_HEADER),1,bitmap_file)!=1)
   return(FILE_HEADER_READING_ERROR);


 if(fwrite(&bitmap_information,sizeof(BITMAP_INFORMATION_HEADER),1,bitmap_file)!=1)
   return(INFO_HEADER_READING_ERROR);

 fseek(bitmap_file,54,SEEK_SET);
 for(screen_y=getmaxy();screen_y>y-1;screen_y--)
   {
    for(screen_x=x;x<getmaxx();screen_x+=2)
      {
       pixel=(getpixel(screen_x,screen_y)<<4)&(getpixel(screen_x+1,screen_y));
       fputc(pixel,bitmap_file);
      }
   }
 fclose(bitmap_file);
}


Но получил просто бмп, весь залитьій черньім цветом...
Программа остановливалась только ctrl+break на єтой строке - fputc(pixel,bitmap_file);
Помогите пожалуйста.  

Автор: ptr 5.6.2006, 08:36
bitmap_header.offset - смещение относительно начала файла до таблицы цветов, длина которой может изменяться от 8 до 1024 байт. Правда не все bmp имеют такую таблицу (например в 24 битных её нет).

bitmap_header.file_size - размер всего файла (заголовки, таблица цветов и сам массив).

bitmap_information.number_of_color_planes = 1.

bitmap_information.image_size - размер картинки в байтах. Оно равно width*height*bits_per_pixel/8. По-моему если bmp не сжата (compression=0), то здесь надо ставить 0, хотя я в этом не уверен.

bitmap_information.colors_used - количество используемых цветов из таблицы. Этот параметр имеет значение только для сжатых картинок. Если color_used равен 0, то используется максимально возможное количество цветов (в твоём случае 16).

bitmap_information.important_colors - количество важных цветов - число цветов, которые необходимы для того, чтобы изобразить рисунок. Если значение равно 0, то все цвета считаются важными.

bitmap_information.horizontal_pixels_per_meter, bitmap_information.vertical_pixels_per_meter - горизонтальное и вертикальное разрешение устройства. Можешь задавать здесь свои значения.

 

Автор: Slay1 5.6.2006, 09:56
Цитата(ptr @  5.6.2006,  08:36 Найти цитируемый пост)
bitmap_header.file_size - размер всего файла (заголовки, таблица цветов и сам массив).

Как узнать размер файла? По логике ширина*висота+54, на на практике виходит где-то на 100-200 байт больше, тогда какая же окончательная формула расчета размера файла так и не могу понять... 


Цитата(ptr @  5.6.2006,  08:36 Найти цитируемый пост)
bitmap_header.offset - смещение относительно начала файла до таблицы цветов, длина которой может изменяться от 8 до 1024 байт. Правда не все bmp имеют такую таблицу (например в 24 битных её нет).

В 4 битных тоже нет, то есть смещение до таблици цветов 0??
Но я для примеру читал один 16-цветной бмп, там оффсет равен 118 smile ... Ничего не понимаю...
 

Автор: Earnest 5.6.2006, 10:47
Вот код для записи заголовка для некомпрессированного bmp. Выдрано из программы с мясом, но, надеюсь, разобраться поможет. Объект Dib, который встречается в коде - это оболочка вокруг DIBSection.

Код

   // Заполнение заголовка файла в зависимости от размера изображения
   BITMAPFILEHEADER Bmfh ;
   Bmfh.bfType = 0x4d42 ; // идентификатор "ВМ" == 0x4d42
   Bmfh.bfReserved1 = 0 ;
   Bmfh.bfReserved2 = 0 ;

   BITMAPINFOHEADER Bmih ;

   m_nFileBpLine = BytesPerBMPLine (pDib->Width(), pDib->BitCount()) ;

   // заполняем LPBITMAPINFO.BITMAPINFOHEADER
   Bmih.biSize = sizeof(BITMAPINFOHEADER) ;
   Bmih.biWidth = pDib->Width() ;
   Bmih.biHeight = pDib->Height() * (Format().BottomUp() ? 1 : -1) ;
   Bmih.biSizeImage = m_nFileBpLine * Bmih.biHeight ;
   Bmih.biBitCount = pDib->BitCount() ;
   Bmih.biPlanes = 1 ;

   if (Bmih.biBitCount < 16)
      Bmih.biClrUsed = min (1u << Bmih.biBitCount, pDib->ClrUsed()) ;
   else
      Bmih.biClrUsed = 0 ;

   Bmih.biClrImportant = 0 ;
   Bmih.biCompression = BI_RGB ;
   Bmih.biXPelsPerMeter = Bmih.biYPelsPerMeter = pDib->Dpm() ;

   Bmfh.bfOffBits = sizeof Bmfh + sizeof Bmih + Bmih.biClrUsed * sizeof (RGBQUAD) ;
   Bmfh.bfSize = Bmfh.bfOffBits + Bmih.biSizeImage ;

   out.write ((const char*)&Bmfh, sizeof Bmfh) ;
   out.write ((const char*)&Bmih, sizeof Bmih) ;

   if (Bmih.biClrUsed)
   {
      CPaletteIP pPalette = pDib->QueryPalette () ;
      ASSERT( pPalette ) ;

      for (int i=0; i < (int)pPalette->ClrUsed(); ++i)
      {
         RGBQUAD rgb = pPalette->GetColor (i) ;
         out.write ((const char*)&rgb, sizeof rgb) ;
      }
   }


Вычисление длины строки:
Код

   UINT BytesPerBMPLine (UINT nWidth, UINT nBitCnt)
   {
      return (((nWidth * nBitCnt + 7) >> 3) + 3) & ~3 ;
   }
 

Автор: ptr 5.6.2006, 11:25
Как это таблицы цветов нет в 4 битных bmp? Как же тогда кодируется массив, содержащий картинку? Таблицы цветов нет только в 24 битных (поскольку там используется RGB) и, по-моему, ещё в 16 битных.

Размер таблицы цветов равен 4*2^n для n-битного bmp (2^n - количество цветов). В твоём случае offset равен 54+4*2^4=118, что и было в файле.

Примерный размер bmp файла равен 54+4*2^n+(width*height*n)/8, где width и height - размер картинки в пикселях (примерный поскольку размер таблицы цветов может быть разный). 

Автор: Slay1 5.6.2006, 20:15
Ну никак не виходит разобраться. Вроде как все елементьі хедера заполнил нормально, но сохраняет просто черний екран, и потом файл в пейнте даже не хочет редактироваться...

Код

unsigned char savebitmap(unsigned char *file_name )
{
 FILE *bitmap_file;

 BITMAP_FILE_HEADER bitmap_header;
 BITMAP_INFORMATION_HEADER bitmap_information;

 int screen_x, screen_y;
 char pixel;

bitmap_header.type[0]='B';
bitmap_header.type[1]='M';
bitmap_header.file_size=118+(getmaxx()+1)*(getmaxy()+1)/2;
bitmap_header.reserved_1=0;
bitmap_header.reserved_2=0;
bitmap_header.offset=118;

bitmap_information.structure_size=40;
bitmap_information.width=getmaxx()+1;
bitmap_information.height=getmaxy()+1;
bitmap_information.number_of_color_planes=1;
bitmap_information.bits_per_pixel=4;
bitmap_information.compression=0;
bitmap_information.image_size=bitmap_information.width*bitmap_information.height*bitmap_information.bits_per_pixel/8;
bitmap_information.horizontal_pixels_per_meter=96;
bitmap_information.vertical_pixels_per_meter=96;
bitmap_information.colors_used=0;
bitmap_information.important_colors=0;

 if((bitmap_file=fopen(file_name,"wb"))==NULL)
   return(FILE_READING_ERROR);

 if(fwrite(&bitmap_header,sizeof(BITMAP_FILE_HEADER),1,bitmap_file)!=1)
   return(FILE_HEADER_READING_ERROR);

 if(fwrite(&bitmap_information,sizeof(BITMAP_INFORMATION_HEADER),1,bitmap_file)!=1)
   return(INFO_HEADER_READING_ERROR);

 for(screen_y=getmaxy();screen_y>=0;screen_y--)
   {
    for(screen_x=0;screen_x<=getmaxx();screen_x+=2)
      {
       pixel=(getpixel(screen_x,screen_y)<<4)|(getpixel(screen_x+1,screen_y));
       fwrite(&pixel,sizeof(pixel),1,bitmap_file);
      }
   }
 fclose(bitmap_file);
}
  

Автор: ptr 6.6.2006, 11:05
А где таблица цветов? Если бы у тебя был 24 битный bmp, то такое решение вполне бы подошло. Но у тебя 4 битный bmp и тебе надо описать каждый используемый цвет. Потом в массиве каждый пиксель будет описываться одним байтом - ссылкой на место, где содержится описание этого цвета.

http://stephen.homeunix.org/Tech/programs/bmp.c  

Автор: ptr 6.6.2006, 15:09
Кстати совсем забыл. В битовом массиве строки кодируются снизу вверх. Количество байт в строке должно быть кратно 4, поэтому если количество пикселей по горизонтали не кратно 4, то справа в каждую строчку дописываются выравнивающие нули. 

Автор: Slay1 6.6.2006, 17:05
Цитата(ptr @  6.6.2006,  11:05 Найти цитируемый пост)
Вот кстати неплохой пример.  

Большое, огромное, жирное спасибо!
Все, разобрался.

 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)