Načítání PNG pro pluginy

Podpora vývojářů nových pluginů, oznámení o nových pluginech nezávislých autorů a diskuse o nich.
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Načítání PNG pro pluginy

Post by zarevak »

Dobrý den,
tento příspěvek je žádostí o vylepšení pro pluginy: Salamander umí načítat PNG, ale jenom z resource a jen pro ImageList. Je možné, aby uměl Salamander načíst ImageList i z PNG v paměti? (předám ukazatel a velikost) - tím by se vyřešilo načítání ze všech možných zdrojů.

Je dále možné, aby Salamander umožnil načíst pluginům jakékoliv PNG a předal zpět jako Bitmapu? (třeba ve stylu SetDIBits(): BITMAPINFO + bitmapa)
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Post by Jan Rysavy »

Možné to je, ale podpora PNG není kompletní, viz použitá knihovna PNGLite: http://www.karlings.com/~danne/pnglite/
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Post by Jan Rysavy »

Abych byl více konkrétní ohledně nepodpořených formátů:

Code: Select all

	if(png->color_type == PNG_INDEXED && png->depth != 8)
		return PNG_NOT_SUPPORTED;

	if(png->depth != 8 && png->depth != 16)
		return PNG_NOT_SUPPORTED;

	if(png->interlace_method)
		return PNG_NOT_SUPPORTED;
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Post by zarevak »

Koukám, že nejsou podporované paletové a prokládané obrázky. Prokládané obrázky snad nikdo nepoužívá. Palety využívat nepotřebuji.

Vzhledem k tomu, že budu mít kontrolu na zdrojovými PNG souboury, tak tato omezení nemám problém dodržet ;)

Dokonce zatím ani nepotřebuji obecou podporu PNG, ale jenom načtení imagelistu z paměti místo z resource.

Má logika je, že CGUIIconListAbstract pracuje s handly (HICON, HIMAGELIST), které bez problému získám buď z resource nebo externího souboru, ale PNG lze načíst jenom z resource.

EDIT: aha, takže 8-bit paletu jste doplnili ;)
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Post by Jan Rysavy »

zarevak wrote:EDIT: aha, takže 8-bit paletu jste doplnili ;)
Tu jsem dopsal a poslal patch na autora knihovny, ale nezahrnul to zatím do balíku.
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Re: Načítání PNG pro pluginy

Post by Jan Rysavy »

zarevak wrote:Dobrý den,
tento příspěvek je žádostí o vylepšení pro pluginy: Salamander umí načítat PNG, ale jenom z resource a jen pro ImageList. Je možné, aby uměl Salamander načíst ImageList i z PNG v paměti? (předám ukazatel a velikost) - tím by se vyřešilo načítání ze všech možných zdrojů.

Je dále možné, aby Salamander umožnil načíst pluginům jakékoliv PNG a předal zpět jako Bitmapu? (třeba ve stylu SetDIBits(): BITMAPINFO + bitmapa)
Oboje bude zahrnuto v příštím buildu Salamandera. Předpokládám využití pro DiskMap plugin, tak jsem žádost odbavil prioritně.
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Re: Načítání PNG pro pluginy

Post by Jan Rysavy »

zarevak wrote:Je dále možné, aby Salamander umožnil načíst pluginům jakékoliv PNG a předal zpět jako Bitmapu? (třeba ve stylu SetDIBits(): BITMAPINFO + bitmapa)
Jedna věc k zamyšlení: nově zavedené metody neřeší případnou alpha transparenci PNG a alpha kanál se při vytváření HBITMAP (DIB) zahodí. Bylo by možné vracet bitmapu s alpha kanálem (minimálně na W2K a dál), ale pod W9x nám vznikne problém.

Momentálně je tedy alpha transparence (včetně vykreslení) podpořena pouze při načítání PNG do CGUIIconListAbstract, který jsme implementovali kompletně sami a běží na všech podporovaných Windows.

Jakmile v Salamanderu 3.0 zahodíme zpětnou kompatibilitu s W9x, bylo by reálné podpořit alpha transparenici také pro bitmapy načtené z PNG.
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Re: Načítání PNG pro pluginy

Post by zarevak »

Děkuji za přidání podpory čtení PNG do Salamanderu ;) Škoda, že pro DiskMapu využití (zatím) nemám :oops:

Napadá mne, že pokud by se při načtení předala barva pozadí, tak může Salamander přednakreslit PNG na toto pozadí. Pro výstup na plochu okna toto plně dostačuje a změna barvy nastane jen v případě změny barev Windows uživatelem. (Pak bych ale potřeboval dvě kopie - normální a "vybranou") Nevím, zda si to zaslouží další čas - své pluginy píšu pro Windows 2000 a vyšší. (DiskMapa je jediná testována i na Win95)

Jiný nápad: nebylo by možné vracet PNG s plným Alpha kanálem jako sadu bitů (32-bit BMP)? (To bylo i původní myšlenkou - BITMAPINFO pro informace a bitmapa jako sada bitů - využitelné v SetDIBits nebo pro ruční zpracování) Plugin by už měl na starosti zajistit, že by si Alpha bity na Win95 ořízl a vytvořil tak 24-bit bitmapu bez Alpha? (Vycházím z toho, že API AlphaBlend je dostupná od Windows 98 (v Msimg32.dll) a Windows 2000)
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Re: Načítání PNG pro pluginy

Post by Jan Rysavy »

zarevak wrote:Děkuji za přidání podpory čtení PNG do Salamanderu ;) Škoda, že pro DiskMapu využití (zatím) nemám :oops:
Vzhled bublin se generuje programově? Nějak jsem si pamatoval, že plugin měl mít možnost změnit look?

Nechce se mi do problematiky investovat další čas, dnešní den je až až. Takže jsem do parametrů funkcí přidal bitové pole flags, kterým bude možné řídit alpha transparenci (zatím nepodpořeno).
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Re: Načítání PNG pro pluginy

Post by zarevak »

Mockrát děkuji!

Omlouvám se za nejasnosti okolo využití PNG. Mám dobrou zprávu: objevil jsem na svém TODO DiskMapy jednu bláznivou položku, pro kterou by se PNG soubory hodily, a navíc jsem právě dostal nápad na jejich další využití ;)
PNG také využiju i v Explorer Thumbnails pluginu pro zobrazení video overlaye.


Pro polštářky používám svůj vlastní formát "ZTC" - Zarevak's Treemap Cushion - obsahující dva kanály Gray a Alpha komprimované upraveným RLE alogoritmem. Zkusil jsem některé své návrhy polštářků uložit jako PNG; při automatické kompresi bych ušetřil cca 25-45% dat. Jen bych musel vymyslet, jak přidat pár doplňujících informací (velikosti okrajů). PNG dovoluje použít doplňující tagy, ale jejich obecné načítání z PNG po vás programovat nechci...

Poznámka: PNGSlim z polštářků v 32bit PNG vyrobí ještě menší Gray+Alpha PNG obrázky. Bohužel Alpha složka těchto PNG není podporována PictView pluginem :( (a asi ani PngLite knihovnou)

Velikosti skleněných polštářků - "bublin":
- ZTC - obě komprese: 13,1kB
- PNG 32bit RGBA z .Net Framework: 8,64kB ! 65%
- PNG Gray+Alpha z PNGSlim: 1,94kB !!! 15%

Velikost starých polštářků:
- ZTC - ruční komprese: 20,3kB
- ZTC - automatická komprese: 215kB
- PNG 32bit RGBA z .Net Framework: 142kB 700% / 66%
- PNG Gray+Alpha z PNGSlim: 12,0kB ! 60%
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Re: Načítání PNG pro pluginy

Post by Jan Rysavy »

Na nějaký problém s Gray+Alpha PNG v PictView jsem myslím narazil. PNGLite jsem patchoval, aby formát podporovala, takže není problém ho použít. Každopádně by tahle drobnost asi neměla být překážkou v nasazení Gray+Alpha?

Můžeš sem prosím vložit ukázku v PV funkčního / nefunkčního obrázku? Jakým způsobem jsi ten Gray+Alpha vytvořil? (Nějak se mi to už vytratilo z hlavy.)

Nějaké tagy navíc načítáme již nyní, viz příloha pro srovnání naší verze a originální: "tRNS" -> png_read_trns() a "PLTE" -> png_read_plte().
pnglite.zip
(14.11 KiB) Downloaded 499 times
Pokud by bylo šikovné přidat čtení nějakého custom tagu, není to problém, stačí se dohodnout.

Zatím jsem iface pro čtení PNG navrhnul takto jednoduše:

Code: Select all

#define SALPNG_CREATEDDB 0x00000001   // misto DIB bitmapy se vytvori DDB, operace bude pomaleji, pouzivat pouze pro zpetnou kompatibilitu s W95
                                      // viz problem http://support.microsoft.com/kb/149585 pri kopirovani DIB to 1-bitove bitmapy

class CSalamanderPNGAbstract
{
  public:
    // vytvori bitmapu na zaklade PNG resource; 'hInstance' a 'lpBitmapName' specifikuji resource,
    // 'flags' obsahuje 0 nebo bity z rodiny SALPNG_xxx
    // v pripade uspechu vraci handle bitmapy, jinak NULL; plugin je zodpovedny za destrukci bitmapy
    // volanim DeleteObject()
    // poznamka: PNG je vhodne komprimovat pomoci PNGSlim, viz http://forum.altap.cz/viewtopic.php?f=15&t=3278
    virtual HBITMAP WINAPI LoadPNGBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName, DWORD flags) = 0;

    // vytvori bitmapu na zaklade PNG podaneho v pameti; 'rawPNG' je ukazatel na pamet obsahujici PNG
    // (napriklad nactene ze souboru) a 'rawPNGSize' urcuje velikost pameti obsazene PNG v bajtech,
    // 'flags' obsahuje 0 nebo bity z rodiny SALPNG_xxx
    // v pripade uspechu vraci handle bitmapy, jinak NULL; plugin je zodpovedny za destrukci bitmapy
    // volanim DeleteObject()
    // poznamka: PNG je vhodne komprimovat pomoci PNGSlim, viz http://forum.altap.cz/viewtopic.php?f=15&t=3278
    virtual HBITMAP WINAPI LoadRawPNGBitmap(const void *rawPNG, DWORD rawPNGSize, DWORD flags) = 0;
};

User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Re: Načítání PNG pro pluginy

Post by zarevak »

Protože jsou polštářky zbytečně velké, vygeneroval jsem 32bit testovací PNG a pak projel PNGSlimem, který ho převedl na Gray + Alpha, jehož Alpha kanál v PictView nefunguje.
32-bit RGBA verze
32-bit RGBA verze
test_rgba.png (33.7 KiB) Viewed 15957 times
Gray + Alpha verze
Gray + Alpha verze
test_GrayA.png (4.68 KiB) Viewed 15956 times
Koukám, že se vrací HBITMAP místo čisté sady bitů. Pro potřeby DiskMapy bych to musel převádět zpět na zdrojové pole bajtů, abych mohl polštářky obarvovat a upravovat jejich velikost. V Explorer Thumbnails pluginu mi zase vyhovuje HBITMAP.

S custom chunky je potíž. Může jich být několik, mohou se opakovat a není znám jejich formát. Navíc myslím, že pro potřeby pluginů je toto zbytečné (Maximálně, že by někdo četl doplňující informace o zdroji tEXt, tIME, ... nebo o barevném profilu gAMA, cHRM, iCCP, ...). V pluginu však není problém si tyto chunky vycucat z PNG ručně - každý chunk obsahuje svoji velikost, takže můžu všechny kromě těch pro mne zajímavých velmi rychle přeskočit.

Tvůj nápad použít PNG pro DiskMapí polštářky se mi líbí více a více ;) Pro základní verzi polštářku postačí jakýkoliv PNG. Po doplnění tEXt a ztCD PNG získá možnosti současného formátu. (ztCD není konečný název. Nevím, zda teď navrhnu jeden velký rozšiřitelný chunk nebo sadu malých specializovaných, které později budou přibývat)

Zjišťuji, že převod HBITMAP do 32-bit dat zas tak problematické není (ošetření chyb vynecháno; kód netestován):
Nepoužívat, kód nefunguje! - GetBitmapDimensionEx() nevrací velikost v pixelech

Code: Select all

HBITMAP hbmp = LoadRawPNGBitmap(rawPNG, rawPNGsize, 0);
SIZE size;
GetBitmapDimensionEx(hbmp, &size);
BITMAPINFO bmi = { 0 };
bmi.bmih.biSize = sizeof(bmi.bmih);
bmi.bmih.biWidth = size.cx;
bmi.bmih.biHeight = size.cy;
bmi.bmih.biPlanes = 1;
bmi.bmih.biBitCount = 32;
bmi.bmih.biCompression = BI_RGB;
BYTE *rgbPixels = new BYTE[size.cx * size.cy * 4];
int scanlines = GetDIBits(hdc, hbmp, 0, bmi.bmih.biHeight, rgbPixels, &bmi, DIB_RGB_COLORS);
DeleteObject(hbmp);
Last edited by zarevak on 19 Apr 2009, 00:11, edited 1 time in total.
Jan Rysavy
ALTAP Staff
ALTAP Staff
Posts: 5231
Joined: 08 Dec 2005, 06:34
Location: Novy Bor, Czech Republic
Contact:

Re: Načítání PNG pro pluginy

Post by Jan Rysavy »

Načítání a následné vykreslené Gray+Alpha PNG pomocí AlphaBlend v Demoplugin vieweru šlape:
alpha.png
alpha.png (26.33 KiB) Viewed 15915 times
Je tu jeden drobný zádrhel. Aby funcke AlphaBlend správně vykreslila bitmapu s per-pixel alpha transparencí, je potřeba přednásobit RGB složky, viz BLENDFUNCTION Structure, AlphaFormat == AC_SRC_ALPHA:
This flag is set when the bitmap has an Alpha channel (that is, per-pixel alpha). Note that the APIs use premultiplied alpha, which means that the red, green and blue channel values in the bitmap must be premultiplied with the alpha channel value. For example, if the alpha channel value is x, the red, green and blue channels must be multiplied by x and divided by 0xff prior to the call.
Pokud data budeme chtít dále zpracovávat (barevně tónovat, případně kreslit pomocí jiných metod), hodilo by se nechat RGB složky zachovány v rozsahu 0 až 255. Asi bych pro potlačení přednásobení zavedl další flag. Samozřejmě pak nebud možné na vrácený handle přímo zavolat AlphaBlend API.

S tagy souhlas. Za zamyšlení by stála i možnost neukládat data do custom PNG tagů, ale uložit je zkrátka externě.
Pro přímý přístup k datům bych vedle handle DIB bitmapy vrátil ještě parametr ppvBits z CreateDIBSection.
Tímto je to asi uzavřené a PNG s alpha transparencí můžeme začít v pluginech vesele používat. Minimálně od W2K dále. Díky za postrčení :)
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Re: Načítání PNG pro pluginy

Post by zarevak »

Na nutnost přednásobení jsem úplně zapomněl - AlphaBlend funkci jsem naposledy používal někdy v roce 2003 v PackView MDI. :oops: I DiskMapa si bitmapu přednásobuje, ale pracuje s Gray+Alpha verzí. Pokud dostane 32-bit bitmapu, bude si ji muset nejdříve převést.

Pro načítání se více hodí oddělená NEpřednásobená Alpha, protože z ní lze vyrobit přednásobenou bez problému. Opačně data rekonstruovat již nejde (pro nízké Alpha se ztrácí přesnost a pro Alpha 0 nezískám nic) :( Flag na přednásobení se pro líné programátory však bude hodit ;)

ppvBits určitě přidej - nikde se nic neomezí a získá se 100% kontrola nad daty 8)

Jen se chci zeptat: jaké formáty bitmap metoda vací? (bude potřeba vědět pro práci s ppvBits)
- Převede všechny na 32-bit ARGB/BGRA/...?
- Jak dopadne s 24-bit PNG? Alpha je v takovém případě zbytečná...
- Jak dopadne se zmíněným Grey + Alpha? Tento formát GDI ani .Net Framework nezná :( (to znamená, že je ani neumím jednoduše vytvořit)
- Jak dopadne s indexovanými obrázky s paletou? Zachová se paleta a jejich indexovanost? Paleta by byla užitečnější než RGBA verze.
- Jak dopadne 8-bit Grey PNG? Vrátí se jako 24/32-bit obárzek nebo jako indexovaný obrázek s černobílou paletou? Paleta nebo jenom jednobajtové odstíny šedi by byly užitečnější.
- Je podporován tRNS chunk? Může obsahovat průhlednou barvu (Grey/24bit) nebo Alpha hodnoty palety... :?
- Jak jsou podporovány 16/48/64-bit verze PNG? Třeba tRNS chunk je potřeba porovnávat na celé 16-bit šířce, než dojde k oříznutí na 8-bit. (Aby průhledná šeď 0x0001 nezprůhlednila i šeď 0x0002)
(Poslední dva body považuji za zbytečnou zvrhlost - teda snad až na jednobarevnou průhlednost podobnou z GIFu. Jen chci, aby chování v těchto situacích bylo popsáno :))

K DiskMapě:
- Polštářek obsahuje: hlavičku (velikost), Grey bitmapu, Alpha bitmapu, šířku okraje (okraje se neroztahuje), autora a název. Uvažuji ještě o různých možnostech roztahování a tapetování.
- PNG umožňuje uložit: hlavičku (velikost), Grey bitmapu, Alpha bitmapu, autora a název. Informace o okrajích a způsobu roztahování je třeba doplnit odjinud.
- Možnosti PNG (uvažuji jen jednosouborová řešení):
  1. Uložit doplňující informace do privátního chunku a uložit jako PNG
    Výhody: polštářek lze prohlížet v jiných programech; jakékoliv PNG je polštářkem.
    Nevýhody: Editace privátní data ztratí; potřeba v DiskMapě ošetřit nečernobílé polštářky
  2. Uložit doplňující informace do privátního chunku a uložit jako PNG, ale s jinou příponou
    Výhody: polštářek lze prohlížek v rozumných programech, které zjištují typ souboru z hlavičky; jiná přípona naznačuje speciální formát a bez změny přípony nelze v editorech uložit
    Nevýhody: Nejasnost ohledně formátu polštářku pro běžného uživatele; potřeba v DiskMapě ošetřit nečernobílé polštářky
  3. Uložit PNG do vlastního kontejner formátu obsahujícího i doplňující informace
    Výhody: Kontrola nad tvorbou polštářku; Můžu předpokládat, že všechny polštářky již jsou černobílé
    Nevýhody: Pro tvorbu polštářků potřeba vytvořit speciální software; Polštářky si užitel nemůže jednoduše prohlédnout
  4. Uložit PNG do ZIPu s druhým souborem obsahující doplňující informace; Speciální přípona
    Výhody: Zip kontejner je současným standardem pro vícesouborová řešení
    Nevýhody: Nelze jednoduše vytvořit uživatelem; Potřeba kód pro načítání ZIP archivů v DiskMapě; Potřeba ošetřit uživatelem pozměněné ZIP archivy (tedy i ne černobílé obrázky)
  5. Jiný nápad?
Nejvíce jsem pro bod B. Oproti současnému proprietárnímu formátu získám lepší kompresi a možnost jednoduchého náhledu na polštářek. Jiná přípona zase zachová možnost přiřadit k typu souboru otevření v DiskMapě a uživatelům naznačí specializovaný formát.
User avatar
zarevak
Plugin Developer
Plugin Developer
Posts: 789
Joined: 04 Feb 2006, 16:49
Location: Prague, Czech Republic

Re: Načítání PNG pro pluginy

Post by zarevak »

Ještě pár poznámek k bitmapám a PNG:
1) Můj kód na získání bitmapy je špatně! GetBitmapDimensionEx() nevrací velikost v pixelech, ale v setinách milimetru, která navíc musí být předem nastavena pomocí SetBitmapDimensionEx()

2) Pro získání informací o bitmapě (velikost, formát) je možno využít buď GetDIBits() s parametrem lpvBits = NULL nebo GetObject()

3) Z minulého příspěvku nebylo moc jasné, že načtené bitmapy by byly vhodné ve 3 formátech:
* 32-bit pro jakékoliv PNG s jakoukoliv průhledností (buď Alpha kanál nebo tRNS chunk)
* 24-bit pro 24-bit a 48-bit PNG. Ostatní nakraslené oproti barvě pozadí (viz bod 6)
* indexované obrázky s paletou pro indexované PNG a greyscale PNG (ty by obsahovaly paletu šedi)

4) Mohl by existovat flag pro převod všech PNG do 24/32-bit bitmapy. Tím by se zjednodušilo zpracování na straně pluginu.

5) (Nápad) Šedé obrázku pokud budou vráceny jako indexovaná bitmapa s paletou šedi by nějakým způsobem mohly informaci o své šedosti předat zpět pluginu, aby nemusela být kontrolována šedost palety.

6) (Dodatek) Vzhledem k jednoduchosti získání ukazatele na bitmapu pomocí GetObject() beru zpět doporučení doplnění ppvBits. Naopak by se hodil parametr barvy pozadí, pokud chci 24-bit bitmapu z 32-bit PNG třeba na starých systémech (Win95).
Post Reply