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:
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.
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.
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.