Avatar billede trumf Nybegynder
22. juli 2009 - 23:02 Der er 22 kommentarer og
1 løsning

Fjerne noger af header i jpg filer

Hejsa E

For at gøre en kort historie lang, så har jeg fået mig en tvix og vil spille min musik på den. Jeg bruger iTunes og den henter covers til mine CD'ere. Dem vil jeg også gerne kunne se på Tvixen, men i iTunes hedder filerne xxx.itc2 og der er lagt nogle informationer ind forrest i headeren.

Det skulle sådan set være lige til (ifølge forskellige foraer) men det er endnu ikke lykkes helt for mig, så nu vil jeg lige høre om nogen kan få det til at fungere.

Selve jpg headeren starter ved HEX værdierne FFD8 FFE0, så i teorien skal man "bare" finde dem og fjerne det der står foran og omdøbe til jpg.
Jeg har gjort mig et par noter, som jeg lige skriver på her, ved ikke om det er helt rigtigt...

Ifølge forskellige foraer skal man bruge en binaryreader, da konvertering til string er alt for langsomt.
Når man læser værdierne læses de to og to, så man kan ikke være sikker på at fange dem med ReadUInt32, man må derfor bruge ReadUInt16 to gange.

Jeg tænker at man måske kan bruge substring eller regex til det.

Her er noget skrivebordskode til at illustrere hvordan jeg tror det kunne se ud:

private void removeiTunesHeader(string filename, string path)
{
    bool found = false;
    int currentPosition = 0;
    FileStream fs = File.OpenRead(filename);
    BinaryReader br = new BinaryReader(fs);
    while (found == false && currentPosition <= br.Length)
    {
    UInt16 headerByte = br.ReadUInt16();  // Start of Image (SOI) marker (FFD8)
    currentPosition += headerByte.Length;
    if (headerByte == 0xd8ff)
    {
        UInt16 headerByte2 = br.ReadUInt16(); // JFIF marker (FFE0)
        if (headerByte2 == 0xe0ff)
        found = true;
    }
    }

    if (found)
    {
    FileStream fs2 = fs.subString(currentPosition, fs.Length);
    fs2.save(path.Replace(".itc2", ".jpg"));
    }
}

Jeg håber nogen kan hjælpe mig med at få det til at virke. Kom med noget kode og ikke bare henvisninger, jeg har læst en masse på nettet og vil gerne videre nu.

PÅ forhånd tak
Avatar billede arne_v Ekspert
23. juli 2009 - 01:30 #1
lidt omorganiseret (men stadig utestet):

FileStream fs = File.OpenRead(filename);
BinaryReader br = new BinaryReader(fs);
bool found = false;
while(!found)
{
    UInt16 headerByte = br.ReadUInt16();
    if (headerByte == 0xd8ff)
    {
        UInt16 headerByte2 = br.ReadUInt16();
        if (headerByte2 == 0xe0ff) found = true;
    }
}
FileStream fs2 = File.OpenRead(filename.Replace(".itc2", ".jpg"));
int c;
while((c = br.Read()) >= 0)
{
    fs2.WriteByte((byte)c);
}
fs2.Close();
br.Close();

Hvis de to marker ikke findes får du en exception som du bare kan catche.
Avatar billede trumf Nybegynder
24. juli 2009 - 17:20 #2
Hej Arne

Det ser fint ud, men der er umiddelbart to mindre issues:

1: Den skal træde to "skridt" tilbage, så den får "d8ff" og "e0ff" med i filen.
2: Det ser ud til at den overskriver filen, men den skal lave en ny med endelsen ".jpg" da jeg skal bruge originalen.

for det førstes vedkommende kan jeg så ikke bare skrive:

fs2.WriteByte((0xd8ff)c);
fs2.WriteByte((0xe0ff)c);
while((c = br.Read()) >= 0)
{
    fs2.WriteByte((byte)c);
}

eller er der en pænere måde ??
Avatar billede arne_v Ekspert
24. juli 2009 - 17:31 #3
re 1)

Det er vist helt fint.

re 2)

FileStream fs2 = File.OpenRead(filename.Replace(".itc2", ".jpg"));

burde give et nyt filnavn *HVIS* den gamle fil hedder ".itc2" ...
Avatar billede trumf Nybegynder
24. juli 2009 - 17:49 #4
Jeg får en fejl ved FileStream fs2 = File.OpenRead(filename.Replace(".itc2", ".jpg")); om at den ikke kan finde filen. Skal den oprettes først som en tom fil eller noget ??
Avatar billede trumf Nybegynder
24. juli 2009 - 17:52 #5
System.IO.FileNotFoundException: Could not find file 'D:\Mp3\iTunes\Album Artwork\Download\F738D7100A3D4B8A\00\15\10\F738D7100A3D4B8A-67DA11AB2F51BAF0.jpg'.
Avatar billede arne_v Ekspert
24. juli 2009 - 17:56 #6
Nej - jeg er en tumbe + det er jo nok ikke OpenRead men OpenWrite for den nye fil ...

:-)
Avatar billede trumf Nybegynder
24. juli 2009 - 18:09 #7
Ja det er meget bedre :)

Får en fejl nu i
while ((c = br.Read()) >= 0)

System.ArgumentException: The output char buffer is too small to contain the decoded characters, encoding 'Unicode (UTF-8)' fallback 'System.Text.DecoderReplacementFallback'.

Parameter name: chars

  at System.Text.Encoding.ThrowCharsOverflow()

  at System.Text.Encoding.ThrowCharsOverflow(DecoderNLS decoder, Boolean nothingDecoded)

  at System.Text.UTF8Encoding.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, DecoderNLS baseDecoder)

  at System.Text.DecoderNLS.GetChars(Byte* bytes, Int32 byteCount, Char* chars, Int32 charCount, Boolean flush)

  at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex, Boolean flush)

  at System.Text.DecoderNLS.GetChars(Byte[] bytes, Int32 byteIndex, Int32 byteCount, Char[] chars, Int32 charIndex)

  at System.IO.BinaryReader.InternalReadOneChar()

  at System.IO.BinaryReader.Read()
Avatar billede arne_v Ekspert
24. juli 2009 - 18:24 #8
while ((c = br.ReadByte()) >= 0)
Avatar billede trumf Nybegynder
24. juli 2009 - 19:06 #9
OK, så kom den lidt længere, men nu får jeg denne fejl mange gange efter hinanden...

System.IO.EndOfStreamException: Unable to read beyond the end of the stream.

  at System.IO.__Error.EndOfFile()

  at System.IO.BinaryReader.ReadByte()

og det er da lidt underligt ik.
Avatar billede arne_v Ekspert
24. juli 2009 - 19:26 #10
Fuck. ReadByte smider exeception fremfor at returnere -1.

while((c = br.Read()) >= 0)
{
    fs2.WriteByte((byte)c);
}

->

bool done = false;
while(!done)
{
    byte[] buf = br.ReadBytes(1024);
    done = buf.Length < 1024;
    fs2.Write(buf, 0, buf.Length);
}
Avatar billede trumf Nybegynder
24. juli 2009 - 20:50 #11
OK, så kom den igennem uden at fejle, men jeg kan ikke åbne billederne. Når jeg prøver at åbne i photoshop får jeg fejlen:

Could not complete your request because unknown or invalid JPEG marker encountered!

Jeg har prøvet at give dem extension png og tif for det tilfælde at det skulle være andre filtyper, men dem kan jeg heller ikke åbne...

Min kode ser nu sådan ud:

FileStream fs = File.OpenRead(filename);
BinaryReader br = new BinaryReader(fs);
bool found = false;
while (!found)
{
    UInt16 headerByte = br.ReadUInt16();
    if (headerByte == 0xd8ff)
    {
    UInt16 headerByte2 = br.ReadUInt16();
    if (headerByte2 == 0xe0ff) found = true;
    }
}
if (found)
{
    FileStream fs2 = File.OpenWrite(path + Path.GetFileName(filename.Replace(".itc2", ".jpg")));
    int c;
    c = 0xd8ff;
    fs2.WriteByte((byte)c);
    c = 0xe0ff;
    fs2.WriteByte((byte)c);
    bool done = false;
    while (!done)
    {
    byte[] buf = br.ReadBytes(1024);
    done = buf.Length < 1024;
    fs2.Write(buf, 0, buf.Length);
    }
    fs2.Close();
}
fs.Close();
br.Close();
Avatar billede arne_v Ekspert
24. juli 2009 - 21:04 #12
Har de den rigtige stoerrelse?
Avatar billede trumf Nybegynder
24. juli 2009 - 21:17 #13
Ja det tyder det på, de er forskellige i størrelse og de varierer fra ca 50 til 100 kb
Avatar billede trumf Nybegynder
24. juli 2009 - 21:18 #14
Kunne det evt. være dette:
int c;
c = 0xd8ff;
fs2.WriteByte((byte)c);
c = 0xe0ff;
fs2.WriteByte((byte)c);

der skrives forkert eller måske bliver overskrevet. Det er jo markeren den brokker sig over...
Avatar billede trumf Nybegynder
24. juli 2009 - 21:41 #15
Jeg har lige hentet en HEX reader og filerne starter ikke med D8 FF E0 FF så det må være fordi markeren ikke skrives eller at den overskrives...
Avatar billede trumf Nybegynder
24. juli 2009 - 21:58 #16
Avatar billede trumf Nybegynder
24. juli 2009 - 22:29 #17
Jeg har lagt en itc2 fil her hvis man skulle have lyst til at prøve den selv:
http://www.c-online.dk/download/coverart.zip
Avatar billede trumf Nybegynder
25. juli 2009 - 00:50 #18
Avatar billede arne_v Ekspert
26. juli 2009 - 04:14 #19
Følgende program kan konvertere filen:

using System;
using System.IO;

namespace E
{
    public class Program
    {
        public static void Convert(string fnm)
        {
            Stream istm = new FileStream(fnm, FileMode.Open, FileAccess.Read);
            Stream ostm = new FileStream(fnm.Replace(".itc2", ".jpg"), FileMode.Create, FileAccess.Write);
            byte[] b = new byte[65536];
            int n;
            bool first = true;
            while((n = istm.Read(b, 0, b.Length)) > 0)
            {
                int ix = 0;
                if(first)
                {
                    while(b[ix] != 0xFF && b[ix+1] != 0xD8 && b[ix+2] != 0xFF && b[ix+3] != 0xE0)
                    {
                        ix++;
                        if(ix > n - 4) throw new Exception(fnm + " does not conatin a JPG file");
                    }
                    first = false;
                }
                ostm.Write(b, ix, n - ix);
            }
            ostm.Close();
            istm.Close();
        }
        public static void Main(string[] args)
        {
            Convert(@"C:\coverart.itc2");
        }
    }
}

men men men - diverse simple billed læse programmer kan ikke læse resultatet. Kun HP Photosmart Premier kunne læse det - og viste det som 3 billeder: bluedot.png, code.png og coverart.jpg.
Avatar billede trumf Nybegynder
26. juli 2009 - 10:28 #20
SÅ med andre ord, er det, om ikke umuligt, så yderst besværligt ??
Avatar billede arne_v Ekspert
27. juli 2009 - 00:43 #21
Det tror jeg.

Hvis du kan finde en beskrivelse af det interne format, så man kan splitte den .itc2 fil op i flere filer, så måske ...
Avatar billede trumf Nybegynder
27. juli 2009 - 19:22 #22
OK. Jeg har allerede fundet ca 50 pladeomslag og manuelt sat dem ind. Jeg har bare over 200 CD'ere endnu som jeg også skal gøre det med...

Smid et svar så lukker jeg den igen.

Mange tak for hjælpen :)
Avatar billede arne_v Ekspert
28. juli 2009 - 00:51 #23
ok
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester