This example shows how to scan a page and make sure that the file is saved with CCITT Group 4 compression, whether the scanner outputs Group 4 compressed data or uncompressed data. If the scanner is capable of outputting Group 4 compressed data, this example constructs an ISIS pipe that does not do compression, and it turns on Group 4 compression in the scanner driver. If the scanner cannot output Group 4 compressed data, this example constructs a pipe that includes the necessary compression drivers and does not attempt to turn on compression in the scanner driver. This sample assumes that a scanner has already been loaded and its handle is hScan.
Copy Code
|
|
---|---|
void ScanPageAndSaveTiffGroup4(HISISDRV hScan) { HISISDRV hFileWriter = 0; LONG compression = 0; WORD choiceCount = 0; bool bGroup4 = false; BYTE buffer[8192]; // We can assume that IG_ISIS_TAG_COMPRESSION will always be a list, // so we didn't do a IG_ISIS_choice_get_flags. // If the following call fails, then there is no compression // available from the scanner. if (IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_COMPRESSION, &choiceCount) != IGE_SUCCESS) { for (WORD index = 0; index < choiceCount; index++) { // Loop thru all choices and put into lComp. IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_COMPRESSION, index, &compression); // If any value of lComp is G4, set bGroup4 to TRUE. if (compression == IG_ISIS_COMPRESSION_G4) { bGroup4 = true; break; } } } if (bGroup4) { // If bGroup4 is True, make a pipe that writes the file without // compression. Set the scanner driver to Group 4. IG_ISIS_drv_load_init_pipe(0, "PIXFPACK", &hFileWriter, 0); IG_ISIS_drv_link(hScan, hFileWriter); IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_COMPRESSION, 0, IG_ISIS_COMPRESSION_G4); } else { // Otherwise, make a pipe that includes G4 compression. Don't try // to turn on compression in the scanner. IG_ISIS_drv_load_init_pipe(0, "RAS2RUN|RUN2G4|PIXFPACK", &hFileWriter, 0); IG_ISIS_drv_link(hScan, hFileWriter); IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_COMPRESSION, 0, IG_ISIS_COMPRESSION_NONE); } // Set the output filename and type. IG_ISIS_tag_set_ascii(hFileWriter, IG_ISIS_TAG_OUTNAME, (char FAR *)"Test.tif"); IG_ISIS_tag_set_long(hFileWriter, IG_ISIS_TAG_FILETYPE, 0, IG_ISIS_FILETYPE_TIFF); // Invoke the pipe. IG_ISIS_run_zone(hScan, buffer, sizeof(buffer)); // Clean up when done. IG_ISIS_drv_link(hScan, 0); IG_ISIS_drv_unload_pipe(hFileWriter); } |
One way to allow a user to set the scanning area is to call the toolkit's built-in Set Scanning Area dialog box by using the IG_ISIS_drv_area_dialog() function. If you would rather use your own interface to set the scanning area, this example will show you how. (The source code sample SCANTEST.C defines a function for setting scanning area and is a good source of additional information.)
The following example shows how to pick a 3" wide by 5" high rectangle as close to the center of a page as possible.
Note that the first step in this example is to set the X position to zero. This is done in case some other code has already defined a scanning area. To reflect the currently-available legal IMAGEWIDTH settings, the legal values of IMAGEWIDTH change if XPOSITION changes. (This is another tag dependency that must be remembered.) The sample does not test whether IG_ISIS_TAG_IMAGEWIDTH is a list or a range, because in ISIS drivers, it is always a range.
Finally, note that all ISIS measurements are in pixels and dots per inch, regardless of how the scanner wants the measurements specified. ISIS drivers make this conversion, if necessary.
Copy Code
|
|
---|---|
bool SetScanArea(HISISDRV hScan) { LONG high = 0, low = 0, step = 0; LONG left = 0, width = 0, top = 0, length = 0; AT_ISIS_RAT rat; // Reset X position to 0 in case some other region was defined. IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_XPOSITION, 0, 0L); // Query the width values. IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGEWIDTH, IG_ISIS_CHOICE_HIGH, &high); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGEWIDTH, IG_ISIS_CHOICE_LOW, &low); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGEWIDTH, IG_ISIS_CHOICE_STEP, &step); // Get the current X position. IG_ISIS_tag_get_rational(hScan, IG_ISIS_TAG_XRESOLUTION, 0, &rat); // Multiply 3" by resolution (after converting to an integer). width = 3 * (rat.Num + rat.Denom - 1) / rat.Denom; if (width > high - low) { // Scanner cannot scan an area 3" wide. return false; } // Compute the left edge of the page to the nearest step. // First find the middle. left = (high - low - width) / 2; // Adjust to closest legal step. left = left - (left % step); // Set the left edge (X position). IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_XPOSITION, 0, left); // Get the new high value for image width. IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGEWIDTH, IG_ISIS_CHOICE_HIGH, &high); // Set image width to actual width or to the new high value, whichever is less. // Ajust width to closest step. width = width - (width % step); if (width > high) { // Legal step value. width = high; } IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_IMAGEWIDTH, 0, width); // Repeat everything to set the height. IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_YPOSITION, 0, 0L); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGELENGTH, IG_ISIS_CHOICE_HIGH, &high); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGELENGTH, IG_ISIS_CHOICE_LOW, &low); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGELENGTH, IG_ISIS_CHOICE_STEP, &step); // Get the current Y position. IG_ISIS_tag_get_rational(hScan, IG_ISIS_TAG_YRESOLUTION, 0, &rat); // Multiply 5" by resolution (after converting to an integer). length = 5 * (rat.Num + rat.Denom - 1) / rat.Denom; if (length > high - low) { // Scanner cannot scan an area 5" high. return false; } // First find the middle. top = (high - low - width) / 2; // Adjust to closest legal step. top = top - (top % step); IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_YPOSITION, 0, top); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_IMAGELENGTH, IG_ISIS_CHOICE_HIGH, &high); // Adjust length to closest. length = length - (length % step); if (length > high) { // Legal step value. length = high; } IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_IMAGELENGTH, 0, length); return true; } |
In the above example, note that the step value for these tags depends on the mode of the scanner. PIXDFLT does not work with fractional bytes of image data; therefore, binary scanning will typically have step values of eight pixels (one byte). The above example truncates to the step to the left, so if the region to be scanned does not fall on a step value, it will be shifted to the nearest step to the left (a maximum of seven pixels).
ISIS scanner drivers default to 300 dots per inch (dpi) if this resolution is available. If 300 dpi is not available, the default resolution is the nearest value that is less 300 dpi. Scanner driver use RATIONAL image resolution values that generally have a denominator of 1, so it is generally safe to work only with the numerator. (Keep in mind that ISIS drivers will accept a RATIONAL value with a denominator of any integer value.) Even though the PixTools/Scan toolkit normally uses RATIONAL values with a denominator of 1, it is quite common for the PixTools/View toolkit to work with TIFF files that have resolutions of, for example, 7,200,000/10,000. This is a valid image resolution according to the TIFF specification.
Some scanners allow X and Y resolutions to be different from one another. To determine if this is the case for the current scanner, you can query the choices for X resolution and Y resolution. On scanners that do not support independent X and Y resolutions, there will only be one choice for the Y resolution, and its value will be the last value set for X resolution. (Note that Standard mode faxes are 200 x 100 dpi.)
The following example makes a list of available color formats from the current scanner. Note that for this code to work it is necessary to set the value of IG_ISIS_TAG_SAMPLESPERPIXEL in order to find out the choices for IG_ISIS_TAG_BITSPERSAMPLE. (Each value of IG_ISIS_TAG_SAMPLESPERPIXEL could cause the choice for IG_ISIS_TAG_BITSPERSAMPLE to return a different set of choices.)
Copy Code
|
|
---|---|
void ListAvailableColorFormats(HISISDRV hScan) { LONG samples = 0; WORD choiceCount = 0; // Find out how many choices there are for SAMPLESPERPIXEL. IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_SAMPLESPERPIXEL, &choiceCount); // Get and set values for SAMPLESPERPIXEL one at a time. for (WORD index = 0; index < choiceCount; index++) { IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_SAMPLESPERPIXEL, index, &samples); IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_SAMPLESPERPIXEL, 0, samples); if (samples==1) { // If SAMPLESPERPIXEL is 1, then must be binary, grayscale or palette color. // IG_ISIS_TAG_BITSPERSAMPLE is normally a list, and the following list // logic will also handle the case where it is a range. However // it is presented here with specific list and range code to // demonstrate how to process both types. IG_ISIS_TAG_RESOLUTION is, for // example, a more common tag that you would want to be able to // process as both a list and a range. // Determine whether BITSPERSAMPLE is a list or a range. AT_LMODE flags = 0; IG_ISIS_choice_get_flags(hScan, IG_ISIS_TAG_BITSPERSAMPLE, &flags); // Handle case where BITSPERSAMPLE is a list. if (flags & IG_ISIS_CONT_LIST) { LONG bits = 0; WORD samplesCount = 0; IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_BITSPERSAMPLE, &samplesCount); for (WORD sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) { IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, sampleIndex, &bits); if (bits == 1) { printf("Binary is supported.\n"); } else { printf("%d-bit grayscale is supported.\n", (int)bits); } } } else if (flags & IG_ISIS_CONT_RANGE) { // Handle case where BITSPERSAMPLE is a range. LONG low = 0, high = 0, step = 0; IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_LOW, &low); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_HIGH, &high); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_STEP, &step); for (LONG bits = low; bits <= high; bits += step) { if (bits==1) { printf("Binary is supported.\n"); } else { printf("%d-bit grayscale is supported.\n", (int)bits); } } } } else if (samples == 3) { // If SAMPLESPERPIXEL is 3, then must be color. // Determine whether BITSPERSAMPLE is a list or a range. AT_LMODE flags = 0; IG_ISIS_choice_get_flags(hScan, IG_ISIS_TAG_BITSPERSAMPLE, &flags); if (flags & IG_ISIS_CONT_LIST) { // Handle case where BITSPERSAMPLE is a list. LONG bits = 0; WORD samplesCount = 0; IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_BITSPERSAMPLE, &samplesCount); for (WORD sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) { IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, sampleIndex, &bits); // The number of bits in color is 3 times the BITSPERSAMPLE. printf("%d-bit color is supported.\n", (int)bits * 3); } } else if (flags & IG_ISIS_CONT_RANGE) { // Handle case where BITSPERSAMPLE is a range. LONG low = 0, high = 0, step = 0; IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_LOW, &low); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_HIGH, &high); IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, IG_ISIS_CHOICE_STEP, &step); for (LONG bits = low; bits <= high; bits += step) { // The number of bits in color is 3 times the BITSPERSAMPLE. printf("%d-bit color is supported.\n", (int)bits * 3); } } } else { // Probably will never see this case: If scanner returns other than // 1 or 3 SAMPLESPERPIXEL, print number of samples scanner supports. printf("Scanner supports %d-sample color.\n", (int)samples); } } } |
PixTools/Scan has functions that read and write the values of all tags in a scanner driver. The following sample shows how to get a list of all tags that a scanner supports.
ISIS allows your application to query a scanner and tell it to give you a list of all tags which exist in a driver. The tag that contains this list is tag number zero (0). The following example shows how to use this special tag to get a list of all tags supported in a driver:
Copy Code
|
|
---|---|
void ListAllScannerTags(HISISDRV hScan) { DWORD numberOfTags = 0; // Ask for tag zero's length; that's the number of tags that the scanner supports. IG_ISIS_tag_get_length(hScan, 0, &numberOfTags); // Get the tag number and the tag type for each of the tags. for (DWORD index = 0; index < numberOfTags; index++) { LONG tagNumber = 0; AT_MODE tagType = 0; char *tagTypeDescription = NULL; IG_ISIS_tag_get_long(hScan, 0, (WORD)index, &tagNumber); IG_ISIS_tag_get_type(hScan, (AT_MODE)tagNumber, &tagType); switch (tagType) { case IG_ISIS_TAG_TYPE_BYTE: tagTypeDescription = "Byte"; break; case IG_ISIS_TAG_TYPE_SHORT: tagTypeDescription = "Short"; break; case IG_ISIS_TAG_TYPE_LONG: tagTypeDescription = "Long"; break; case IG_ISIS_TAG_TYPE_RATIONAL: tagTypeDescription = "Rational"; break; case IG_ISIS_TAG_TYPE_STRING: tagTypeDescription = "Ascii"; break; default: tagTypeDescription = "Unknown"; break; } // Print the tag number and type, one tag per line. printf("Tag number %ld is supported, and is of type %s\n", tagNumber, tagTypeDescription); } } |
The above example prints the number and type of each tag. The string representation for the tag name is not in the toolkit. The # defines that associate strings with tag numbers can be found in PIXTAGS.H
Once you have found the type of a tag, you could extend this example to find out its choices. You can also use this method to find all tag values. Another way to do this is to use the library function IG_ISIS_tag_save_file(). This function saves the current value of all scanner state tags for the referenced driver to a file (usually SETSCAN.INI), in a section of the specified name. A corresponding function is IG_ISIS_tag_restore_file() which can be used after a IG_ISIS_tag_save_file() to restore the values of all tags to their previous saved values. These two functions used together can save and restore the state of an application's settings for a driver.
The following example shows how to determine whether or not eight-bit grayscale is available from a scanner:
Copy Code
|
|
---|---|
bool Is8BppGrayscaleAvailable(HISISDRV hScan) { WORD bitsPerSampleCount = 0; bool isAvailable = false; // Set SAMPLESPERPIXEL to 1. // 1-sample-per-pixel is always allowed (it's needed for binary). IG_ISIS_tag_set_long(hScan, IG_ISIS_TAG_SAMPLESPERPIXEL, 0, 1L); // Get how many options exist for BITSPERSAMPLE. IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_BITSPERSAMPLE, &bitsPerSampleCount); for (WORD i = 0; i < bitsPerSampleCount; i++) { // Get each value of IG_ISIS_TAG_BITSPERSAMPLE. LONG bitsPerSample = 0; IG_ISIS_choice_get_long(hScan, IG_ISIS_TAG_BITSPERSAMPLE, i, &bitsPerSample); // If a value of 8 is found, stop looking--8-bit gray is supported. if (bitsPerSample == 8) { isAvailable = true; break; } } return isAvailable; } |
The following example displays a list of dither patterns that a driver supports:
Copy Code
|
|
---|---|
void ListDitherPatterns(HISISDRV hScan) { WORD ditherCount = 0; char buffer[1024]; // ASCII tags are always represented as lists. IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_DITHER, &ditherCount); printf("There are %d dither patterns.\n", ditherCount); for (WORD i = 0; i < ditherCount; i++) { IG_ISIS_choice_get_ascii(hScan, IG_ISIS_TAG_DITHER, i, buffer); printf("%d. %s\n", i, buffer); } } |
The following example displays all of the X resolution values that a driver supports:
Copy Code
|
|
---|---|
void ListAllXResolutions(HISISDRV hScan) { AT_LMODE flags = 0; // RATIONAL tags can be represented as a range or list. IG_ISIS_choice_get_flags(hScan, IG_ISIS_TAG_XRESOLUTION, &flags); if (flags & IG_ISIS_CONT_RANGE) { // Choices are represented as a range. When a driver supports a large number of choices // (such as resolution or zoning information), and when the choices are represented as a // list, then accessing the choice values through the special indexes(LOW, HIGH, STEP) will // be much more efficient. AT_ISIS_RAT ratValueLow, ratValueHigh, ratValueStep; IG_ISIS_choice_get_rational(hScan, IG_ISIS_TAG_XRESOLUTION, IG_ISIS_CHOICE_LOW, &ratValueLow); IG_ISIS_choice_get_rational(hScan, IG_ISIS_TAG_XRESOLUTION, IG_ISIS_CHOICE_HIGH, &ratValueHigh); IG_ISIS_choice_get_rational(hScan, IG_ISIS_TAG_XRESOLUTION, IG_ISIS_CHOICE_STEP, &ratValueStep); // Give ratValueLow and ratValueStep a common denominator. if (ratValueStep.Denom != ratValueLow.Denom) { ratValueLow.Num *= ratValueStep.Denom; ratValueLow.Denom *= ratValueStep.Denom; ratValueStep.Num *= ratValueLow.Denom; ratValueStep.Denom *= ratValueLow.Denom; } while (ratValueLow.Num * ratValueHigh.Denom <= ratValueHigh.Num * ratValueLow.Denom) { printf("%ld / %ld\n", ratValueLow.Num, ratValueLow.Denom); ratValueLow.Num += ratValueStep.Num; } } else { // (flags & IG_ISIS_CHOICE_LIST) // Choices are represented as a list. Note that this code // would work even if the choices are represented as a range. WORD choiceCount = 0; IG_ISIS_choice_get_count(hScan, IG_ISIS_TAG_XRESOLUTION, &choiceCount); for (WORD i = 0; i < choiceCount; i++) { AT_ISIS_RAT ratValue; IG_ISIS_choice_get_rational(hScan, IG_ISIS_TAG_XRESOLUTION, i, &ratValue); printf("%ld / %ld\n", ratValue.Num, ratValue.Denom); } } } |