Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Polyline c AntiAliasing и Прозрачностью в PNGImage


Автор: Flashboy 10.8.2010, 03:26
Есть ли решение, нарисовать Polyline на Canvas PNGImage или TImage c AntiAliasing и прозрачностью?
В обычном случае Polyline при прорисовке под углом выводит линии с зазубринами.
Подскажите пожалуйста кто сталкивался с подобным, бьюсь над этой задачкой уже давно, все что знал перепробовал.

Автор: Alexeis 10.8.2010, 09:35
Flashboy, самый простой способ удвоить высоту и ширину и рисовать линии двойной толщины, после чего уменьшить картинку усредняя цвет по 4м соседним пикселам. Но эта операция произведет сглаживание всей картинки целиком. Если сглаживать нужно отдельные элементы то такой вариант не годиться. 

Автор: Flashboy 10.8.2010, 10:11
Да не годиться!
Допустим линия Pen.Width:=5, нарисовав на Canvas TBitmap(BitMap pf32bit, заготовлен с Альфаканалом) и определив TBitmap.Tranparent:=True; TBitmap.Transparent.Color:=TBitmap.Canvas.Pixels[0,0];, получим изображение  линии с прозрачностью, но контур будет не ровный там она идет под углом.
Как сделать сглаживание контура не потеряв прозрачности изображения, либо как получить прозрачность после сглаживания не потеряв при этом качество цвета вдоль контура?

Автор: AntonN 10.8.2010, 13:53
Alexeis, 
Цитата

 Но эта операция произведет сглаживание всей картинки целиком. 

нет, для исходной картины ничего не изменится, если увеличивать ее "без качества" (я до сих пор не знаю как называется этот метод, вроде "box" в ACDSee), тупо увеличивая пиксели в 2/4 раза, а потом уменьшая мы получим все тот же пиксель, т.к. среднее арифметическое для них будет ведь равно исходному.

Пример суперсемплинга могу предложить тут http://desksoft.ru/index.php?forum=13&th=46

Добавлено через 3 минуты и 1 секунду
Чтобы не потерять прозрачность придется отдельно рисовать маску-альфаканал (в grayscale) и отдельно RGB слой, т.к. GDI обнуляет альфу. Примерно так же, как я выводил шрифты и рисовал прогрессбар в сплеше http://desksoft.ru/index.php?forum=13&th=187

Автор: RomanEEP 10.8.2010, 20:01
Может это пойдет http://www.graphics32.org/wiki/

Автор: Flashboy 10.8.2010, 21:56
Цитата(RomanEEP @ 10.8.2010,  20:01)
Может это пойдет http://www.graphics32.org/wiki/

Даже не представляю как в Graphics32 реализовать Antialiasing c прозрачностью и сохранить это в PNGImage.
Слишком громоздко получиться, вязать к проекту целую библиотеку лишь для того чтобы нарисовать линию.
Я так и не нашел в GR32 Как использовать PolyLine, не нашел ни одного примера.
Может у вас есть какие либо примеры PolyLine в GR32?
Хотелось бы найти алгоритм PolyLine с Anti-Alias и Alpha как в Photoshop, чтобы уровень искажения крайних Пикселей  был не заметен глазу и независим от угла линии.
Результат что-то в этом роде сохраненный в PNGImage:
user posted image

Автор: x128 11.8.2010, 09:57
Еще можно реализлвать на http://www.progdigy.com/ или http://sourceforge.net/projects/tfastdib/, GDI+ на сколько мне известно, умеет работать с PNG, а из FastDIB можно позаимствовать процедуры рисования линий.

Автор: Flashboy 11.8.2010, 13:39
Цитата(x128 @ 11.8.2010,  09:57)
Еще можно реализлвать на http://www.progdigy.com/ или http://sourceforge.net/projects/tfastdib/, GDI+ на сколько мне известно, умеет работать с PNG, а из FastDIB можно позаимствовать процедуры рисования линий.

FastDib, довольно таки сложен пока для моего освоения.
А в GDI+ у меня все получилось отлично , с AntiAliasing все ровно и красиво как в Photoshop, но одно но - я так и не смог получить прозрачность.(Код приведу позже)

Автор: Flashboy 11.8.2010, 15:36
GDI+ Неплохой результат, но получить прозрачность не удается:
Код

Unit Unit2;

Interface

Uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, ExtCtrls, GdiPlus, PngImage;

Type
   TForm2 = Class(TForm)
      Image1: TImage;
      Image2: TImage;
      Procedure FormCreate(Sender: TObject);
   Private
      { Private declarations }
   Public
      { Public declarations }
   End;
Var
   Form2: TForm2;
Procedure AntialiasingLine;
Implementation

{$R *.dfm}

Procedure TForm2.FormCreate(Sender: TObject);
Begin
   AntialiasingLine;
End;

Procedure AntialiasingLine;
Var
   Graphics: IGPGraphics;
   PNG: TPngImage;
   Pen: IGPPen;
   Points: Array[0..9] Of TGPPoint;
Begin
   PNG := TPngImage.CreateBlank(Color_RGB, 8, 790, 383);
   Graphics := TGPGraphics.Create(PNG.Canvas.Handle);
   Graphics.Clear(TGPColor.White);
   Pen := TGPPen.Create(TGPColor.Red, 5);
   Graphics.SmoothingMode := SmoothingModeHighQuality;
   Points[0].Initialize(1, 350);
   Points[1].Initialize(170, 350);
   Points[2].Initialize(200, 80);
   Points[3].Initialize(320, 80);
   Points[4].Initialize(340, 370);
   Points[5].Initialize(460, 370);
   Points[6].Initialize(480, 80);
   Points[7].Initialize(600, 80);
   Points[8].Initialize(620, 350);
   Points[9].Initialize(789, 350);
   Graphics.DrawLines(Pen, Points);
 //PNG.TransparentColor := PNG.Canvas.Pixels[0, 0];
 //PNG.Transparent := True;
   Form2.Image1.Picture.Assign(PNG);

End;
End.


user posted image

Если же раскомментировать 2 строчки:
 
Код

 PNG.TransparentColor := PNG.Canvas.Pixels[0, 0];
 PNG.Transparent := True;

То результат:
user posted image

Автор: AntonN 11.8.2010, 17:18
TransparentColor и альфаканал - разные вещи, зачем ты его постоянно дергаешь?
То, что представлено на последнем скрине совершенно нормальная ситуация. Ты получаешь линию, которая была нарисована на отдельном буфере на белом фоне. Не трудно предположить, что после того как ты попробуешь нарисовать этот буфер где либо будет проглядывать фон. Вывод - рисуй красную линию на буфере закрашенном красным цветом.

Либо копируй часть своей картинки, на которой ведется рисование на буфер GDI+, рисуй линию с АА, и копируй потом буфер обратно на картинку.

Добавлено через 3 минуты и 45 секунд
Я выше тебе дал пару ссылок.
Отстань от PNG, рисуй все промежуточные шаги на Tbitmap с альфаканалом. Загоняй в них свои исходные PNG, после всех рисований в финале перегоняй Tbitmap в PNG. А так ты будешь костыль на костыле вертеть, все равно пнг преобразуется в подобие битмапа, не ведется с ним работа "напрямую".
Разберись с механизмами доступа к каналам пикселя через scanline и простыми алгоритмами блитинга, и ты сам сможешь наваять красивые вещи без костылей и ожидания на форуме.

Добавлено через 5 минут и 49 секунд
И как бы в дополнение. Если имеется что-то типа редактора или "живого" графика, то оптимальней рисовать всю мишуру на одном буфере и выводить его на форму (или в image загонять). У меня есть сомнения что ты используешь для этого несколько контролов - в совокупности с альфой это может потом вылезти боком.

Автор: Flashboy 11.8.2010, 17:59
AntonN, вы просто знаете подход к моему мозгу, несколько ключевых фраз и 10 мин. работы и логических измышлений, и Вуаля - все как я и хотел:
user posted image

Огромное спасибо что в очередной раз подталкиваете на здравую мысль.

P.S. Если кому интересно решение исходник выложу следующим постом.

Автор: Flashboy 11.8.2010, 18:20
Как и обещал:
Код

Unit Unit2;

Interface

Uses
   Windows,  SysUtils, Variants,  Graphics,  Forms,
   ExtCtrls, GdiPlus, PngImage, GraphUtil, Classes, Controls;
Const
   MaxPixelCountA = MaxInt Div SizeOf(TRGBQuad);
Type
   PRGBAArray = ^TRGBAArray;
   TRGBAArray = Array[0..MaxPixelCountA - 1] Of TRGBQuad;
   TForm2 = Class(TForm)
      Image1: TImage;
      Image2: TImage;
      Procedure FormCreate(Sender: TObject);
   Private
      { Private declarations }
   Public
      { Public declarations }
   End;
Var
   Form2: TForm2;
Procedure BuildPNG2BMP(png: TPNGImage; bmp: tbitmap);
Procedure BuildBMP2PNG(bmp: Tbitmap; PNG: TPngImage);
Procedure AntialiasingLine(Image: TImage; Color: TColor);
Implementation

{$R *.dfm}

Procedure TForm2.FormCreate(Sender: TObject);
Begin
   AntialiasingLine(Image1, clRed);
End;

Procedure AntialiasingLine(Image: TImage; Color: TColor);
Var
   Graphics: IGPGraphics;
   PNG: TPngImage;
   Pen: IGPPen;
   AColor: TGPColor;
   Points: Array[0..9] Of TGPPoint;
   BTOut: Tbitmap;
Begin
   BTOut := Tbitmap.Create;
   BTOut.SetSize(790, 383);
   PNG := TPngImage.Create;
   Graphics := TGPGraphics.Create(BTOut.Canvas.Handle);
   AColor := TGPColor.CreateFromColorRef(Color);
   Graphics.Clear(AColor);
   Pen := TGPPen.Create(AColor, 5);
   Graphics.SmoothingMode := SmoothingModeHighQuality;
   Points[0].Initialize(1, 350);
   Points[1].Initialize(170, 350);
   Points[2].Initialize(200, 80);
   Points[3].Initialize(320, 80);
   Points[4].Initialize(340, 370);
   Points[5].Initialize(460, 370);
   Points[6].Initialize(480, 80);
   Points[7].Initialize(600, 80);
   Points[8].Initialize(620, 350);
   Points[9].Initialize(789, 350);
   Graphics.DrawLines(Pen, Points);
   BuildBMP2PNG(BTOut, PNG);
   Image.Picture.Assign(PNG);
   FreeANDNil(BTout);
   FreeANDNil(PNG);
End;

Procedure BuildPNG2BMP(png: TPNGImage; bmp: tbitmap);
Var
   iii, ii: integer;
   PNB: TPngImage;
   fff: PRGBAArray;
   aaa: pByteArray;
Begin
   PNB := TPngImage.Create;
   Try
      PNB.Assign(png);
      pnb.CreateAlpha;
      bmp.Assign(pnb);
      bmp.PixelFormat := pf32bit;
      For ii := 0 To bmp.Height - 1 Do
      Begin
         fff := bmp.ScanLine[ii];
         aaa := pnb.AlphaScanline[ii];
         For iii := 0 To bmp.Width - 1 Do
         Begin
            fff[iii].rgbReserved := aaa[iii];
         End;
      End;
   Finally
      PNB.free;
   End;
End;
//==========================================================

//==========================================================

Procedure BuildBMP2PNG(bmp: Tbitmap; PNG: TPngImage);
Var
   iii, ii: integer;
   PNB: TPngImage;
   fff: PRGBAArray;
   aaa: pByteArray;
Begin
   PNB := TPngImage.Create;
   Try
      PNB.Assign(bmp);
      pnb.CreateAlpha;
      For ii := 0 To bmp.Height - 1 Do
      Begin
         fff := bmp.ScanLine[ii];
         aaa := pnb.AlphaScanline[ii];
         For iii := 0 To bmp.Width - 1 Do
         Begin
            aaa[iii] := fff[iii].rgbReserved;
         End;
      End;
      PNG.Assign(PNB);
   Finally
      PNB.free;
   End;
End;
End.




И кстати никто не знает Как в GDI+ использовать в IGPGraphics.SmoothingMode равным SmoothingModeAntiAlias8x8?
 В исходнике и примерах есть, а при использовании пишет Undeclared identifier: 'SmoothingModeAntiAlias8x8' 

Автор: AntonN 11.8.2010, 19:19
а зачем так много? 4х вполне качественно выглядит

Автор: Flashboy 11.8.2010, 19:34
Цитата(AntonN @ 11.8.2010,  19:19)
а зачем так много? 4х вполне качественно выглядит

Мне ради принципа и ради саморазвития интересно это использовать.
В модуле GDIPlus.pas описаны режимы:
Код

//---------------------------------------------------------------------------
// Smoothing Mode
//---------------------------------------------------------------------------

type
  TGPSmoothingMode = (
    SmoothingModeInvalid     = Ord(QualityModeInvalid),
    SmoothingModeDefault     = Ord(QualityModeDefault),
    SmoothingModeHighSpeed   = Ord(QualityModeLow),
    SmoothingModeHighQuality = Ord(QualityModeHigh),
    SmoothingModeNone,
    SmoothingModeAntiAlias
    {$IF (GDIPVER >= $0110)}
    ,
    SmoothingModeAntiAlias8x4 = Ord(SmoothingModeAntiAlias),
    SmoothingModeAntiAlias8x8
    {$IFEND}
    );


Хотелось бы последний использовать:
Код

    SmoothingModeAntiAlias8x8


 А если нет, то кто знает почему поделитесь пожалуйста!?

Автор: RomanEEP 12.8.2010, 20:31
Закомментарь 2 строчки с фигурными скобками так:
Код

type
  TGPSmoothingMode = (
    SmoothingModeInvalid     = Ord(QualityModeInvalid),
    SmoothingModeDefault     = Ord(QualityModeDefault),
    SmoothingModeHighSpeed   = Ord(QualityModeLow),
    SmoothingModeHighQuality = Ord(QualityModeHigh),
    SmoothingModeNone,
    SmoothingModeAntiAlias
    //{$IF (GDIPVER >= $0110)}
    ,
    SmoothingModeAntiAlias8x4 = Ord(SmoothingModeAntiAlias),
    SmoothingModeAntiAlias8x8
    //{$IFEND}
    );

но чтобы быьб уверенным в работоспособности своего кода на других компах надо видимо в коде делать проверки на версию библиотеки.

Автор: AntonN 12.8.2010, 21:12
а если там ниже еще есть такое условие? smile

Автор: Flashboy 13.8.2010, 00:04
Цитата(RomanEEP @ 12.8.2010,  20:31)
Закомментарь 2 строчки с фигурными скобками так:
Код

type
  TGPSmoothingMode = (
    SmoothingModeInvalid     = Ord(QualityModeInvalid),
    SmoothingModeDefault     = Ord(QualityModeDefault),
    SmoothingModeHighSpeed   = Ord(QualityModeLow),
    SmoothingModeHighQuality = Ord(QualityModeHigh),
    SmoothingModeNone,
    SmoothingModeAntiAlias
    //{$IF (GDIPVER >= $0110)}
    ,
    SmoothingModeAntiAlias8x4 = Ord(SmoothingModeAntiAlias),
    SmoothingModeAntiAlias8x8
    //{$IFEND}
    );

но чтобы быьб уверенным в работоспособности своего кода на других компах надо видимо в коде делать проверки на версию библиотеки.

Уже пробовал так, выдает ошибку:
user posted image

ОС Vista x64 SP2 bild 6002

А может кто-нибудь знает как реализовать прорисовку с подобным качеством - SmoothingModeAntiAlias, но без GDI+, а с чем-нибудь пошустрее?
GDI+ Конечно отличная библиотека для построения графических редакторов, но ее скорость не позволяет делать что либо большее.
С помощью обычного GDI все рисуется достаточно быстро, но как и всегда есть одно но качество графики страдает из-за отсутствия сглаживания и многих других эффектов!

Автор: RomanEEP 13.8.2010, 09:19
Я думаю GDI+ реализована достаточно грамотно и врят ли есть алгоритм который делает тоже самое ощутимо быстрее.
Другой выход - использовать видеокарту через интерфейсы OpenGL или DirectX

Автор: Flashboy 13.8.2010, 13:35
Цитата(RomanEEP @ 13.8.2010,  09:19)
Я думаю GDI+ реализована достаточно грамотно и врят ли есть алгоритм который делает тоже самое ощутимо быстрее.
Другой выход - использовать видеокарту через интерфейсы OpenGL или DirectX

Согласен, более грамотного сглаживания ни в одном компоненте пока еще не видел.
Но я надеюсь что кто-нибудь, реализовал такие превращения на ASM'е в какую нибудь грамотную библиотечку.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)