Share

AcGiRequestScanLines

C++

struct AcGiRequestScanLines {
  enum IEDitherMethod {
    kIEAnyPalette,
    kCustomDithering,
    kCustomDitheringMethod
  };
  enum IEColorSystem {
    kBitonal,
    kCMY,
    kCMYK,
    kRGB
  };
  enum ImagePaletteType {
    kFromDevice,
    kFromIeWholeImage
  };
  Adesk::UInt32 mPixelMinX = 0;
  Adesk::UInt32 mPixelMinY = 0;
  Adesk::UInt32 mPixelMaxX = 0;
  Adesk::UInt32 mPixelMaxY = 0;
  AcGePoint2d mLowerLeft;
  AcGePoint2d mUpperRight;
  void * mpImageId = nullptr;
  AcGiImageOrg mImageOrg;
  AcGiImageOrient mImageOrient;
  Adesk::Int16 mWindowId = 0;
  Adesk::Int16 mColorDepth = 8;
  union {
  } mBackgroundColor;
  union {
  } mTransparentColor;
  union {
  } mEntityColor;
  Adesk::Int32 mPaletteIncarnation = 0;
  Adesk::Int8 * mpPalette = nullptr;
  Adesk::Int16 mIsDisplay = 0;
  double mRasterRatio = 1.0;
  AcGeMatrix2d mPixelToDc;
  ImagePaletteType mPaletteType;
  void * mpDataBuffer = nullptr;
  Adesk::Int32 mRowWidth = 0;
  Adesk::Int32 mNumRows;
  Adesk::Int32 const * mpBoundaryPoints = nullptr;
  Adesk::UInt32 mnContours = 0;
  Adesk::Int32 const * mpCounts = nullptr;
  AcGiScaleType mScalingType;
  AcGiScaleFilterType mScaleFilterType;
  AcGiRotationFilterType mRotationFilterType;
  short mnTotalChunks = 0;
  short mnThisChunk = 0;
};

File

acgi.h

Description

[The following is adapted from the HEIDI Driver Developer Kit documentation. Please refer to the section describing the RequestScanLines structure in that document for essential and detailed information on the use of this API.]

The AcGiRequestScanLines structure is the information packet sent from the display or plot driver to the AcDbImage entity in the AcDbImage::getScanLines() callback when the image is to rendered. The packet corresponds to the HEIDI RequestScanLines structure. The only significant difference between AcGiRequestScanLines and RequestScanLines is the coordinate system used to define the extent of the original image entity. AcGiRequestScanLines uses floating point world coordinates while RequestScanLines uses integer "logical" coordinates. The coordinate transformation is done by AutoCAD's graphics pipeline.

The AcGiRequestScanLines structure is defined as:

struct AcGiRequestScanLines {
    Adesk::UInt32   mPixelMinX;
    Adesk::UInt32   mPixelMinY;
    Adesk::UInt32   mPixelMaxX;
    Adesk::UInt32   mPixelMaxY;
    AcGePoint2d     mLowerLeft;
    AcGePoint2d     mUpperRight;
    void*           mpImageId;
    AcGiImageOrg    mImageOrg;
    AcGiImageOrient mImageOrient;
    Adesk::Int16    mWindowId;
    Adesk::Int16    mColorDepth;
    union {
        Adesk::Int16 mBackgroundIndex;
        Adesk::Int8 mBackgroundRGB[3];
    } mBackgroundColor;
    union {
        Adesk::Int16 mTransparentIndex;
        Adesk::Int8 mTransparentRGB[3];
    } mTransparentColor;
    union {
        Adesk::Int16 mEntityIndex;
        Adesk::Int8 mEntityRGB[3];
    } mEntityColor;
    Adesk::Int32        mPaletteIncarnation;
    Adesk::Int8*        mpPalette;
    Adesk::Int16        mIsDisplay;
    Adesk::Int16        mRasterRatio;
    AcGeMatrix2d        mPixelToDc;
    char*               mpCompressionModes;
    ImagePaletteType    mPaletteType;
    void*               mpDataBuffer;
    Adesk::Int32        mRowWidth;
    Adesk::Int32        mNumRows;
    Adesk::Int32 const* mpBoundaryPoints;
    Adesk::UInt32       mContours;
    Adesk::Int32 const* mpCounts;
}
Bi-tonal Rasters

Drivers may request IORG_PALETTE with mColorDepth = 1 for monochrome support with one pixel per byte, or they may request IORG_BITONAL for packed pixel data with 8 pixels per byte. If the driver reports mImageOrganization is IORG_PALETTE and sets mColorDepth to 1, then monochrome rasters will be sent at one pixel per byte, with values of either 0 or 1. If the driver reports mImageOrganization is IORG_BITONAL, then mColorDepth must be 1 and monochrome rasters will be sent in a packed pixel format with 8 pixels per byte and the rightmost pixel in the most significant bit. Monochrome rasters are the one case where the background color and the transparent color must be equal. In all other cases, they must be distinct.

ImageOrientation

mImageOrient specifies which way the scan lines run and the order that the scan lines are sent, and may be any one of the AcGiImageOrg enumeration values. Although the driver may request different image orientations for different HT_ISM_Images, it may not change this selection during its handling of a single HT_ISM_Image. However, the driver must request a desired orientation, color depth and organization and stick with them for all of the get_scan_line() requests associated with the image. The driver's ImageOrientation selection does not change the origin of the coordinate system used to describe rasters in HT_ISM_Image, nor the origin of the coordinates used in RequestScanLines, it only affects the ordering of the data supplied in pPixelBuffer.

The value of AcGiSentScanLines::mRowBytes takes image orientation into account. If scan lines run along the Y axis, so does AcGiSentScanLines::mRowBytes.

Here are some simple illustrations of what the driver should expect to get for each image orientation request. The original packet image coordinates and the request coordinates passed by the driver, that indicate a given sub-part of the image, are all relative to a lower left corner origin and are not affected by the request orientation. The same request coordinates should always obtain exactly the same pixels, but in different sequences in the data buffer with different requested orientations. Depending on the size and coordinates of the requested block, the amount of padding at the scanline ends may differ with the requested orientation as well.

The image orientation dictates the order in which the pixels appear in the sent scan lines data buffer. Left, right, top, and bottom in the orientation names are all relative to the lower left corner origin.

For example, if the total image is from (0,0) to (2,2), in a 3x3 square, we can number each pixel from 1 to 9 to indicate its sequential order in the data buffer:

  1. IORIENT_X_LEFT_TO_RIGHT_TOP_FIRST
123

456

789

  1. IORIENT_X_LEFT_TO_RIGHT_BOTTOM_FIRST
789

456

123

  1. IORIENT_X_RIGHT_TO_LEFT_TOP_FIRST
321

654

987

  1. IORIENT_X_RIGHT_TO_LEFT_BOTTOM_FIRST
987

654

321

  1. IORIENT_Y_TOP_TO_BOTTOM_LEFT_FIRST
147

258

369

  1. IORIENT_Y_TOP_TO_BOTTOM_RIGHT_FIRST
741

852

963

  1. IORIENT_Y_BOTTOM_TO_TOP_LEFT_FIRST
369

258

147

  1. IORIENT_Y_BOTTOM_TO_TOP_RIGHT_FIRST
963

852

741

Because the example above shows a 3x3 square, 24 bit Blue/Green/Red looks like the following example, byte by byte, because double word padding increases AcGiSentScanLines::mRowBytes from 9 to 12:

[BGRBGRBGR???BGRBGRBGR???BGRBGRBGR???]

And at 1-8 bits, paletted, the data buffer would look like the following example, byte by byte, because dword padding increases AcGiSentScanLines::mRowBytes from 3 to 4:

[PPP?PPP?PPP?]

The data delivered to the driver in the sent scan lines structure must be padded based on the Y direction if orientations involving TOP_TO_BOTTOM or BOTTOM_TO_TOP are involved - not the X direction. Only by coincidence would the same amount of padding be required in both directions, as in the previous examples. Therefor, the AcGiSentScanLines::mRowBytes field in the sent scan lines structure must be assigned the value of the length, rounded up to whole double words, of a scanline in the direction requested by the driver. For half of those orientations, AcGiSentScanLines::mRowBytes would be based on the Y height of the requested block.

For paletted requests, the palette color corresponding to the transparent color is unused for purposes of rendering the requested image even if bTransparent is FALSE. Be sure to set the transparent index to an unimportant color regardless of bTransparent's value. Index 9 is a good first choice for this purpose, because 9 is usually poorly defined in the AutoCAD palette.

If you are requesting IORG_PALETTE, colorDepth = 1, for an opaque monochrome raster, it is advisable to set uTransparentColor to index 4, which is an unused index. The mTransparentColor union is ignored for 32 bit data formats. If bTransparent is TRUE, an alpha ('A') value of 0 indicates transparency in the 32 bit formats, and a value of 0xff indicates totally opaque. Any blending is handled in the application, not the driver. Applications should not send alpha values between 1 and 0xfe, otherwise the driver's behavior is undefined.

Each time the driver changes its palette, it must also change the value of mPaletteIncarnation, typically by incrementing it. This is used by the application as a hint that the palette has changed.

The hardcopy driver is responsible for allocation and management of the memory associated with mpPalette. It initializes it either with a palette or with the values for unused palette entries, depending on the fPaletteType it requests. Paletted hardcopy drivers may tell AutoCAD about their palette, in which case ISM adjusts the raster's palette to fit the driver's palette. Since this involves computation, the driver is responsible for providing a unique palette incarnation number which changes if the driver's palette has changed, thus telling the ISM to recompute. Successive incarnation numbers are formed by incrementing the initial number.

Although the driver is allowed to supply its palette, it is expected that the driver does its best to match the AutoCAD palette documented in Appendix A of the ADI 4.2 manual. The WHIP driver, for example, supports a palette very close to that expected by AutoCAD, but prefers for the sake of speed to have rasters supplied using its physical palette, which reorganizes the AutoCAD palette index sequence. If the color model is not paletted, then mpPalette may be NULL. The driver is required to maintain the data pointed to by mpPalette until it calls AcDbImage::freeScanLines(). If a driver wants to force a palette update, it can also use the magic incarnation number -1, which will always cause the ISM to recompute. The ISM persists from plot to plot, but HDI drivers are created for each plot and deleted after each plot, so drivers must be careful to always begin each plot by using the magic incarnation -1, to force the ISM to recompute the palette..

If mPaletteType is set to kFromIeWholeImage, then the application must provide the original palette for an originally paletted image, or recommend a palette for images that were originally RGB. In all cases, the device allocates 768 bytes for the palette and passes a pointer to the allocated memory. It is the device's responsibility to free this memory. If the number of colors is less than 256, the used colors should occur contiguously starting from the lowest entry. The block of memory that mpPalette points to should be a full [256][3] bytes in size, regardless of the number of colors used. If the returned palette has fewer than 256 color entries, the unused entries should be left with the values supplied by the device. The device is responsible for initializing the palette memory it allocates to the value that the device desires to see for unused entries.

When the driver wants to use the palette generation abilities of the ISM it should follow these steps:

  1. Set fPalette to kFromIeWholeImage.
  2. Allocate and initialize the 256 * 3 pPalette buffer.
  3. Set the paletteIncarnation value to a unique value.
  4. Fill the remainder of the AcGiRequestScanLines structure.
  5. Call AcDbImage::GetScanLines() with the AcGiRequestScanLines structure.
When AcDbImage::GetScanLines() returns, the mpPalette buffer contains the palette generated by the ISM. The data returned by AcGiSentScanLines is rendered in this palette.
  1. Reset the fPalette member from kFromIeWholeImage to kFromDevice.

At this point the driver becomes the owner of the new palette. By returning this palette as the drivers palette and keeping the mPaletteIncarnation value unchanged (only for the duration of the handling of this image entity), the generated palette will be used in all subsequent requests made on this image entity. The palette is a 256x3 array of unsigned characters, corresponding to R, G and B values, respectively. If the image organization is not a paletted type, then the mpPalette pointer may be NULL.

For reduced raster resolution, a hint is provided to drivers that tells them the approximate size in pixels of the visible portion of the source raster. The purpose of this hint is to allow the driver to make smart decisions about the use of super pixels either to support dithering or so that the driver does not request a 1000 dpi raster when the source raster is only 100 dpi. The Image Engine can deliver such a raster, but a great deal of memory will be wasted. By use of mRasterRatio, the driver may request a reduced raster resolution in a case like this. In this example, if the driver specifies a raster ratio of 10, it will be sent 100 dpi instead of 1000 dpi.

The number of pixels rendered on hardcopy devices should not be less than the number of pixels in the visible portion of the source image. In the case where the original source image's resolution is much higher than the device's resolution, the driver doesn't do anything special. The ISM resamples the raster to suit the device's resolution. The question of super pixels does not arise in this case.

The member mRasterRatio will normally be set to 1.0, assuming that the driver uses the same resolution for raster as for vector and polygon drawing. If the driver chooses to make raster resolution lower, it reports the ratio of raster to vector resolution here, as a floating point number. Thus, if mRasterRatio is 4.0, the driver is reporting a raster resolution 1/4 that of the vector and polygon resolution. This would typically imply that the driver uses 4x4 superpixels for each raster pixel. The center of each device pixel always corresponds to an integral coordinate in the device coordinate system.

Super Pixels

Hardcopy vectors and polygons are always drawn in device pixel coordinates. Images are sometimes rendered in "super pixels". Super pixels are groupings of device pixels. The width/height of one super pixel is exactly equal to mRasterRatio times the width/height of one device pixel.

There are two reasons to use super pixels:

  1. To reduce the volume of image data sent to the device, particularly when the source image resolution (say 200 pixels/inch) is much coarser than the device resolution (say 1000 pixels per inch). This may be done in response to the user's raster quality hints. The raster resolution for hardcopy devices should not be reduced below about 100 dpi or the number of visible pixels in the source image, whichever is higher.
  2. To provide better color resolution on output devices that have limited color resolution. By averaging together multiple device pixels to create a single super pixel, the device can more accurately render colors or greyscales.
AutoCAD is not aware of super pixels. All graphics requests (including the mScrMinX and so forth fields of RequestScanLines) are given in device pixels. The ISM only finds out about super pixels through mRasterRatio in the getScanLines() call. The ISM and the driver must agree on how to compute the device-to-super-pixel transformation. The ISM uses the following transformation to convert the requested region (given in device coordinates) from device coordinates to super pixel coordinates:
SuperX = ((SrcX - mScrMinX + 0.5) / mRasterRatio) - 0.5
SuperY = ((ScrY - mScrMinY + 0.5) / mRasterRatio) - 0.5

and

ScrX = ((SuperX + 0.5) * mRasterRatio) - 0.5 * mScrMinx
ScrY = ((SuperY + 0.5) * mRasterRatio) - 0.5 * mScrMinY

The center of the first device pixel on the page is the origin of the device coordinate system. The center of each super pixel corresponds to an integral coordinate in the super pixel coordinate system. The origin of the super pixel coordinate system is at the center of the super pixel that contains the center of the first device pixel.

Note

The center of the super pixel doesn't necessarily correspond to an integral coordinate in the device coordinate system. The number of super pixels generated by the ISM is equal to

SuperWidth = ceil((nScrMaxX - mScrMinX + 1.0) / mRasterRatio)
SuperHeight = ceil((nScrMaxY - mScrMinY + 1.0) / mRasterRatio)

In other words, Heidi rounds up to the next integral number of super pixels required to cover the requested region. It is important that only complete super pixels be painted on the page - in cases where the driver is dithering, partial super pixels are the wrong color.

Although the ISM is able to use floating point coordinates to specify device coordinates, HDI drivers may use an integer coordinate system. As a result, Heidi has agreed with the ISM on a convention for how hardcopy driver writers should think about super pixels.

    |AAAABBBB
    |AAAABBBB
    |AAAABBBB
    |aAAAbBBB
    |--------
0,0

In the preceding example picture, mRasterRatio is 4. The origin of the printable page in this example is at the lower left corner at 0,0. The first super pixel is represented by a block of 16 'A's. One way of thinking about this is to consider the origin of the first super pixel to be at its lower left corner, which lines up with the lower left corner of the first (0,0) physical pixel - where there is an 'a' in the diagram. In the ISM, the origin of the 'A' super pixel is at 1.5, 1.5 (in the center of the super pixel), and the origin of the 0,0 physical pixel is at 0.5, 0.5 - at its center. The second super pixel in this example is represented by a block of 'B's. The ISM computes its center at 5.5, 1.5.

The bounding box the driver supplies should, ideally, exactly enclose the pixels desired. Describing this bounding box accurately requires floating point coordinates since it is 0.5 pixels from the integer coordinate that is the center of each pixel. The HDI hardcopy driver simply returns a bounding box defined by the integral centers of the device pixels at the corners of the desired raster and AcGi expands the logical bounds to the outside of the requested pixel region.

ISMnLogMinX = m_bounds_in_dc.MinX - 0.5
ISMnLogMaxX = m_bounds_in_dc.MaxX + 0.5
ISMnLogMinY = m_bounds_in_dc.MinY - 0.5
ISMnLogMaxY = m_bounds_in_dc.MaxY + 0.5

The mPixelToDc transform maps image pixel coordinates to AutoCAD "eye" or viewport coordinates, as in:

origin.transformBy(modelToEye);
     u.transformBy(modelToEye);
     v.transformBy(modelToEye);
AcGePoint2d  o2(origin[0], origin[1]);
AcGeVector2d u2(u[0], u[1]);
AcGeVector2d v2(v[0], v[1]);
pixelToDc.setToAlignCoordSys(
    AcGePoint2d(-0.5, -0.5),
    AcGeVector2d(size.x, 0),
    AcGeVector2d(0, size.y),
    o2 + v2,
    u2,
    -v2);

The image is rotated by an angle other than a 90 degree increment if all elements of the upper left 2x2 submatrix are non-zero (with magnitude greater than some fuzz factor.)

mpCompressionModes make it possible to ask the ISM to compress raster data before returning it to the driver. mpCompressionModes is a pointer to a block of memory containing a NULL-terminated list of NULL-terminated strings. There are an arbitrary number of NULL-terminated strings, each of which is the canonical name of a compression mode. The standard compression mode names are shown in the following table. Refer to the Autodesk Image Engine API Manual for more information about each compression mode.

The following table shows how compression modes apply to different raster image organizations.

Compression Mode Name Bitonal Paletted RGB RGBA
CCITT G3 1D BYTE-ALIGN Yes No No No
CCITT G3 1D BYTE-ALIGN LSB-TO-MSB Yes No No No
CCITT G3 1D EOL LEAD-EOL Yes No No No
CCITT G3 1D EOL LEAD-EOL LSB-TO-MSB Yes No No No
CCITT G4 2D Yes No No No
CCITT G4 2D LSB-TO-MSB Yes No No No
MACPAINT PACKBITS Yes Yes Planar Planar
HP RLE Yes Yes Planar Planar
HP TIFF PACKBITS Yes Yes Planar Planar
HP SEED ROW Yes Yes Planar Planar
NoOpCodec Yes Yes Planar Planar
ZSOFT PACKBITS Yes Yes Planar Planar
Note

When RGB or RGBA data are compressed by the ISM, this is done on a plane by plane basis. The block of data returned in mpDataBuffer contains 4 long offsets followed by 3 or 4 blocks of compressed data:

unsigned long[4]
Uint8 data[red bytes]
Uint8[Green bytes]
Uint8[blue bytes]
Uint8[alpha bytes]

Compressed planar data is packed together on byte boundaries. Thus, the number of bytes of compressed data in each plane is the difference between the byte offsets of adjacent planes, or, for the last plane, the difference between the last offset and SentScanlines.nBytes. The row pitch, SentScanLines.rowBytes, applies to each plane. SentScanLines.rowBytes is always a multiple of 4. All planes have the same row pitch, for example, three planes with rowBytes = 4 decompress to RRRR and GGGG and BBBB.

Note

If mpCompressionModes is non NULL, RGB and RGBA data will be returned in planar form, even if the only codec listed is the NoOpCodec. If you want non-planar data for RGB or RGBA, set mpCompressionModes to NULL.

The ISM then honors the request by the hard-copy driver to supply a palette based on the original image. The generated palette is returned in the memory allocated for the palette by the driver and the pointer to the memory is a member of the RequestScanLines structure. For more details on this process, see mpPalette.

If the device is requesting uncompressed image data, it may allocate the buffer at mpDataBuffer, into which the IE puts the raster. The buffer should be 4 byte aligned. If the device chooses not to allocate the image buffer, for example because it is requesting compressed data, the device can leave mpDataBuffer NULL. The device should not allocate the memory for a compressed buffer since the device doesn't know how large to make the buffer.

mRowWidth is used if the device is allocating mpDataBuffer, because then it must also fill in mRowWidth with the number of bytes per scan line expected in the buffer. If the device leaves pDataBuffer NULL, then mRowWidth is zero.

mNumRows tells the application how many rows of pixels to put into mpDataBuffer.

mpBoundaryPoints is used by the ISM to perform clipping to a non-rectangular boundary defined by a list of contours. If the device wants the application to handle clipping to the complex region, the driver should fill in mpBoundaryPoints, mnContours and mpCounts. If no such clipping services are desired, pBoundaryPoints and pCounts should be NULL and mContours should be 0.

The contour sets handed to the ISM must be of the Even-Odd winding rule type.

Remarks

If the original source image information received indicates that the raster image is IORG_BITONAL and not transparent, and a complex clip region needs to be applied, a driver should request IORG_PALETTE data from ISM, with a color depth of 2. This is because the resulting ISM data could contain three colors - foreground, opaque background, and transparent (clipped). This is essentially the same situation that occurs when requesting data for an opaque, rotated bitonal raster, although in the latter case, the original image organization is IORG_PALETTE, color depth 2 - a hint provided by the ISM.

It may be tempting to do an extra check to see if the raster boundaries are all within the complex clip region (via point_inside()), and if so, just get unclipped data from the ISM, thereby reducing ISM computation. Avoid this temptation, however, since the clip region could intersect the raster away from the boundary corners, or even only in the interior of the raster. For example, imagine a complex clipping region made of two circles, one larger than the raster rectangle, and one smaller. The resulting raster should have the interior circle clipped out. Note that AutoCAD will allow this sort of clip region if the user uses an AutoCAD "region" entity as their viewport clipping object.

The member pBoundaryPoints is an array of int X,Y pairs. This is an array of points defining mContours polylines. The list of point counts for each polyline is in the pCounts array. The driver is responsible for managing the memory in the two arrays. Thus, a square with a triangular hole will be 2 mContours, a pCounts array containing 4 and 3, and an array of 7 pBoundaryPoints - 4 for the square and 3 for the triangle.

Links

AcGiRequestScanLines Enumerations, AcGiRequestScanLines Data Members

Was this information helpful?