Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.221.13.173] |
|
Сообщ.
#1
,
|
|
|
Необходимо, при помощи GDI+, вывести на десктоп картинку Луны и наложить на нее тень. С выводом картинки проблем нет. Код ниже, за исключением нескольких строк для таскания мышкой и popup menu.
Не получается вывести тень. Алгоритм рисования тени позаимствован на просторах Инета из старой проги. Вкратце он следующий: - В зависимости от фазы Луны, левая или правая половинка диска темная (рисуем сектор эллипса). - Уточняем фазу и рисуем посередине эллипс. Если эллипс темный - тень увеличивется, белый - тень становится меньше. Используя TGPGraphics.FillEllipse (FillPie) и полупрозрачную черную кисть тень отлично рисуется. Но только если она в половину или более диска Луны. Попытка использовать полупрозрачную белую кисть поверх черной привела к закономерному извращению. Как назначить белый цвет прозрачным не нашел. Я так понимаю, что при наличии альфа канала эта возможность не нужна. Можно порисовать в обычном TBitmap по описанному алгоритму. Назначить нужный цвет прозрачным. И даже, видал на форумах, сделать полупрозрачным. Но как потом натянуть его на картинку средствами GDI+ сообразить не могу. Что посоветуете? procedure TMoonForm.FormCreate(Sender: TObject); Var screendc : HDC; img : TGPBitmap;//GDI+ hbmp : HBITMAP; //Прозрачная картинка backdc : HDC; //Контекст для прозрачной картинки pt1, pt2 : TPoint; sz : TSize; BF : TBlendFunction;//Прозрачность Луны AlphaShadow : Byte; begin //Если есть ini, то читаем из него if FileExists(ExtractFilePath(Application.ExeName)+'MoonCalendar.ini') then begin MoonForm.Left:=Inif.ReadInteger('FormPlace','Left'); MoonForm.Top :=Inif.ReadInteger('FormPlace','Top'); BF.SourceConstantAlpha:=Inif.ReadInteger('View','AlphaMoon'); AlphaShadow:=Inif.ReadInteger('View','AlphaShadow'); end; //Если прозрачность 0 или больше чем байт, то ставим макс.значение 255 if (BF.SourceConstantAlpha=0) OR (BF.SourceConstantAlpha>255) then BF.SourceConstantAlpha:=255; //Если прозрачность 0 или больше чем байт, то ставим макс.значение 255 if (AlphaShadow=0) OR (AlphaShadow>255) then AlphaShadow:=255; Application.HintHidePause:=10000;//Время показа подсказки 10 сек // Убираем рамку окна. Иначе ничего не выйдет. Self.BorderStyle := bsNone; // Делаем окно многослойным if SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED) = 0 then ShowMessage(SysErrorMessage(GetLastError)); // Загружаем 32-битный PNG с альфа каналом и получаем его HBITMAP img := TGPBitmap.Create('moon3.png',True); //Можно порисовать используя TGPGraphics // GPgrahpMoon:=TGPGraphics.Create(img); //HBITMAP with img do begin GetHBITMAP(0,hbmp); Width := GetWidth; Height := GetHeight; Free; end; // Получаем контекст экрана screendc := GetDC(0); // Создаем контекст, совместимый с экраном backdc := CreateCompatibleDC(screendc); // Загружаем в него картинку SelectObject(backdc, hbmp); // Вызываем UpdateLayeredWindow pt1 := Point(Left, Top); pt2 := Point(0,0); sz.cx := Width; sz.cy := Height; with bf do begin BlendOp := AC_SRC_OVER; BlendFlags := 0; // SourceConstantAlpha := $FF; // Можно ставить общую прозрачность AlphaFormat := AC_SRC_ALPHA; end; UpdateLayeredWindow(Handle,screendc,@pt1,@sz,backdc,@pt2,0,@bf,ULW_ALPHA); // Освобождаем контекст экрана ReleaseDC(0,screendc); end; |
Сообщ.
#2
,
|
|
|
Пока решил поступить следующим образом:
1. Рисую на TGPBitmap с альфа каналом непрозрачными кистями. 2. Обхожу каждый пиксел и убиваю белый цвет, а черный делаю полупрозрачным. 3. Натягиваю bmp на картинку Луны. bmpShadow:=TGPBitmap.Create(128,128,PixelFormat32bppARGB); gp:=TGPGraphics.Create(bmpShadow); WhiteColor:=MakeColor(255,255,255,255); BlackColor:=MakeColor(255,0,0,0); BlackBrush:=TGPSolidBrush.Create(BlackColor); WhiteBrush:=TGPSolidBrush.Create(WhiteColor); //Рисуем gp.FillEllipse и т.д. //Обесцвечиваем белые пиксели, //а черные делаем полупрозрачными ClearColor:=MakeColor(0,0,0,0); AlphaBlackColor:=MakeColor(96,0,0,0); For Y:=0 to bmpShadow.GetHeight-1 do For X:=0 to bmpShadow.GetWidth-1 do begin bmpShadow.GetPixel(X,Y,bmpColor); if bmpColor=WhiteColor then bmpShadow.SetPixel(X,Y,ClearColor) else if bmpColor=BlackColor then bmpShadow.SetPixel(X,Y,AlphaBlackColor); end; //Загружаем 32-битный PNG с альфа каналом (картинка Луны) pngMoon:=TGPBitmap.Create('moon3.png',True); graphShadow:=TGPGraphics.Create(pngMoon); graphShadow.DrawImage(bmpShadow,0,0,128,128);//Натягиваем тень на картинку Но этот метод мне кажется не очень оптимальным, все же не scanline. А еще захотелось размыть границу терминатора, тоже должно замедлять. //Код взят с http://www.kansoftware.ru/?tid=363 Но вообще, попадается повсеместно. //Размытие изображения. Прозрачности каждой точки присваивается // среднее значение цветов соседних точек. procedure Blur(var TransGPBitmap:TGPBitmap); const width = 128; height = 128; d = 2; var x, y: integer; i, j: integer; c: integer; Pix: array [0..width-1, 0..height-1] of byte; rColor:TGPColor; begin randomize; with TransGPBitmap do begin for y := 0 to height - 1 do for x := 0 to width - 1 do begin GetPixel(x,y,rColor); //Посмотреть почему ошибка на rColor.GetAlpha; Pix[x,y] := BYTE(rColor shr AlphaShift); end; for y := d to height - d - 1 do for x := d to width - d - 1 do begin c := 0; for i := -d to d do for j := -d to d do c := c + Pix[x+i,y+j]; c := round(c / sqr(2 * d + 1)); SetPixel(x,y,MakeColor(c,BYTE(rColor shr RedShift),BYTE(rColor shr GreenShift),BYTE(rColor shr BlueShift))); end; end; end; В общем вопрос остался прежним. Может стоит изучить TGPImageAttributes.SetRemapTable(2,@ColorMap)? Сходу применить не получилось, есть работающий пример? |
Сообщ.
#3
,
|
|
|
Получилось вроде того
http://my-files.ru/dczr3p Не знаю, что за файлообменник, но вроде ничего не просит за скачивание. P.S. Прога, после закрытия создает ini. Так что не удивляйтесь появлению левого файла. |
Сообщ.
#4
,
|
|
|
Э, а где фулл сорс коде? зачем мне этот эгзе ?
|