1 |
5 |
jwdonal |
//----------------------------------------------------------------------------
|
2 |
|
|
// Copyright (C) 2007 Jonathon W. Donaldson
|
3 |
|
|
// jwdonal a t opencores DOT org
|
4 |
|
|
//
|
5 |
|
|
// This program is free software; you can redistribute it and/or modify
|
6 |
|
|
// it under the terms of the GNU General Public License as published by
|
7 |
|
|
// the Free Software Foundation; either version 2 of the License, or
|
8 |
|
|
// (at your option) any later version.
|
9 |
|
|
//
|
10 |
|
|
// This program is distributed in the hope that it will be useful,
|
11 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13 |
|
|
// GNU General Public License for more details.
|
14 |
|
|
//
|
15 |
|
|
// You should have received a copy of the GNU General Public License
|
16 |
|
|
// along with this program; if not, write to the Free Software
|
17 |
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
18 |
|
|
//
|
19 |
|
|
//----------------------------------------------------------------------------
|
20 |
|
|
//
|
21 |
|
|
// $Id: bmpParse.c,v 1.1 2007-05-25 11:20:18 jwdonal Exp $
|
22 |
|
|
//
|
23 |
|
|
// Description: This program parses a BMP file and writes the
|
24 |
|
|
// necessary image data to a Xilinx COE file. The COE file
|
25 |
|
|
// can be used to initialize any instantiated BRAM memory!
|
26 |
|
|
//
|
27 |
|
|
// There is a significant difference between using binary vs hex COE files.
|
28 |
|
|
// Be sure that you use the radix that will allow you to match the exact data
|
29 |
|
|
// width (i.e. bits/color) of the LCD being used.
|
30 |
|
|
//
|
31 |
|
|
// For instance using hex radix in the COE files for the lq057q3dc02 (6
|
32 |
|
|
// bits/color) will result in 38 BRAMs being used to store the data since
|
33 |
|
|
// the hex radix would result in 8 bits of data output to the COE file instead
|
34 |
|
|
// of 6 bits. There would be 2 extra unused bits of data storage required in
|
35 |
|
|
// the BRAMs.
|
36 |
|
|
//
|
37 |
|
|
// If we use binary radix instead we can match the data width of the LCD
|
38 |
|
|
// exactly. Using binary radix we use only 29 BRAMs. For the Virtex-II Pro
|
39 |
|
|
// this is a difference of 29*3/136 vs. 38*3/136. Resulting in a 64% vs. 84%
|
40 |
|
|
// BRAM usage.
|
41 |
|
|
//
|
42 |
|
|
// The time required to generate the BRAM source files is also much less when
|
43 |
|
|
// using binary instead of hex for the lq057q3dc02. Generating the source files
|
44 |
|
|
// with binary radix COE files only takes 5min 45sec per color while a hex
|
45 |
|
|
// radix COE file requires approx 7 minutes. This is mainly due to Java's
|
46 |
|
|
// ridiculously slow I/O operations.
|
47 |
|
|
//
|
48 |
|
|
//
|
49 |
|
|
//---------------------------------------------------------------------
|
50 |
|
|
#include <stdio.h>
|
51 |
|
|
#include <stdlib.h>
|
52 |
|
|
|
53 |
|
|
#define NUM_COE_FILES 3
|
54 |
|
|
#define R_FILE_LOC 0
|
55 |
|
|
#define G_FILE_LOC 1
|
56 |
|
|
#define B_FILE_LOC 2
|
57 |
|
|
#define ARGV_BMP_NUM 1
|
58 |
|
|
#define ARGV_COE_R_NUM 2
|
59 |
|
|
#define ARGV_COE_G_NUM 3
|
60 |
|
|
#define ARGV_COE_B_NUM 4
|
61 |
|
|
#define ARGV_HDR_NUM 5
|
62 |
|
|
#define ARGV_DBG_NUM 6
|
63 |
|
|
#define ARGV_RAD_NUM 7
|
64 |
|
|
#define R_BYTE_LOC 2
|
65 |
|
|
#define G_BYTE_LOC 1
|
66 |
|
|
#define B_BYTE_LOC 0
|
67 |
|
|
#define BMP_REQUIRED_WIDTH_MULTIPLE 4
|
68 |
|
|
#define BMP_BYTES_PER_PIXEL 3
|
69 |
|
|
#define LCD_BIT_DEPTH 18
|
70 |
|
|
#define LCD_NUM_COLORS 3
|
71 |
|
|
#define RADIX_BIN 2
|
72 |
|
|
#define RADIX_HEX 16
|
73 |
|
|
|
74 |
|
|
//Type definitions
|
75 |
|
|
typedef unsigned char BYTE; /* 8 Bit Value ( 0x00 - 0xFF ) */
|
76 |
|
|
typedef unsigned short WORD; /* 16 Bit Value ( 0x0000 - 0xFFFF ) */
|
77 |
|
|
typedef unsigned long DWORD; /* 32 Bit Value ( 0x00000000 - 0xFFFFFFFF ) */
|
78 |
|
|
|
79 |
|
|
//File Header (bf = "bitmap file")
|
80 |
|
|
//Information about the file itself, not the image
|
81 |
|
|
typedef struct tagBITMAPFILEHDR {
|
82 |
|
|
|
83 |
|
|
WORD bfType; //specifies the file type
|
84 |
|
|
DWORD bfSize; //specifies the size in bytes of the bitmap file
|
85 |
|
|
WORD bfRes1; //reserved; must be 0
|
86 |
|
|
WORD bfRes2; //reserved; must be 0
|
87 |
|
|
DWORD bfOffset; //offset (in bytes) from the bitmapfileheader to image data
|
88 |
|
|
|
89 |
|
|
} BITMAPFILEHDR;
|
90 |
|
|
|
91 |
|
|
//Info Header (bi = "bitmap info")
|
92 |
|
|
//Information about the actual image
|
93 |
|
|
typedef struct tagBITMAPINFOHDR {
|
94 |
|
|
|
95 |
|
|
DWORD biSize; //specifies the number of bytes required by the struct
|
96 |
|
|
DWORD biWidth; //specifies width in pixels
|
97 |
|
|
DWORD biHeight; //species height in pixels
|
98 |
|
|
WORD biPlanes; //specifies the number of color planes, must be 1
|
99 |
|
|
WORD biBitCnt; //specifies the number of bit per pixel
|
100 |
|
|
DWORD biComp; //specifies the type of compression
|
101 |
|
|
DWORD biImgSizeWithPad; //stored image size in bytes (including row 'pad' bytes)
|
102 |
|
|
DWORD biXPelsPerMtr; //number of pixels per meter in x axis
|
103 |
|
|
DWORD biYPelsPerMtr; //number of pixels per meter in y axis
|
104 |
|
|
DWORD biClrUsed; //number of colors used by the bitmap. If zero, 2^biBitCount
|
105 |
|
|
DWORD biClrImp; //number of colors that are important. If zero, all are important
|
106 |
|
|
|
107 |
|
|
} BITMAPINFOHDR;
|
108 |
|
|
|
109 |
|
|
//This struct simply contains values that
|
110 |
|
|
//were calculated based on the information
|
111 |
|
|
//provided in the info header. NOTE! None
|
112 |
|
|
//of these values are actually in the image file!
|
113 |
|
|
typedef struct tagBITMAPINFOHDR_CALC {
|
114 |
|
|
|
115 |
|
|
DWORD biWidthInBytes;
|
116 |
|
|
DWORD biWidthInBytesMod4;
|
117 |
|
|
DWORD biWidthInBytesPadded;
|
118 |
|
|
|
119 |
|
|
} BITMAPINFOHDR_CALC;
|
120 |
|
|
|
121 |
|
|
//OutBinary
|
122 |
|
|
//Want to make equal to size of data of LCD. Do you have a way of knowing this?
|
123 |
|
|
void OutBinary( FILE *file, BYTE *bitmapImageData ) {
|
124 |
|
|
|
125 |
|
|
BYTE mask = 0x80;
|
126 |
|
|
char bin_str[LCD_BIT_DEPTH/LCD_NUM_COLORS + 1]; // +1 for NULL byte! Compiler will add a null byte for us
|
127 |
|
|
int i;
|
128 |
|
|
|
129 |
|
|
for( i = 0; i < LCD_BIT_DEPTH/LCD_NUM_COLORS; i++ ) {
|
130 |
|
|
|
131 |
|
|
bin_str[i] = ((*bitmapImageData & mask) == 0) ? '0' : '1';
|
132 |
|
|
mask >>= 1;
|
133 |
|
|
|
134 |
|
|
}
|
135 |
|
|
|
136 |
|
|
bin_str[6] = '\0'; //can't forgot to null-terminate our string!
|
137 |
|
|
|
138 |
|
|
//printf( "\nFinal hex to binary conversion for the given byte was: 0x%x", bin_str[6] );
|
139 |
|
|
//printf( "\nFinal hex to binary conversion for the given byte was: %s", bin_str );
|
140 |
|
|
fprintf( file, "\n%s,", bin_str );
|
141 |
|
|
|
142 |
|
|
return;
|
143 |
|
|
|
144 |
|
|
}//end OutBinary
|
145 |
|
|
|
146 |
|
|
// The Parser
|
147 |
|
|
BYTE* ParseBitmapFile( char* filename, BITMAPFILEHDR *bitmapFileHdr, BITMAPINFOHDR *bitmapInfoHdr, BITMAPINFOHDR_CALC *bitmapInfoHdr_Calc ) {
|
148 |
|
|
|
149 |
|
|
//CREATE necessary variables
|
150 |
|
|
FILE *filePtr; //file pointer
|
151 |
|
|
BYTE *bitmapImageData; //pointer to stored image data
|
152 |
|
|
|
153 |
|
|
|
154 |
|
|
//OPEN bitmap image file and VERIFY
|
155 |
|
|
//Note that the `b' option for fopen has no effect on POSIX compliant systems
|
156 |
|
|
//and the `b' option may cause non-POSIX systems to read the file in different
|
157 |
|
|
//manners - RTFM!
|
158 |
|
|
if ( !(filePtr = fopen( filename, "r" )) ) {
|
159 |
|
|
|
160 |
|
|
fprintf( stderr, "File Not Found!\n" ); //print exception to error
|
161 |
|
|
return NULL;
|
162 |
|
|
|
163 |
|
|
}
|
164 |
|
|
|
165 |
|
|
|
166 |
|
|
//PARSE the bitmap fileHeader - must be done this way instead of with one fread
|
167 |
|
|
//operation because a single fread will skip the 3rd and 4th bytes for some reason ???
|
168 |
|
|
fread( &(*bitmapFileHdr).bfType, sizeof((*bitmapFileHdr).bfType), 1, filePtr );
|
169 |
|
|
fread( &(*bitmapFileHdr).bfSize, sizeof((*bitmapFileHdr).bfSize), 1, filePtr );
|
170 |
|
|
fread( &(*bitmapFileHdr).bfRes1, sizeof((*bitmapFileHdr).bfRes1), 1, filePtr );
|
171 |
|
|
fread( &(*bitmapFileHdr).bfRes2, sizeof((*bitmapFileHdr).bfRes2), 1, filePtr );
|
172 |
|
|
fread( &(*bitmapFileHdr).bfOffset, sizeof((*bitmapFileHdr).bfOffset), 1, filePtr );
|
173 |
|
|
|
174 |
|
|
//VERIFY that this is a bmp file by checking bitmap id
|
175 |
|
|
if( ((*bitmapFileHdr).bfType != 0x4D42) &&
|
176 |
|
|
((*bitmapFileHdr).bfRes1 != 0x0000) &&
|
177 |
|
|
((*bitmapFileHdr).bfRes2 != 0x0000) ) {
|
178 |
|
|
|
179 |
|
|
fprintf( stderr, "INVALID File Type or Reserved Values!\n" ); //print exception to error
|
180 |
|
|
fclose( filePtr ); //close file
|
181 |
|
|
return NULL;
|
182 |
|
|
|
183 |
|
|
}
|
184 |
|
|
|
185 |
|
|
|
186 |
|
|
// PARSE the InfoHeader
|
187 |
|
|
if ( fread( bitmapInfoHdr, sizeof( BITMAPINFOHDR ), 1, filePtr ) != 1 ) {
|
188 |
|
|
|
189 |
|
|
fclose( filePtr );
|
190 |
|
|
printf( "\nRead bitmap info header failed\n" );
|
191 |
|
|
return NULL;
|
192 |
|
|
}
|
193 |
|
|
|
194 |
|
|
|
195 |
|
|
//VERIFY bitmap has not already undergone some type of compression
|
196 |
|
|
if( (*bitmapInfoHdr).biComp != 0x00000000 ) {
|
197 |
|
|
|
198 |
|
|
fprintf( stderr, "File is compressed!\n" ); //print exception to error
|
199 |
|
|
fclose( filePtr ); //close file
|
200 |
|
|
return NULL;
|
201 |
|
|
|
202 |
|
|
}
|
203 |
|
|
|
204 |
|
|
|
205 |
|
|
//Get width of image (in bytes)
|
206 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytes = (*bitmapInfoHdr).biWidth * BMP_BYTES_PER_PIXEL;
|
207 |
|
|
|
208 |
|
|
//Get width of image (in bytes) with padding bytes
|
209 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesMod4 = (*bitmapInfoHdr_Calc).biWidthInBytes % BMP_REQUIRED_WIDTH_MULTIPLE;
|
210 |
|
|
|
211 |
|
|
//If the width of the image is already a multiple of 4 then no pad bytes would have been added by the program that created the bitmap image and we simply set the pad value equal to the non-pad value.
|
212 |
|
|
if( !(*bitmapInfoHdr_Calc).biWidthInBytesMod4 ) {
|
213 |
|
|
|
214 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesPadded = (*bitmapInfoHdr_Calc).biWidthInBytes;
|
215 |
|
|
|
216 |
|
|
} else { //if the image width is not a multiple of 4, then calculate the number of pad bytes that were added
|
217 |
|
|
|
218 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesPadded = (*bitmapInfoHdr_Calc).biWidthInBytes + (BMP_REQUIRED_WIDTH_MULTIPLE - (*bitmapInfoHdr_Calc).biWidthInBytesMod4 );
|
219 |
|
|
|
220 |
|
|
}
|
221 |
|
|
|
222 |
|
|
|
223 |
|
|
//If the bitmap's info header states that the image has 0 size then we need to calculate the size manually so we know how much to allocate in memory for the image data! This phenomena is likely due to the image being originally created as some other image file format and then later converted to BMP. The parser will now calculate the expected value below.
|
224 |
|
|
if( (*bitmapInfoHdr).biImgSizeWithPad == 0 ) {
|
225 |
|
|
|
226 |
|
|
(*bitmapInfoHdr).biImgSizeWithPad = (*bitmapInfoHdr_Calc).biWidthInBytesPadded * (*bitmapInfoHdr).biHeight;
|
227 |
|
|
|
228 |
|
|
}
|
229 |
|
|
|
230 |
|
|
|
231 |
|
|
//MOVE file point to the begging of bitmap data
|
232 |
|
|
//SEEK_SET = 0 (default) - seek from beginning of file
|
233 |
|
|
fseek( filePtr, (*bitmapFileHdr).bfOffset, SEEK_SET );
|
234 |
|
|
|
235 |
|
|
|
236 |
|
|
//ALLOCATE enough memory for the bitmap image data
|
237 |
|
|
//"malloc" returns pointer to the space requested
|
238 |
|
|
bitmapImageData = (BYTE*)malloc( (*bitmapInfoHdr).biImgSizeWithPad );
|
239 |
|
|
//Could also use:
|
240 |
|
|
//bitmapImageData = (BYTE*)malloc( bitmapInfoHdr -> biImgSizeWithPad );
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
//VERIFY memory allocation
|
244 |
|
|
if( !bitmapImageData ) { //(if NULL)
|
245 |
|
|
|
246 |
|
|
fprintf( stderr, "Bitmap Image Data Memory Allocation Failed!\n" ); //print exception to std error
|
247 |
|
|
free( bitmapImageData );
|
248 |
|
|
fclose( filePtr );
|
249 |
|
|
return NULL;
|
250 |
|
|
|
251 |
|
|
}
|
252 |
|
|
|
253 |
|
|
|
254 |
|
|
//PARSE the bitmap image data
|
255 |
|
|
fread( bitmapImageData, bitmapInfoHdr -> biImgSizeWithPad, 1, filePtr );
|
256 |
|
|
|
257 |
|
|
|
258 |
|
|
//VERIFY bitmap image data was read
|
259 |
|
|
if( bitmapImageData == NULL ) {
|
260 |
|
|
|
261 |
|
|
fprintf( stderr, "Bitmap image data was not read!\n" ); //print exception to std error
|
262 |
|
|
fclose(filePtr);
|
263 |
|
|
return NULL;
|
264 |
|
|
|
265 |
|
|
}
|
266 |
|
|
|
267 |
|
|
|
268 |
|
|
//CLOSE file and return bitmap image reference
|
269 |
|
|
fclose( filePtr );
|
270 |
|
|
return bitmapImageData; //return the starting address of the bitmap image data
|
271 |
|
|
|
272 |
|
|
} //end ParseBitmapFile
|
273 |
|
|
|
274 |
|
|
|
275 |
|
|
//Used to display the bitmap header info
|
276 |
|
|
void DispBitmapHdrs( BITMAPFILEHDR *bitmapFileHdr, BITMAPINFOHDR *bitmapInfoHdr, BITMAPINFOHDR_CALC *bitmapInfoHdr_Calc ) {
|
277 |
|
|
|
278 |
|
|
//DISPLAY file header values in each variable
|
279 |
|
|
printf( "\n-- Bitmap File Header --\n%xh type\tFile Type\n%xh bytes\tFile Size\n%xh resrvd\tReserved1\n%xh resrvd\tReserved2\n%xh bytes\tImage Offset\n",
|
280 |
|
|
(*bitmapFileHdr).bfType,
|
281 |
|
|
(*bitmapFileHdr).bfSize,
|
282 |
|
|
(*bitmapFileHdr).bfRes1,
|
283 |
|
|
(*bitmapFileHdr).bfRes2,
|
284 |
|
|
(*bitmapFileHdr).bfOffset );
|
285 |
|
|
|
286 |
|
|
|
287 |
|
|
//DISPLAY info header values in each variable
|
288 |
|
|
//Each "bitmapInfoHdr" must be dereferenced b/c it was passed through to the function as a pointer
|
289 |
|
|
//and not as a local variable like "bitmapFileHdr".
|
290 |
|
|
printf( "\n-- Bitmap Info Header --\n%xh bytes\tInfo Size\n%xh pixels\tImage Width\n%xh pixels\tImage Height\n%xh planes\tColor Planes\n%xh bits\tBits/Pixel\n%xh method\tCompression\n%xh bytes\tImgSizeWithPad\n%xh pixels\tXPelsPerMtr\n%xh pixels\tYPelsPerMtr\n%xh colors\tColors Used\n%xh colors\tColrsImportant\n",
|
291 |
|
|
(*bitmapInfoHdr).biSize,
|
292 |
|
|
(*bitmapInfoHdr).biWidth,
|
293 |
|
|
(*bitmapInfoHdr).biHeight,
|
294 |
|
|
(*bitmapInfoHdr).biPlanes,
|
295 |
|
|
(*bitmapInfoHdr).biBitCnt,
|
296 |
|
|
(*bitmapInfoHdr).biComp,
|
297 |
|
|
(*bitmapInfoHdr).biImgSizeWithPad,
|
298 |
|
|
(*bitmapInfoHdr).biXPelsPerMtr,
|
299 |
|
|
(*bitmapInfoHdr).biYPelsPerMtr,
|
300 |
|
|
(*bitmapInfoHdr).biClrUsed,
|
301 |
|
|
(*bitmapInfoHdr).biClrImp );
|
302 |
|
|
|
303 |
|
|
|
304 |
|
|
//DISPLAY the calculated header values derived from the info header values
|
305 |
|
|
printf( "\n-- Bitmap Info Header (Calculated) --\n%xh bytes\tImage Width\n%xh bytes\tImage Width Mod 4\n%xh bytes\tImage Width with Padding\n",
|
306 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytes,
|
307 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesMod4,
|
308 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesPadded );
|
309 |
|
|
|
310 |
|
|
return;
|
311 |
|
|
|
312 |
|
|
} // end DispBitmapHdrs
|
313 |
|
|
|
314 |
|
|
|
315 |
|
|
//Used to write the bitmap header data to a file
|
316 |
|
|
void WriteBitmapHdrFile( char *filename, BITMAPFILEHDR *bitmapFileHdr, BITMAPINFOHDR *bitmapInfoHdr, BITMAPINFOHDR_CALC *bitmapInfoHdr_Calc, int *radix ) {
|
317 |
|
|
|
318 |
|
|
FILE* hdr_file;
|
319 |
|
|
|
320 |
|
|
//OPEN and VERIFY
|
321 |
|
|
if( !(hdr_file = fopen( filename, "w" )) ) {
|
322 |
|
|
|
323 |
|
|
fprintf( stderr, "Error Opening/Creating File!\n" ); //print exception to error
|
324 |
|
|
exit( 1 );
|
325 |
|
|
|
326 |
|
|
}
|
327 |
|
|
|
328 |
|
|
//WRITE file header values in each variable
|
329 |
|
|
fprintf( hdr_file, "-- Bitmap File Header --\n%xh type\tFile Type\n%xh bytes\tFile Size\n%xh resrvd\tReserved1\n%xh resrvd\tReserved2\n%xh bytes\tImage Offset\n",
|
330 |
|
|
(*bitmapFileHdr).bfType,
|
331 |
|
|
(*bitmapFileHdr).bfSize,
|
332 |
|
|
(*bitmapFileHdr).bfRes1,
|
333 |
|
|
(*bitmapFileHdr).bfRes2,
|
334 |
|
|
(*bitmapFileHdr).bfOffset );
|
335 |
|
|
|
336 |
|
|
|
337 |
|
|
//WRITE info header values in each variable
|
338 |
|
|
//Each "bitmapInfoHdr" must be dereferenced b/c it was passed through to the function as a pointer
|
339 |
|
|
//and not as a local variable like "bitmapFileHdr".
|
340 |
|
|
fprintf( hdr_file, "\n-- Bitmap Info Header --\n%xh bytes\tInfo Size\n%xh pixels\tImage Width\n%xh pixels\tImage Height\n%xh planes\tColor Planes\n%xh bits\tBits/Pixel\n%xh method\tCompression\n%xh bytes\tImgSizeWithPad\n%xh pixels\tXPelsPerMtr\n%xh pixels\tYPelsPerMtr\n%xh colors\tColors Used\n%xh colors\tColrsImportant\n",
|
341 |
|
|
(*bitmapInfoHdr).biSize,
|
342 |
|
|
(*bitmapInfoHdr).biWidth,
|
343 |
|
|
(*bitmapInfoHdr).biHeight,
|
344 |
|
|
(*bitmapInfoHdr).biPlanes,
|
345 |
|
|
(*bitmapInfoHdr).biBitCnt,
|
346 |
|
|
(*bitmapInfoHdr).biComp,
|
347 |
|
|
(*bitmapInfoHdr).biImgSizeWithPad,
|
348 |
|
|
(*bitmapInfoHdr).biXPelsPerMtr,
|
349 |
|
|
(*bitmapInfoHdr).biYPelsPerMtr,
|
350 |
|
|
(*bitmapInfoHdr).biClrUsed,
|
351 |
|
|
(*bitmapInfoHdr).biClrImp );
|
352 |
|
|
|
353 |
|
|
|
354 |
|
|
//WRITE the calculated header values derived from the info header values
|
355 |
|
|
fprintf( hdr_file, "\n-- Bitmap Info Header (Calculated) --\n%xh bytes\tImage Width\n%xh bytes\tImage Width Mod 4\n%xh bytes\tImage Width with Padding\n",
|
356 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytes,
|
357 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesMod4,
|
358 |
|
|
(*bitmapInfoHdr_Calc).biWidthInBytesPadded );
|
359 |
|
|
|
360 |
|
|
//WRITE the required BRAM options
|
361 |
|
|
if( *radix == RADIX_BIN ) {
|
362 |
|
|
|
363 |
|
|
fprintf( hdr_file, "\n-- BRAM Instance Parameters --\nWidth = %d\nDepth = %d\n", LCD_BIT_DEPTH/LCD_NUM_COLORS, (*bitmapInfoHdr).biWidth * (*bitmapInfoHdr).biHeight );
|
364 |
|
|
|
365 |
|
|
} else { //if RADIX_HEX
|
366 |
|
|
|
367 |
|
|
fprintf( hdr_file, "\n-- BRAM Instance Parameters --\nWidth = 8\nDepth = %d\n", (*bitmapInfoHdr).biWidth * (*bitmapInfoHdr).biHeight );
|
368 |
|
|
|
369 |
|
|
}
|
370 |
|
|
|
371 |
|
|
//CLOSE the header output file
|
372 |
|
|
fclose( hdr_file );
|
373 |
|
|
|
374 |
|
|
return;
|
375 |
|
|
|
376 |
|
|
} // end WriteBitmapHdrFile
|
377 |
|
|
|
378 |
|
|
|
379 |
|
|
//This function writes out the COE byte data for each colors
|
380 |
|
|
void WriteCoeFiles( char *filenames[], BYTE *bitmapImageData, BITMAPFILEHDR *bitmapFileHdr, BITMAPINFOHDR *bitmapInfoHdr, BITMAPINFOHDR_CALC *bitmapInfoHdr_Calc, int *debug, int *radix ) {
|
381 |
|
|
|
382 |
|
|
FILE* coeFile[3];
|
383 |
|
|
int coeFileNum;
|
384 |
|
|
int byteNum;
|
385 |
|
|
int rowNum;
|
386 |
|
|
int numOfFirstByteInRow;
|
387 |
|
|
|
388 |
|
|
//OPEN and VERIFY each COE file
|
389 |
|
|
for( coeFileNum = 0; coeFileNum < NUM_COE_FILES; coeFileNum++ ) {
|
390 |
|
|
|
391 |
|
|
coeFile[coeFileNum] = fopen( filenames[coeFileNum + 2], "w" ); //open for writing
|
392 |
|
|
|
393 |
|
|
if( coeFile[coeFileNum] == NULL ) { // check if file opening was successful
|
394 |
|
|
|
395 |
|
|
fprintf( stderr, "Error Opening/Creating File!\n" ); //print exception to error
|
396 |
|
|
exit( 1 );
|
397 |
|
|
|
398 |
|
|
} // end NULL pointer check
|
399 |
|
|
|
400 |
|
|
} //end file open check
|
401 |
|
|
|
402 |
|
|
//Add COE file color specifier
|
403 |
|
|
fprintf( coeFile[R_FILE_LOC], "; RED Image Data\n" );
|
404 |
|
|
fprintf( coeFile[G_FILE_LOC], "; GREEN Image Data\n" );
|
405 |
|
|
fprintf( coeFile[B_FILE_LOC], "; BLUE Image Data\n" );
|
406 |
|
|
|
407 |
|
|
//Add initial COE file info
|
408 |
|
|
for( coeFileNum = 0; coeFileNum < NUM_COE_FILES; coeFileNum++ ) {
|
409 |
|
|
|
410 |
|
|
fprintf( coeFile[coeFileNum], "\nMEMORY_INITIALIZATION_RADIX =\n%d;\n", *radix );
|
411 |
|
|
fprintf( coeFile[coeFileNum], "\nMEMORY_INITIALIZATION_VECTOR = " );
|
412 |
|
|
|
413 |
|
|
}
|
414 |
|
|
|
415 |
|
|
//It is important to note that bitmap image data is stored upside down
|
416 |
|
|
//with the last row of the image first and the first row of the image last.
|
417 |
|
|
//So, for example, if you were to number each pixel in a 3pixelx2row image with
|
418 |
|
|
//memory address numbers starting @ address 0, it would look like this:
|
419 |
|
|
//
|
420 |
|
|
//[B G R ][B G R ][B G R ][P P P ]
|
421 |
|
|
// | | | | | | | | | | | |
|
422 |
|
|
//[12,13,14][15,16,17][18,19,20][21,22,23] (Actual top of image if you were looking at it)
|
423 |
|
|
//[00,01,02][03,04,05][06,07,08][09,10,11] (Actual bottom of image if you were looking at it)
|
424 |
|
|
// | | | | | | | | | | | |
|
425 |
|
|
//[B G R ][B G R ][B G R ][P P P ]
|
426 |
|
|
//
|
427 |
|
|
//The above is how the image data is stored in memory with 'bitmapImageData' referencing address
|
428 |
|
|
//'00'. Each set of brackets represents one pixel. But then why are there 4 sets of brackets?
|
429 |
|
|
//I said that the image was 3 pixels wide didn't I? Well, that's true, but the BMP
|
430 |
|
|
//file format pads out all rows to be a multiple of 4 bytes wide. 3pixels x 3bytes/pixel = 9
|
431 |
|
|
//Because 9 bytes is not a multiple of 4 we have to pad out 3 bytes of '0' (blank) data to get
|
432 |
|
|
//to 12!
|
433 |
|
|
//Likewise, if the image were only 2 pixels wide = 6 bytes across, we would have to pad out
|
434 |
|
|
//2 blank bytes of '0' data to get to 8. Yes, I know, it's retarded. But like they say,
|
435 |
|
|
//don't shoot the messenger. :-)
|
436 |
|
|
//For my byte reader algorithm the blue element of the bottom left pixel of the image is
|
437 |
|
|
//coordinate: (row0, byte0). The very upper right byte is (HeightInPixels-1,
|
438 |
|
|
//biWidthInBytesPadded-1), which may be a red element (if the original image width in bytes was
|
439 |
|
|
//already a multiple of 4) or a pad byte (if the original image width in byte was not a multiple
|
440 |
|
|
//of 4).
|
441 |
|
|
for( rowNum = (*bitmapInfoHdr).biHeight-1; rowNum >= 0; rowNum-- ) {
|
442 |
|
|
|
443 |
|
|
numOfFirstByteInRow = rowNum * (*bitmapInfoHdr_Calc).biWidthInBytesPadded;
|
444 |
|
|
|
445 |
|
|
//This loop reads 3 bytes (R,G,B) at a time
|
446 |
|
|
for( byteNum = numOfFirstByteInRow; byteNum <= numOfFirstByteInRow + (*bitmapInfoHdr_Calc).biWidthInBytes - 1; byteNum = byteNum + LCD_NUM_COLORS ) {
|
447 |
|
|
|
448 |
|
|
if( !(*debug) ) { //if the user does NOT want debug output
|
449 |
|
|
|
450 |
|
|
if( *radix == RADIX_BIN ) {
|
451 |
|
|
|
452 |
|
|
OutBinary( coeFile[R_FILE_LOC], bitmapImageData + byteNum + R_BYTE_LOC );
|
453 |
|
|
OutBinary( coeFile[G_FILE_LOC], bitmapImageData + byteNum + G_BYTE_LOC );
|
454 |
|
|
OutBinary( coeFile[B_FILE_LOC], bitmapImageData + byteNum + B_BYTE_LOC );
|
455 |
|
|
|
456 |
|
|
} else { //RADIX_HEX
|
457 |
|
|
|
458 |
|
|
fprintf( coeFile[R_FILE_LOC], "\n%x,", *(bitmapImageData + byteNum + R_BYTE_LOC) );
|
459 |
|
|
fprintf( coeFile[G_FILE_LOC], "\n%x,", *(bitmapImageData + byteNum + G_BYTE_LOC) );
|
460 |
|
|
fprintf( coeFile[B_FILE_LOC], "\n%x,", *(bitmapImageData + byteNum + B_BYTE_LOC) );
|
461 |
|
|
|
462 |
|
|
}
|
463 |
|
|
|
464 |
|
|
} else { // if the user DOES want debug output (debug output disregards the user's RADIX value since the COREGEN tool cannot parse COE file with debug information. We simply force HEX_RADIX.
|
465 |
|
|
|
466 |
|
|
fprintf( coeFile[R_FILE_LOC], "\n%x\t-\t(Row %d, Byte %d)", *(bitmapImageData + byteNum + R_BYTE_LOC), rowNum, byteNum );
|
467 |
|
|
fprintf( coeFile[G_FILE_LOC], "\n%x\t-\t(Row %d, Byte %d)", *(bitmapImageData + byteNum + G_BYTE_LOC), rowNum, byteNum );
|
468 |
|
|
fprintf( coeFile[B_FILE_LOC], "\n%x\t-\t(Row %d, Byte %d)", *(bitmapImageData + byteNum + B_BYTE_LOC), rowNum, byteNum );
|
469 |
|
|
|
470 |
|
|
} // end debug output check
|
471 |
|
|
|
472 |
|
|
} // end if inner loop (byte navigation)
|
473 |
|
|
|
474 |
|
|
} // end of outer loop (row navigation)
|
475 |
|
|
|
476 |
|
|
|
477 |
|
|
//Need to replace the last character in all three files with a semi-colon instead of a comma
|
478 |
|
|
for( coeFileNum = 0; coeFileNum < NUM_COE_FILES; coeFileNum++ ) {
|
479 |
|
|
fseek( coeFile[coeFileNum], -1, SEEK_CUR ); // go back one character from the current
|
480 |
|
|
fprintf( coeFile[coeFileNum], ";" ); //replace the last character with a semi-colon
|
481 |
|
|
fclose( coeFile[coeFileNum] ); //CLOSE the output file because we're done
|
482 |
|
|
}
|
483 |
|
|
|
484 |
|
|
|
485 |
|
|
return;
|
486 |
|
|
|
487 |
|
|
} //end WriteCoeFiles
|
488 |
|
|
|
489 |
|
|
|
490 |
|
|
/****MAIN FUNCTION****/
|
491 |
|
|
int main( int argc, char* argv[] ) {
|
492 |
|
|
|
493 |
|
|
BITMAPFILEHDR bitmapFileHdr;
|
494 |
|
|
BITMAPINFOHDR bitmapInfoHdr;
|
495 |
|
|
BITMAPINFOHDR_CALC bitmapInfoHdr_Calc;
|
496 |
|
|
BYTE *bitmapImageData;
|
497 |
|
|
int debug;
|
498 |
|
|
int radix;
|
499 |
|
|
|
500 |
|
|
|
501 |
|
|
//CHECK for proper number of arguments
|
502 |
|
|
if( argc != 8 ) {
|
503 |
|
|
|
504 |
|
|
//Print exception to error (argv[0] is the program name itself)
|
505 |
|
|
fprintf( stderr, "Usage: %s <24bpp_bitmap> <R_coe_output> <G_coe_output> <B_coe_output> <bitmap_hdr_output> <debug> <radix>\n", argv[0] );
|
506 |
|
|
exit(1);
|
507 |
|
|
|
508 |
|
|
} //end argument check
|
509 |
|
|
|
510 |
|
|
//Check for proper radix values
|
511 |
|
|
radix = atoi( argv[ARGV_RAD_NUM] );
|
512 |
|
|
if( radix != RADIX_BIN &&
|
513 |
|
|
radix != RADIX_HEX ) {
|
514 |
|
|
|
515 |
|
|
fprintf( stderr, "Invalid value for <radix>. Choose either 2 or 16." );
|
516 |
|
|
exit(1);
|
517 |
|
|
|
518 |
|
|
}
|
519 |
|
|
|
520 |
|
|
//get debug value
|
521 |
|
|
debug = atoi( argv[ARGV_DBG_NUM] );
|
522 |
|
|
if( debug ) {
|
523 |
|
|
fprintf( stderr, "Debug output has been requested. RADIX value will be ignored!" );
|
524 |
|
|
}
|
525 |
|
|
|
526 |
|
|
//PARSE the bitmap file
|
527 |
|
|
bitmapImageData = ParseBitmapFile( argv[ARGV_BMP_NUM], &bitmapFileHdr, &bitmapInfoHdr, &bitmapInfoHdr_Calc );
|
528 |
|
|
|
529 |
|
|
//make sure we got a good reference address from our parser
|
530 |
|
|
if( bitmapImageData == NULL ) {
|
531 |
|
|
fprintf( stderr, "The parser did not return a valid reference address for the bitmap data!\nExiting..." );
|
532 |
|
|
exit(1);
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
if( debug ) {
|
536 |
|
|
DispBitmapHdrs( &bitmapFileHdr, &bitmapInfoHdr, &bitmapInfoHdr_Calc );
|
537 |
|
|
}
|
538 |
|
|
|
539 |
|
|
|
540 |
|
|
//WRITE out bitmap header info to specified file
|
541 |
|
|
WriteBitmapHdrFile( argv[ARGV_HDR_NUM], &bitmapFileHdr, &bitmapInfoHdr, &bitmapInfoHdr_Calc, &radix );
|
542 |
|
|
|
543 |
|
|
|
544 |
|
|
//WRITE out COE file color data for BRAMs
|
545 |
|
|
WriteCoeFiles( argv, bitmapImageData, &bitmapFileHdr, &bitmapInfoHdr, &bitmapInfoHdr_Calc, &debug, &radix );
|
546 |
|
|
|
547 |
|
|
printf( "\nImage Parsing and COE Data Collection Successful!\n" );
|
548 |
|
|
|
549 |
|
|
return 0;
|
550 |
|
|
|
551 |
|
|
} //end main function
|