[C#] Converteren 8bit png naar transparante versie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb een aantal png bestanden in verschillend formaat:
Format8bppIndexed
Format32bppArgb

De 8Bit plaatjes hebben een witte achtergrond en de andere een zwarte.
Op de plaatjes staan maar een paar gekleurde lijnen.
Ik probeer van deze plaatjes transparante plaatjes te maken, maar dat lukt niet zo goed.
Ik ben al een poosje aan het zoeken en heb al veel voorbeeldcode uitgeprobeerd, maar zonder succes.

Hier is mijn laatste creatie:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    private static void MakeTransparent(string inputFileName, string outputFileName)
    {
        Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
        Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format16bppArgb1555);
        converted.MakeTransparent(converted.GetPixel(0, 0));
        using (Graphics g = Graphics.FromImage(converted))
        {
            // Prevent DPI conversion
            g.PageUnit = GraphicsUnit.Pixel;
            // Draw the image
            g.DrawImageUnscaled(converted, 0, 0);
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        }
        converted.Save(outputFileName, ImageFormat.Png);
        converted.Dispose();
        bmpIn.Dispose();
    }


Het nieuwe bestand wordt wel fors groter in bestandgrootte, tot wel een factor 10, maar geen transparantie.

Als ik het origineel in IrFanView laat en vervolgens opsla en de transparante kleur opgeef, gaat het wel goed. Dus mijn png is wel OK, maar mijn code niet ;)

Iemand een idee?

Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Heb er niet zoveel ervaring mee dus m'n post zal wel wild uit de richting zijn. Maar is je linker-boven pixel ook wel echt exact gelijk aan alle andere "witte" pixels? Een verschil in ongeveer 5 tot 10 in RGB waarde zul je zelf niet kunnen zien, het zal nog steeds puur wit lijken, maar de pc zal die pixels toch niet transparent maken omdat ze niet exact wit zijn.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 15-09 21:49

CodeIT

Code IT

Zo even snel bekeken, kopieer je nooit de image van bmpIn naar converted.
Ook maak je een graphics object van je converted afbeelding waar je vervolgens dezelfde image op tekent.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@CodeIT: Doet Graphics.FromImage(converted) het kopieren dan niet?
Dat had ik nl. wel begrepen.
Hoe moat ik het anders doen?

Edit: Ik zie het al het moet Graphics.FromImage(BmpIn) zijn.
Dat maakt overigens voor het resultaat niets uit ;(

[ Voor 31% gewijzigd door Verwijderd op 20-05-2010 16:25 ]


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Volgens mij moet het wel gewoon Graphics.FromImage(converted) zijn. Je wilt toch een graphics object van het nieuwe, lege, 'converted' bitmap object, waar je daarna op gaat tekenen? Anders maak je een graphics object van de originele bitmap aan, dus dan ga je op je originele bitmap tekenen.

Ik denk dat je MakeTransparent pas moet aanroepen nadat je de bmpIn op converted hebt getekend (dus na regel 11), aangezien je ook de linker-boven pixel kleur neemt als transparent kleur. Voordat je getekend hebt is die pixel natuurlijk gewoon leeg (is dat dan null of Color.Transparent? weet niet), maar in ieder geval niet de kleur die de 'bmpIn' bitmap op dat punt heeft.

[ Voor 8% gewijzigd door NickThissen op 20-05-2010 16:33 ]

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 15-09 21:49

CodeIT

Code IT

Verwijderd schreef op donderdag 20 mei 2010 @ 16:23:
@CodeIT: Doet Graphics.FromImage(converted) het kopieren dan niet?
Dat had ik nl. wel begrepen.
Hoe moat ik het anders doen?

Edit: Ik zie het al het moet Graphics.FromImage(BmpIn) zijn.
Dat maakt overigens voor het resultaat niets uit ;(
De graphics kun je van converted maken, maar dan moet je er wel bmpin op tekenen. Hierna pas de aanroep naar MakeTransparant.

Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
CodeIT schreef op donderdag 20 mei 2010 @ 16:35:
[...]

De graphics kun je van converted maken, maar dan moet je er wel bmpin op tekenen. Hierna pas de aanroep naar MakeTransparant.
Dat had ik nog gemist inderdaad. pmeems: je moet natuurlijk wel 'bmpIn' gebruiken op regel 11, anders ga je een lege bitmap op een lege bitmap tekenen :p

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 15-09 21:49

CodeIT

Code IT

Pas trouwens wel op bij het gebruik van Format16bppArgb1555. (zie: http://paulmaddox.net/200...ofmemoryexception-on.html).
Als je de regel "converted.MakeTransparent(converted.GetPixel(0, 0));" verplaatst onder je using blok (wat nodig is voor de goede werking), krijg je waarschijnlijk een OutOfMemoryException.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Inderdaad kreeg ik een OutOfMemoryException en ook een lege bitmap overigens ;)
Ik heb de code weer aangepast en krijg nu weer de juiste bitmap, alleen nog steeds niet transparent:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    private static void MakeTransparent(string inputFileName, string outputFileName)
    {
        Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
        Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format32bppArgb);
        //bmpIn.MakeTransparent(Color.Black);
        using (Graphics g = Graphics.FromImage(converted))
        {
            // Prevent DPI conversion
            g.PageUnit = GraphicsUnit.Pixel;
            // Draw the image
            g.DrawImageUnscaled(bmpIn, 0, 0);
            
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        }
        converted.MakeTransparent(Color.Black);
        converted.Save(outputFileName, ImageFormat.Png);
        converted.Dispose();
        bmpIn.Dispose();
    }


Iemand nog een idee?

Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 15-09 21:49

CodeIT

Code IT

Heb het zelf even getest en deze code werkt bij mij:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static void MakeTransparent(string inputFileName, string outputFileName)
        {
            Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
            Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(converted))
            {
                // Prevent DPI conversion 
                g.PageUnit = GraphicsUnit.Pixel;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                // Draw the image 
                g.DrawImageUnscaled(bmpIn, 0, 0);
            }
            converted.MakeTransparent(converted.GetPixel(0, 0));
            converted.Save(outputFileName, ImageFormat.Png);
            converted.Dispose();
            bmpIn.Dispose();
        }

Acties:
  • 0 Henk 'm!

  • Feanathiel
  • Registratie: Juni 2007
  • Niet online

Feanathiel

Cup<Coffee>

Op een of andere manier krijg ikzelf allemaal problemen met de voorbeelden die jullie nu geven; het plaatje wordt klein geplaatst in de linkerbovenhoek.

Waar je voor kunt kiezen is om een ColorKey te definiëren bij het kopiëren. Wat deze colorkey doet, is aangeven welke (range van) kleuren als transparant moeten worden gezien (zo kunnen ook twee afbeeldingen worden gemerged met twee verschillende keys). Daarna hoef je niet meer aan te geven welke kleur transparant is. Een mogelijk voorbeeld, met (minimale) commentaar in de code:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
        private static void MakeTransparent(string inputFileName, string outputFileName)
        {
            Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
            Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format32bppArgb);

            using (Graphics g = Graphics.FromImage(converted))
            {
                g.CompositingQuality = CompositingQuality.HighQuality;

                /* Overbodig? We zijn niet aan het resizen */
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;

                // Grootte
                Rectangle rect = new Rectangle(0, 0, bmpIn.Width, bmpIn.Height);

                // Kleur
                Color color = bmpIn.GetPixel(0, 0);

                // Keymap
                ImageAttributes attrs = new ImageAttributes();
                attrs.SetColorKey(color, color, ColorAdjustType.Bitmap);

                // Uiteindelijke copy
                g.DrawImage(bmpIn, rect, 0, 0, bmpIn.Width, bmpIn.Height, GraphicsUnit.Pixel, attrs);
            }

            converted.Save(outputFileName, ImageFormat.Png);
            converted.Dispose();
            bmpIn.Dispose();
        }

[ Voor 0% gewijzigd door Feanathiel op 21-05-2010 09:17 . Reden: Paragraaf gesplitst ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Het lukt me nog steeds niet.
Ik begin me af te vragen of er misschien toch iets mis is met het plaatje.

Als ik de png open in FireFox, MS PicturViewer of Photoshop dan wordt het origineel wel met een transparante achtergrond getoond.
Maar open ik het plaatje met IrfanView of MapWindow GIS dan heeft die een zwarte achtergrond
http://svn.mapwindow.org/...ResampleImage/Sample3.png

Dit plaatje gaat wel goed en wordt in alle programma's goed getoond:
http://svn.mapwindow.org/...ResampleImage/Sample2.png
Maar als ik dit plaatje door MaakTransparant() haal, heeft het nieuwe plaatje weer een zwarte achtergrond.

Dit plaatje heeft een witte achtergrond in alle programma's en veranderd helemaal niet in MaakTransparant()
http://svn.mapwindow.org/...ResampleImage/Sample1.png

BTW. Het uiteindelijke doel is om alle plaatjes als lagen bovenop elkaar in MapWindow te tonen.
Dat gaat prima als ik ze eerst handmatig bewerk in IrfanView en de transparante kleur aangeef.

[Edit:]
De code van Feanathiel blijkt toch goed te werken. Als ik die alleen uitvoer op Sample1, die met de witte achtergrond dan krijg ik een nieuw plaatje met een transparante achtergrond. Alleen kan ik dan niet bmpIn.GetPixel(0, 0); gebruiken want in dit voorbeeld begint daar net de lijn. |:(
Ik zal alle hoeken van de bitmap testen. De kleur is toch wit of zwart en die kleuren worden verder in de plaatjes niet gebruikt.
Overigens blijkt er nog wel een bug te zitten in MapWindow, want die kan niet overweg met plaatjes waarbij de transparante kleur wit is en bij sommige plaatjes word de transparantie niet herkend.
Als ik handmatig 'Use transparency' aanzet voor alle samples dan krijg ik netjes wat ik nodig heb.

Bedankt allen, ik ben er zeer mee opgeschoten _/-\o_

[ Voor 26% gewijzigd door Verwijderd op 21-05-2010 11:16 . Reden: Ik zag het licht ;) ]


Acties:
  • 0 Henk 'm!

  • Feanathiel
  • Registratie: Juni 2007
  • Niet online

Feanathiel

Cup<Coffee>


Grappig, Bitmap.getPixel(0,0) geeft bij die laatste (a: 255, r: 0, g: 0, b: 0) terwijl Bitmap.getPixel(1,1) (a:255, r:255, g:255, b:255) geeft. Zit dus ergens iets niet goed op die eerste pixel, danwel in de afbeelding, danwel in het script. Als je hem dan ook door mijn codevoorbeeld heen haalt (met als color die .getPixel(1,1) of Color.White), zul je zien dat er een (1px) zwarte border overblijft.

Uitdraai op imageshack (popups!): http://img714.imageshack.us/i/testfi.png/

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Als ik Color.White gebruik, zie ik geen zwarte border, maar als dat wel zo zou zijn is dat niet eens heel erg in mijn situatie.
Waar ik nu nog mee worstel is het controleren of een plaatje al transparant is. Dan hoef ik die nl. niet meer te converteren. En de originele bestanden zijn ook veel kleiner omdat ze 8Bit Indexed zijn.
Ik had gehoopt dat er een property zou zijn 'IsTransparent' in het Bitmap object, maar die is er niet.
Ik heb ook al even gekeken naar de PropertyItems, maar die zijn leeg.

Iemand nog een hint?

Acties:
  • 0 Henk 'm!

  • Feanathiel
  • Registratie: Juni 2007
  • Niet online

Feanathiel

Cup<Coffee>

Image.Flags
http://msdn.microsoft.com...mage.flags(v=VS.100).aspx

Kijk wel uit dat Translucent en Transparent (alpha) verschillende betekenis hebben. De een heeft betrekking op een pixel (alpha, red, green, blue) en de andere heeft een Alpha mask/laag.

Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 15-09 21:49

CodeIT

Code IT

Als je de kleur die je transparant maakt altijd van hetzelfde punt (0,0) of (1,1) krijgt, kun je de alpha waarde van die pixel natuurlijk ook testen of deze al transparant is.
Bijvoorbeeld:
C#:
1
2
3
4
 if(bmpIn.GetPixel(0,0).A == 255)
{
     //deze moet nog worden gedaan
}

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Geweldig! Ik gebruik de flags en het werkt als een trein:
C#:
1
2
3
4
5
6
7
8
9
    private static bool IsImageTransparent(string imageFileName)
    {
        bool isTransparent = false;
        using (Bitmap bmp = (Bitmap)Bitmap.FromFile(imageFileName))
        {
            isTransparent = ((bmp.PixelFormat & PixelFormat.Alpha) != 0);
        }
        return isTransparent;
    }


Ik krijg netjes terug dat sample1 niet transparant is en de rest wel.

Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Nu online
Verwijderd schreef op vrijdag 21 mei 2010 @ 10:45:
Het lukt me nog steeds niet.
Ik begin me af te vragen of er misschien toch iets mis is met het plaatje.

Als ik de png open in FireFox, MS PicturViewer of Photoshop dan wordt het origineel wel met een transparante achtergrond getoond.
Maar open ik het plaatje met IrfanView of MapWindow GIS dan heeft die een zwarte achtergrond
http://svn.mapwindow.org/...ResampleImage/Sample3.png
Met dit plaatje is op zich niks mis, maar het zou zo niet door de certificering van Kadaster heen mogen hebben komen (zie http://www.kadaster.nl/kl...nscherping_eisen_PNGs.pdf). De achtergrondkleur is namelijk "zwart" transparant en niet "wit" transparant. En antialiasing met gedeeltelijke transparantie mag ook niet.
Dit plaatje gaat wel goed en wordt in alle programma's goed getoond:
http://svn.mapwindow.org/...ResampleImage/Sample2.png
Maar als ik dit plaatje door MaakTransparant() haal, heeft het nieuwe plaatje weer een zwarte achtergrond.
Dit plaatje is op zich correct volgens de eisen van KLIC omdat de achtergrondkleur wit transparent is. Alleen mag voor datatransport alleen fel groen gebruikt worden en niet donkergroen... zal wel KPN zijn :)
Dit plaatje heeft een witte achtergrond in alle programma's en veranderd helemaal niet in MaakTransparant()
http://svn.mapwindow.org/...ResampleImage/Sample1.png
Dit plaatje heeft geen transparante kleuren in het palette inderdaad.
BTW. Het uiteindelijke doel is om alle plaatjes als lagen bovenop elkaar in MapWindow te tonen.
Dat gaat prima als ik ze eerst handmatig bewerk in IrfanView en de transparante kleur aangeef.
Vervanger aan het maken voor www.klicviewer.nl ? Je bent niet de enige met een probleem met het tekenen van transparante PNG's, want de netbeheerders die willen aansluiten op KLIC-online moeten zich in bochten wringen om PNG's aan te leveren die geen bugs triggeren in de software voor het maken van gelaagde PDF's of in de KLIC-viewer...

Ik heb in Java een tooltje gemaakt om het palette van PNG's te controleren. Hiermee kan je dan exact controleren welke kleuren transparant zijn en niet. Dat is erg handig om dit soort problemen mee te debuggen. Voor Sample2.png krijg je dan bijvoorbeeld:

$ java -cp [url="http://www.openwion.nl/openwion-common.jar"]openwion-common.jar[/url] nl.openwion.graphics.ImageInfo Sample2.png
Inlezen PNG...
Tellen aantal pixels per palette entry...
PNG palette en aantal pixels:
palette index   0: argb=00ffffff (transparent)   11382656 pixels
palette index   1: argb=ff00c800                     1672 pixels
palette index   2: argb=ff00ff00                    40323 pixels
palette index   3: argb=ff00bf00                      581 pixels

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@Matthijsln:
Bedankt voor je antwoord. Ik zal zeker eens naar je tooltje kijken en zien of ik het ook kan gebruiken in mijn C# applicatie.
Inderdaad ben ik ook een KLIC viewer aan het maken en loop ik ook tegen de genoemde problemen aan met de png bestanden.
Ik denk dat dat nog wel even zou zal blijven, totdat de beheerders GML bestanden kunnen produceren.
Pagina: 1