[.NET] Afbeeldingen uit een ICO file lezen / schrijven

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Hey,

Ik moet af en toe wel eens een eigen icoontje maken voor verschillende doeleindes, en ik gebruik daarvoor steeds een andere 'trial' versie van betaalde software om meerdere afbeeldingen in één ICO file te krijgen. Dat is natuurlijk niet handig, en ik ga er echt niet voor betalen, dus wilde ik graag een eigen programmaatje maken waarmee ik ICO files kan schrijven (met meerdere afbeeldingen) en ook weer kan inlezen (waarmee de afbeeldingen weer apart tevoorschijn komen).

Ik heb even gezocht of er al een implementatie in .NET is maar ik heb niets kunnen vinden. Wel eentje in Java, maar die lijkt ook heel veel andere dingen te doen dus dat is ook niet ideaal. Daarbij wil ik het ook graag een keer zelf proberen. Ik weet namelijk niet zo heel veel af van filetypes lezen/schrijven (behalve simpele txt of xml bestanden), dus dit lijkt me een goede mogelijkheid om dat te doen.

Ik heb besloten om maar even te beginnen met het lezen van ICO bestanden, dat kan ik het makkelijkst testen en als ik weet waar alle data vanaf komt dan zal schrijven ook niet zoveel moeite kosten denk ik.

In de Wikipedia pagina staat uitgelegd hoe het ICO file format is opgebouwd, en daarop gebaseerd heb ik (na een aantal aannames die ik niet duidelijk uitgelegd vond op wikipedia) een class geschreven die in ieder geval het aantal afbeeldingen, hun grootte, en de plaats+grootte van de afbeelding data uit kan lezen.

In principe was dit vrij makkelijk, ik gebruik een BinaryReader en zijn verschillende Read methodes die overeenkomen met wat in de wiki staat. Dat sla ik op in een IcoFile class:
Visual Basic .NET:
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    Public Shared Function Read(ByVal path As String) As IcoFile
        Dim ico As New IcoFile()

        Dim imageCount As Integer
        Dim images As New List(Of IcoImage)

        Using input = File.OpenRead(path)
            Using reader As New BinaryReader(input)

                reader.ReadBytes(2)                             ' Reserved, should be 0
                reader.ReadInt16()                              ' Icon type (1 for ICO, 2 for CUR)
                imageCount = reader.ReadInt16()                 ' Number of images

                For i As Integer = 0 To imageCount - 1
                    reader.BaseStream.Position = 6 + 16 * i     ' 6 for the first 6 bytes, then 16 extra every iteration
                    Dim width As Integer = reader.ReadByte()
                    Dim height As Integer = reader.ReadByte()

                    If width = 0 Then width = 256 ' see wiki
                    If height = 0 Then height = 256 ' see wiki

                    Dim colors As Integer = reader.ReadByte
                    reader.ReadByte()                           ' Reserved (skip)

                    reader.ReadInt16()                           ' skip 2 bytes for color planes (I'm assuming it is 0 or 1)
                    Dim bpp As Integer = reader.ReadInt16()      ' bits per pixel

                    Dim bmpSize As Integer = reader.ReadInt32()     ' size (in bytes) of the image data
                    Dim bmpAddress As Integer = reader.ReadInt32()  ' offset (in bytes) of the iamge data

                    ' Create a new 'IcoImage' that stores the size, number of colors, bpp, img size and img offset, and add it to a list
                    Dim img As New IcoImage()
                    img.Size = New Size(width, height)
                    img.NumberOfColors = colors
                    img.BitsPerPixel = bpp
                    img.BmpSize = bmpSize
                    img.BmpAddress = bmpAddress

                    images.Add(img)
                Next

                ' Convert the BMP data to images
                ico._Images = IcoFile.GetBitmaps(reader, images)
            End Using
        End Using

        Return ico
    End Function


Uiteindelijk als ik alle data heb gebruik ik de GetBitmaps functie om de bitmap rauwe data naar Images om te zetten. Maar dat wil dus niet lukken.

Ik probeer het gewoon via de Bitmap.FromStream methode, maar het lijkt erop alsof de bytes niet in het juiste formaat zijn.
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
    Private Shared Function GetBitmaps(ByVal reader As BinaryReader, ByVal images As IEnumerable(Of IcoImage)) As List(Of Image)
        Dim bmps As New List(Of Image)

        For Each img As IcoImage In images
            reader.BaseStream.Position = img.BmpAddress
            Using Stream As New MemoryStream(reader.ReadBytes(img.BmpSize))
                Dim bmp = Bitmap.FromStream(Stream, True)
                bmps.Add(bmp)
            End Using
        Next

        Return bmps
    End Function

Als ik deze code run krijg ik een 'Parameter is invalid' exceptie (geen omschrijving of niets) op de FromStream methode.

Als ik de wiki opnieuw lees dan zie ik dat de afbeeldingen niet zo simpel opgeslagen zijn. Ik kom er echter niet uit hoe ik nou van deze data (start op adres 'BmpAddress' en is 'BmpSize' bytes lang) in een Image omzet...

Hoe doe ik dit nu?


Overigens: als ik de images niet probeer om te zetten lijkt het te werken. Ik krijg dan het juiste aantal afbeeldingen en de juiste grootte terug, maar natuurlijk de afbeeldingen zelf niet.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • apokalypse
  • Registratie: Augustus 2004
  • Laatst online: 21-09 10:21
Dit lijkt me eenzelfde probleem als hier

C#:
1
2
ImageConverter imageConverter = new System.Drawing.ImageConverter();
Image image = imageConverter.ConvertFrom(byteArray) as Image;

[ Voor 44% gewijzigd door apokalypse op 09-07-2010 15:40 ]


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
apokalypse schreef op vrijdag 09 juli 2010 @ 13:19:
Dit lijkt me eenzelfde probleem als hier
Nope, daar krijg ik dezelfde error.

Ik denk dat het probleem heel simpel is: deze image converters (alsook de FromStream methode) verwachten de bytes gewoon in een bepaald format (ofwel BMP, JPG, GIF, etc), maar de afbeeldingen in de ICO files zijn niet opgeslagen als afbeelding. In de wiki staat daar wat meer informatie over, maar niet genoeg (voor mij tenminste) om er uit op te maken hoe ik het dan wel naar een afbeelding moet converteren...

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • apokalypse
  • Registratie: Augustus 2004
  • Laatst online: 21-09 10:21
Kan de Icon klasse niet helpen?

C#:
1
public Icon(Stream stream, Size size)

Lijkt me.

Heb je de hele code niet meer nodig? 8)


De wiki negeert welke type/formaat het image zelf is

[ Voor 14% gewijzigd door apokalypse op 09-07-2010 15:42 ]


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Voor zover ik weet is de Icon klasse maar 1 afbeelding en kun je dus niet aan de andere formaten.

Ik vind net wel dit:
http://www.codeproject.com/KB/vb/MultiIcon.aspx
Dat lijkt precies te zijn wat ik nodig heb... Raar dat ik dat niet eerder gevonden heb :/


EDIT
En daarmee is dit voor nu opgelost. Lezen lukt, en ik weet zeker dat schrijven nu ook zal lukken :)
Toch bedankt!

[ Voor 19% gewijzigd door NickThissen op 09-07-2010 16:21 ]

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 21-08 11:20
Slightly offtopic, maar je zou ook kunnen kijken naar Paint.NET en een plugin ervoor waardoor je alsnog naar ICO kunt exporteren, geheel gratis.

We are shaping the future


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 26-09 20:57

Sebazzz

3dp

Of je gebruik IcoFX. Die is gratis en er specifiek op gericht.

Daarnaast biedt de .NET bitmap class geloof ik ook een methode om naar ICO te exporteren.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik gebruik al jaren naar volle tevredenheid Microangelo; kost een paar tientjes maar dan heb je ook wat. Maar waarom ik dit post is: sure, leuk om zelf zoiets te bouwen en als je dat graag doet: ga vooral zo door d:)b. Maar als je het doet om niet te hoeven betalen voor software dan moet je eens nagaan hoeveel tijd je iets gaat kosten om het te maken en ga dan nog eens narekenen of het niet goedkoper is om een paar tientjes uit te geven (los van het feit dat er ook nog eens zat gratis alternatieven zijn).

Eer je met je project op 't niveau van de commerciële of gratis beschikbare pakketten zit ben je echt wel een paar weken verder en als het niet je primaire business is en het alleen maar een "interne tool" wordt is het echt wel verstandiger even verder te surfen dan je neus lang is en een beter alternatief te kiezen.

Then again; we zitten in de Devschuur en ik kan alleen maar aanmoedigen dat je de wil hebt om zoiets zelf te bouwen; ik wilde het alleen even in perspectief zetten.

[ Voor 35% gewijzigd door RobIII op 11-07-2010 00:37 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 09-09 10:50
Ik weet niet hoe het in Paint.NET zit, maar ik heb wel een plugin voor Photoshop en die kan voor zover ik weet ook maar één enkele afbeelding naar ICO converteren, dus dan heb je niet meerdere afbeeldingen in één icoontje. Als Paint.NET dat wel kan is dat inderdaad een mooie gratis optie.

Zelfde geldt voor de .NET functies. Voor zover ik weet ook maar een enkele afbeelding.

En ik weet ook wel dat er goeie programma's voor bestaan, maar ik ben wel vaker op zoek naar projectjes die ik zelf kan doen om m'n programmeer vaardigheden op peil te houden of te vergroten. Het maken van een programmaatje dat ICO files leest en schrijft leek me daar een prima project voor.

d
Ten slotte heb ik zojuist gemerkt dat transparante* ICO files niet goed lijken te gaan (leveren een lege afbeelding op). Ik zal er nog even zelf naar kijken, maar als ik er niet uit kom dan zal ik hier verder in posten.

* Ik heb maar 1 ICO file kunnen vinden en die had ik zelf gemaakt, van een (transparant) PNG bestand wat ik met de Photoshop plugin naar een ICO geconverteerd heb. Die wil hij niet goed lezen. Kan dus aan de ICO plugin van photshop liggen of aan het feit dat het uit een PNG bestand gemaakt is, dat heb ik nog niet kunnen onderzoeken.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Een goede bron voor bestandsformaten is wotsit.org, waar je ook informatie vindt over ico bestanden. Als de .Net classes niet de (volledige) ondersteuning bieden die je zoekt (en dat zou kunnen, dat weet ik zo niet 1 2 3) dan kun je nog eens kijken naar de Windows API die ook, als het goed is, ook een hele berg functies biedt hiervoor (en waar de .Net wrapper dan waarschijnlijk maar een deel van implementeert). Met wat PInvokes kom je dan een heel eind denk ik.

En anders wordt het zelf het bestand lezen/parsen; voor een .ico is dat, voor zover ik daar in een heel grijs verleden wel eens wat mee gestoeid heb, geen rocket science :P

[ Voor 68% gewijzigd door RobIII op 11-07-2010 01:13 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 00:26
Visual Studio kan toch zelf ook icon file lezen en maken?

Roomba E5 te koop

Pagina: 1