Конвертер из Bmp в Tga - C (СИ)
Формулировка задачи:
Доброго времени суток.
Возникла проблема с конвертером изображений (Bmp->Tga). Дело в том, что изображение, получившееся в результате кодирования, наклонено вбок (можете удостовериться сами, запустив программу). Третьи сутки борюсь с этой проблемой, совсем отчаялся, прошу помощи. Уж не покиньте, пожалуйста
Вот код (пока написал исключительно для преобразования 24-битного бмп в несжатый тга):
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include "stdlib.h"
#include "math.h"
// Структура BITMAP FILE HEADER ---------------------------------------------------------------------------------------------------------
#pragma pack(push)
#pragma pack(1)
typedef struct
{ unsigned char b1, b2;
unsigned long bfSize; //Размер файла в байтах (Смещение 2, длина 4)
unsigned short bfReserved1; //Бесполезно (Смещение 6, длина 2)
unsigned short bfReserved2; //Бесполезно (Смещение 8, длина 2)
unsigned long bfOffBits; //Смещение до самого изображения (Смещение 10, длина 4)
} BmpHeader;
#pragma pack(pop)
// Структура BITMAP INFO HEADER ---------------------------------------------------------------------------------------------------------
typedef struct
{
unsigned long biSize; //Размер данной структуры в байтах. Опред. версия формата
unsigned long biWidth; //Ширина изображения в пикселях.
unsigned long biHeight; //Высота изображения в пикселях.
unsigned short biPlanes; //Количество цветовых плоскостей и в формате BMP содержит единицу.
unsigned short biBitCount; //Количество бит на пиксель.
unsigned short biCompression; //Тип сжатия для сжатых изображений
unsigned short biSizeImage; //Размер изображения в байтах. Может содержать ноль для BI_RGB-изображений.
unsigned long biXPelsPerMeter; //Горизонтальное разрешение в пикселях на метр для целевого устройства.
unsigned long biYPelsPerMeter; //Вертикальное разрешение в пикселях на метр для целевого устройства.
unsigned short biClrUsed; //Количество используемых цветовых индексов в палитре.
unsigned short biClrImportant; //Количество элементов палитры, необходимых для отображения изображения.
} BmpImageInfo;
// Структура TGA INFO HEADER ---------------------------------------------------------------------------------------------------------
typedef struct {
char idlength;
char colourmaptype;
char datatypecode;
short int colourmaporigin;
short int colourmaplength;
char colourmapdepth;
short int x_origin;
short int y_origin;
short width;
short height;
char bitsperpixel;
char imagedescriptor;
} TgaImageInfo;
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
// unsigned char a;
} RGB;
void MergeBytes(RGB *,unsigned char *,int);
int main(int argc, char *argv[])
{
int n=0, i,j;
BmpHeader bmpheader;
BmpImageInfo bmpimageinfo;
TgaImageInfo tgaimageinfo;
RGB *pixels, *outpixels;
unsigned char tmp[5];
//int massR[i][j], massG[i][j], massB[i][j];
int pad, size;
int bytes2read;
FILE *BmpImage = fopen("E:/Jazblki programmirovanija/Kursovaya_Revchenko_10-IT-3/example.bmp","rb");
FILE *BmpCode = fopen("E:/Jazblki programmirovanija/Kursovaya_Revchenko_10-IT-3/BmpCode.txt","w");
FILE *TgaCode = fopen("E:/Jazblki programmirovanija/Kursovaya_Revchenko_10-IT-3/TgaCode.txt","w");
FILE *TgaImage = fopen("E:/Jazblki programmirovanija/Kursovaya_Revchenko_10-IT-3/TgaImage.tga","wb");
setlocale(LC_ALL, "");
if (!BmpImage ) {
printf("Ошибка чтения BMP-файла.\n");
return 1;
}
//Выравнивание структуры--------------------------------------------------
pad = sizeof(BmpHeader);
printf("BmpHeader до выравнивания: %d\n", pad);
if (pad > 14)
{
while (pad != 14)
{
pad -= 1;
}
}
printf("BmpHeader после выравнивания: %d\n", pad);
//---------------------------------------------------------------------------------------
if (fread(&bmpheader, pad, 1, BmpImage) != 1){
printf("Ошибка чтения заголовка Bmp-изображения\n");
return 2;
}
if (fread (&bmpimageinfo, sizeof(BmpImageInfo), 1, BmpImage) != 1 ){
printf("Ошибка чтения информации Bmp-изображения.\n");
return 3;
}
printf("sizeof(BmpImageInfo) = %d\n", sizeof(BmpImageInfo));
printf("_______Данные_о_BITMAP_FILE_HEADER_______\n");
printf("Тип файла : %c%c\n", bmpheader.b1, bmpheader.b2);
printf("Размер файла : %d bytes\n", bmpheader.bfSize);
printf("Резервный слот 1 : %d\n", bmpheader.bfReserved1);
printf("Резервный слот 2 : %d\n", bmpheader.bfReserved2);
printf("Смешение до изображения : %d bytes\n\n", bmpheader.bfOffBits);
printf("_______Данные_о_BITMAP_INFO_HEADER_______\n");
printf("Размер структ. в байтах : %d bytes\n", bmpimageinfo.biSize);
printf("Ширина изображения : %d px\n", bmpimageinfo.biWidth);
printf("Высота изображения : %d px\n", bmpimageinfo.biHeight);
printf("Кол. цветовых плоск. : %d\n", bmpimageinfo.biPlanes);
printf("Кол. бит на пиксель : %d-bit\n", bmpimageinfo.biBitCount);
printf("Тип сжатия : %d\n", bmpimageinfo.biCompression);
bmpimageinfo.biSizeImage = bmpimageinfo.biXPelsPerMeter;
bmpimageinfo.biXPelsPerMeter = bmpimageinfo.biYPelsPerMeter;
bmpimageinfo.biYPelsPerMeter = bmpimageinfo.biClrUsed;
bmpimageinfo.biClrUsed = 0;
printf("Размер изобр. в байтах : %d bytes\n", bmpimageinfo.biSizeImage);
printf("Горизонт. разрешение : %d px\n", bmpimageinfo.biXPelsPerMeter);
printf("Вертикальное разрешение : %d px\n", bmpimageinfo.biYPelsPerMeter);
printf("Кол. цветов. инд. в пал.: %d\n", bmpimageinfo.biClrUsed);
printf("Кол. элементов палитры : %d\n\n", bmpimageinfo.biClrImportant);
size = bmpimageinfo.biHeight * bmpimageinfo.biWidth;
printf("size * sizeof(RGB) = %d\n", size * sizeof(RGB));
if ((pixels = malloc(size * sizeof(RGB))) == NULL){
printf("Malloc error\n");
}
for (int i=0;i<size;i++) {
pixels[i].r = 0;
pixels[i].g = 0;
pixels[i].b = 0;
//pixels[i].a = 0;
}
// Считываем Цветовые индексы-------------------------------------------------------------------------------------------------------------------
fseek(BmpImage, bmpheader.bfOffBits, 0); //смещение на bmpheader.bfOffBits = 54 символа (пропускаем данные о BmpHeader и BmpImageInfo)
bytes2read = bmpimageinfo.biBitCount / 8;
if (bmpimageinfo.biBitCount == 24){
printf("Считывание\n");
if(size > 0){
for (int i=0; i<size; i++)
{
fread(tmp, 1, bytes2read, BmpImage);
MergeBytes(&(pixels[i]),tmp,bytes2read);
}
printf("Цветовые индексы считаны\n");
for(int i=0; i<size; i++){
fprintf(BmpCode,"%d %d %d\n",pixels[i].r, pixels[i].g, pixels[i].b);
//printf("%d\n",i);
//if((pixels[i].r==0)&&(pixels[i].g==0)&&(pixels[i].b==0)) { printf("%d\n",i); return 10;}
//tmp[0] = pixels[i].r;
//tmp[1] = pixels[i].g;
//tmp[2] = pixels[i].b;
//printf("%d %d %d\n",tmp[0],tmp[1],tmp[2]);
//MergeBytes(&(outpixels[i]),tmp,bytes2read);
fprintf(TgaCode, "%d %d %d\n", pixels[i].r, pixels[i].g, pixels[i].b);
}
}
}
putc(0,TgaImage);
putc(0,TgaImage);
putc(2,TgaImage); /* uncompressed RGB */
putc(0,TgaImage); putc(0,TgaImage);
putc(0,TgaImage); putc(0,TgaImage);
putc(0,TgaImage);
putc(0,TgaImage); putc(0,TgaImage); /* X origin */
putc(0,TgaImage); putc(0,TgaImage); /* y origin */
putc((bmpimageinfo.biWidth & 0x00FF),TgaImage);
putc((bmpimageinfo.biWidth & 0xFF00) / 256,TgaImage);
putc((bmpimageinfo.biHeight & 0x00FF),TgaImage);
putc((bmpimageinfo.biHeight & 0xFF00) / 256,TgaImage);
putc(24,TgaImage); /* 24 bit bitmap */
putc(0,TgaImage);
for (int i=0;i<size;i++) {
putc(pixels[i].b,TgaImage);
putc(pixels[i].g,TgaImage);
putc(pixels[i].r,TgaImage);
//putc(pixels[i].a,TgaImage);
}
fclose(BmpImage);
fclose(BmpCode);
fclose(TgaImage);
fclose(TgaCode);
return 0;
}
void MergeBytes(RGB *pixel,unsigned char *p,int bytes)
{
if (bytes == 4) {
pixel->r = p[2];
pixel->g = p[1];
pixel->b = p[0];
//pixel->a = p[3];
} else if (bytes == 3) {
pixel->r = p[2];
pixel->g = p[1];
pixel->b = p[0];
//pixel->a = 0;
} else if (bytes == 2) {
pixel->r = (p[1] & 0x7c) << 1;
pixel->g = ((p[1] & 0x03) << 6) | ((p[0] & 0xe0) >> 2);
pixel->b = (p[0] & 0x1f) << 3;
//pixel->a = (p[1] & 0x80);
}
}Решение задачи: «Конвертер из Bmp в Tga»
textual
Листинг программы
//.... int sz = (size*bytes2read)+56; //размер putc(sz,BmpImage); putc(0,BmpImage); putc(0,BmpImage); putc(0,BmpImage); //....
Объяснение кода листинга программы
- В первой строке кода объявлена переменная
sz, которая вычисляет размер изображения в байтах, учитывая размер изображения и количество байтов, которые необходимо прочитать. - Затем происходит запись значения переменной
szв файлBmpImage. - После этого записываются 4 дополнительных байта со значением 0 в файл
BmpImage.