In this article, I will describe some kinds of Digital Camera Raw files' format/data structure. With these data structures, we can convert 24bit(true color) bitMap file to DCR file.
Introduction
This article describes some kinds of DCR (Digital Camera Raw) files' format/data structure.
With this data structure, we can convert 24bit(true color) bitMap file to dcr file.
Application Scenario
Dave Coffin's dcraw.c can decode many raw photos. If we get his license, then we can port the code into our project. But, how to get lots of raw photos, to test our code?
- We can buy many camera in different kinds (too much money).
- We can wait for photos which are uploaded by cameraman, not jpeg format, not png format, must be raw format (too much time).
- We can use this article, to make raw files by ourselves with our small
bitMap
s.
Data Structure
| Maker | Model | tiff_bps |
1 | Kodak | DCS760C | 8 |
2 | ricoh | GR Digital | 12 |
3 | NIKON | SUPER COOLSCAN 5000 ED |
4 | EPSON | R-D1 |
5 | Pentax | K110D |
6 | Leaf | |
7 | Sinar |
8 | Minolta | DiMAGE 5 |
9 | FujiFilm | FinePix S5100 | 14 |
10 | LEICA | Digilux 2 | 16 |
11 | Panasonic | DMC-LC1 |
12 | OLYMPUS | E-10 |
13 | Casio | EX-P600 |
14 | Phase One | H 10 |
In lots of raw files, H(Height) and W(Width) are fixed, which cannot be changed by our source bitMap
. They are out of the scope of this article.
Background
Some kinds of raw files cannot be converted by different decoders (example for rollei's d530flex
raw format, it is not exported by acdsee's id_dcRaw.apl version 2.2). They are out of the scope of this article, too.
If we declare "unsigned char bitMap[H][W][3]
", and read them from small 24bit 3channel bitMap
(file)s, then we can make raw files by ourselves, with the following file format.
Note: 24bit 3channel bitMap
's file format is:
0000~
0001: | 0002~
0005: | 0006~
0009: | 000a~
000d: | 000e~0035:(long head[0x0a]) | 0x36~(0x35+H*W4) |
'B', 'M' | 0x36
+H*W4 | 0 | 0x36 | 000e~
0011: | 0012~
0015: | 0016~
0019: | 001a~001d: | 001e~
0021: | ... | 0032~
0035: | unsigned char
bitMap[H][W4] |
0x28 | W | H | 1 | 24 | 0 | ... | 0 |
flag | long
file size | ? | long
&bitMap | long
head_size | long
Width | long
Height | short
plane,bps | long
compress | ... | long
cnt2 |
W4 (Number of bytes in each scanLine
of bitMap
file)=(W*3+3)&(~3), it is align to 4 byte, for acceleration.)
Most of the above raw files use tiff (tag image file format) format. In this format, there will be some ifde (image file directory entry) in the front of file, and each ifde is a 12_bytes_structure
: {short tag; short type; long count; long value(or offset)}.
Some raw will use their color matrix. At that time, we shall use our default matrix, to change from xyz to rgb space.
signed long ColorMatrix[3][6]=
(?+0000)~
(?+0017): | {3240479,1000000,
-1537151,1000000,
-498535,1000000} | //means: 3.240479, -1.537151, -0.498535 |
(?+0018)~
(?+002f): | {-969256,1000000,
1875992,1000000,
41556,1000000} | //means: -0.969256, 1.875992, 0.041556 |
(?+0030)~
(?+0047): | { 55648,1000000,
-204043,1000000,
1057311,1000000} | //means: 0.055648, -0.204043, 1.057311 |
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1 |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count=8 |
There are at least 8 entries that follow, and each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0xAc621,?,0x90 | &ColorMatrix |
2 | 0018~0023: | 0x10f, ?, 0x70 | &str_make |
3 | 0024~002f: | 0x110, ?, 0x80 | &str_model |
4 | 0030~003b: | 0x100, 1, W | W>=22(for irfanView) |
5 | 003c~0047: | 0x101, 1, H | H>=22(for dcRaw) |
6 | 0048~0053: | 0x102, 0, 8 | tiff_bps |
7 | 0054~005f: | 0x103, 1, 1 | tiff_compress |
8 | 0060~006b: | 0x144, 1, 0xe0 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change the entry_count
above.
006c~006f: | long entries_2=0 |
0070~007f: | char str_make[ ]={"Kodak"} |
0080~008f: | char str_model[]={"DCS760C"} |
0090~00d7: | signed long ColorMatrix[3][6] |
00d8~00df: | ? |
int order[2][2]={{G,R},{B,G}};
(In the following text, bitMap[y][x][c]
abbreviates to m[y,x,c]
,
and order[(y)&1][(x)&1]
abbreviates to "o(y,x)
").
file addr | unsigned char raw_data[H*W] |
00e0~
(00df+W): | m[0,0,G] | m[0,1,R] | m[0,2,G] | m[0,3,R] | ... | m[0,W-1,(1&W)?G:R] |
(00e0+W)~
(00df+W*2): | m[1,0,B] | m[1,1,G] | m[1,2,B] | m[1,3,G] | ... | m[1,W-1,(1&W)?B:G] |
(00e0+W*2)~
(00df+W*3): | m[2,0,G] | m[2,1,R] | m[2,2,G] | m[2,3,R] | ... | m[2,W-1,(1&W)?G:R] |
(00e0+W*3)~
(00df+W*4): | m[3,0,B] | m[3,1,G] | m[3,2,B] | m[3,3,G] | ... | m[3,W-1,(1&W)?B:G] |
... | ... |
(00e0+W*(H-1))~
(00df+W*H): | m[H-1,0,
o(H-1,0)] | m[H-1,1,
o(H-1,1)] | m[H-1,2,
o(H-1,2)] | m[H-1,3,
o(H-1,3)] | ... | m[H-1,W-1,
o(H-1,W-1)] |
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 7,0 | short entry_count; |
There are 7 entries followed.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, w*2 | w*2>=22
(irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22
(dcRaw) |
5 | 003c~0047: | 0x102,0, 0x0c | tiff_bps |
6 | 0048~0053: | 0xfd04,4, 0 | tag(P-series) |
7 | 0054~005f: | 0x144,1, 0x90 | &raw_data |
The entries are in disarray. And we can add any into them, of course we must change entry_count
above.
Here, we use w=W/2, //it means half of width
because acdsee 5.0(id_dcRaw.apl version 2.2) declare there are (12*W
) bits per scanLine
,
and cxImg6.0(libdcr
version 0.1.8.93) declare there are (12*raw_width
) bits per scanLine
,
and irfan 4.42(formats.dll 4.42) declare there are (12*raw_width+7
)&(~7) bits per scanLine
.
0060~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"ricoh"}; |
0080~008f: | char str_model[16]={"GR Digital"}; |
int order[2][2]={{R,G},{G,B}};
(In the following text, bitMap[y][x][c]
abbreviates to m[y,x,c]
,
and order[(y)&1][(x)&1]
abbreviates to "o(y,x)
")
1st line:
a~
(a+u-1): | m[0,0,R] | m[0,1,G]>>4 | m[0,1,G]<<4 | m[0,2,R] | m[0,3,G]>>4 | m[0,3,G]<<4 | ... | m[0,2*w-2,R] | m[0,2*w-1,G]>>4 | m[0,2*w-1,G]<<4 |
2nd line:
(a+u)~
(a+u*2-1): | m[1,0,G] | m[1,1,B]>>4 | m[1,1,B]<<4 | m[1,2,G] | m[1,3,B]>>4 | m[1,3,B]<<4 | ... | m[1,2*w-2,G] | m[1,2*w-1,B]>>4 | m[1,2*w-1,B]<<4 |
3rd line:
(a+u*2)~
(a+u*3-1): | m[2,0,R] | m[2,1,G]>>4 | m[2,1,G]<<4 | m[2,2,R] | m[2,3,G]>>4 | m[2,3,G]<<4 | ... | m[2,2*w-2,R] | m[2,2*w-1,G]>>4 | m[2,2*w-1,G]<<4 |
4th line:
(a+u*3)~
(a+u*4-1): | m[3,0,G] | m[3,1,B]>>4 | m[3,1,B]<<4 | m[3,2,G] | m[3,3,B]>>4 | m[3,3,B]<<4 | ... | m[3,2*w-2,G] | m[3,2*w-1,B]>>4 | m[3,2*w-1,B]<<4 |
... | ... |
Last line:
(a+u*(H-1))~
(a+u* H-1): | m[H-1,0,
o(H-1,0)] | m[H-1,1,
o(H-1,1)]>>4 | m[H-1,1,
o(H-1,1)]<<4 | m[H-1,2,
o(H-1,2)] | m[H-1,3,
o(H-1,3)]>>4 | m[H-1,3,
o(H-1,3)]<<4 | ... | m[H-1,2*w-2,
o(H-1,2*w-2)] | m[H-1,2*w-1,
o(H-1,2*w-1)]>>4 | m[H-1,2*w-1,
o(H-1,2*w-1)] |
For ricoh, a=0x90, u=w*3;
For NIKON, a=0xa0, u=w*3;
For Pentax, a=0xe0, u=w*3;
For EPSON, a=0xe0, u=w*3+((w*2)/10)
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count; |
There are 8 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, w*2 | w*2>=22
(irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22
(dcRaw) |
5 | 003c~0047: | 0x102,0, 0x0c | tiff_bps |
6 | 0048~0053: | 0x828e,1, 0 | clear filter |
7 | 0054~005f: | 0x828e,4,
0x2010100 | set filter=
0x94949494 |
8 | 0060~006b: | 0x144,1, 0xA0 | &raw_data |
The entries are in disarray. And we can add any into them, of course we must change entry_count
above.
Here, we use w=W/2, //it means half of width
because acdsee 5.0(id_dcRaw.apl version 2.2) declare there are (12*W
) bits per scanLine
,
and cxImg6.0(libdcr
version 0.1.8.93) declare there are (12*raw_width
) bits per scanLine
,
and irfan 4.42(formats.dll 4.42) declare there are (12*raw_width+7
)&(~7) bits per scanLine
.
006c~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"NIKON"}; |
0080~009f: | char str_model[32]={"SUPER COOLSCAN 5000 ED"}; |
0xa0~
(0x9f+u*H) | unsigned char raw_data[H*u]; |
(Note: u=w*3)
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 7,0 | short entry_count; |
There are 7 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, w*2 | w*2>=22
(irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22
(dcRaw) |
5 | 003c~0047: | 0x102,0, 0x0c | tiff_bps |
6 | 0048~0053: | 0xAc621,?, 0x90 | &ColorMatrix |
7 | 0054~005f: | 0x144,1, 0xe0 | &raw_data |
The entries are in disarray. And we can add any into them, of course we must change the entry_count
above.
Here, we use w=W/2, //it means half of width
because acdsee 5.0(id_dcRaw.apl version 2.2) declares there are (12*W
) bits per scanLine
,
and cxImg6.0(libdcr
version 0.1.8.93) declares there are (12*raw_width
) bits per scanLine
,
and irfan 4.42(formats.dll 4.42) declares there are (12*raw_width+7
)&(~7) bits per scanLine
.
0060~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"Pentax"}; |
0080~008f: | char str_model[16]={"K110D"}; |
0090~00d7: | signed long ColorMatrix[3][6]; |
00d8~00df: | ? |
0xe0~
(0xdf+u*H) | unsigned char raw_data[H*u]; |
(Note: u=w*3
)
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count; |
There are 8 entries followed.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, w*2 | w*2>=22
(irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22
(dcRaw) |
5 | 003c~0047: | 0x102,0, 0x0c | tiff_bps |
6 | 0048~0053: | 0x103,0,0x8001 | tiff_compress |
7 | 0054~005f: | 0xAc621,?, 0x90 | &ColorMatrix |
8 | 0060~006b: | 0x144,1, 0xe0 | &raw_data |
The entries are in disarray. And we can add any into them, of course we must change entry_count
above.
Here, we use w=W/2, //it means half of width
because acdsee 5.0(id_dcRaw.apl version 2.2) declare there are (12*W
) bits per scanLine
,
and cxImg6.0(libdcr
version 0.1.8.93) declare there are (12*raw_width
) bits per scanLine
,
and irfan 4.42(formats.dll 4.42) declare there are (12*raw_width+7
)&(~7) bits per scanLine
.
006c~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"EPSON"}; |
0080~008f: | char str_model[16]={"R-D1"}; |
0090~00d7: | signed long ColorMatrix[3][6]; |
00d8~00df: | ? |
0xe0~
(0xdf+u*H) | unsigned char raw_data[H*u]; |
//Note: u=w*3+((w*2)/10).
Only for EPSON: Every 15_bytes
of raw_data
in a (scan)Line, we must insert 1 byte zero after these 15_bytes
(align to 16 byte, for acceleration.)
So, if(2<=(width%10)<8)
, these zero_bytes
will cause a bug in cxImg7.0
, but not in cxImg6.0
.
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count; |
There are 8 entries followed.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x85ff,
?, ? | leaf tag |
2 | 0018~0023: | 0x100,1, W | W>=22(for irfanView) |
3 | 0024~002f: | 0x101,1, H | H>=22(for dcRaw) |
4 | 0030~003b: | 0x115,1, 1 | tiff_samples |
5 | 003c~0047: | 0xAc621,?, 0x70 | &ColorMatrix |
6 | 0048~0053: | 0x144,1, 0xc0 | &raw_data |
7 | 0054~005f: | 0x142,1, W | tile_width |
8 | 0060~006b: | 0x143,1, H-1 | tile_length |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
006c~006f: | long entries_2[]={0} |
0070~00b7: | signed long ColorMatrix[3][6] |
00b8~00bf: | ? |
00c0~00cf: | long ptr[4]={0xd0, 0xd0+(H-1)*W*2};
//&1st line, &Last line |
int order[2][2]={{R,G},{G,B}};
(In following text, bitMap[y][x][c] abbreviate to m[y,x,c],
and order[(y)&1][(x)&1] abbreviate to "o(y,x)")
1st line:
a~
(a+W*2-1): | m[0,0,R]<<s | m[0,1,G]<<s | m[0,2,R]<<s | m[0,3,G]<<s | ... | m[0,W-1,(1&W)?R:G]<<s |
2nd line:
(a+W*2)~
(a+W*4-1): | m[1,0,G]<<s | m[1,1,B]<<s | m[1,2,G]<<s | m[1,3,B]<<s | ... | m[1,W-1,(1&W)?G:B]<<s |
3rd line:
(a+W*4)~
(a+W*6-1): | m[2,0,R]<<s | m[2,1,G]<<s | m[2,2,R]<<s | m[2,3,G]<<s | ... | m[2,W-1,(1&W)?R:G]<<s |
4th line:
(a+W*6)~
(a+W*8-1): | m[3,0,G]<<s | m[3,1,B]<<s | m[3,2,G]<<s | m[3,3,B]<<s | ... | m[3,W-1,(1&W)?G:B]<<s |
... | ... |
Last line:
(a+W*2*(H-1))~
(a+W*2* H-1): | m[H-1,0,
o(H-1,0)]<<s | m[H-1,1,
o(H-1,1)]<<s | m[H-1,2,
o(H-1,2)]<<s | m[H-1,3,
o(H-1,3)]<<s | ... | m[H-1,W-1,
o(H-1,W-1)]<<s |
For Leaf, a= 0xd0, s=4;
For Sinar, a= 0xb0, s=4;
For FujiFilm, a= 0xe0, s=6;
For LEICA, a= 0x90, s=8;
For Panasonic, a= 0xe0, s=8;
For OLYMPUS, a=0x100, s=8;
For Casio, a= 0xc0, s=8;
For Minolta, a=0x110, s=4
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 5,0 | short entry_count; |
There are 5 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x50 | &str_make |
2 | 0018~0023: | 0x100,1, W | W>=22(for irfanView) |
3 | 0024~002f: | 0x101,1, H | H>=22(for dcRaw) |
4 | 0030~003b: | 0xAc621,?, 0x60 | &ColorMatrix |
5 | 003c~0047: | 0x144,1, 0xB0 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
0048~004f: | long entries_2[]={0}; |
0050~005f: | char str_make[16]={"Sinar"}; |
0060~00a7: | signed long ColorMatrix[3][6]; |
00a8~00af: | ? |
00b0~
(00af+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 7,0 | short entry_count; |
There are 7 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 003c~0047: | 0x102,0, 0x0E | tiff_bps |
6 | 0048~0053: | 0xAc621,?, 0x90 | &ColorMatrix |
7 | 0054~005f: | 0x144,0, 0xe0 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
0060~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"FujiFilm"}; |
0080~008f: | char str_model[16]={"FinePix S5100"}; |
0090~00d7: | signed long ColorMatrix[3][6]; |
00d8~00df: | ? |
00e0~
(00df+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 7,0 | short entry_count; |
There are 7 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 003c~0047: | 0x102,0, 0x10 | tiff_bps |
6 | 0048~0053: | 9,1, 1 | set filter(for irfanView) |
7 | 0054~005f: | 0x144,0, 0x90 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
0060~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"LEICA"}; |
0080~008f: | char str_model[16]={"Digilux 2"}; |
0090~
(008f+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count; |
There are 8 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 003c~0047: | 0x102,0, 0x10 | tiff_bps |
6 | 0048~0053: | 9,1, 1 | set filter(for irfanView) |
7 | 0054~005f: | 0xAc621,?, 0x90 | &ColorMatrix |
8 | 0060~006b: | 0x144,0, 0xe0 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
006c~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"Panasonic"}; |
0080~008f: | char str_model[16]={"DMC-LC1"}; |
0090~00d7: | signed long ColorMatrix[3][6]; |
00d8~00df: | ? |
00e0~
(00df+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 8,0 | short entry_count; |
There are 8 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0x70 | &str_make |
2 | 0018~0023: | 0x110,?, 0x80 | &str_model |
3 | 0024~002f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 003c~0047: | 0x102,0, 0x10 | tiff_bps |
6 | 0048~0053: | 0x8769,1, 0x92 | (&exif_3)+2 |
7 | 0054~005f: | 0xAc621,?, 0xb0 | &ColorMatrix |
8 | 0060~006b: | 0x144,0,0x100 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
006c~006f: | long entries_2[]={0}; |
0070~007f: | char str_make[16]={"OLYMPUS"}; |
0080~008f: | char str_model[16]={"E-10"}; |
0090~00af: | unsigned long str_exif[8]=
{0x1????,41730,8,0xA0,0x20002,0x2010100};
//single &entry=0xa0, which tag==41730 |
00b0~00f7: | signed long ColorMatrix[3][6]; |
00f8~00ff: | ? |
0100~
(00ff+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to the main menu.
0000~0001: | 'I','I' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0002~0003: | 0x2a,0 | tif version |
0004~0007: | 0x0a,0,0,0 | long &entries_1; |
0008~0009: | ?,? | |
(entries_1)
000a~000b: | 0B,0 | short entry_count; |
There are 0B entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_signed_long_array
:
1 | 000c~0017: | 0x10f,?, 0xA0 | &str_make |
2 | 0018~0023: | 0x110,?, 0xb0 | &str_model |
3 | 0024~002f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0030~003b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 003c~0047: | 0x102,0, 0x10 | tiff_bps |
6 | 0048~0053: | 0x103,1, 1 | tiff_compress |
7 | 0054~005f: | 0x115,1, 1 | tiff_samples |
8 | 0060~006b: | 0xc612,1,0x1000000 | dng_version |
9 | 006c~0077: | 0x828e,1, 0 | clear filter |
0A | 0078~0083: | 0x828e,4,0x2030100 | set filter=
0x94949494 |
0B | 0084~008f: | 0x144,0,0xc0 | &raw_data |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
0090~009f: | long entries_2[]={0}; |
00A0~00Af: | char str_make[16]={"Casio"}; |
00b0~00bf: | char str_model[16]={"EX-P600"}; |
00c0~
(00bf+W*2*H) | unsigned short raw_data[H*W]; |
That's all, return to the main menu.
0000~0003: | 0,'M','R','M' | mark |
0004~0007: | 0,0,1,8 | long &row_data-8 |
0008~000b: | 0,'P','R','D' | tag |
000c~000f: | 0,0,0,0x18 | long pascal_len |
0010~0017: | ?...? | |
0018~0019: | H(bigEndian) | short height |
001a~001b: | W(bigEndian) | short width |
001c~0027: | ?...? | |
0028~002b: | 0,'T','T','W' | tag |
002c~002f: | 0x7f,0xff,0xff,0xff | long len |
0030~0031: | 'M','M' | order:littleEndian("II":intel)
or bigEndian("MM":motorola) |
0032~0033: | 0,0x2a | tif version |
0034~0037: | 0,0,0,0x0a | long &entries_1; |
0038~0039: | ?,? | |
(entries_1)
003a~003b: | 0,7 | short entry_count; |
There are 7 entries that follow.
And each entry is a 12_bytes_structure
, we can assert each is 3_bigEndian_signed_long_array
:
1 | 003c~0047: | 0x10f,?, 0x70 | (&str_make)-(&order) |
2 | 0048~0053: | 0x110,?, 0x80 | (&str_model)-(&order) |
3 | 0054~005f: | 0x100,1, W | W>=22(for irfanView) |
4 | 0060~006b: | 0x101,1, H | H>=22(for dcRaw) |
5 | 006c~0077: | 0x102,0, 0x10 | tiff_bps |
6 | 0078~0083: | 0xAc621,?, 0x90 | (&ColorMatrix)-(&order) |
7 | 0084~008f: | 0x144,0,0x110 | &raw_data |
The entries are in disarray. And we can add any into them, of course we must change entry_count
above.
0090~009f: | long entries_2[]={0}; |
00A0~00Af: | char str_make[16]={"Minolta"}; |
00b0~00bf: | char str_model[16]={"DiMAGE 5"}; |
00c0~0107: | signed long ColorMatrix[3][6];
(bigEndian) |
0108~010f: | ? |
0110~
(010f+W*2*H) | unsigned short raw_data[H*W];
(bigEndian) |
That's all, return to main menu.
0000~0003: | 'I','I','I','I' | order:intel("IIII")
or motorola("MMMM") |
0004~0007: | 0, 'w','a','R' | raw flag |
0008~000b: | 0x0c,0, 0, 0 | long &entries==000c |
(entries:)
000c~000f: | 6,0,0,0 | long entry_count=6 |
0010~0013: | | ? |
There are at least 6 entries that follow, and each entry is a 16_bytes_structure
, we can assert each is 4_signed_long_array
:
1 | 0014~0023: | 0x108, ?, 4, W | W >=22(for irfanView) |
2 | 0024~0033: | 0x109, ?, 4, H | H >=22(for dcRaw) |
3 | 0034~0043: | 0x10e, ?, 4, 1 | tiff_compress==1 |
4 | 0044~0053: | 0x10f, ?, 4, 0x80 | long &row_data==0080 |
5 | 0054~0063: | 0x112, ?, 4, 0 | short akey,bkey |
6 | 0064~0073: | 0x301, ?, 4, 0x74 | long &str_model==0074 |
The entries are in disarray. And we can add any into them, of course, we must change entry_count
above.
0074~007f: | char str_model[]={"H 10"} |
int order[2][2]={{R,G},{G,B}};
(In the following text, bitMap[y][x][c]
abbreviate to m[y,x,c]
(and we declare "bitMap[y][W][c]==bitMap[y][W-1][c]
" in case of edge),
and bitMap[y][x][order[(y)&1][(x)&1]]
abbreviatea to "p[y,x]
")
file addr | unsigned short raw_data[H*W] |
1st line:
0x80~
(0x80+W*2-1): | ((m[0,0,R]<<8)&0x5555)
+((m[0,1,G]<<8)&0xaaaa) | ((m[0,1,G]<<8)&0x5555)
+((m[0,0,R]<<8)&0xaaaa) | ((m[0,2,R]<<8)&0x5555)
+((m[0,3,G]<<8)&0xaaaa) | ((m[0,3,G]<<8)&0x5555)
+((m[0,2,R]<<8)&0xaaaa) | ... | ((m[0, W-1, (1&W)?R:G]<<8)&0x5555)
+((m[0,(W-1)^1,(1&W)?G:R]<<8)&0xaaaa) |
2nd line:
(0x80+W*2)~
(0x80+W*4-1): | ((m[1,0,G]<<8)&0x5555)
+((m[1,1,B]<<8)&0xaaaa) | ((m[1,1,B]<<8)&0x5555)
+((m[1,0,G]<<8)&0xaaaa) | ((m[1,2,G]<<8)&0x5555)
+((m[1,3,B]<<8)&0xaaaa) | ((m[1,3,B]<<8)&0x5555)
+((m[1,2,G]<<8)&0xaaaa) | ... | ((m[1, W-1, (1&W)?G:B]<<8)&0x5555)
+((m[1,(W-1)^1,(1&W)?B:G]<<8)&0xaaaa) |
3rd line:
(0x80+W*4)~
(0x80+W*6-1): | ((m[2,0,R]<<8)&0x5555)
+((m[2,1,G]<<8)&0xaaaa) | ((m[2,1,G]<<8)&0x5555)
+((m[2,0,R]<<8)&0xaaaa) | ((m[2,2,R]<<8)&0x5555)
+((m[2,3,G]<<8)&0xaaaa) | ((m[2,3,G]<<8)&0x5555)
+((m[2,2,R]<<8)&0xaaaa) | ... | ((m[2, W-1, (1&W)?R:G]<<8)&0x5555)
+((m[2,(W-1)^1,(1&W)?G:R]<<8)&0xaaaa) |
4th line:
(0x80+W*6)~
(0x80+W*8-1): | ((m[3,0,G]<<8)&0x5555)
+((m[3,1,B]<<8)&0xaaaa) | ((m[3,1,B]<<8)&0x5555)
+((m[3,0,G]<<8)&0xaaaa) | ((m[3,2,G]<<8)&0x5555)
+((m[3,3,B]<<8)&0xaaaa) | ((m[3,3,B]<<8)&0x5555)
+((m[3,2,G]<<8)&0xaaaa) | ... | ((m[3, W-1, (1&W)?G:B]<<8)&0x5555)
+((m[3,(W-1)^1,(1&W)?B:G]<<8)&0xaaaa) |
... | ... |
Last line:
(0x80+W*2*(H-1))~
(0x80+W*2* H-1): | ((p[H-1,0]<<8)&0x5555)
+((p[H-1,1]<<8)&0xaaaa) | ((p[H-1,1]<<8)&0x5555)
+((p[H-1,0]<<8)&0xaaaa) | ((p[H-1,2]<<8)&0x5555)
+((p[H-1,3]<<8)&0xaaaa) | ((p[H-1,3]<<8)&0x5555)
+((p[H-1,2]<<8)&0xaaaa) | ... | ((p[H-1, W-1 ]<<8)&0x5555)
+((p[H-1,(W-1)^1]<<8)&0xaaaa) |
That's all, return to the main menu.
Using the Code
The attached zip contains bmp2raw.exe and demo.bmp, the former can run in command window, and the latter is a normal 24bit true color bitMap
file.
In the command window, we can:
use "bmp2raw.exe /e=1 demo.bmp
" to get a raw file, whose maker=="Kodak"
and model=="DCS760C"
, by ourselves;
or use "bmp2raw.exe /e=2 demo.bmp" to get a raw file, whose maker=="ricoh"
and model=="GR Digital";
...
or use "bmp2raw.exe /e=14 demo.bmp
" to get a raw file, whose maker=="Phase One"
and model=="H 10"
.
The usage is "bmp2raw [/e=enum] <src_file.bmp>", and the meaning of enum is same in main menu of this article.
The bmp2raw.exe can(can!=must) be build with a single c file (bmp2raw.c, 43k bytes), which can be build by tinycc, borland c, visual c. And the command lines (for how to build it) are in the front of the c file.
And this bmp2raw.exe (in the attached zip) is a single 32bit executable file,17k bytes, can run in any win32(64) platform. Here, we build it with 32stub.asm (Thomas Pytel's pMode), so it can run independently in dos, without any extender like dos4g or hxDos.
Why Don't We Describe the Source Code Here?
Oh, no! fread()
, fwrite()
, fill in the blank, too boring...
Example for Kodak:
unsigned char str_tif_head_littleEndian[0x0c]={
'I','I', 0x2a,0, 0x0a,0,0,0, '?','?', '?',0, };
unsigned long str_kodak_head[8][3]={
{0xAc621,0x3f3f3f3f, 0x90}, {0x10f, 0x3f3f3f3f, 0x70}, {0x110, 0x3f3f3f3f, 0x80}, {0x100, 1, 0x3f3f3f3f}, {0x101, 1, 0x3f3f3f3f}, {0x102, 0, 8}, {0x103, 1, 1}, {0x144, 1, 0xe0}, };
unsigned long str_zero[4]={0, 0x3f3f3f3f,0x3f3f3f3f,0x3f3f3f3f};
char str_kodak_make[ 16]={"Kodak"}; char str_kodak_model[16]={"DCS760C"};
signed long str_matrix[4][6]={
{3240479,1000000, -1537151,1000000, -498535,1000000}, {-969256,1000000, 1875992,1000000, 41556,1000000}, { 55648,1000000, -204043,1000000, 1057311,1000000}, {0x3f3f3f3f,0x3f3f3f3f, 0x3f3f3f3f,0x3f3f3f3f, 0x3f3f3f3f,0x3f3f3f3f},
};
unsigned int bmp_width,abs_height;
unsigned int src_byte_per_line,dst_byte_per_line;
FILE *h_src=0,*h_dst;
unsigned char str_in[ MAX_BUFF];
unsigned char str_out[MAX_BUFF];
int write_kodak_8bit_fail(void)
{
unsigned int x,y;
unsigned char L,R;
unsigned long ofs;
unsigned char *p24, *p8;
int order[2][2]={{G,R},{B,G}};
str_tif_head_littleEndian[0x0a]=8; str_kodak_head[3][2]=bmp_width;
str_kodak_head[4][2]=abs_height;
fwrite(str_tif_head_littleEndian, 1,
sizeof(str_tif_head_littleEndian),h_dst); fwrite(str_kodak_head, 1,
sizeof(str_kodak_head),h_dst); fwrite(&str_zero, 1,4,h_dst); fwrite(str_kodak_make, 1,16,h_dst); fwrite(str_kodak_model, 1,16,h_dst); fwrite(str_matrix,1,0x50,h_dst);
src_byte_per_line = (bmp_width*3+3)&0xfffc;
dst_byte_per_line=bmp_width;
ofs=0x36L+src_byte_per_line*(abs_height-1);
fseek(h_src,ofs,SEEK_SET);
for(y=0;y<abs_height;y++)
{
fread(str_in,1,src_byte_per_line,h_src);
p24=str_in;
p8 =str_out;
x=0;
while(x<bmp_width)
{L=p24[order[y&1][0]]; p24+=3; x++;
R=p24[order[y&1][1]]; p24+=3; x++;
p8[0]=L; p8[1]=R; p8+=2;
}
fwrite(str_out,1,dst_byte_per_line,h_dst);
ofs-=src_byte_per_line; fseek(h_src,ofs,SEEK_SET);
}
}
As you see, so boring... even if we can read this source code without any commentary.
History
- 9th April, 2023: Article submitted (can be compiled with bc4.5 and vc 6.0)