• 0
Zyablik3000

Нарисовать на канве ID2D1RenderTarget (ID2D1Bitmap)

Вопросы

Здравствуйте!

Есть самописный компонент - индикатор загрузки написанныый под VCL с использованием Direct2D.

TD2DProgressBar = class(TCustomControl)
FRenderTarget: ID2D1RenderTarget;

FD2DFactory.CreateWicBitmapRenderTarget(FWicBitmap, RenderTargetProp, FRenderTarget);
    FInteropTarget := FRenderTarget as ID2D1GdiInteropRenderTarget;

Вся отрисовка происходит на FRenderTarget.

Затем беру

FInteropTarget.GetDC(D2D1_DC_INITIALIZE_MODE_COPY, FRenderDC);

и вывожу на поверхность функцией
 

procedure TD2DProgressBar.UpdateWindow(sourceDC : HDC);
var
  info : TUpdateLayeredWindowInfo;
begin
  ZeroMemory(@info, sizeof(info));
  with info do begin
    cbSize  := sizeof(TUpdateLayeredWindowInfo);
    pptSrc  := @FSourcePosition;
    pptDst  := @FWindowPosition;
    psize   := @FWndSize;
    pblend  := @FBlend;
    dwFlags := ULW_ALPHA;
  end;
  info.hdcSrc := SourceDC;

  if not UpdateLayeredWindowIndirect(handle, @info) then
  begin
    RaiseLastOSError();
  end

end;

Но это только под VCL.

В Firemonkey не нашел способа комбинировать градиенты и/или нарисовать арку градиентом (саму линию арки а не залить сектор) или комбинацией градиентов.

 

Как вывести этот FRenderTarget на канву Firemonkey-контрола?

Самая большая проблема в том, что компонент полупрозрачный, и вариант с переливом через Vcl.Graphics.TBitmap и MemoryStream не дает нужного результата.
 

MS:=TMemoryStream.Create;

Blend.BlendOp            := AC_SRC_OVER;
Blend.BlendFlags         := 0;
Blend.AlphaFormat        := AC_SRC_NO_PREMULT_ALPHA;
Blend.SourceConstantAlpha:= 255; // // Уровень прозрачности


Res:=Winapi.Windows.AlphaBlend(VCLBitmap.Canvas.Handle, 0, 0, VCLBitmap.Width, VCLBitmap.Height,
                                                              FRenderDC, 0, 0, VCLBitmap.Width, VCLBitmap.Height, Blend);
  {или эта функция

StretchBlt(bm.Canvas.Handle, 0, 0, VCLBitmap.Width, VCLBitmap.Height,
                      FRenderDC, 0, 0, VCLBitmap.Width, VCLBitmap.Height, SRCCOPY); }

VCLBitmap.SaveToStream(MS);

FFMXBitmap.SetSize(TSize.Create(VCLBitmap.Width, VCLBitmap.Height));
FFMXBitmap.LoadFromStream(MS);
FreeAndNil(MS);

 

В Blend пробовал разные комбинации BlendOp и AlphaFormat.

Хелп плизз!

Во вложении компонент под VCL. ( Может кому пригодится)) )

D2DProgressbar.zip

D2DProgressBarImage.jpg

Изменено пользователем Zyablik3000

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 ответ на этот вопрос

  • 0

Здравствуйте!

Отвечу сам себе))

Переписал компонент с использованием функционала Firemonkey.

Спасибо за наличие Canvas.ClearRect()

Приложил *.pas, вдруг кому пригодится))

Хотя есть нерешенные проблемы, но о них задам вопросы в других постах.

Однако вопрос про рисование на канве ID2D1RenderTarget остается открытым (хотя-бы с целью повышения образованности).

 

FMXProgress.7z

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От Ильдар
      Добрый день, идеология такая:
      - создать битмап, рисовать на нем, не делая его видимым.
      - нашлепать на канву панели подготовленный битмап.
       
      На деле не получается нарисовать линию на битмапе. Т.е после процедуры Draw2 прожимаю процедуру Draw - получаю на панели красный прямоугольник битмапа без нарисованной линии...
      Посоветуйте чего-нибуть, спасибо!
       
      //BITMAP Bm:= TBitmap.Create; bm.Width:= round (Panel.Width/2); bm.Height:= round (Panel.Height/2); bm.Canvas.BeginScene(); bm.Canvas.Clear(TAlphacolorrec.Red); //($FF484848); bm.Canvas.EndScene; procedure TChart.Draw2; var A,B:TPointF; begin A:=TPointF.Create(0,0); B:=TPointF.Create(200, 200); bm.Canvas.BeginScene(); bm.Canvas.DrawLine(A,B,1); bm.Canvas.EndScene; end; procedure TChart.Draw; var A: TPointF; R: TRectF; begin A.X:= Panel.Position.X+3; A.Y:= Panel.Position.Y+3; R:= TRectF.Create(A, bm.Width , bm.Height); panel.Canvas.BeginScene(); Panel.Canvas.DrawBitmap(bm,r,r, 20); panel.Canvas.EndScene; end;  
    • От Julia
      Загружаю через opendialog картинку  формата bmp в image
      Есть переменные с:TColor, c1:Tcolor
      Необходимо  вначале узнать цвет определенного пикселя на загруженной картинке и записать в  c1, а затем изменить цвет определенного пикселя на загруженной картинке на цвет, хранящийся в переменной c.
      Ищу очень давно, но внятного объяснения нигде не нашла(
       
       
    • От Maximus
      Доброго всем времени суток. Хочу снова поднять вопрос про отрисовку линий на канве, обсуждавшейся здесь
      С горизонтальными и вертикальными линиями проблем нет, при смещении на половину от толщины линии всё прекрасно выглядит. Однако при отрисовке линий под различными углами такой финт не проходит: слева VCL, справа FMX

      Линия всё так же размазывается, в итоге визуально утолщается и становится не такой чёткой.
      Как всё же добиться такого же результата как на VCL? Интересует только Windows.
      const OFFSET_LINE = 0.5; ... Image.Bitmap.Canvas.BeginScene; Image.Bitmap.Canvas.Stroke.Kind := TBrushKind.Solid; Image.Bitmap.Canvas.Stroke.Thickness := 1.0; Image.Bitmap.Canvas.DrawLine( PointF(10.0 - OFFSET_LINE, 10.0 - OFFSET_LINE), PointF(500.0 - OFFSET_LINE, 10.0 - OFFSET_LINE), 1.0); Image.Bitmap.Canvas.DrawLine( PointF(10.0 - OFFSET_LINE, 10.0 - OFFSET_LINE), PointF(10.0 - OFFSET_LINE, 500.0 - OFFSET_LINE), 1.0); Image.Bitmap.Canvas.DrawLine( PointF(10.0 - OFFSET_LINE, 10.0 - OFFSET_LINE), PointF(500.0 - OFFSET_LINE, 500.0 - OFFSET_LINE), 1.0); Image.Bitmap.Canvas.EndScene;  
    • От ODmitrijS
      Подскажите алгоритм или готовый пример заливки замкнутой области рисунка произвольной формы определенным цветом?
      Моё решение часто приводит к переполнению стека.
    • От Error
      *** Небольшой обмен опытом ***
      Вижу что вопросы о размере текста довольно частые, поделюсь своими наработками.
      function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF;
      Функция для расчета размера прямоугольника, занимаемого однострочным текстом.
      Параметры:
      Text - Текст Font - Шрифт с которым будет выводиться текст Size - если 0, то Font.Size будет использоваться из Font, иначе из данного параметра Исходный код:
      uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF; var TextLayout: TTextLayout; begin TextLayout := TTextLayoutManager.DefaultTextLayout.Create; try TextLayout.BeginUpdate; try TextLayout.Text := Text; TextLayout.MaxSize := TPointF.Create(9999, 9999); TextLayout.Font.Assign(Font); if not SameValue(0, Size) then begin TextLayout.Font.Size := Size; end; TextLayout.WordWrap := False; TextLayout.Trimming := TTextTrimming.None; TextLayout.HorizontalAlign := TTextAlign.Leading; TextLayout.VerticalAlign := TTextAlign.Leading; finally TextLayout.EndUpdate; end; Result.Width := TextLayout.Width; Result.Height := TextLayout.Height; finally TextLayout.Free; end; end;   function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer;
      Функция возвращающая максимально возможный размер шрифта, для текста вписанного в заданный прямоугольник.
      Параметры:
      Text - Текст Font - Шрифт с которым будет выводиться текст Width, Height - Ширина и высота прямоугольника MaxFontSize - Максимально возможный размер шрифта Исходный код:
      uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; const cMaxFontSize = 512; function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer; var Size, Max, Min, MaxIterations: Integer; Current: TSizeF; begin Max := Trunc(MaxFontSize); Min := 0; MaxIterations := 20; repeat Size := (Max + Min) div 2; Current := CalcTextSize(Text, Font, Size); if ((Abs(Width - Current.Width) < 1) and (Width >= Current.Width)) and ((Abs(Height - Current.Height) < 1) and (Height >= Current.Height)) then break else if (Width < Current.Width) or (Height < Current.Height) then Max := Size else Min := Size; Dec(MaxIterations); until MaxIterations = 0; Result := Size; end; ---
      Также данные функции можно найти в этом юните
    • От web_warp
      В этой теме я уже задавал вопрос, но, наверное, я просто ошибся разделом. Аккумулирую вопрос:
      10.1 Berlin, C++, Win8, FMX. Интересует особенность работы Canvas->FillText(), вот код:
      void __fastcall TTabbedForm::StringGrid1DrawColumnCell(TObject *Sender, TCanvas * const Canvas, TColumn * const Column, const TRectF &Bounds, const int Row, const TValue &Value, const TGridDrawStates State) { // код... UnicodeString CT = TabbedForm->StringGrid1->Cells[Column->Index][Row]; Canvas->FillText(Bounds, CT, false, 100,TFillTextFlags() << TFillTextFlag::ftRightToLeft, TTextAlign::taTrailing, TTextAlign::taTrailing); } В итоге наблюдаются совсем странные "фишки":
      1. Разворот времени, хотя в FillText() текст передаётся правильный.
      2. Если текст заканчивается на скобку, то скобка разворачивается и переносится в начало текста.
      3. И, если есть и кириллица, и латиница, то текст просто не выводится)) (хотя есть подозрение, что это кавычки виноваты).
       
      Кто сталкивался? Что делать? Есть альтернативы?
    • От Steepe_Hare
      Под Windows 32  приложение собирается и работает отлично, под Android при запуске из RAD-среды сразу говорит: Project project1.apk raised exception class ECanvasException with message 'Handle not allocated' и отказывается работать.
      В чем может быть причина?
    • От web_warp
      В DrawColumnCell провожу зарисовку некоторых строк, необходима подсветка цветом. И тут возникла неожиданная проблема на ровном месте: ячейка, где текстом записано время, почему-то меняет местами время и дату, хотя передаётся в функцию FillText как надо.
      TabbedForm->StringGrid1->Canvas->Fill->Color = background_color; TabbedForm->StringGrid1->Canvas->FillRect(Bounds, 0, 0, AllCorners, 100); TabbedForm->StringGrid1->Canvas->Fill->Color = font_color; TabbedForm->StringGrid1->Canvas->Font->Style << fsBold; TabbedForm->StringGrid1->Canvas->FillText(Bounds,TabbedForm->StringGrid1->Cells[Column->Index][Row], false, 100,TFillTextFlags() << TFillTextFlag::ftRightToLeft, TTextAlign::taTrailing, TTextAlign::taTrailing); Подскажите пожалуйста, как развернуть время обратно?

      Ну и параллельно вопрос: как строку сплошным цветом заливать? Без белых границ?
    • От rareMax
      Привет.
      Как можно узнать сколько кадров в секунду рисует мой компонент?
      Пытался сделать так:
      procedure TCoordinatePlane.Paint; var aBM: TStopwatch; begin aBM := TStopwatch.Create; try aBM.Start; inherited Paint; FCells.DrawShape(Self); PaintXY; PaintAllShapes; PaintDebugInfo; aBM.Stop; Canvas.TextOut(0, 20, (1 / aBM.Elapsed.TotalSeconds).ToString); finally // aBM.Free; end; end;  Выдает значения довольно разные(В зависимости от масштаба) от 30 .. >1000. Как то не доверяю этим значениям. Можете подсказать как правильно сделать замер FPS?
    • От Navovvol
      Как вывести текст на изображение так, чтобы его можно было сохранить в .jpg формате.
      P.S. Нет метода TextOut у Image.
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу