Przepisanie funkcji z C# do C++ (QT5)

Odpowiedz Nowy wątek
2014-03-14 12:58

Rejestracja: 7 lat temu

Ostatnio: 1 rok temu

0

Witam, chciałbym odczytać sprite o danym ID z pliku Tibia.spr (Tak chodzi o Tibie)
Znalazłem funkcję napisaną w C# lecz chciałbym przepisać ja do C++/QT5

// Thanks to OpiF at http://otfans.net/showthread.php?t=102065
        // and to Thomac at http://otfans.net/showthread.php?t=141982
        public static Image GetSpriteImage(string file, int spriteId)
        {
            if (spriteId < 2)// || spriteId > 28722)
                throw new ArgumentOutOfRangeException("spriteId");

            int size = 32;
            Bitmap bitmap = new Bitmap(size, size);

            using (BinaryReader reader = new BinaryReader(File.OpenRead(file)))
            {
                ushort currentPixel = 0;
                long targetOffset;

                reader.BaseStream.Seek(6 + (spriteId - 1) * 4, SeekOrigin.Begin);
                reader.BaseStream.Seek(reader.ReadUInt32() + 3, SeekOrigin.Begin);

                targetOffset = reader.BaseStream.Position + reader.ReadUInt16();

                while (reader.BaseStream.Position < targetOffset)
                {
                    ushort transparentPixels = reader.ReadUInt16();
                    ushort coloredPixels = reader.ReadUInt16();
                    currentPixel += transparentPixels;
                    for (int i = 0; i < coloredPixels; i++)
                    {
                        bitmap.SetPixel(
                            currentPixel % size,
                            currentPixel / size,
                            Color.FromArgb(reader.ReadByte(), reader.ReadByte(), reader.ReadByte())
                        );
                        currentPixel++;
                    }
                }
            }

            return bitmap;
        }

Jak to przepisać, wiele razy próbowałem lecz nie moge znaleźć podobnych funkcji w QT :/


Wole programowac niz spac :)

Pozostało 580 znaków

2014-03-14 13:04

Rejestracja: 16 lat temu

Ostatnio: 28 sekund temu

0

lecz nie moge znaleźć podobnych funkcji w QT
Której konkretnie?
Kod w C# jest raczej zrozumiały i samokomentujący.
Masz tu po pierwsze operacje na pliku (binarnym) – jak to zrobić w Qt to łatwo znajdziesz, zresztą masz też do dyspozycji STL i bibliotekę standardową C.
A po drugie bitmapę, składaną piksel po pikselu.

Szukaj informacji na te dwa tematy, a nie dokładnych odpowiedników każdej funkcji...

edytowany 1x, ostatnio: Azarien, 2014-03-14 13:04

Pozostało 580 znaków

2014-03-14 13:10

Rejestracja: 7 lat temu

Ostatnio: 1 rok temu

0

Problem dotyczy przesunięć (seek). Jakaś pomoc dotycząca tej funckji w QFile ? Czy funkcja seek w QFile zawsze zaczyna od początku i trzeba podawać pozycje przy każdym przesunieciu czy jak?


Wole programowac niz spac :)

Pozostało 580 znaków

2014-03-14 13:41

Rejestracja: 6 lat temu

Ostatnio: 4 lata temu

2014-03-14 14:18

Rejestracja: 12 lat temu

Ostatnio: 37 minut temu

0

Jeśli się nie walnąłem to powinno być tak

QImage readSpriteFromDataStream(QDataStream &data) {
    const int size = 32;
    QImage bitmap(size, size, QImage::Format_ARGB32);
    bitmap.feel(0x0); // black fully transparent

    quint16 dataSize;
    reader >> dataSize;
    int readCount=sizeof(dataSize), currentPixel=0;

    while (readCount<dataSize) {
         quint16  transparentPixels, coloredPixels;
         data >> transparentPixels >> coloredPixels;
         readCount += sizeof(transparentPixels) + sizeof(coloredPixels) + coloredPixels * 3;
         currentPixel += transparentPixels;

         for (int i = 0; i < coloredPixels; i++) {
               quint8 r,g,b;
               data >> r >> g >> b;
               bitmap.setPixel(currentPixel % size, currentPixel / size, qRgba(r,g,b, 0xff));
               currentPixel++;
         }
    }
   Q_ASSERT(readCount==dataSize); // data coherency 
    return bitmap;
}

QImage getSpriteImageFormFileNamed(const QString &file, int spriteId)  {
    if (spriteId < 2) {
         return QImage();
    }

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly))
         return;

    QDataStream reader(&file);
    reader.setByteOrder(QDataStream::LittleEndian); // zakładam że format pliku jest związany x86, więc ma być mała endiana
    int locationOfSpriteOffset = 6 + (spriteId - 1) * 4;
    reader.skipRawData(locationOfSpriteOffset);
    quint32 spriteOffset;
    reader >> spriteOffset;
    file.seek(spriteOffset+3); // czy te 3 bajty nie zawierają jakiegoś znacznika lub innej użytecznej informacji?
    return readSpriteFromDataStream(reader);
}

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 5x, ostatnio: MarekR22, 2014-03-14 14:26
Widze ze 5x edytowałeś, zaraz sprawdze to, bo ja sprawdziłem tą pierwszą wersje - TheAifam5 2014-03-14 14:32
"file.seek(spriteOffset+3);" tego to nie wiem... w C# działa wszystko dobrze - TheAifam5 2014-03-14 14:42

Pozostało 580 znaków

2014-03-14 14:31

Rejestracja: 7 lat temu

Ostatnio: 1 rok temu

0

Wykorzystałem Twój kod.
Otóż poprawiłem pare rzeczy.
Wygląda to tak:

QImage MainWindow::readSpriteFromDataStream(QDataStream &data) {
    const int size = 32;
    QImage bitmap(size, size, QImage::Format_ARGB32);
    bitmap.fill(0x0); // black fully transparent

    quint16 dataSize;
    data >> dataSize;
    int readCount=sizeof(dataSize), currentPixel=0;

    while (readCount<dataSize) {
         quint16  transparentPixels, coloredPixels;
         data >> transparentPixels >> coloredPixels;
         readCount += sizeof(transparentPixels) + sizeof(coloredPixels) + coloredPixels * 3;
         currentPixel += transparentPixels;

         for (int i = 0; i < coloredPixels; i++) {
               quint8 r,g,b;
               data >> r >> g >> b;
               bitmap.setPixel(currentPixel % size, currentPixel / size, qRgba(r,g,b, 0xff));
               currentPixel++;
         }
    }
   Q_ASSERT(readCount==dataSize); // data coherency
    return bitmap;
}

QImage MainWindow::getSpriteImageFormFileNamed(const QString &fileName, int spriteId)  {
    if (spriteId < 2) {
         return QImage();
    }

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly))
         return QImage();

    QDataStream reader(&file);
    reader.setByteOrder(QDataStream::LittleEndian); // zakładam że format pliku jest związany x86, więc ma być mała endiana
    int locationOfSpriteOffset = 6 + (spriteId - 1) * 4;
    reader.skipRawData(locationOfSpriteOffset);
    quint32 spriteOffset;
    reader >> spriteOffset;
    file.seek(spriteOffset+3); // czy te 3 bajty nie zawierają jakiegoś znacznika lub innej użytecznej informacji?
    return readSpriteFromDataStream(reader);
}

Linia 36 to Q_ASSERT(readCount==dataSize); // data coherency i tu wywala


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5, 2014-03-14 14:41
jeszcze poprawiłem, brakowało "*3" w jednej linijce i stąd ten problem. Pisząc na sucho w przeglądarce łatwiej się pomylić :). Reszta poprawek to była kosmetyka. - MarekR22 2014-03-14 14:35

Pozostało 580 znaków

2014-03-14 14:51

Rejestracja: 12 lat temu

Ostatnio: 37 minut temu

0

Asercja wywala, bo albo nadal jest coś źle, albo kod wyjściowy ma jakieś błędy.
Ta asercja sprawdza czy nie dokonano czytania poza planowaną wielkość bloku (można ją wywalić, ale lepiej ustalić czemu jest źle).
Np poprawiając asercję w ten sposób:

Q_ASSERT(readCount==dataSize, 
       "czytanie spritea",
       QString("Dane są niekonsystentne przeczytano za dużo o %1 bajtów ").arg(readCount-dataSize).toAscii().data());

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2014-03-14 14:59

Rejestracja: 7 lat temu

Ostatnio: 1 rok temu

0

"ASSERT failure in czytanie spritea: "Dane s? niekonsystentne przeczytano za du?o o 2 bajt?w ", file mainwindow.cpp, line 36"

Użyłem:
Q_ASSERT_X(readCount==dataSize, "czytanie spritea", QString("Dane są niekonsystentne przeczytano za dużo o %1 bajtów ").arg(readCount-dataSize).toLocal8Bit().data());


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5, 2014-03-14 14:59
jest takie ładne słowo: niespójne. - Azarien 2014-03-14 17:55

Pozostało 580 znaków

2014-03-14 15:44

Rejestracja: 12 lat temu

Ostatnio: 37 minut temu

0

sprawdź czy kod wyjściowy z C# daje tą samą różnice (jeśli tak to tam też jest błąd, który nie przynosi poważnych konsekwencji).
Chodzi o różnicę: reader.BaseStream.Position - targetOffset po pętli while.
Dalej już sam ustalaj czy to błąd z kodu C# czy błąd nastąpił przy konwersji kodu. I tak już dostałeś więcej niż chciałeś. Możesz też pójść na lenia i wywalić asercję.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2014-03-14 16:18

Rejestracja: 6 lat temu

Ostatnio: 6 lat temu

0
int locationOfSpriteOffset = 6 + (spriteId - 1) * 4;

Jeżeli używasz Tibia.spr w wersji powyżej 9.7 (lub coś koło tego) to ilość sprite jest zapisana na 4 bajtach, a nie na dwóch. Wynika to z faktu, iż CipSoft przekroczył limit 2 bajtów (65535) i nie dałoby rady wrzucić więcej obrazków. Więc będzie 8 zamiast 6.

Jeszcze jedno, 3 bajty o które pytałeś to kolor, który ma służyć jako transparent. We wszystkich jest to magenta (255, 0, 255).

edytowany 2x, ostatnio: Dantez, 2014-03-14 16:45

Pozostało 580 znaków

2014-03-14 17:06

Rejestracja: 7 lat temu

Ostatnio: 1 rok temu

0

Ustawiłem 8 zamiast 6... Pusty obraz.. Zostawilem 6... Wszystko dziala, tylko caly czas mysle o tych dwóch bajtach.. zaraz sprawdze w C# jak to jest.

Sprawdzilem i ... 7858612 =/= 7858610
reader.BaseStream.Position wynosi 7858612
a targetOffset wynosi 7858610


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5, 2014-03-14 17:16

Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0