Inverting Colors

To make this application a bit more fun, let's create the Edit ® Invert Colors command to enable the user to invert colors in the selected image (see Figure 17-7).

image from book
Figure 17-7: Inverting colors in an image

To invert colors in a bitmap image, you only have to call the Windows API InvertRect function. The InvertRect function accepts two parameters:

function InvertRect(hDC: HDC; const lprc: TRect): BOOL; stdcall;

The hDC parameter expects a valid device context handle — a handle of an object that supports drawing. In a VCL Forms application, you can pass the Canvas.Handle as the hDC parameter (to learn more about the Canvas property, see Chapter 22). The second parameter is a TRect record that defines the rectangle that should be inverted. To invert the entire image, pass the image's ClientRect rectangle as the lprc parameter.

If the user opens a JPEG image, we have to convert it to a bitmap before we can use the InvertRect function to invert colors in the image.

The implementation of the Edit ® Invert Colors command is displayed in the following thoroughly commented listing.

Listing 17-4: Inverting colors

image from book
 procedure TMainForm.InvertColorsItemClick(Sender: TObject); var   ActiveView: TChildForm;   NewBitmap: TBitmap; begin   if MDIChildCount = 0 then   begin     MessageDlg('Open an image first!', mtWarning, [mbOK], 0);     Exit;   end;   // convert the active child form provided by the ActiveMDIChild   // property to our child form type   ActiveView := TChildForm(ActiveMDIChild);   // if it's a bitmap - invert colors   if ActiveView.Image1.Picture.Graphic is TBitmap then   begin     InvertRect(ActiveView.Image1.Canvas.Handle, ActiveView.Image1.ClientRect);   end else if ActiveView.Image1.Picture.Graphic is TJPEGImage then   begin     // if it's a jpeg - first convert to bitmap, then invert colors     NewBitmap := TBitmap.Create;     try       // to convert a jpeg image to a bitmap, you only have to assign       // it to a bitmap       NewBitmap.Assign(ActiveView.Image1.Picture.Graphic);       // invert colors in the temporary bitmap       InvertRect(NewBitmap.Canvas.Handle, ActiveView.Image1.ClientRect);       // assign the temporary bitmap back       ActiveView.Image1.Picture.Graphic.Assign(NewBitmap);     finally       NewBitmap.Free;     end;   end;   // this is important - refresh the form   ActiveView.Image1.Invalidate; end;
image from book

Inverting Colors in C++

To invert colors in C++ you have to do the same thing as in Delphi: test if the image is a bitmap and invert its colors or convert the image to a bitmap if it's a JPEG and then invert its colors. To gain access to the TJPEGImage class you have to include the jpeg.hpp header file.

But if you try to typecast the image to a TBitmap using the following code, you'll get the "Ambiguity between TBitmap and 'Windows::TBitmap'" error message.

TGraphic* graphic = actChild->Image1->Picture->Graphic; if(dynamic_cast<TBitmap *>(graphic)) // here's the problem {    InvertRect(actChild->Image1->Canvas->Handle, &imgRect); }

This error results because two totally different TBitmap types exist and the compiler cannot determine which one you want to use.

One TBitmap type (a structure) exists in the Windows.hpp file, inside the Windows namespace, and the other TBitmap type (the VCL TBitmap class) exists in the Graphics.hpp file, inside the Graphics namespace.


Besides units, which are the default containers for data types, languages like C++, Delphi, and C# also store types in namespaces. A namespace is an additional container that groups types under a unique name and allows us to declare more classes with the same name.

For instance, the following code shows how to use namespaces to declare two completely different classes that are both called MyClass:

namespace This {    class MyClass {    public:       int x;    }; } namespace That {    class MyClass {    public:       char c;    }; }

In order to access these two classes, you'll have to use the scope access operator (::) like this:


The following code shows how you can create an instance of the MyClass class from the This namespace and the MyClass class from the That namespace:

MyClass a;        // Error - Undefined Symbol This::MyClass b; That::MyClass c; 

You can also use the reserved word using to access everything stored in a namespace. When you "open" a namespace with the reserved word using, you no longer have to use the scope access operator to access its types:

using namespace This; MyClass mc;       // This::MyClass mc.x = 5;

Everything will work properly as long as you're using only the This namespace. If you decide to use both the This and That namespaces, you'll receive exactly the same "Ambiguity…" error as we did with the TBitmap code:

using namespace This; MyClass mc;       // This::MyClass mc.x = 5; using namespace That; MyClass mc2;     // Ambiguity between MyClass and This::MyClass mc2.c = 'A';

When both namespaces have been accessed with the reserved word using, you'll need to use the scope access operator to tell the compiler which class you're interested in:

using namespace This; using namespace That; This::MyClass mc; mc.x = 5; That::MyClass mc2; mc2.c = 'A';

Now that you know a bit more about namespaces, you also know the solution to the TBitmap typecasting problem: You have to use the scope access operator to tell the compiler you want to use the VCL TBitmap class from the Graphics namespace:

if(dynamic_cast<Graphics::TBitmap *>(graphic)) {    InvertRect(actChild->Image1->Canvas->Handle, &imgRect); } 

Invert Colors Implementation

Listing 17-5 shows how to implement the Edit ® Invert Colors command in C++Builder.

Listing 17-5: Inverting colors in C++

image from book
void __fastcall TMainForm::InvertColorsItemClick(TObject *Sender) {    if(MDIChildCount == 0)    {       MessageDlg("Open an image first!", mtWarning,         TMsgDlgButtons() << mbOK, 0);       return;    }    TChildForm* actChild = dynamic_cast<TChildForm*>(ActiveMDIChild);    TGraphic* graphic = actChild->Image1->Picture->Graphic;    TRect imgRect = actChild->Image1->ClientRect;    if(dynamic_cast<Graphics::TBitmap *>(graphic))    {       InvertRect(actChild->Image1->Canvas->Handle, &imgRect);    }    else if(dynamic_cast<TJPEGImage *>(graphic))    {       Graphics::TBitmap* NewBitmap = new Graphics::TBitmap;       try       {         NewBitmap->Assign(graphic);         InvertRect(NewBitmap->Canvas->Handle, &imgRect);         graphic->Assign(NewBitmap);       }       __finally       {         delete NewBitmap;       }    }    actChild->Invalidate(); }
image from book

Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: