tsc_Image

Overview

This class supports the loading of images for use with UI components or any other purpose.  It supports the loading of PNG, JPG, and BMP images from files.  A number of drawing methods are also included as of version 1.80, and from 20.10 further drawing methods were added and the Windows GDI+ interface removed.

Transparency

There are two transparency models used by tsc_Image.  Alpha-channel transparency is supported for loaded PNG images, but be aware that some parts of Survey Core do not support the alpha channel.

Any time a PNG image with an alpha channel is used where the alpha channel is not supported, only fully transparent pixels (those with an alpha of zero) will be transparent; all other pixels will be fully opaque.

Changes starting at version 20.10

From this version, Android is a supported platform for Scapi applications. Nearly all of the Scapi interface remains unchanged and can be used in the same way on both platforms. One exception is this tsc_Image class which has a number of methods added to it, plus a couple of minor changes, to remove all reliance on the Windows GDI+ API. Trimble Access no longer uses GDI+ and instead uses the QImage class of the Qt GUI framework.

Most basic drawing functions are provided by the tsc_Image class, without the caller having to see the QImage object which is doing all the work behind the interface. 

For advanced drawing, a reference to the QImage object associated with a tsc_Image can be obtained and Qt methods can be used to draw on it. To do this, the Qt framework must be licensed and installed on the development computer.

Also in 20.10, the use of resource DLLs is deprecated, though old plugins (those built for Windows with an SDK version less than 20.10) will continue to function with Trimble Access 2020.10. More information is provided further down this page.

Public methods

tsc_Image();
Constructs an empty image object.  The only valid operations on such an object are assignment to it,  and the Empty() test.

tsc_Image (const tsc_Size& size);
Constructs an image of a specific size and clears it to the transparent colour.

tsc_Image (int width, int height, tsc_Color initialColor);
Constructs an image of a specific size and clears it to the given colour.

tsc_Image (const tsc_Size& size, tsc_Color initialColor);
Constructs an image of a specific size and clears it to the given colour.

tsc_Image (const tsc_Image& image);
Constructs a reference to the original image.

tsc_Image Clone() const;
Constructs a separate deep copy of the image.

tsc_Size Size();
Returns the size of the image in pixels.

int Width  ();
Returns the width of the image in pixels.

int Height ();
Returns the height of the image in pixels.

bool Empty ();
Returns true if the image is null.  That is, it was constructed with no parameters.

tsc_Image&  operator= (const tsc_Image& image);
The "=" operator makes a reference to the original image, even when assigning to an instance.

tsc_Color TransparentColor () const;
Returns the current transparent color. For images with an alpha channel, this is not useful. Since version 20.10 the use of transparent colors is no longer necessary; use image alpha-channel transparency instead, such as that provided by .png images.

void TransparentColor (tsc_Color transparentColor);
Sets the transparent color.  The use of transparent colors is no longer very useful; use image alpha-channel transparency instead, such as that provided by .png images.
When this image is drawn or copied over another image, any area of this exact color will not be painted, allowing any pixels underneath to show through.  The default transparent color is white. Note that the tsc_Color::Empty() color is magenta (R=255, G=0, B=255).

void Clear (tsc_Color color);
Clears all pixels of the image to the given color.

void Clear ();
Clears all pixels of the image to the current transparent color.

tsc_Size MeasureString (const char* string, tsc_Font font, int rotation = 0);
Returns the number of pixels that will be required to draw the supplied string.  The size gives the dimensions of a rectangle that would enclose all pixels that would be drawn.  Note that Windows inflates the size slightly, so the rectangle will never be smaller than the required size.  See DrawString() for details about the font and rotation parameters.

void DrawString (const char* string, tsc_Font font, tsc_Color color, int x, int y, int rotation = 0);
Draws the supplied string on the image, using the supplied color and font.  The top-left pixel of the string is positioned at the supplied x and y coordinates.  The string is drawn horizontally unless rotation is given.  The rotation specifies an angle in degrees measured clockwise from horizontal (3 o'clock).  The font may be one of the standard Survey Core fonts - see the tsc_Font class for details.

void DrawStrings (tsc_StringList& strings, tsc_Font font, tsc_Color color, int x, int y);
Draws the supplied strings, one to a line, using the supplied color and font.

Drawing images

The various overloads of DrawImage copy all or some part of the supplied source image over a part or all of the destination image.  The destination is always the instance containing the method being called.  The top-left corner of the source image is positioned at the supplied destination X and Y pixel coordinates (the dstX and dstY parameters).  

The source image must fit within the remaining area in the destination; if this is not so, use another overload of DrawImage to specify how the source image is to be fitted - either truncated or resized.  

Source pixels that have an alpha channel value specified will be drawn with the correct opacity, allowing target image pixels to show through. 

It is allowable in the DrawImage calls for the source image to be the same as the destination image, however if the source and destination areas overlap the results may be surprising.

Alpha-channel transparency is handled correctly for all image copying operations where the image format includes an alpha channel.

void DrawImage (tsc_Image& sourceImage, int dstX, int dstY);
Draws the whole of the source image over a part or all of the destination image at the supplied coordinates.

void DrawImage (tsc_Image& sourceImage, int dstX, int dstY, tsc_Size dstSize);
Draws the whole of the source image at the given destination coordinates, and resizes it to fit within dstSize in the destination image.

void DrawImage (tsc_Image& sourceImage, int srcX, int srcY, tsc_Size srcSize, int dstX, int dstY);
Draws a part of the supplied source image as defined by the rectangle srcX,srcY,srcSize over a part or all of the destination without resizing.

void DrawImage (tsc_Image& sourceImage, int srcX, int srcY, tsc_Size srcSize,
        int dstX, int dstY, tsc_Size dstSize);
Draws a part of the supplied source image as defined by the rectangle srcX,srcY,srcSize over a part or all of the destination.  If srcSize and dstSize are different, the source rectangle is resized to fit into dstSize.

HDC GetHdc();   Windows only, TA versions 1.80 to 19.10 only.
Obtains a Windows Device Context handle (HDC) suitable for drawing to this image bitmap.  GetHdc may be called multiple times and will continue to return the same HDC until ReleaseHdc is called.
From version 20.10 onwards, this function will always return nullptr.

void ReleaseHdc();   Windows only. TA versions 1.80 to 19.10 only.
Releases an HDC that was obtained by calling GetHdc().  ReleaseHdc only needs to be called once per HDC, regardless of how many times GetHdc was called.
From version 20.10 onwards, this function does nothing.

About Android and the demise of resource DLLs

Previous to version 20.10, Scapi would load images from a resource DLL appropriate to the screen size of the current device. With the advent of Qt as a GUI layer, followed by the port to Android, resource DLLs were no longer appropriate and they are no longer supported.

To keep existing plugins working on Windows platforms, Scapi will continue to look for a <pluginName>_1024x800.DLL (and other similarly named DLLs) and if one is found then its contents will be unpacked into simple files in a resources folder. They will be given names like Resource_1006.png since the actual name is not available. A mapping between the resource ID and the plugin file path is created so that resources will continue to load correctly with no change to the plugin. Plugin DLLs will not need to be rebuilt; the current binaries will continue to work, provided that no drawing using an HDC is done as explained above.

We recommend that resource DLLs be dispensed with. While it is easy to simply load the image by name, some Scapi methods still require a resource ID - and also for compatibility's sake - Scapi allows the resource Id system to continue to work. To continue using resource IDs you need to add a some code to map the ID to a filename in the tsc_InitializePlugin() function, where it is explained in detail.

The resourceId continues to be a simple integer obtained by name from a resource.h file, such as IDB_JobButtonImage. There is no special reason to use a resource ID instead of the actual filename except where the resourceId is required in an API call. There is also nothing special about resource.h, and anything that equates the name with an integer will work.

Writing and reading images from a file or resource

static tsc_Image  FromResource (int resourceId);
Loads a PNG image from the plugin's resource folder. 

static tsc_Image  FromFile (const char* filename);
Loads an image from a PNG file (or JPG, BMP as of v2.00).  If filename is not an absolute path, it is relative to the directory of the plugin timxml file.

From Survey Core Version 2.00, loading JPG and BMP files is also supported, and the file type is determined from the extension of the specified filename, which must be one of png, jpg, jpeg, or bmp.  Note that BMP files must have the 24 bits-per-pixel colour format, but for other file types most formats are accepted.

x_Code Save (const char* filename, int quality = -1);
Saves the image to a file. If the file already exists, it is overwritten.
The file format is determined from the filename extension, which may be .gif, .bmp, .jpg, or .jpeg (plus a number of less-common formats documented by Qt for the function QImage::save(), which we call with the format parameter set to nullptr).
The quality parameter is primarily there for the Jpeg format and may be a value from 0 (worst, small) to 100 (best, large), or -1 (the default) which usually provides a reasonable compromise.
The return value is X_Null for success, X_Image if the object contains no image, or X_FailedToCreateFile if the QImage::save() function returned false, which would generally indicate a problem creating or writing the file.

Graphic drawing methods

(Version 20.10 and above)

These methods use the concept of a path, and replace the old Windows GDI+ methods. Most shapes should be drawable using these methods.

Path construction methods (eg. LineTo, ArcTo, ClosePath) do not draw anything, but simply create a 2D shape (i.e. a polyline) which must be stroked and/or filled to actually paint pixels. More information about using paths can be found in the Qt documentation for QPainterPath, though a brief description follows.

There is a Current point concept. This is a pixel coordinate (x,y) related to the tsc_Image and it is used as the starting coordinate for any path segment operations. The current point can be set by calling MoveTo(), and it is updated by path drawing operations.

All coordinates are given in pixels, and all angles are specified in degrees counter-clockwise from nine o'clock (or West if you prefer). A negative angle is measured clockwise.

void  MoveTo (int x, int y);
Sets the current point to the supplied position. Must be used to set the start point of a new path.

void  LineTo (int x, int y);
Adds a  line segment to the current path, from the current point to the supplied position. The current point is updated to the end of the line, at (x,y) 

void  ArcTo (int x, int y, int width, int height, float startAngle, float sweepAngle);
Adds an arc of an ellipse that exactly occupies the rectangle [x, y, width, height]. The arc begins at the specified startAngle (ccw from 9 o'clock), and extends for sweepAngle degrees counter-clockwise (or clockwise if sweepAngle is negative). 

A straight line segment is added from the current point to the start of the arc if necessary. Finally, the current point is updated to the end of the arc.

void  ClosePath ();
Adds a  straight line segment to the current path, from the current point back to the start of the path. ClosePath should be called prior to any filling operation.

void  ClearPath ();
Sets the current path to empty and clears the current point.

void  StrokePath (tsc_Color color, int thickness);
Draws a line along the current path. The thickness is given in pixels, and odd values will create a line that is symmetrical either side of the path.

void  FillPath   (tsc_Color color, bool useWindingRule = false);
Fills the inside of the path with the given solid color. The "insideness" method used is determined by the useWindingRule parameter. If true, a non-zero winding rule is used, otherwise the default odd-even rule is used. The winding rule affects how the shape is filled when the path crosses itself.

void  FillPath   (tsc_Color color, tsc_HatchingBrush hatchBrush, bool useWindingRule = false);
Similarly to the solid color fill, the inside of the path is filled, but with a pattern specified by hatchBrush instead of a solid color. Please see the relevant Qt documentation for a description of the patterns (or just experiment with them).

Using Qt framework for drawing on a tsc_Image

Using the Qt classes and methods directly provides greater control, however it is first necessary to install the correct version of Qt, and also obtain an appropriate license to use it for the purposes you have in mind. Some experience with Qt might be useful, and you may have to add #include statements to gain access to the required Qt class definitions. It is not possible to use those Qt types for which Trimble Access has not installed the supporting libraries (.so or .dll).

It also means your plugin will be dependent on the version of Qt used by Trimble Access which reduces backward compatibility. In other words, avoid using Qt if at all possible.

You must also change the scapi.props file in the project directory. The user macro "SupportsQt" must be set to "1" (one). This exposes the correct type and methods for using the QImage and related classes. You will probably need some #include statements to get the appropriate headers - for instance:

#include "qpainter.h"

The code below illustrates the use of both Qt and tsc_Image methods to create and display an image. Both methods may be used interchangeably on the same tsc_Image.

    // Create an image filled with red.

    tsc_Image img1 (200, 100, tsc_Color::TrimbleMediumRed2());

    tsc_Image img2 = tsc_Image::FromResource(IDB_MenuFolder);    // Get an icon from a resource


    img1.DrawImage (img2, 30, 15);    // Draw the icon over part of the image


    // Obtain a reference to the QImage and draw a line using Qt methods.

    QImage& qi = img1.GetQImage();

    QPainter qp;

    qp.begin(&qi);

    qp.setPen (QPen(Qt::black, 16, Qt::SolidLine, Qt::RoundCap));

    qp.drawLine (10, 30, 150, 80);

    qp.end();


    // Add some text using tsc_Image methods.

    img1.DrawString ("Hlo wld", tsc_Font(tsc_Font::ControlFont), tsc_Color::TrimbleLightYellow(), 5, 5);


    // Create a control containing the resulting image.

    tsc_ImageControl* ic1 = new tsc_ImageControl (X_Other, img1);

    // Add it to a form so the result can be viewed. No one said it would be pretty.

    this->Controls.Add (ic1);