-3

In Delphi 10 Seattle, I need to insert an image into an ImageList. The image is in a descendant of TGraphicControl (see source code below). The insertion seems to work. However, I get only a white rectangle in the ImageList:

function InsertCloudImageIntoImageList(AdvCloudImage1: TAdvCloudImage): Integer;
// TAdvCloudImage = class(TGraphicControl)
// WebPicture is TCloudPicture = class(TGraphic)
var
  TempBitmap: TBitmap;
  R: TRect;
begin
  Result := 0;
  TempBitmap := TBitmap.Create;
  try
    TempBitmap.SetSize(16, 16);
    R.Width  := 16;
    R.Height := 16;
    R.Top := 0;
    R.Left := 0;

    AdvCloudImage1.WebPicture.Draw(TempBitmap.Canvas, R);
    Result := Form1.ImageList1.Add(TempBitmap, nil);
  finally
    TempBitmap.Free;
  end;
end;

I suspect the bug is in the drawing on the bitmap canvas?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
user1580348
  • 5,721
  • 4
  • 43
  • 105
  • I'm also wondering what happened with http://stackoverflow.com/questions/34139196/saveto-stringhelper and http://stackoverflow.com/questions/34559867/exception-with-german-umlaut-characters-in-tmeminifile-create and http://stackoverflow.com/questions/29077977/how-to-get-the-data-from-a-shelllink-even-when-the-link-target-does-not-exist-an and http://stackoverflow.com/questions/24288185/tbutton-deficiencies I think these questions, and probably some more, could usefully be finished off – David Heffernan Jan 06 '16 at 20:18
  • 2
    The comments were not going in a productive direction, and were a meta-discussion about the suitability of the question, not the subject matter itself. They were removed once insults started being thrown around and flags started accumulating. If you wish to discuss this further, you can ask about it on [Meta.SO](http://meta.stackoverflow.com). – Brad Larson Jan 06 '16 at 20:18
  • @DavidHeffernan So flag what you think needs to be removed and we'll take a look. With a flag we have a record we can check easily, with comments we do not. – George Stocker Jan 07 '16 at 15:52
  • @GeorgeStocker I don't think anything needs to be removed, I just think that these questions have been answered – David Heffernan Jan 07 '16 at 16:10

1 Answers1

1

The correct way to draw here is to call Draw on the destination bitmap's canvas, passing the source graphic. The method you call is declared protected in TGraphic which indicates that you are not meant to call it from consumer code.

So instead of

AdvCloudImage1.WebPicture.Draw(TempBitmap.Canvas, R);

You should use

TempBitmap.Canvas.Draw(0, 0, AdvCloudImage1.WebPicture);

This greatly simplifies the function since you no longer need the TRect variable. Furthermore, there's no point assigning to Result more than once. The entire function can be:

function InsertCloudImageIntoImageList(AdvCloudImage1: TAdvCloudImage): Integer;
var
  TempBitmap: TBitmap;
begin
  TempBitmap := TBitmap.Create;
  try
    TempBitmap.SetSize(16, 16);
    TempBitmap.Canvas.Draw(0, 0, AdvCloudImage1.WebPicture);
    Result := Form1.ImageList1.Add(TempBitmap, nil);
  finally
    TempBitmap.Free;
  end;
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Obviously the `Draw` method has been made public to allow drawing. Why would you regard this as a bug? – user1580348 Jan 04 '16 at 21:18
  • It's not public in `TBitmap`, and that class works fine. That refutes what you state as being "obvious". It's protected because consumers are not meant to call it. It's meant only to be called from derived classes. So I would regard it being public as a bug. The [documentation](http://docwiki.embarcadero.com/Libraries/en/Vcl.Graphics.TGraphic.Draw) says, *Descendants of TGraphic should override this function with a specific rendering implementation.* – David Heffernan Jan 04 '16 at 21:23
  • Have you looked at the source of `WebPicture`? If not, why do you assume that it doesn't have a specific rendering implementation? – user1580348 Jan 04 '16 at 21:30
  • Well, I expect it does have that. But it doesn't need to be public. Because it's called from inside the class, or one of its associated classes. And TGraphic.Draw is abstract. So overriding and keeping protected is the norm. The point of my quote is that the docs are written for the benefit of derivers and not consumers. This is a method to be overridden and not to be called. – David Heffernan Jan 04 '16 at 21:33
  • @DavidHeffernan You say that there is no point in assigning the `Result` more than once. I beg the difference. Since `Result` is assigned within the `try block` it is possible that if an exception is raised within that block `Result` would never get assigned at all. And that means that `Result` would contain just some random number. And in case if `Result` would be of referenced type (an object for instance) then the `Result` would be uninitialized and would cause AV upon exiting of that method. So OP has to write a default value to the `Result` before entering the `try..finally` statement. – SilverWarior Jan 05 '16 at 00:11
  • @SilverWarior I agree. I always assign a default result value at the begin of a function, for this reason. – user1580348 Jan 05 '16 at 01:55
  • 1
    @Silver and @ user You are both quite wrong. If an exception is raised, no value at all is returned. Because of the exception. – David Heffernan Jan 05 '16 at 03:50
  • @silver I also pick apart your statement, "Since Result is assigned within the try block it is possible that if an exception is raised within that block". Exceptions can be raised at any time. They don't need to be inside a try block. – David Heffernan Jan 05 '16 at 03:57
  • @silver Are you going to put right your erroneous comment? – David Heffernan Jan 05 '16 at 22:41
  • @DavidHeffernan It's often just CONVENIENT to initialize the Result with a default value at the beginning of a function: Instead of writing several additional condition lines to get the Result to a default value, a one-liner at the beginning is clearly shorter and adds clarity to the function code. – user1580348 Jan 06 '16 at 20:00
  • That is sometimes the case, and a valid approach. I was commenting on the erroneous statement that @SilverWarior made, and that you agreed with. The function in my answer is accurate, and whenever it returns a value, that value is well defined. – David Heffernan Jan 06 '16 at 20:03
  • The downside of this approach is that you cannot specify the size (e.g. through the TRect). Some TGraphic descendants handle drawing scaled ideally. The only solution is to crack `TGraphic` and call the protected method that takes a rect. – Ian Boyd May 07 '18 at 17:57