Форум программистов, компьютерный форум CyberForum.ru

Открытие и запись файла bmp. Что здесь не так ? - C++

Восстановить пароль Регистрация
 
mariko_11
2 / 2 / 1
Регистрация: 11.03.2013
Сообщений: 64
21.03.2014, 23:33     Открытие и запись файла bmp. Что здесь не так ? #1
Имеется программа, копирующая содержимое из указанного bmp в файл result. Проблема: файл stars копируется нормально, а вместо скопированного tank получается какая-то ерунда. Почему ?

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <iostream>
 
using namespace std;
 
typedef struct pixel {
    char red;
    char green;
    char blue;
 
} pixel_t;
 
typedef struct pixel_array {
    pixel_t **array_of_pixel;
    long height;
    long width;
 
} pixel_array_t;
 
typedef struct tagBITMAPFILEHEADER {
    unsigned short    bfType;
    unsigned long     bfSize;
    unsigned short    bfReserved1;
    unsigned short    bfReserved2;
    unsigned long     bfOffBits;
} BITMAPFILEHEADER;
 
typedef struct tagBITMAPINFOHEADER {
    unsigned long biSize;
    unsigned long biWidth;
    unsigned long biHeight;
    unsigned short  biPlanes;
    unsigned short  biBitCount;
    unsigned long biCompression;
    unsigned long biSizeImage;
    long  biXPelsPerMeter;
    long  biYPelsPerMeter;
    unsigned long biClrUsed;
    unsigned long biClrImportant;
} BITMAPINFOHEADER;
 
const int MAX_PATH_LEN = 260;
 
void parse_file(FILE *file, pixel_array_t *pix_arr, BITMAPFILEHEADER &header, BITMAPINFOHEADER &info_header) {
 
    unsigned long image_size = 0;
    long height = 0;
    long width = 0;
 
    // Читаем первую структуру (BITMAPFILEHEADER)
    fread(&header.bfType, 1, sizeof(header.bfType), file);
    fread(&header.bfSize, 1, sizeof(header.bfSize), file);
    fread(&header.bfReserved1, 1, sizeof(header.bfReserved1), file);
    fread(&header.bfReserved2, 1, sizeof(header.bfReserved2), file);
    fread(&header.bfOffBits, 1, sizeof(header.bfOffBits), file); // Нам нужно это поле
 
 
    cout << hex << "bfType = " << "0x" << header.bfType << endl;
    cout << hex << "bfSize = " << "0x" << header.bfSize << endl;
    cout << hex << "bfOffBits = " << "0x" << header.bfOffBits << endl;
 
    // Читаем вторую структуру (BITMAPINFOHEADER) чтобы узнать размер буфера пикселей
    fread(&info_header, 1, sizeof(info_header), file);
    cout << "biWidth = " << info_header.biWidth << endl;
    cout << "biHeight = " << info_header.biHeight << endl;
 
    if (info_header.biSizeImage == 0) { // Если это поле оказалось нулевым
        image_size = info_header.biWidth * 3 + info_header.biWidth % 4;
        image_size *= info_header.biHeight; // считаем вручную
    } else {
        image_size = info_header.biSizeImage; // иначе - берем как есть
    }
 
    cout << "size = " << image_size << endl;
 
    fseek(file, header.bfOffBits, SEEK_SET); // Смещаемся к буферу пикселей
    //fread(array_of_pixel, image_size, 1, file); // Читаем
 
    // Заводим двухмерный массив под структуры пикселя
    pix_arr->height = height = info_header.biHeight;
    pix_arr->width = width = info_header.biWidth;
    pix_arr->array_of_pixel = new pixel_t *[width];
    for (int i = 0; i < width; ++i) {
        pix_arr->array_of_pixel[i] = new pixel_t[height];
    }
 
    //задаем значения массиву
    for (int i = 0; i < width; ++i) {
        for (int j = 0; j < height ; ++j)
            fread(&pix_arr->array_of_pixel[i][j], sizeof(pixel_t), 1, file);
    }
 
}
 
void create_image(const char *name, pixel_t **pixels, int width, int height, BITMAPFILEHEADER &header, BITMAPINFOHEADER &info_header) {
    FILE *f;
 
    f = fopen(name, "wb");
    fwrite(&header.bfType, sizeof(header.bfType), 1, f);
    fwrite(&header.bfSize, sizeof(header.bfSize),1, f);
    fwrite(&header.bfReserved1, sizeof(header.bfReserved1),1, f);
    fwrite(&header.bfReserved2, sizeof(header.bfReserved2),1, f);
    fwrite(&header.bfOffBits, sizeof(header.bfOffBits),1, f);
 
    fwrite(&info_header, sizeof(info_header), 1, f);
 
    for(int i = 0; i < width; ++i) {
        for (int j = 0; j < height; ++j) {
            unsigned char pix [] = {pixels[i][j].red, pixels[i][j].green, pixels[i][j].blue};
            //unsigned char pix [] = {0, 0, (char)pixels[i][j]};
            fwrite(pix, 1, 3, f);
        }
    }
    fclose(f);
}
 
 
int main()
{
    char file_path[MAX_PATH_LEN] = "tank.bmp";
    pixel_array_t arr_info = {NULL, 0, 0}; // Массив структур пикселя.
 
    FILE *bmp_file;
 
    bmp_file = fopen(file_path, "r");
    if (bmp_file == NULL) {
        cout << "Error, file not found" << endl;
        return -1;
    }
 
    BITMAPFILEHEADER header; BITMAPINFOHEADER info_header;
 
    parse_file(bmp_file, &arr_info, header, info_header);
 
    cout << "w = " << arr_info.width << " h = " << arr_info.height << endl;
 
    create_image("result.bmp", arr_info.array_of_pixel, arr_info.width, arr_info.height, header, info_header);
 
    fclose(bmp_file);
 
 
    cout << "finished" << endl;
 
    return 0;
}
Вложения
Тип файла: zip bmp.zip (90.9 Кб, 10 просмотров)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.03.2014, 23:33     Открытие и запись файла bmp. Что здесь не так ?
Посмотрите здесь:

C++ Открытие и запись bmp-файла
C++ Что здесь не так
Что здесь не так? C++
C++ Кто знает что здесь не так
C++ что здесь не так? (из промежутка [n; m] вывести число, которое имеет наибольшее делителей)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
mariko_11
2 / 2 / 1
Регистрация: 11.03.2013
Сообщений: 64
21.03.2014, 23:44  [ТС]     Открытие и запись файла bmp. Что здесь не так ? #2
А вот этот файл вообще копируется битым
Вложения
Тип файла: zip test_apache.zip (59.1 Кб, 3 просмотров)
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
22.03.2014, 14:55     Открытие и запись файла bmp. Что здесь не так ? #3
Цитата Сообщение от mariko_11 Посмотреть сообщение
C++
1
2
FILE *bmp_file;
bmp_file = fopen(file_path, "r");
Открываете файл в текстовом режиме, а используете бинарные методы чтения. "rb" нужно.
mariko_11
2 / 2 / 1
Регистрация: 11.03.2013
Сообщений: 64
22.03.2014, 15:08  [ТС]     Открытие и запись файла bmp. Что здесь не так ? #4
Исправлено, но стало не сильно лучше. Последний рисунок всё равно получается битым. При открытии его в среде видна чёрная полоса наверху, а виндовая программа просмотра вообще его не открывает. В остальных битых рисунках та же история. Изображение почему-то полностью не влазит. Не могу понять, почему.
zss
Модератор
Эксперт С++
 Аватар для zss
5943 / 5548 / 1783
Регистрация: 18.12.2011
Сообщений: 14,170
Завершенные тесты: 1
22.03.2014, 18:31     Открытие и запись файла bmp. Что здесь не так ? #5
Не забывайте, что строки изображения выровнены на границу двойного слова
(т.е. длина строки кратна 8).
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
23.03.2014, 21:59     Открытие и запись файла bmp. Что здесь не так ? #6
Цитата Сообщение от zss Посмотреть сообщение
(т.е. длина строки кратна 8).
А не четырём?

Добавлено через 1 час 56 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <iostream>
using namespace std;
 
typedef struct pixel 
{
    char red;
    char green;
    char blue;
 
} pixel_t;
 
typedef struct pixel_array 
{
    pixel_t **array_of_pixel;
    long height;
    long width;
 
} pixel_array_t;
 
typedef struct tagBITMAPFILEHEADER {
    unsigned short    bfType;
    unsigned long     bfSize;
    unsigned short    bfReserved1;
    unsigned short    bfReserved2;
    unsigned long     bfOffBits;
} BITMAPFILEHEADER;
 
typedef struct tagBITMAPINFOHEADER {
    unsigned long biSize;
    unsigned long biWidth;
    unsigned long biHeight;
    unsigned short  biPlanes;
    unsigned short  biBitCount;
    unsigned long biCompression;
    unsigned long biSizeImage;
    long  biXPelsPerMeter;
    long  biYPelsPerMeter;
    unsigned long biClrUsed;
    unsigned long biClrImportant;
} BITMAPINFOHEADER;
 
const int MAX_PATH_LEN = 260;
 
void parse_file(FILE *file, pixel_array_t& pix_arr, BITMAPFILEHEADER &header, BITMAPINFOHEADER &info_header) {
 
    unsigned long image_size = 0;
    long height = 0;
    long width = 0;
 
    // Читаем первую структуру (BITMAPFILEHEADER)
    fread(&header.bfType, 1, sizeof(header.bfType), file);
    fread(&header.bfSize, 1, sizeof(header.bfSize), file);
    fread(&header.bfReserved1, 1, sizeof(header.bfReserved1), file);
    fread(&header.bfReserved2, 1, sizeof(header.bfReserved2), file);
    fread(&header.bfOffBits, 1, sizeof(header.bfOffBits), file); // Нам нужно это поле
 
 
    cout << hex << "bfType = " << "0x" << header.bfType << endl;
    cout << hex << "bfSize = " << "0x" << header.bfSize << endl;
    cout << hex << "bfOffBits = " << "0x" << header.bfOffBits << endl;
 
    // Читаем вторую структуру (BITMAPINFOHEADER) чтобы узнать размер буфера пикселей
    fread(&info_header, 1, sizeof(info_header), file);
    cout << "biWidth = " << info_header.biWidth << endl;
    cout << "biHeight = " << info_header.biHeight << endl;
 
    if (info_header.biSizeImage == 0) { // Если это поле оказалось нулевым
        image_size = info_header.biWidth * 3 + info_header.biWidth % 4;
        image_size *= info_header.biHeight; // считаем вручную
    } else {
        image_size = info_header.biSizeImage; // иначе - берем как есть
    }
 
    cout << "size = " << image_size << endl;
 
    fseek(file, header.bfOffBits, SEEK_SET); // Смещаемся к буферу пикселей
    //fread(array_of_pixel, image_size, 1, file); // Читаем
    
    // Заводим двухмерный массив под структуры пикселя
    pix_arr.height = height = info_header.biHeight;
    pix_arr.width = width = info_header.biWidth;
 
    pix_arr.array_of_pixel = new pixel_t* [height];
    for (int i = 0; i < height; ++i)
        pix_arr.array_of_pixel[i] = new pixel_t [width];
    
    int length_str = (3 * width + 3) & (-4); // длина строки в файле, включая округление вверх до кратного 4
    int n = length_str - width * 3; // количество байтов выравнивания в строке
    
    //задаем значения массиву
    for (int i = 0; i < height; ++i)
    {
        int j;
        for (j = 0; j < width; ++j)
            fread(&(pix_arr.array_of_pixel[i][j]), sizeof(pixel_t), 1, file);
        
        for (int k = 0; k < n; ++k) // пропуск байтов выравнивания
            fgetc(file);
    }
}
 
void create_image(const char *name, pixel_t** pixels, int width, int height, BITMAPFILEHEADER &header, BITMAPINFOHEADER &info_header) {
    FILE *f;
 
    f = fopen(name, "wb");
    fwrite(&header.bfType, sizeof(header.bfType), 1, f);
    fwrite(&header.bfSize, sizeof(header.bfSize),1, f);
    fwrite(&header.bfReserved1, sizeof(header.bfReserved1),1, f);
    fwrite(&header.bfReserved2, sizeof(header.bfReserved2),1, f);
    fwrite(&header.bfOffBits, sizeof(header.bfOffBits),1, f);
 
    fwrite(&info_header, sizeof(info_header), 1, f);
 
    int length_str = (3 * width + 3) & (-4); // длина строки в файле, включая округление вверх до кратного 4
    int n = length_str - width * 3; // количество байтов выравнивания в строке
    
    for (int i = 0; i < height; ++i)
    {
        for (int j = 0; j < width; ++j)
        {
            unsigned char pix [] = {pixels[i][j].red, pixels[i][j].green, pixels[i][j].blue};
            fwrite(pix, 1, 3, f);
        }
        for (int k = 0; k < n; ++k) // запись байтов выравнивания
        {
            fputc(0, f);
        }
    }
    
    for (int i = 0; i < info_header.biSizeImage - length_str * height; ++i)
        fputc(0, f);
    fclose(f);
}
 
 
int main()
{
    char file_path[MAX_PATH_LEN] = "test_apache.bmp";
    pixel_array_t arr_info = {NULL, 0, 0}; // Массив структур пикселя.
 
    FILE *bmp_file;
 
    bmp_file = fopen(file_path, "rb");
    if (bmp_file == NULL) {
        cout << "Error, file not found" << endl;
        return -1;
    }
 
    BITMAPFILEHEADER header; BITMAPINFOHEADER info_header;
 
    parse_file(bmp_file, arr_info, header, info_header);
 
    cout << "w = " << arr_info.width << " h = " << arr_info.height << endl;
 
    create_image("result.bmp", arr_info.array_of_pixel, arr_info.width, arr_info.height, header, info_header);
 
    fclose(bmp_file);
 
 
    cout << "finished" << endl;
 
    cin.get();
    return 0;
}
Добавлено через 20 часов 5 минут
mariko_11, что молчим? Проблема решена?
Yandex
Объявления
23.03.2014, 21:59     Открытие и запись файла bmp. Что здесь не так ?
Ответ Создать тему
Опции темы

Текущее время: 12:57. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru