DOWNLOAD LATEST DCRAW ZIP FILE NOW.
New since last update:
Changed for 01/03/2010 version
1. Updates for the latest cameras.New since last update:
2. Changed the names of the following TRawSettings variables..
iBlack_Level:Integer;
iScale1:Single;
iScale2:Single;
iScale3:Single;
iScale4:Single;
iUse_auto_wb:byte;
iUse_camera_wb:byte;
iHighlight:Integer;
iMedianFilter:Integer;
iUser_Sat:Integer;
iNoiseReduction:Integer;
TO THESE NEW NAMES
evBlack_Level:Integer;
evScale1:Single;
evScale2:Single;
evScale3:Single;
evScale4:Single;
evUse_auto_wb:byte;
evUse_camera_wb:byte;
evHighlight:Integer;
evMedianFilter:Integer;
evUser_Sat:Integer;
evNoiseReduction:Integer;
The reason for these changes is so that as you are using the variable in the OnImageDone EVent, you will KNOW by the name of the variable if it can be MODIFIED in the OnImageDone EVent.
3. Made the CSTDIO.PAS file a component. So now there is a TRawObject contained in there. That means that you can NOT simply call functions and set properties that were in the CSTDIO file. You now HAVE TO CREATE a TRawObject in your code and then reference the object to set properties and call mentods. This makes it so that it's easier to do MULTITHREADING and it encapsulates teh code better too for organizational purposes. There are also many EVENTS that are now available for use to do cool things. You now reference the methods like so....FRawObject.Raw_Info(...parameters...);
FRawObject.RAW_LoadRAW(...parameters...);Properties
MULTITHREAD can be set to TRUE, if you plan to use the object in various threads
NOTE: If you set it to TRUE, then you MUST have the $DEFINE DYNAMICDLL variable set in CSTDIO.INC
If you set it to FALSE, then you can still have a bunch of them created as objects, BUT you can
only use those TRawObjects from a SINGLE thread (typically your main thread).
I M P O R T A N T: M U S T R E A D T H I S.......
NOTE: You NEEEEEED to call RAW_ThreadEnd in order to clean up the temp dll that is copied
into your temp folderEVENT Properties
OnAfterLoadRetry:
OnHistogramMake:
OnHistogramSearch:
OnGammaCurve:
OnImageDoneQuery:
OnImageDone:1. Create TRawObject TObject
2. You create it and then assign MultiThread:=True if you wish
3. You assign the Event Properties if you need to
4. You prefix all your references to the raw functions with the name of the object, for example...
FRawObject:=TRawObject.Create;
... some code....
FRawObject.OnHistogramMake:=SomeHistMakeFunction;
... maybe assign some other events too
FRawObject.RAW_Info;
... some more code...
FRawObject.Free;5. Made some changes to the CallBack functions. They now all have an additional
parameter called SENDER as the first parameter. For example.....
Procedure TForm1.Event_HistogramMake_Custom(Sender:TObject;Var RawSettings:TRAWSettings;HistP:Pointer;HistSize:Integer;RAWWidth,RAWHeight,Width,Height,Colors,BrightMode:Integer;Image:PPUSHORT;ImageBlockSize:Integer);
NOTE: The reason we pass this new paramter is so that your code can now access any properties or methods of the TRawObject that you are currently using.
6. Added a bunch of simple USER variables.
UserChar
UserByte
UserWord
UserInteger
UserInt64
UserDouble
UserPointerNOTE: Used properly, these can be very useful
7. Better approach to TEMP DLL stuff. Instead of each process, creating a list
of temp DLLs, I create ONE temp dll for each THREAD.
NOTE: This is better, BECAUSE if a thread is creating and destroying the TRawObject
over and over, then the new way is more efficient (less disk acces).
PLUS: The old way left room for a 2nd and 3rd copy of your program to be
running and the temp dll names COULD CONFLICT between each process!!! BUT SINCE
each THREAD ID IS UNIQUE throughout the system, this new method will NEVER have
a conflict between multiple copies of your program running at the same time.
8. In order for this new way to work properly, YOU NEED MUST BETTER let the TRawObject
KNOW when you shut down your thread. So when the thread shuts down, THEN and ONLY THEN
do we remove the temp dll from the temp folder. You do this by calling tthe function
called RAW_ThreadEnd.
NOTE: If you do NOT call RAW_ThreadEnd, then the temp dlls will stick aroud and start
to waste space
HINT: Actually, you don't NEEEED to call the RAW_ThreadEnd explicitly because the temp
files ARE REMOVED AUTOMATICALLY. It's just that they are NOT REMOVED PRECISELY when
you terminate the thread. There is a TTIMER gTimerCleanup that checks every 5 seconds
to see if it needs to cleanup any temp files that RAW_EndThread would otherwise clean up.
So, by default ti's easier to just let the background timer automatically clean up your
temp files, unless you are maticulous about cleaning things up EXACTLY when they are no
longer needed ;)
9. Added a property so that you know what THREAD created the TRAWObject
Property ThreadID:DWord read FThreadID;
10. IF Your TRAWObject is used in a thread that is NOT your main thread, THEN if you
FORGET to set the MultiThread to TRUE, then the moment you attempt to call one of the
DLL functions, you will get an Exception that tells you to set MultiThread:=True;
1. Updates for the latest cameras.
2. Changed the way the following function is setup....
Procedure HistogramLutCalc(Var Ptrs:TRAWEvents;Var LUT:TLUT;
White,Bright:Single;BrightMode:Integer;FlipFlag,Width,Height,Colors:Integer;Image:PPUSHORT;ImageBlockSize:Integer);cdecl;
It now looks like this.....
Procedure HistogramLutCalc(Var Ptrs:TRAWEvents;Var GammaCurve:TGammaCurve;
White:Integer;Bright:Single;FlipFlag,Width,Height,Colors:Integer;Image:PPUSHORT;ImageBlockSize:Integer);cdecl;Also in the UNIT1.PAS file, then cooresponding function called....
Procedure TForm1.Event_HistogramLutCalc_Custom(Var RawSettings:TRAWSettings;LUTP:Pointer;
White,Bright:Single;BrightMode:Integer;RAWWidth,RAWHeight,Width,Height,Colors:Integer;Image:PPUSHORT;ImageBlockSize:Integer);now looks like this....
Procedure TForm1.Event_HistogramLutCalc_Custom(Var RawSettings:TRAWSettings;GammaCurveP:Pointer;
White:Integer;Bright:Single;FlipFlag,Width,Height,Colors:Integer;Image:PPUSHORT;ImageBlockSize:Integer);TIP: You will notice that I changed WHITE from single to integer; I also removed the brightmode variable. ALSO, the LUT table has been changed to a CURVE table. It performs the same basic function, BUT instead of being an array of 8 bit numbers, it's now an array of 16bit numbers. So, now this table can be used to produce nice 8 bit images, BUT ALSO NICE 16 bit images. So, the values in each slot in the table now range from 0-65535 instead of 0-255.
3. When you checkmark the Use 16bit dataa only, it NOW allows you to use the Real-Time-Enhancements. And when you are done, the Demo program asks if you want the image to be strtched to look good. Click YES, and then the 16 bit image will look great instead of the typical super dark image.
Changed for 03/11/2009 version
1. CSTDIO is now a UNIT
instead of an $Included file.
2. The following procedures
in CSTDIO.PAS have been renamed for better organizational purposes....
adj_defaults is now RAW_Adj_Defaults
MyProgress is now RAW_MyProgress
RawInfo is now RAW_Info
FromRAWToPSD is now RAW_LoadRAW
Extract_Thumbnail is now RAW_Extract_Thumbnail
GetGammaVariables is now RAW_GetGammaVariables
3. Since it's a unit now,
you can see all of the procedure/functions names near the top of the unit.
If you want to double check their spelling.
procedure
Raw_CheckDLL_RaiseError this checks to make sure the dll is found and
if NOT it raises an error if the DLL is found BUT it's not of the correct
version, then it raises a different error message. With the dynamic loading
of the DLL, you can have many different names for the DLL. TYPICALLY, you
will have MSDCRAW.DLL and just leave it alone. BUT, if for some reason,
you will create programs that use DIFFERENT versions of this dll, then
you can name them MSDCRAW5.DLL and MSDCRAW6.DLL and thus
you will be able to keep both of them in the same folder. AND the program
that needs version 5 will find version 5 and the program that needs version
6 will find version 6. No muss-, no-fuss.
4. Several callback functions
are now passed an EXTRA parameter of TRAWSettings.
TRAWCallBack_AfterLoadRetry = Function(
Var EventLoopData:TEventLoopData;
Var RawSettings:TRAWSettings;
Changed for 09/09/2008 version
1. Some images when loaded
in FULL SIZE mode could get a MAZE pattern in the image.
This is caused by an inbalance in the G1 and G2 sensors. This fix, averages
the two
together and removesthe maze effect. It would have been UNNOTICED in the
half size
mode because of the way interpolation is performed.
2. Several callback functions
are now passed an EXTRA parameter of TRAWSettings.
Several people wanted to know certain input values into the FromRAWtoPSD
function
and didn't want to keep global variables hanging around. So, now these
callback functions
have a way of knowing what the settings were when then main decoding function
was called.
TRAWCallBack_AfterLoadRetry = Function(
Var EventLoopData:TEventLoopData;
Var RawSettings:TRAWSettings;
Var BrightAdded,Contrast,Gamma:Single) :Integer Of Object;
TRAWCallBack_HistMake = Procedure(
Var RawSettings:TRAWSettings;
Hist:Pointer;
HistSize:Integer;
RAWWidth,RAWHeight,Width,Height,Colors,BrightMode:Integer;
Image:PPUSHORT;
ImageBlockSize:Integer) Of Object;
TRAWCallBack_HistSearch = Function(
Var RawSettings:TRAWSettings;
Hist:Pointer;
RAWWidth,RAWHeight,Width,Height,Colors,BrightMode:Integer;
Percentage:Single;
Image:PPUSHORT;
ImageBlockSize:Integer):Integer Of Object;
TRAWCallBack_HistLUTCalc = Procedure(
Var RawSettings:TRAWSettings;
LUT:Pointer;
White,Bright:Single;BrightMode:Integer;
RAWWidth,RAWHeight,Width,Height,Colors:Integer;
Image:PPUSHORT;
ImageBlockSize:Integer) Of Object;
TRAWCallBack_ImageDone = Procedure(
Var RawSettings:TRAWSettings;
Image:PPUSHORT;
ImageBlockSize:Integer;
Width,Height:Integer) Of Object;
3. Added NEW event.
TRAWCallBack_ImageDoneQUERY = Procedure(
Var RawSettings:TRAWSettings;
Image:PPUSHORT;
ImageBlockSize:Integer;
Width,Height:Integer;
Var FixMazeEffect:Boolean) Of Object;
You can see that this event can OVERRIDE the default operation of fixing
the MAZE effect.
By default the logic is to fix the maze effect only for images that is
of RGBG type and is 3 colors.
So, the value of FIXMAZEEFFECT will be true or false depending on RGBG
type and colors=3.
The Query event allows you to OVERRIDE the FixMazeEffect to true or false.
This effectively allows YOU to decide if you want that logic performed.
If you do nothing to change the variable, then
the default logic will be taken.
HINT: The MazeFixup logic basically balances the G1 and G2 color scales.
For cameras that don't have a misbalanced
G1/G2 channels, the fixup will not affect the output visually. So,
no need to worry about fixing up an image that doesn't need fixing up.
The reason we check for RGBG in the CDesc field is that if you have a RGBE
or GMCY value, then there IS NOT G1/G2.
The RGBE has a G1 and an EMERALD channel. So, balancing will screw it up.
The GMCY is an odd ball and of course doesn't
have 2 green channels. So, balancing will screw it up.
NOTE: Unless you know what you are doing, DO NOT USE THIS EVENT.
4. Also the TRAWSettings
structure has a few new items.
iCustomUserDataPointer:Pointer;
The user can use this for ANYTHING he wants to in order for the callback
functions to be able to know certain things
oFilters:Integer; //Filter value
reported from dcraw (tech stuff)
oColors:Integer; //Colors reported
from dcraw (3 or 4)
oCDesc:TChar5; //contains RGBG, or GMCY,
or RBTG or RGBE or maybe others
oMake:TChar50; //Make of camera
oModel:TChar50; //Model of camera
Changed for 09/01/2008 version
1. Added support for the -n Noise reduction command from dcraw into MSDCRAW.
In the TRawSettings there is a new variable called iNoiseReduction:Integer;
You can supply a value of ZERO <default> that means NO noise reduction NR.
Or you can pass a value of 500 which is a pretty strong NR value, and 1000
which is very very strong smoothing.
2. The AfterLoadRetry event that gets TEventLoopData passed into it, now has 2 new variables defined in the teventloopdata...
iNoiseReduction:Single;
iQuality:Integer;This means that in the AfterLoadRetry callback, you can set the NoiseReduction value to a new value and you can change the Quality setting too. And great care was taken to make sure that all of this functions as fast as possible using temp copies of the loaded image. For exampe: If you load an image with a NR value of 1000, then it takes about 5 seconds to smooth the image before any color correction is done. Well, if you then want to change the color space to Adobe or XYZ or RAW, then we swap the IMAGE data with the temp data that was saved away. Thus eliminating the need for the 5 seconds of NR logic ;) It's all very efficient now. It uses RAM to keep these extra copies of the image to swap around, and if there is not enough RAM then we use your temp drive. ALL done automatically.3. Changed the way the Make, Model and TimeStamp are passed to the two main functions of RawInfo and FromPSDtoRaw
NOTE: See, the AfterLoadRetry is cool because before the image is completely done loading, you can SEE the image on your screen and change some parameters and tell it to RE-SHOW you the image. And it does it fast because it doesn't have to reload/decode the image etc..... And you can keep playing with the parameters (Scale colors, gamma, contrast, brightness, noise reduction level, etc...) until they are the way you want them. Then you tell the AfterLoadRetry to stop looping and to finish the load. MUCH FASTER than loading the image and then changing a value, then reloading the image etc....
The old way wasStatus:= RawInfo (@FilePtrs, @ExifRecordB, @ExifEssentials, IFileName, FShrinkFactor, IWidth, IHeight, IFovWidth, IFovHeight, @PMake, @PModel, @PTimeStamp);The NEW way isStatus:= RawInfo (@FilePtrs, @ExifRecordB, @ExifEssentials, IFileName, FShrinkFactor, IWidth, IHeight, IFovWidth, IFovHeight, PMake, PModel, PTimeStamp);You can see that the @ is no longer required, and instead of defining them as Array[0..xxx] of char, they are NOW declaed as TChar50. And you do NOT need to fillchar them to initialize them. All that is handledf for you now.
NOTE: Since they are now 50 bytes, and YOU MAY HAVE some fillchar functions to initialize your arrays of let's pretend 100 bytes, THEN when you switch to TChar50, your program will blow up or should, because you are zeroing out 100 bytes instead of 50 ;) So, remove your fillchar stuff on those variables.
4. Fixed a date time stamp problem. It seemed that some images returned the wrong TIME (jhour) it had to do with time zones. Very strange stuff, but that is fixed now.
Changed for 08/06/2008 version
1. Added additional camera support
2. Added new features to the MSDCRAW package.
A. 5 New EVENTS that can be used for custom things.HistogramMake_CallBack:TRAWCallBack_HistMake; //Event to MAKE your own histogram
2 Histogram building and searching for white point for auto brightening.
Histogram GammaLUT event function so that you can have your own
gamma curve etc... You could apply contrast and brightness to the raw data
so that you don't have to manipulate the image twice. Just apply the enhancements
as you decode the image and then you won't have to run the image through
another manipulation via some other software.
ImageDone event allows you to see and modify the image data after it was loaded and before any manipulation has been done. Could be useful for special purposes.
AfterLoadRetry event. THIS ONE IS COOL. This allows you to alter the contrast and brightness and gamma of the image. adj_Gamme, adj_Brightness, adj_Contrast are 3 variables used to controls those effects. PLUS the Bright value that you supply in the RawSettings record is used as well. So, you have TWO brightness variables ;) You may say "WHY use two brightness variables?" Well, they both operate differently. The old style BRIGHT value that dcraw uses is basically a MULTIPLIER. So bright areas are made much brighter and dark areas are NOT made much brighter. The new adj_brightness variable is ADDITIVE. So, brightness over the whole image is raised, reguardless of original brightness of an individual pixel!!!. Basically here is what happens. After the image is loaded into your memory bitmap, BUT BEFORE dcraw dll exits it's function, a call is made to the AfterLoadRetry event. This function returns a FALSE or TRUE or 0 or 1 value. Simple. If FALSE / 0 is returned, then the dcraw code finishes up and returns as usual. BUT if you return a TRUE / 1 then the dcraw code LOOPS BACK and re-translates the data from the raw image to the memory bitmap. You may say "What good is that?" WELLLLL, since it loops back and does the output logic again, that means the GammaLUT gets a chance to be rebuilt. Remember the event above? ;) Okay, so if you rebuild the LUT table to show a gamma change or a contrast change, then the output will reflect that change ;) So, then the image will be brighter or darker or whatever. THE ADVANTAGE is that this the re-translation to the output IS SUPER FAST. It can be done in about 1/4 second. There is no wasted time loading the image and no wasted time doing the interpolation etc, etc,etc. So this is VERY COOL indeed. NOTE: Of course you don't have to use it to redo the ouput bmp, you could use this event for other purposes. It's just a simple function with a simple result.
B. Changed the Rawinfo(?,?/,?,?,?) function to require 2 more parameters. Added ability for the RawInfo() function to get the TRUE Foveon/Sigma *.X3F dimensions. There are now two more parameters to this function that return these values, FovWidth,FovHeight. These are for people who want the true dimensions of a foveon/sigma camera. Because those images are TRIMMED to a slightly smaller dimension as the image is processed..This is to trime away a thin outer border.
C. Changed the
raw_progress_init(ProgressInfo,Self);
and
FromRawToPSD(@FilePtrs, @ExifRecord, @ExifEssentials,
@ProgressInfo,
IFileName, OFileName, RAWSettings, ScanLines, IWidth, IHeight, @PMake,
@PModel, @PTimeStamp);
You need to change the ProgressInfo parameter to RawEvents and create a variable called RawEvents:TRAWEvents; so that they look like this...
raw_progress_init(RawEvents,Self);
and
FromRawToPSD(@FilePtrs, @ExifRecord, @ExifEssentials,
@RawEvents,
IFileName, OFileName, RAWSettings, ScanLines, IWidth, IHeight, @PMake,
@PModel, @PTimeStamp);
D. Added 3 additional methods of calculating the Auto-Brightness. The dcraw code prodoces decent auto-bright for most images, but for tough ones like pics of the moon where most of the sky is black etc... the dcraw doesn't quite do a good job. Sooooo, I added 3 more methods of exposure sensing.
C_AB_MikesWay=1;
C_AB_CenterWeight=2;
C_AB_Minimal=3;The MIKE'S way is the best and should be the one you use for all your images unless you can show me a reason why. That is why it is now the DEFAULT mode of auto exposure.
E. Added ability to control the contrast, brightness, and gamma of the developed image. Here are the variables for thatChanged for 06/29/2008 version
adj_Gamma_Def=0.45; {0.01=brightened way up, 1.0=darkened way down with GAMMA curve}
adj_Contrast_Def=1.0; {1=default 0 = ZERO contrast, 1=decent, 4=way too contrasty}
adj_Brightness_Def=0; {0=default 0 = no additional brightness, -1=total darkness, +1=total brightness}
adj_Gamma:Single=adj_Gamma_Def;
adj_Contrast:Single=adj_Contrast_Def;
adj_Brightness:Single=adj_Brightness_Def;
So, by changing these values, you can effectively control the brightness and contrast and gamma of the image. NOW you may be wondering, why have "adj_brightness" when there is ALREADY a value being passed to dcraw called "RawSettings.iBright" Well, this is true. We now have TWO brightness controls. The BRIGHT variable used by dcraw is used as a MULTIPLIER for the incoming data. The "adj_brightness" is not a multiplier, instead it's an ADDITIVE. So, all pixels are brightened the same amount. This is the traditional method of brightness operation.F. You need to add CSTDIO_TYPES to your USES clause, because I have separated out all the types of record structures and event method types into a new files.
G. YThe variable GammaVal has been renamed to Gamma.
Changed for 04/23/2008 version
1. Added code to control AUTO ROTATE of RAW images.
You now have 5 options
Auto Rotate
No Rotate
90 Degree rotate
180 Degree rotate
270 Degree rotate
Changed for 04/04/2008 version
5. Added source code for MSDCRAW.C in case you feel
the need ;)
4. Added support for MEMORY thumbnails instead of
thumbnails saved to file.
3. Much more camera support
2. A couple of new options (you can see the new
checkboxs etc...)
1. Improved CSTDIO.PAS file (mostly in MyProgress
funtion)
========= E N D O F H I S T O R Y =================================
========= S T A R T O F D A V I D
C O F F I N S E C T I O N =================================
David Coffin: Please click here for your test files.
The DCRAW c++ files allow you to read RAW images from higher end digital cameras. If you don't know c++, then you are at a disadvantage to use them. That is why I've written a wrapper for Delphi that can make use of the DCRAW c++ code.
The first thing I had to do was to compile the DCRAW.C code along with additional c++ files I created in order to produce a viable DLL that could be used with Delphi. This compiled code is MSDCRAW.DLL. You need this DLL to be included with your application and keep the DLL in the same folder as your application program.
DCRAW c++ code was generously written by David Coffin and you can view his website by clicking here.
The purpose of the DCRAW functionality is so that programmers can have
the ability to load RAW digital images. For example: The Canon G2, G3,
G5 Digital EOS Rebel all have the ability to save photos in either RAW
or JPG format. The JPG format is best for 95% of what you photograph. However,
if you are taking an award winning photo and you want the very best results,
some people choose to save in the RAW format. For Canon, these files are
*.crw, for Nikon, they are *.nef and other manufacturers have there own
extensions as well. Please refer to David Coffin's web site for a complete
list of extensions.
========= E N D O F D A V I D C
O F F I N S E C T I O N =================================
There are 3 functions that you can use to work with RAW images:
These 3 functions are located in the CstdIO.pas file. In order to show
you how to use them, I've provided a sample project that utilizes them.
The sample project allows you to browse for a file and then either get
INFO on it, or LOAD the raw file, or Extract the thumbnail.
** NOTE: The TFastFile class is basically a BUFFERED file
I/O system that uses a 4K buffer. This produces MUCH faster processing
of reading single byte at a time. It's about 20 times faster than using
the standard TFileStream class. Have fun with it.
**** NOTE: The CSTDIO not only contains the 3 Raw function calls, but it also contains all of the FILE I/O faking needed. See, the C++ library has it's own TStream which is DIFFERENT from Delphi's TStream :( So, I had to create all of the C++ stream functions like fseek, feof, fread, fwrite, fopen, fclose etc...
Please DONATE to keep my efforts worth it. As long as the donations are fair, I will keep this web site up.
Click on the "Make A Donation" button to donate an amount that you think is fair.
OLDER Previous Versions
OLDER Download Sample Delphi
Project files. (dated May 2009)
OLDER Download Sample Delphi
Project files. (dated Mar 2009)
OLDER Download Sample Delphi
Project files. (dated Sept 2008)
OLDER Download Sample Delphi
Project files. (dated Aug 2008)
OLDER Download Sample Delphi
Project files. (dated June 2008)
OLDER Download Sample Delphi
Project files. (dated April 2008)
OLDER Download Sample Delphi
Project files. (dated June 2007)
NOTE: You NEED to make sure you have the latest version of the
MSDCRAW.DLL
on an ongoing basis. This is because it's periodically updated to add new
camera models to the list of what RAW files it can deal with.
If you wish to leave us mail just click on the name below:
E-Mail to: Davie Lee Reed
We use the PayPal System to accept donations.
If you have a PayPal account, then you have many ways to donate. If you do NOT have a PayPal account, then you can just use one of your credit cards to pay thru the PayPal system secure site.
Donate a specific amount in US Dollars
Once again, thank you for donating so that we can continue to offer some free services and software. If it were not for people like yourself, these great services wouldn't be available.
THANK YOU VERY MUCH
David, here are the files in question:
SIGMA Problem dated 01/24/2006
Sigma photo of a bird IMG00203.X3F
Same photo converted to jpg with the sigma software IMG00203_sRGB.JPG
Files below are older problem files that have been resolved.
2 Sample NEF Files:
File to produce a JPG thumbnail: nef_jpg.nef
File to produce a PPM thumbnail: nef_ppm.nef
08/2005
Canon 350D file that decodes as black :(: Download
CANON.350D CR2 raw file.
05/2005
PHASE_ONE doesn't parse a viable thumbnail : Download
phaseone raw file.
CANON_CR2 doesn't dcraw a viable image: Download
CANON.CR2 raw file.
RT16.TIF file that dcraw decodes black and parse extracts white thumbnail:
Download
RT16.TIF.