Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

DCR (Digital Camera Raw) File Format

5.00/5 (1 vote)
24 Apr 2023CPOL18 min read 7.1K   55  
Some kinds of DCR files' format/data structure
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?

  1. We can buy many camera in different kinds (too much money).
  2. We can wait for photos which are uploaded by cameraman, not jpeg format, not png format, must be raw format (too much time).
  3. We can use this article, to make raw files by ourselves with our small bitMaps.

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

1. Kodak

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.

2. ricoh

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)")

unsigned char raw_data[H*u]

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.

3. NIKON

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.

5. Pentax

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.

4. EPSON

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.

6. Leaf

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)")

unsigned short raw_data[H*W]

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.

7. Sinar

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.

9. FujiFilm

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.

10. LEICA

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.

11. Panasonic

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.

12. OLYMPUS

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.

13. Casio

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.

8. Minolta

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.

14. Phase One

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:

C++
unsigned char	str_tif_head_littleEndian[0x0c]={
 'I','I',	    //[0000~0001]: order:intel("II") or motorola("MM")
 0x2a,0,	    //[0002~0003]: tif version
 0x0a,0,0,0,	//[0004~0007]: long &entries_1==000A
 '?','?',	    //[0008~0009]:
 '?',0,		    //[000a~000b]: pascal_len
};

unsigned long str_kodak_head[8][3]={
//tag	     len,	info or ofs
 {0xAc621,0x3f3f3f3f,	0x90},		//[000c~0017]: &color_matrix
 {0x10f, 0x3f3f3f3f,	0x70},		//[0018~0023]: &str_make ==0070
 {0x110, 0x3f3f3f3f,	0x80},		//[0024~002f]: &str_model==0080
 {0x100, 1,		0x3f3f3f3f},	    //[0030~003b]: width >=22(irfanView)
 {0x101, 1,		0x3f3f3f3f},	    //[003c~0047]: height>=22(dcRaw)
 {0x102, 0,		8},		            //[0048~0053]: tiff_bps
 {0x103, 1,		1},		            //[0054~005f]: tiff_compress
 {0x144, 1,		0xe0},		        //[0060~006b]: &raw_data ==00e0
};
 unsigned long	str_zero[4]={0, 0x3f3f3f3f,0x3f3f3f3f,0x3f3f3f3f};
 char str_kodak_make[ 16]={"Kodak"};	//[0070~007f]
 char str_kodak_model[16]={"DCS760C"};	//[0080~008f]

signed long	str_matrix[4][6]={
 {3240479,1000000, -1537151,1000000, -498535,1000000},	//means: 3.240479, 
                                                        // -1.537151, -0.498535
 {-969256,1000000,  1875992,1000000,   41556,1000000},	//means:-0.969256,  
                                                        //  1.875992,  0.041556
 {  55648,1000000,  -204043,1000000, 1057311,1000000},	//means: 0.055648, 
                                                        //  -0.204043,  1.057311
 {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}};

//----------- write head ---------------------------
 str_tif_head_littleEndian[0x0a]=8;//8 entry
 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);//0000~000b
 fwrite(str_kodak_head, 1,
	sizeof(str_kodak_head),h_dst);		    //000c~006b
 fwrite(&str_zero, 1,4,h_dst);			    //006c~006f
 fwrite(str_kodak_make, 1,16,h_dst);		//0070~007f
 fwrite(str_kodak_model, 1,16,h_dst);		//0080~008f
 fwrite(str_matrix,1,0x50,h_dst);		    //0090~00df

//----------- write body ---------------------------
 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);
	//read y_th line from bitMap to strIn[]

	p24=str_in;
	p8 =str_out;
	x=0;
	while(x<bmp_width)
		{L=p24[order[y&1][0]]; p24+=3; x++;
		//src=24bit bmp, means: 3bytes/pixel
		R=p24[order[y&1][1]]; p24+=3; x++;

		p8[0]=L; p8[1]=R; p8+=2;
		//dst=8 bit/channel
		}
	fwrite(str_out,1,dst_byte_per_line,h_dst);
	//write y_th line from strOut[] to dcr [(00e0+y*W)~(00df+W+y*W)]

	ofs-=src_byte_per_line;//file point to next 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)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)