Почему CopyRect перевернул второе изображение в Delphi 10.3? - PullRequest
6 голосов
/ 18 апреля 2019

Я хочу сделать снимок экрана со своей страницей и поместить результат в растровое изображение. Поскольку на странице есть полоса прокрутки, мне нужно сделать несколько снимков экрана и объединить эти растровые изображения.

Если вы использовали этот код для создания и сохранения скриншота: Сделайте скриншот определенной области в Delphi 7

я использовал код, чтобы объединить их с этой страницы http://www.delphigroups.info/2/8/309463.html

Если бы я скопировал его напрямую, это привело бы к использованию первого изображения, а для второго - белого прямоугольника. поэтому я попытался немного его изменить, и теперь я получаю оба изображения в одном файле.

Это код, который я использую для объединения растровых изображений:

    function ConcatenateBitmaps(const MainBitmap: TBitmap; const BitmapToAdd: 
    TBitmap): TBitmap;
    begin
      Result := MainBitmap;

      If BitmapToAdd.Width > MainBitmap.Width then
        Result.Width := BitmapToAdd.Width;

      Result.Height := MainBitmap.Height + MainBitmap.Height;
      Result.Canvas.CopyRect(
        Rect(0,MainBitmap.Height,BitmapToAdd.Width,BitmapToAdd.Height),
        BitmapToAdd.Canvas,
        Rect(0,0,BitmapToAdd.Width,BitmapToAdd.Height)
      );
    end;

Проблема в том, что второе изображение переворачивается по вертикали и горизонтали;

Что я здесь не так делаю?

EDIT: Пример результата: первое изображение хорошее, второе изображение перевернуто: enter image description here

как я вижу, мое описание было неверным, оно зеркально отражено по горизонтали и перевернуто по вертикали

1 Ответ

9 голосов
/ 18 апреля 2019

Причина и быстрое исправление:

Проблема в этой части:

Rect(0,MainBitmap.Height,BitmapToAdd.Width,BitmapToAdd.Height)

Вы делаете прямоугольник, из которого top - это общая высотарезультирующее изображение, а внизу - высота растрового изображения для добавления.Таким образом, этот прямоугольник в основном перевернут (его нижняя часть выше его верхней части).

И, вероятно, также деформируется, поскольку высота этого прямоугольника не является высотой растрового изображения для добавления.

Быстрое исправление будет:

Rect(0,Result.Height- BitmapToAdd.Height,BitmapToAdd.Width,Result.Height)

Другие проблемы и путаница:

Но я думаю, что причина вашей путаницы в том, что вы думаете, что Result и MainBitmap - это две разные битовые карты, хотя на самом деле они обе являются ссылками на одну и ту же битовую карту.Задание, которое вы делаете в начале, просто копирует ссылку, а не фактический объект TBitmap.

Кроме того, вы смешиваете «высоту» и «низ».TRect ожидает, что вы установите верхнюю и нижнюю координаты, а не верх и высоту.Это, вместе с предыдущей проблемой, приводит не только к тому, что растровое изображение переворачивается вверх ногами, но также к тому, что оно будет растягиваться и частично покрывать предыдущие изображения.Чем больше изображений вы добавите, тем яснее будет этот эффект.

Лично я считаю, что в этом сценарии гораздо эффективнее изменить существующее растровое изображение, главным образом потому, что в противном случае вам пришлось бы очистить свое старое растровое изображение.время, плюс у вас есть функция, которая волшебным образом создает растровые изображения.Возникает вопрос о владении объектами растрового изображения, и с этим возникает риск утечек памяти, что не очень хорошо, особенно при работе с большими растровыми изображениями.

Моя предложенная версия:

Итак, я бы просто сделал это процедурой, в которой первое растровое изображение изменяется путем добавления второго растрового изображения к нему.

В приведенной ниже версии я также использовал Canvas.ClipRect, который для растрового изображения по сути является ограничивающим прямоугольником растрового изображения.И затем я использовал OffsetRect, чтобы «переместить» этот прямоугольник (увеличив его верхний Y и нижний Y).

Делая это в отдельной переменной, вы можете получить относительно чистую версию по сравнению с быстрым исправлением, которое я представил выше, потому что вы можете использовать размеры MainBitmap до его фактического изменения.

procedure AppendBitmap(const MainBitmap: TBitmap; const BitmapToAdd:
TBitmap);
var
  TargetRect: TRect;
begin
  // Widen the main bitmap if needed
  if BitmapToAdd.Width > MainBitmap.Width then
    MainBitmap.Width := BitmapToAdd.Width;

  // Set TargetRect to the right size
  TargetRect := BitmapToAdd.Canvas.ClipRect;
  // And then to the right position
  OffsetRect(TargetRect, 0, MainBitmap.Height);

  // Make room for the bitmap to add
  MainBitmap.Height := MainBitmap.Height + BitmapToAdd.Height;

  // Draw it in the created space
  MainBitmap.Canvas.CopyRect(
    TargetRect,
    BitmapToAdd.Canvas,
    BitmapToAdd.Canvas.ClipRect
  );
end;

А если хотите, вы можете создать функцию-обертку с подписью оригинала, которая создаст копию основного изображения и вернет ее.Обратите внимание, что MainBitmap и результат этой функции больше не являются одним и тем же растровым изображением, и вы должны быть уверены, что правильно освободили их оба, когда закончите.

function ConcatenateBitmaps(const MainBitmap: TBitmap; const BitmapToAdd:
TBitmap): TBitmap;
begin
  Result := TBitmap.Create;
  Result.Assign(MainBitmap);
  AppendBitmap(Result, BitmapToAdd);
end;

PS: мне нравятся вопросыкак то, из чего я чему-то учусь.Я никогда не понимал, что вы можете перевернуть изображение, перевернув прямоугольник, переданный в CopyRect.: D

...