Разные результаты при использовании CopyRect

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Разные результаты при использовании CopyRect

Сообщение Eprinter » 06.02.2023 05:52:40

Доброго дня.

Ещё с Делфи осталось ощущение, что все свойства канвы доступны лишь очень продвинутым кодерам, коим я не являюсь даже близко ))
По примерам из разных форумов и блогов создал в модальном окне следующую процедуру размещения изображений из файлов на форме:
Код: Выделить всё
procedure TFormSetLoc.DrawPictLoc(LocRow: Integer);
var
  S: string;
  PictRect, TempRect: TRect;
begin
  S:= CurrDir+'/images/'+StringGridLoc.Cells[1, LocRow]+'.bmp';
  TempRect:= Rect(0, 0, 48, 32);
  if DirectLoc then
    PictRect:= Rect(48, 32 * (LocRow - 1), 0, 32 * LocRow)
  else
    PictRect:= Rect(0, 32 * (LocRow - 1), 48, 32 * LocRow);
  Try
    if FileExists(S) then
      ImgTmp.Picture.LoadFromFile(S)
    else
      ImgTmp.Picture.PNG.Canvas.CopyRect(TempRect, ImageLoc0.Picture.Bitmap.Canvas, TempRect);
    ImgLoc.Picture.PNG.Canvas.CopyRect(PictRect, ImgTmp.Picture.Bitmap.Canvas, TempRect);
    ImgLoc.Repaint;
  except
    ShowMessage(MessagePictLocNotFound+#$D#$A+S);
  end;
end;

Позже слегка модифицировал и повторил в главном окне, изображения во временный имидж читались, но далее ничего не происходило (сверху кусочек главного окна, где ожидались картинки, остальное модальное):
Изображение
Фрагмент кода (естественно пробовал копировать и напрямую в любой имидж на главной форме, без поиска):
Код: Выделить всё
      ImgTmp.Picture.PNG.Canvas.CopyRect(TempRect, ImageLoc0.Picture.Bitmap.Canvas, TempRect);
    (Findcomponent('ImageLoc'+IntToStr(PictNum+8)) as TImage)
            .Picture.PNG.Canvas.CopyRect(PictRect, ImgTmp.Picture.Bitmap.Canvas, TempRect);

После плясок с бубном получил такой рабочий код:
Код: Выделить всё
procedure TFormMain.DrawPictLocs(PictNum, LocRow: Integer);
var
  S: string;
  PictRect, TempRect: TRect;
begin
  S:= CurrDir+'/images/'+FormSetLoc.StringGridLoc.Cells[1, LocRow]+'.bmp';
  TempRect:= Rect(0, 0, 48, 32);
  if DirectLoc then
    PictRect:= Rect(48, 0, 0, 32)
  else
    PictRect:= Rect(0, 0, 48, 32);
  Try
    if FileExists(S) then
      ImgTmp.Picture.LoadFromFile(S)
    else
      ImgTmp.Canvas.CopyRect(TempRect, ImageLoc0.Canvas, TempRect);
    (Findcomponent('ImageLoc'+IntToStr(PictNum+8)) as TImage)
            .Canvas.CopyRect(PictRect, ImgTmp.Canvas, TempRect);
    (Findcomponent('ImageLoc'+IntToStr(PictNum+8)) as TImage).Repaint;
  except
    ShowMessage(MessagePictLocNotFound+#$D#$A+S);
  end;
end;

И результат:
Изображение

Попробовал в модальной форме упростить ImgTmp.Picture.PNG.Canvas.CopyRect до ImgTmp.Canvas.CopyRect и получил закрашенный чёрным имидж:
Изображение

То есть более длинный путь к холсту работает в модальном окне, но не работает в главном, а более короткий - наоборот. Или тут какая-то другая причина, о которой даже не подозреваю?
Как бы выход (на костылях) найден, но если кто сможет, раскройте пожалуйста глубинную сущность данного метода (можно ссылкой на почитать про нюансы).
Eprinter
новенький
 
Сообщения: 12
Зарегистрирован: 17.01.2023 17:56:58
Откуда: Нашенский

Re: Разные результаты при использовании CopyRect

Сообщение zub » 06.02.2023 09:15:52

Минимальный пример кода демонстрирующий проблему. вместо тысячи слов
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Разные результаты при использовании CopyRect

Сообщение Alex2013 » 06.02.2023 13:45:37

Поэтому я предпочитаю использовать BitBlt и StretchBlt ( или вообще прямую работу с растром в памяти ). А "неясности" с LCL настолько глобальны, что не столкнуться с ними можно только при использовании совершенно стандартных приемов и "то шаг влево шаг вправо расстрел" . ( Даже просто перекрасить стандартные контролы уже целая история )
В VCL "от делфи" все чуть надежнее, но именно что "чуть" в этом смысле лучшая библиотека классов это старый добрый КОЛ . Вот там "все по честному" с минимумом непоняток ( кроме тех что "на совести у микрософта" ). А вообще для серьезной работы с 2д-графикой ни LCL ни VCL неприспособлен .

Конкретно с "черным квадратом" сталкивался когда неправильно установлен Pen.Мode или нет нормальной инициализации "приемника" (например если он имеет нулевой размер (или меньший чем копируемый спрайт ( иногда даже на один пиксель )) то при использовании CopyRect он может проинициализировать (точнее "отмасштабироваться" ) автоматом ( хотя и с тормозом ), а может и не сработать совсем ) еще бывает что нужно вызвать Application.ProcessMessages по завершении отрисовки.

В общем мой совет для начала попробуй заменить CopyRect на BitBlt или StretchBlt, а дальше видно будет .
Зы
Кажется понял в чем дело! ImgTmp.Picture.PNG.Canvas можно обрезать до ImgTmp.Picture.Canvas (или записать как ImgTmp.Picture.Bitmap.Canvas) но если обрезать до ImgTmp.Canvas то получим "пустой" Canvas от ImgTmp ( его Canvas это по сути аналог PaintBox (или даже еще боле прмитивного канваса от TPanel) то есть если нет отрисовки то нет картинки ) Пасаж насчет модального и не модального окна скорее всего "мимо кассы" хотя возможно, что для модального онка отрисовка TImage действительно происходит чуть иначе .
Последний раз редактировалось Alex2013 06.02.2023 23:50:42, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Разные результаты при использовании CopyRect

Сообщение Eprinter » 06.02.2023 17:44:04

Alex2013 BitBlt не подходит - мне нужна кроссплатформенность. В том числе и на малинке. Так что будем пилить дальше, тем более что графики нужно совсем чуть-чуть ))
По "чёрному квадрату" и "Зы" спасибо, поэкспериментирую. Хотя, емнип, я пробовал разные варианты, и только полное обрезание вдруг заработало. Кстати, ещё можно попробовать рисовать на модальном окне из главного, тоже интересен результат. Отпишу.
Да, ещё - модальное окно в стиле bsToolWindow, может тут что повлияло.
Eprinter
новенький
 
Сообщения: 12
Зарегистрирован: 17.01.2023 17:56:58
Откуда: Нашенский

Re: Разные результаты при использовании CopyRect

Сообщение Alex2013 » 07.02.2023 00:23:31

Внутри канвас тот же BitBlt ( Полной кроссплатформенность у него нет но часть winapi успешно эмулируется на других платформах ) + вроде есть Platform independent аналоги вроде LCLIntf.StretchMaskBlt
https://wiki.lazarus.freepascal.org/lclintf
function StretchMaskBlt(DestDC: HDC; X, Y, Width, Height: Integer; SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer; Mask: HBITMAP; XMask, YMask: Integer; Rop: DWORD): Boolean ;
Зы
По идеи интересная тема "Прозрачность PNG в проектах Lazarus ..." ( Возможно суть проблемы в этом причем там как я понял как раз кроссплатформенный случай )
http://www.freepascal.ru/forum/viewtopic.php?t=4800
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Разные результаты при использовании CopyRect

Сообщение Eprinter » 07.02.2023 18:21:40

Потратил время, провёл эксперимент. Положил 8 имиджей на главную форму, 8 на вновь созданную модальную. На кнопку повесил код:
Код: Выделить всё
procedure TFormMain.ButtonSendDateClick(Sender: TObject);
var
  S: string;
  TR: TRect;
begin
  TR:= Rect(0, 0, 48, 32);
  ImgTmp1.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  Label1.Caption:='ImgTmp1.Picture.PNG.Canvas.CopyRect('+
                  'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
  //ImgTmp2.Picture.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR); - unitmain.pas(1400,19) Error: identifier idents no member "Canvas"
  Label2.Caption:='ImgTmp2.Picture.Canvas.CopyRect('+
                  'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
  ImgTmp3.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  Label3.Caption:='ImgTmp3.Picture.Bitmap.Canvas.CopyRect('+
                  'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
  ImgTmp4.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  Label4.Caption:='ImgTmp4.Canvas.CopyRect('+
                  'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';

  ImgTmp5.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  Label5.Caption:='ImgTmp5.Picture.PNG.Canvas.CopyRect('+
                  'TR,ImgTmp.Canvas,TR)';
  //ImgTmp6.Picture.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  Label6.Caption:='ImgTmp6.Picture.Canvas.CopyRect('+
                  'TR,ImgTmp.Canvas,TR)';
  ImgTmp7.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  Label7.Caption:='ImgTmp7.Picture.Bitmap.Canvas.CopyRect('+
                  'TR,ImgTmp.Canvas,TR)';
  ImgTmp8.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  Label8.Caption:='ImgTmp8.Canvas.CopyRect('+
                  'TR,ImgTmp.Canvas,TR)';

  with FormSetSwitch do
  begin
    ImgTmp1.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
    Label1.Caption:='ImgTmp1.Picture.PNG.Canvas.CopyRect('+
                    'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
    //ImgTmp2.Picture.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
    Label2.Caption:='ImgTmp2.Picture.Canvas.CopyRect('+
                    'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
    ImgTmp3.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
    Label3.Caption:='ImgTmp3.Picture.Bitmap.Canvas.CopyRect('+
                    'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';
    ImgTmp4.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
    Label4.Caption:='ImgTmp4.Canvas.CopyRect('+
                    'TR,ImgTmp.Picture.Bitmap.Canvas,TR)';

    ImgTmp5.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
    Label5.Caption:='ImgTmp5.Picture.PNG.Canvas.CopyRect('+
                    'TR,ImgTmp.Canvas,TR)';
    //ImgTmp6.Picture.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
    Label6.Caption:='ImgTmp6.Picture.Canvas.CopyRect('+
                    'TR,ImgTmp.Canvas,TR)';
    ImgTmp7.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
    Label7.Caption:='ImgTmp7.Picture.Bitmap.Canvas.CopyRect('+
                    'TR,ImgTmp.Canvas,TR)';
    ImgTmp8.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
    Label8.Caption:='ImgTmp8.Canvas.CopyRect('+
                    'TR,ImgTmp.Canvas,TR)';
  end;
  FormSetSwitch.ShowModal;
end;

И в главном окне, и в модальном работает только вариант ImgTmp8.Canvas.CopyRect, остальные имиджи остаются чистыми:
Изображение
Добавил в модальную форму обработчик:
Код: Выделить всё
procedure TFormSetSwitch.FormDblClick(Sender: TObject);
var
  S: string;
  TR: TRect;
begin
  S:= 'D:\lazarus2\_test_\MDCSv1/images/e1000.bmp';
  ImgTmp.Picture.LoadFromFile(S);
  TR:= Rect(0, 0, 48, 32);
  ImgTmp1.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  //ImgTmp2.Picture.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  ImgTmp3.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);
  ImgTmp4.Canvas.CopyRect(TR,ImgTmp.Picture.Bitmap.Canvas,TR);

  ImgTmp5.Picture.PNG.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  //ImgTmp6.Picture.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  ImgTmp7.Picture.Bitmap.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
  ImgTmp8.Canvas.CopyRect(TR,ImgTmp.Canvas,TR);
end;

Тот же результат. При этом на другой модальной форме по-прежнему работает ImgLoc.Picture.PNG.Canvas.CopyRect
Ради порядка скомпилировал последнюю версию на малинке - абсолютно та же картина, по всем формам. Из чего делаю вывод: это непостоянство - внутренняя багофича лазаруса ))

Спасибо за советы, но я всё же останусь на CopyRect, ибо в принципе работает и там, и там. Бубен под рукой, основные ритмы выучил ))
Eprinter
новенький
 
Сообщения: 12
Зарегистрирован: 17.01.2023 17:56:58
Откуда: Нашенский

Re: Разные результаты при использовании CopyRect

Сообщение Mikhail » 08.02.2023 12:39:00

Не совсем понял, причем здесь вообще CopyRect? Здесь может быть проблема с тем что формат пикселей на холстах разный, например. Зачем вообще в качестве временного холста использовать TImage?
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Разные результаты при использовании CopyRect

Сообщение Eprinter » 08.02.2023 15:26:18

Mikhail, спасибо! Действительно, я протупил...
Прежде, чем работать с PNG, нужно было отдельно задать его размер. В первый раз увидел в примерах и сделал, но в другой процедуре, а спустя время забыл.
Добавил строчку ImgTmp1.Picture.PNG.SetSize(48,32); и заработала команда ImgTmp1.Picture.PNG.Canvas.CopyRect
Ну а сокращённый вариант ImgTmp4.Canvas.CopyRect работать перестал, чёрный квадрат...

Век живи, век учись, а итог один ))

ПС аналогично работает ImgTmp4.Picture.Bitmap.SetSize(48,32);
То есть неважно, какую разновидность Picture собираемся использовать - задаём размер хоть PNG, хоть Bitmap, и можно адресоваться хоть к тому, хоть к другому, без разницы (в моём случае, когда прозрачность не нужна)...

Добавлено спустя 39 минут 11 секунд:
Mikhail писал(а):Зачем вообще в качестве временного холста использовать TImage?

Так проще отлаживать - видно, что изображение подгрузилось нормально, а проблема где-то дальше ))
Eprinter
новенький
 
Сообщения: 12
Зарегистрирован: 17.01.2023 17:56:58
Откуда: Нашенский

Re: Разные результаты при использовании CopyRect

Сообщение Mikhail » 08.02.2023 16:44:43

Eprinter писал(а):Добавил строчку ImgTmp1.Picture.PNG.SetSize(48,32); и заработала команда ImgTmp1.Picture.PNG.Canvas.CopyRect
Ну а сокращённый вариант ImgTmp4.Canvas.CopyRect работать перестал, чёрный квадрат...

TImage.Canvas и TImage.Picture.PNG.Canvas это разные холсты.

Eprinter писал(а):Так проще отлаживать - видно, что изображение подгрузилось нормально, а проблема где-то дальше ))

Одинаково, если будут проблемы, то будет исключение.
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47

Re: Разные результаты при использовании CopyRect

Сообщение Eprinter » 08.02.2023 17:37:24

Mikhail писал(а):TImage.Canvas и TImage.Picture.PNG.Canvas это разные холсты.

А TImage.Picture.Bitmap.Canvas получается третий холст?

Когда делаю ImgTmp.Picture.Bitmap.SetSize(48,32); то:
- ImgTmp.Picture.PNG.Canvas.CopyRect работает
- ImgTmp.Picture.Bitmap.Canvas.CopyRect работает
- ImgTmp.Canvas.CopyRect работает

Когда делаю ImgTmp.Picture.PNG.SetSize(48,32); то:
- ImgTmp.Picture.PNG.Canvas.CopyRect работает
- ImgTmp.Picture.Bitmap.Canvas.CopyRect работает
- ImgTmp.Canvas.CopyRect НЕ работает

Когда не делаю SetSize, то работает только ImgTmp.Canvas.CopyRect

Mikhail писал(а):Одинаково, если будут проблемы, то будет исключение.

Согласен. Но всё же приятнее видеть промежуточный результат глазами ))

А вообще стало немного понятнее, как работать с холстами, спасибо.
Eprinter
новенький
 
Сообщения: 12
Зарегистрирован: 17.01.2023 17:56:58
Откуда: Нашенский

Re: Разные результаты при использовании CopyRect

Сообщение Mikhail » 08.02.2023 17:57:40

Eprinter писал(а):А TImage.Picture.Bitmap.Canvas получается третий холст?

Нет.

Вообще есть вики на подобную тему.
https://wiki.freepascal.org/Developing_with_Graphics/ru#.D0.A0.D0.B0.D0.B1.D0.BE.D1.82.D0.B0_.D1.81_TLazIntfImage.2C_TRawImage_.D0.B8_TLazCanvas

Если вкраце,то содержимое TImage.Canvas не сохраняется между перерисовками компонента.
Mikhail
энтузиаст
 
Сообщения: 562
Зарегистрирован: 24.10.2013 16:06:47


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 24

Рейтинг@Mail.ru