2012-07-30 21 views
6
#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 

int main() 
{ 
    FILE* bmp = NULL; 
    uint32_t offset; 
    uint8_t* temp = NULL; 
    size_t read; 
    unsigned int x_dim = 600, y_dim = 388; 

    bmp = fopen("test_colour.bmp", "r"); 

    if (!bmp) 
     return -1; 

    /* Get the image data offset */ 
    fseek(bmp, 10, SEEK_SET); 
    fgets((char*)&offset, 4, bmp); 

    printf("Offset = %u\n", offset); 

    temp = malloc(3*x_dim*y_dim*sizeof(uint8_t)); 

    if (!temp) 
     return -1; 

    /* Go the the position where the image data is stored */ 
    fseek(bmp, offset, SEEK_SET); 

    /* Copy image data to array */ 
    printf("%u bytes requested!\n", 3*x_dim*y_dim); 
    read = fread((void*)temp, sizeof(uint8_t), 3*x_dim*y_dim, bmp); 
    printf("%Iu bytes read!\n", read); 

    fclose(bmp); 
    free(temp); 

    return 0; 
} 

Używam powyższego kodu do odczytu danych RGB 24-bitowego piksela na obraz pikselowy BMP do tablicy. Przesunięcie od początku pliku, w którym dane obrazu są uruchamiane (po nagłówku BMP), jest podawane przy przesunięciu 10 zgodnie ze specyfikacją BMP. Otrzymuję następujące dane wyjściowe podczas wykonywania powyższego kodu.Nieoczekiwana wartość zwracana z fread()

Offset = 54 
698400 bytes requested! 
33018 bytes read! 

Wydajność przesunięcia wydaje się być poprawna, ponieważ rozmiar pliku wynosi 698454 bajtów (= 698400 + 54). Jednak wartość zwrócona przez fread() wydaje się wskazywać, że nie można odczytać całych danych obrazu. Jednak później używam danych z tablicy temp, aby przekonwertować dane RGB na skalę szarości i ponownie zapisać te dane do pliku BMP. Wizualne sprawdzenie obrazu wyjściowego nie wskazuje żadnych błędów, tzn. Wydaje się, że faktycznie czytałem cały obraz wejściowy, chociaż wydaje się, że fread() wskazuje inaczej.

Czy ktoś może wyjaśnić to zachowanie?

+0

Dwa pytania: 1) Czy możesz sprawdzić zawartość 'temp' po wywołaniu' fread', aby sprawdzić, czy rzeczywiście przestał czytać po 33018 bajtach? 2) Nie jestem zaznajomiony ze specyfikatorem formatu "% Iu" - czy możesz sprawdzić faktyczną wartość 'read' w debugerze? – Treb

+0

Nie sądzę, że to jest przyczyną objawów, które widzisz, ale powinieneś używać poprawnych ciągów w formacie 'printf'. Format 'size_t' to' "% zu" '. '"% Iu "' jest niestandardowe. Jeśli twoja implementacja nie obsługuje ''% zu "', możesz użyć 'printf (" przeczytane% lu! \ N ", (unsigned long) read);' –

+0

Używam gcc z MinGW do kompilacji i kompilator nie rozpoznaje specyfikatora '% zu' (próbowałem go użyć wcześniej). Czytałem, że trzeba użyć '% Iu' w oknach. – simon

Odpowiedz

20

(założę się, że jesteś na Windows)

bmp = fopen("test_colour.bmp", "r"); 

powinny być

bmp = fopen("test_colour.bmp", "rb"); 

Jeśli plik jest otwarty w trybie tekstowym w systemie Windows, środowisko wykonawcze będzie przestać czytać, kiedy to się dzieje trafienie bajtu 0x1a (Ctrl-Z), który system Windows uznaje za znacznik EOF dla plików tekstowych. Nawet jeśli nie uderzy w Ctrl-Z, otrzymasz uszkodzone dane, gdy Windows konwertuje sekwencje CR/LF na pojedynczy znak LF.

Jednak nie potrafię wyjaśnić, dlaczego można uzyskać dobry obraz z częściowego odczytu pliku (po prostu szczęście?).

Możesz renderować obraz z bufora, ponieważ implementacja fread() odczytuje liczbę żądanych bajtów (lub prawie tyle - liczba zaokrągla się do wielokrotności pewnego rozmiaru bloku) do bufora, a następnie skanuje bufor szukając sekwencji CR/LF do konwersji i flag Ctrl-Z EOF.

Tak więc chociaż fread() zwraca 33018, bufor został prawie całkowicie zapisany z danymi z pliku. Dane nie są w 100% poprawne (na przykład niektóre znaki CR zostały prawdopodobnie odrzucone) lub kompletne, ale w tym przypadku jest wystarczająco blisko, aby renderować obraz, który wygląda jak ten, którego się spodziewałeś.

Oczywiście jest to po prostu obserwacja zachowania tego konkretnego środowiska wykonawczego - nie zawsze zachowuje się w ten sposób w przyszłości (lub nawet we wszystkich dzisiejszych systemach).

+0

Rzeczywiście jestem, zapomniałem wspomnieć w OP. Dzięki za wskazanie tego, rozwiązałeś problem! Jesteś pewien, że faktycznie przestaje czytać? Jak już wspomniałem, wciąż byłem w stanie podać poprawny obraz w skali szarości całego obrazu BMP, chociaż według 'Fread' tylko ~ 5% danych pliku było faktycznie przeczytanych. – simon

+0

@imon: możliwe, że środowisko wykonawcze odczytuje liczbę żądanych bajtów w buforze, a następnie przechodzi przez nią i "naprawia" zakończenia linii i tłumaczenia EOF. Ale zgaduję. –

+0

Porównałem dwa generowane obrazy wyjściowe (jeden otwierając plik z '" r "' i drugi z '" rb "') z różnicą i nie są one takie same. Wizualnie patrząc na zdjęcia, jedyna różnica polega na tym, że kilka ostatnich pikseli na obrazie "r" jest czarnych, podczas gdy powinny być białe. Tak więc myślę, że 'fread' faktycznie czyta więcej bajtów niż wskazuje wartość zwracana, ale niekoniecznie wymagana liczba bajtów. – simon

Powiązane problemy