JavaRush /Blog Java /Random-PL /Harvard CS50: Zadania w tygodniu 4 (wykłady 9 i 10)
Masha
Poziom 41

Harvard CS50: Zadania w tygodniu 4 (wykłady 9 i 10)

Opublikowano w grupie Random-PL
Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 1

Przygotowanie do pracy

Jak zawsze najpierw otwórz okno terminala i uruchom polecenie. update50 aby upewnić się, że Twoja aplikacja jest już aktualna. Zanim zaczniesz, wykonaj poniższe czynności, cd ~ / workspace wget http://cdn.cs50.net/2015/fall/psets/4/pset4/pset4.zip aby pobrać archiwum ZIP tego zadania. Teraz, jeśli uruchomisz ls, zobaczysz, że masz plik o nazwie pset4.zip w swoim katalogu ~/workspace . Wyodrębnij go za pomocą polecenia: Jeśli unzip pset4.zip ponownie uruchomisz polecenie ls , zobaczysz, że pojawił się inny katalog. Teraz możesz usunąć plik zip, jak pokazano poniżej: rm -f pset4.zip Otwórzmy katalog pset4 cd pset4 , uruchom ls i upewnij się, że katalog zawiera bmp / jpg / questions.txt

whodunit lub „Kto to zrobił?”

Jeśli kiedykolwiek widziałeś domyślny pulpit systemu Windows XP (https://en.wikipedia.org/wiki/Bliss_(image)) (wzgórza i błękitne niebo), to widziałeś BMP. Na stronach internetowych najprawdopodobniej widziałeś pliki GIF. Czy oglądałeś zdjęcia cyfrowe? Mieliśmy więc radość zobaczyć JPEG. Jeśli kiedykolwiek zrobiłeś zrzut ekranu na komputerze Mac, najprawdopodobniej widziałeś plik PNG. Przeczytaj w Internecie o formatach BMP, GIF, JPEG, PNG i odpowiedz na następujące pytania:
  1. Ile kolorów obsługuje każdy format?

  2. Który format obsługuje animację?

  3. Jaka jest różnica między kompresją stratną i bezstratną?

  4. Który z tych formatów wykorzystuje kompresję stratną?

Osobom znającym język angielski zaleca się zapoznanie z artykułem z MIT . Jeśli się go przestudiujesz (lub znajdziesz w Internecie inne zasoby dotyczące przechowywania plików na dyskach i systemach plików), możesz odpowiedzieć na następujące pytania:
  1. Co się dzieje z technicznego punktu widzenia, gdy plik zostanie usunięty w systemie plików FAT?

  2. Co można zrobić, aby mieć pewność (z dużym prawdopodobieństwem), że usuniętych plików nie będzie można odzyskać?

A teraz – do naszej historii, która płynnie przechodzi w pierwsze zadanie czwartego tygodnia. Witamy w rezydencji Tudorów! Właściciel osiedla, pan John Boddy, nagle nas opuścił, padając ofiarą mało znanej gry. Aby dowiedzieć się, co się stało, musisz zdefiniować whodunit . Na nieszczęście dla ciebie (a jeszcze bardziej nieszczęście dla pana Boddy'ego) jedynym dowodem, jaki posiadasz, jest 24-bitowy plik BMP wskazówka.bmp . To jego zawartość widać poniżej. Panu Boddy'emu udało się to zrobić i zapisać na swoim komputerze w ostatnich chwilach swojego życia. Plik zawiera obraz kryminału ukryty wśród czerwonego szumu . Teraz musisz pracować nad rozwiązaniem jak prawdziwy specjalista techniczny. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 2Ale najpierw trochę informacji. Prawdopodobnie najłatwiej jest wyobrazić sobie obraz jako siatkę pikseli (czyli kropek), z których każdy może mieć określony kolor. Aby ustawić kolor punktu na obrazie czarno-białym, potrzebujemy 1 bitu. 0 może reprezentować kolor czarny, a 1 może oznaczać kolor biały, jak pokazano na poniższym obrazku. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 3Zatem obrazy reprezentowane w ten sposób są po prostu mapą bitów (bitmapą lub bitmapą, jak to się mówi w języku angielskim lub slangu). W przypadku czerni i bieli wszystko jest tak proste, jak to możliwe, ale aby uzyskać kolorowe obrazy, potrzebujemy tylko większej liczby bitów na piksel. Format pliku (taki jak GIF) obsługujący „8-bitowy kolor” wykorzystuje 8 bitów na piksel. Format pliku (np. BMP, JPG, PNG) obsługujący „24-bitowy kolor” wykorzystuje 24 bity na piksel (BMP faktycznie obsługuje kolor 1-, 4-, 8-, 16-, 24- i 32-bitowy) . W 24-bitowym BMP, którego używa pan Boddy, potrzeba 8 bitów, aby wskazać ilość koloru czerwonego, tyle samo dla koloru zielonego i ponownie 8 bitów, aby wskazać ilość koloru niebieskiego w każdym pikselu. Jeśli kiedykolwiek słyszałeś o kolorach RGB , to właśnie on (R=czerwony, G=zielony, B=niebieski). Jeśli wartości R, G i B jakiegoś piksela w BMP wynoszą, powiedzmy, 0xff, 0x00 i 0x00 w formacie szesnastkowym, wówczas piksel będzie czysto czerwony, ponieważ 0xff (znane również jako 255 w formacie dziesiętnym) oznacza „dużo czerwonego " w tym czasie, ponieważ 0x00 i 0x00 oznaczają odpowiednio „brak zieleni” i „niebieski także zera”. Biorąc pod uwagę, jak czerwony obraz BMP pana Boddy'ego wydaje się nam, intuicyjnie widać, że czerwony „przedział” ma wyraźnie większą wartość niż czerwony i niebieski „przedział”. Jednak nie wszystkie piksele są czerwone; niektóre mają wyraźnie inny kolor. Nawiasem mówiąc, w HTML i CSS (języku znaczników i pomagających mu arkuszach stylów, które są używane do tworzenia stron internetowych) modele kolorów są ułożone w ten sam sposób. Jeśli jesteś zainteresowany, sprawdź link: https://ru.wikipedia.org/wiki/Colors_HTMLpo więcej szczegółów. Teraz podejdźmy do problemu bardziej technicznie. Przypomnijmy, że plik to po prostu sekwencja bitów ułożonych w określonej kolejności. 24-bitowy plik BMP to sekwencja bitów, z których każde 24 (no, prawie) określa kolor którego piksela. Oprócz danych o kolorze plik BMP zawiera także metadane – informacje o szerokości i wysokości obrazu. Te metadane są przechowywane na początku pliku w postaci dwóch struktur danych powszechnie zwanych „nagłówkami” (nie mylić z plikami nagłówkowymi C). Pierwszy z tych nagłówków to BITMAPFILEHEADER i ma długość 14 bajtów (lub 14*8 bitów). Drugi nagłówek to BITMAPINFOHEADER (długość 40 bajtów). Po tych nagłówkach następuje bitmapa: tablica bajtów, z których trójki reprezentują kolor piksela (1, 4 i 16 bitów w BMP, ale nie 24 lub 32, mają one dodatkowy nagłówek zaraz po BITMAPINFOHEADER. Nazywa się to tablica RGBQUAD, określająca „wartość intensywności” dla każdego z kolorów w palecie). Jednak BMP przechowuje te trójki w odwrotnej kolejności (można powiedzieć, że BGR), z 8 bitami dla koloru niebieskiego, 8 bitami dla koloru zielonego i 8 bitami dla koloru czerwonego. Nawiasem mówiąc, niektóre BMP przechowują także całą bitmapę wstecz, zaczynając od górnej linii obrazu na końcu pliku BMP. W naszym zadaniu zapisaliśmy VMR zgodnie z opisem tutaj, najpierw górny rząd obrazu, potem dolne. Innymi słowy, zamieniliśmy jednobitowe emoji na 24-bitowe, zastępując czarny kolor czerwonym. 24-bitowy BMP będzie przechowywać tę mapę bitową, gdzie 0000ff oznacza kolor czerwony, a ffffff oznacza kolor biały; podświetliliśmy wszystkie wystąpienia 0000ff na czerwono. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 4Ponieważ przedstawiliśmy te fragmenty od lewej do prawej, od góry do dołu, możesz zobaczyć czerwoną buźkę w tych literach, jeśli odsuniesz się nieco od monitora. Przypomnijmy, że cyfra w systemie liczb szesnastkowych reprezentuje 4 bity. W związku z tym ffffff w formacie szesnastkowym w rzeczywistości oznacza 1111111111111111111111111 w formacie binarnym. Teraz zwolnij i nie idź dalej, dopóki nie będziesz pewien, że rozumiesz, dlaczego 0000ff reprezentuje czerwony piksel w 24-bitowym pliku BMP. W oknie CS50 IDE rozwiń (np. klikając na mały trójkąt) folder pset4 , a w nim - bmp . W tym folderze znajdziesz Smiley.bmp , kliknij dwukrotnie plik, a znajdziesz tam małą buźkę o wymiarach 8x8 pikseli. W rozwijanym menu zmień skalę obrazu, powiedzmy ze 100% na 400%, pozwoli to zobaczyć większą, ale jednocześnie bardziej „rozmytą” wersję emotikonu. Chociaż w rzeczywistości ten sam obraz nie powinien być rozmyty nawet po powiększeniu. Tyle, że CS50 IDE próbuje Ci wyświadczyć przysługę (w stylu serii CIA) wygładzając obraz (wizualnie rozmazując krawędzie). Tak będzie wyglądać nasza buźka jeśli ją powiększymy bez wygładzania: Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 5Piksele zamieniły się w duże kwadraty. Kontynuujmy. W terminalu przejdź do ~/workspace/pset4/bmp . Uważamy, że już pamiętasz, jak to zrobić. Przeanalizujmy przydzielone bajty w pliku Smiley.bmp . Można to zrobić za pomocą edytora szesnastkowego wiersza poleceń, programu xxd . Aby go uruchomić, uruchom polecenie: xxd -c 24 -g 3 -s 54 smiley.bmp Powinieneś zobaczyć to, co pokazano poniżej; Ponownie podkreśliliśmy na czerwono wszystkie wystąpienia 0000ff. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 6Na obrazku w lewej kolumnie widać adresy w pliku, które odpowiadają przesunięciu od pierwszego bajtu pliku. Wszystkie podane są w systemie szesnastkowym. Jeśli przekonwertujemy liczbę szesnastkową 00000036 na dziesiętną, otrzymamy 54. Zatem patrzysz na 54. bajt z pliku Smiley.bmp . Przypomnijmy, że w 24-bitowych plikach BMP pierwsze 14 + 40 = 54 bajty są wypełnione metadanymi. Jeśli więc chcesz zobaczyć metadane, uruchom następujące polecenie: xxd -c 24 -g 3 smiley.bmp Jeśli plik Smiley.bmp zawiera znaki ASCII , zobaczymy je w skrajnej prawej kolumnie w xxd zamiast tych wszystkich kropek. Zatem buźka jest 24-bitowym BMP (każdy piksel jest reprezentowany przez 24 ÷ 8 = 3 bajty) o rozmiarze (rozdzielczości) 8x8 pikseli. Każda linia (lub, jak się ją nazywa, „Scanline”) zajmuje (8 pikseli) x (3 bajty na piksel) = 24 bajty. Liczba ta jest wielokrotnością czterech i jest to ważne, ponieważ plik BMP jest przechowywany nieco inaczej, jeśli liczba bajtów w linii nie jest wielokrotnością czterech. Zatem w small.bmp, kolejnym 24-bitowym pliku BMP w naszym folderze, widać zielone pole o wymiarach 3x3 piksele. Jeśli otworzysz go w przeglądarce obrazów, zobaczysz, że przypomina obraz pokazany poniżej, tylko jest mniejszy. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 7Każda linia w small.bmp zajmuje zatem (3 piksele) × (3 bajty na piksel) = 9 bajtów, co nie jest wielokrotnością 4. Aby uzyskać długość linii będącą wielokrotnością 4, jest ona dopełniana dodatkowymi zerami: pomiędzy 0 a 3 bajtami wypełniamy każdą linię w 24-bitowym formacie BMP (czy domyślasz się dlaczego?). W przypadku small.bmp potrzebne są 3 bajty zer, ponieważ (3 piksele) x (3 bajty na piksel) + (3 bajty dopełnienia) = 12 bajtów, co w rzeczywistości jest wielokrotnością 4. Aby „zobaczyć” to dopełnienie, wykonaj następujące czynności. xxd -c 12 -g 3 -s 54 small.bmp Zauważ, że używamy innej wartości dla -c niż dla Smiley.bmp , więc xxd wyświetla tym razem tylko 4 kolumny (3 dla zielonego kwadratu i 1 dla wypełnienia). Dla przejrzystości podświetliliśmy wszystkie wystąpienia 00ff00 na zielono. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 8Dla kontrastu, użyjmy xxd dla dużego pliku.bmp . Wygląda dokładnie tak samo jak small.bmp, tylko jego rozdzielczość wynosi 12x12 pikseli, czyli czterokrotnie większa. Uruchom poniższe polecenie. Może być konieczne rozwinięcie okna, aby uniknąć przeniesienia. xxd -c 36 -g 3 -s 54 large.bmp Zobaczysz coś takiego: Harvard CS50: Zadania w tygodniu 4 (wykłady 9 i 10) – 9Uwaga, w tym BMP nie ma żadnych dygresji! W końcu (12 pikseli) × (3 bajty na piksel) = 36 bajtów, a to jest wielokrotność 4. Edytor szesnastkowy xxd pokazał nam bajty w naszych plikach BMP. Jak możemy je uzyskać programowo? W copy.c istnieje jeden program, którego jedynym celem w życiu jest utworzenie kopii BMP, kawałek po kawałku. Tak, możesz do tego użyć cp . Jednak cp nie będzie w stanie pomóc panu Boddy. Miejmy nadzieję, że copy.c to zrobi, więc zaczynamy: ./copy smiley.bmp copy.bmp jeśli teraz uruchomisz ls (z odpowiednią flagą), zobaczysz, że pliki Smiley.bmp i copy.bmp rzeczywiście mają ten sam rozmiar. Sprawdźmy jeszcze raz, czy to rzeczywiście prawda? diff smiley.bmp copy.bmp Jeśli to polecenie nie wyświetla niczego na ekranie, oznacza to, że pliki rzeczywiście są identyczne (ważne: niektóre programy, np. Photoshop, dołączają zera na końcach niektórych VMP. Nasza wersja kopii je odrzuca, więc nie rób tego) martw się, jeśli w przypadku kopiowania innych plików BMP, które pobrałeś lub utworzyłeś do testów, kopia będzie o kilka bajtów mniejsza niż oryginał). Możesz otworzyć oba pliki w przeglądarce obrazów Ristretto (kliknij dwukrotnie), aby potwierdzić to wizualnie. Ale diff porównuje bajt po bajcie, więc jej wzrok jest ostrzejszy niż twój! Jak powstała ta kopia? Okazuje się, że copy.c jest powiązany z bmp.h. Upewnijmy się: otwórz bmp.h. Zobaczysz tam rzeczywiste definicje nagłówków, o których już wspominaliśmy, zaadaptowane z własnych implementacji Microsoftu. Dodatkowo plik ten definiuje typy danych BYTE, DWORD, LONG i WORD, które są typami danych zwykle spotykanymi w świecie programowania Win32 (tj. Windows). Zauważ, że są to zasadniczo aliasy dla prymitywów, które (miejmy nadzieję) już znasz. Okazuje się, że BITMAPFILEHEADER i BITMAPINFOHEADER używały tych typów. Ten plik definiuje również strukturę o nazwie RGBTRIPLE. „Hermetyzuje” trzy bajty: jeden niebieski, jeden zielony i jeden czerwony (w tej kolejności będziemy szukać trójek RGB na dysku). W jaki sposób te struktury są przydatne? Podsumowując, plik to po prostu sekwencja bajtów (lub ostatecznie bitów) na dysku. Jednak te bajty są zazwyczaj uporządkowane w taki sposób, że kilka pierwszych reprezentuje coś, następnie kilka następnych reprezentuje coś innego i tak dalej. „Formaty” plików istnieją, ponieważ mamy standardy lub reguły definiujące, co oznaczają bajty. Teraz możemy po prostu wczytać plik z dysku do pamięci RAM jako jedną dużą tablicę bajtów. I pamiętamy, że bajt na pozycji [i] reprezentuje jedno, natomiast bajt na pozycji [j] oznacza coś innego. Ale dlaczego nie nadać niektórym z tych bajtów nazw, abyśmy mogli łatwiej odzyskać je z pamięci? Właśnie w tym pomagają nam struktury w bmp.h. Zamiast myśleć o pliku jako o jednej długiej sekwencji bajtów, widzimy go podzielonego na bardziej zrozumiałe bloki – sekwencje struktur. Przypomnijmy, że plik Smiley.bmp ma rozdzielczość 8x8 pikseli, więc zajmuje na dysku 14 + 40 + (8 × 8) × 3 = 246 bajtów (możesz to sprawdzić za pomocą polecenia ls). Według Microsoftu tak to wygląda na dysku: Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 10Widzimy, że kolejność ma znaczenie, jeśli chodzi o elementy struktur. Bajt 57 to rgbtBlue (nie, powiedzmy, rgbtRed), ponieważ rgbtBlue jest najpierw zdefiniowany w RGBTRIPLE. Nawiasem mówiąc, użycie przez nas atrybutu spakowanego zapewnia, że ​​clang nie będzie próbował „wyrównać słów” elementów (adres pierwszego bajtu każdego elementu będzie wielokrotnością 4), dzięki czemu nie skończy się to dziurami w naszych struktur, które w ogóle nie istnieją na dysku. Przejdźmy dalej. Znajdź adresy URL pasujące do BITMAPFILEHEADER i BITMAPINFOHEADER, zgodnie z komentarzami w bmp.h. Uwaga, świetny moment: zaczynasz korzystać z MSDN (Microsoft Developer Network)! Zamiast przewijać dalej copy.c , odpowiedz na kilka pytań, aby zrozumieć, jak działa kod. Jak zawsze, twoim prawdziwym przyjacielem jest polecenie man, a teraz także MSDN. Jeśli nie znasz odpowiedzi, wpisz w Google i pomyśl. Możesz także zapoznać się z plikiem stdio.h pod adresem https://reference.cs50.net/.
  1. Ustaw punkt przerwania w głównym (klikając po lewej stronie linijki z numerami linii głównych).

  2. Na karcie terminala przejdź do ~/workspace/pset4/bmp i skompiluj plik copy.c do programu kopiującego za pomocą make.

  3. Uruchom debug50 copy Smiley.bmp copy.bmp , otworzy to panel debugera po prawej stronie.

  4. Przejdź przez program krok po kroku korzystając z panelu po prawej stronie. Uwaga bf i bi . W pliku ~/workspace/pset4/questions.txt odpowiedz na pytania:

  • Co to jest stdint.h ?

  • Jaki jest sens używania uint8_t , uint32_t , int32_t i uint16_t w programie?

  • Ile bajtów zawierają odpowiednio BYTE , DWORD , LONG i WORD (zakładając architekturę 32-bitową)?

  • Jakie powinny być pierwsze dwa bajty pliku BMP (ASCII, dziesiętny czy szesnastkowy)? (bajty początkowe, które służą do identyfikacji formatu pliku (z dużym prawdopodobieństwem) nazywane są często „liczbami magicznymi”).
  • Jaka jest różnica między bfSize i biSize?

  • Co oznacza ujemna wartość biHeight?

  • Które pole w BITMAPINFOHEADER definiuje głębię kolorów w BMP (tj. bity na piksel)?

  • Dlaczego funkcja fopen może zwrócić NULL w copy.c 37?

  • Dlaczego trzeci argument fread w naszym kodzie jest równy 1?

  • Jaka wartość w copy.c 70 definiuje dopełnienie, jeśli bi.biWidth wynosi 3?

  • Co robi fseek?

  • Co to jest SEEK_CUR?

Wracając do pana Boddy'ego. Ćwiczenia:

Napisz program o nazwie whodunit w pliku o nazwie whodunit.c , który będzie wyświetlał rysunek pana Boddy'ego. Hmmmm, co? Podobnie jak kopia, program musi przyjmować dokładnie dwa argumenty wiersza poleceń i jeśli uruchomisz program w sposób pokazany poniżej, wynik zostanie zapisany w pliku verdict.bmp, w którym rysunek pana Boddy'ego nie będzie zaszumiony. ./whodunit clue.bmp verdict.b Sugerujemy, abyś zaczął rozwiązywać tę zagadkę, uruchamiając poniższe polecenie. cp copy.c whodunit.c Możesz być zaskoczony, ile linii kodu musisz napisać, aby pomóc panu Boddy. W Smiley.bmp nie ma nic niepotrzebnego , więc możesz przetestować program na tym pliku. Jest mały i możesz porównać wyniki swojego programu z wynikami xxd podczas programowania (a może jest coś ukrytego w pliku Smiley.bmp ? Właściwie nie). Nawiasem mówiąc, problem ten można rozwiązać na różne sposoby. Kiedy już zidentyfikujesz rysunek pana Boddy'ego, będzie on spokojny. Ponieważ whodunit można zaimplementować na wiele sposobów, nie będziesz w stanie sprawdzić poprawności implementacji za pomocą check50 . I niech to zepsuje ci zabawę, ale rozwiązanie asystentów również nie jest dostępne w przypadku problemu kryminału . Na koniec w pliku In ~/workspace/pset4/questions.txt odpowiedz na następujące pytanie: Whodunit? //ктоэтосделал?

Zmień rozmiar

Cóż, teraz - następny test! Napiszmy program o nazwie resize w pliku resize.c . Zmieni rozmiar nieskompresowanego 24-bitowego obrazu BMP w krokach co n. Twoja aplikacja musi akceptować dokładnie trzy argumenty wiersza poleceń, przy czym pierwszy (n) jest liczbą całkowitą nie większą niż 100, drugi to nazwa pliku, który będzie modyfikowany, a trzeci to nazwa zapisanej wersji zmodyfikowanego plik. Usage: ./resize n infile outfile Za pomocą takiego programu moglibyśmy utworzyć duży.bmp z małego.bmp, zmieniając jego rozmiar o 4 (tj. mnożąc szerokość i wysokość przez 4), jak pokazano poniżej. ./resize 4 small.bmp large.bmp Dla uproszczenia możesz rozpocząć zadanie, kopiując ponownie plik copy.c i nadając mu nazwę resize.c . Ale najpierw zadaj sobie pytanie i odpowiedz na te pytania: co oznacza zmiana rozmiaru BMP (możesz założyć, że n-krotność rozmiaru pliku nie przekroczy 232 - 1) . Określ, które pola w BITMAPFILEHEADER i BITMAPINFOHEADER należy zmienić. Zastanów się, czy chcesz dodać, czy usunąć pola linii skanowania . I tak, bądź wdzięczny, że nie prosimy Cię o rozważenie wszystkich możliwych wartości n od 0 do 1! (chociaż, jeśli jesteś zainteresowany, jest to problem z książki hakerskiej ;)). Zakładamy jednak, że dla n = 1 program będzie działał poprawnie, a plik wyjściowy będzie miał taki sam rozmiar jak oryginalny plik wejściowy. Chcesz sprawdzić program za pomocą check50? Wpisz następujące polecenie: check50 2015.fall.pset4.resize bmp.h resize.c Chcesz pobawić się implementacją aplikacji wykonaną przez asystentów CS50? Uruchom następujące polecenie: ~cs50/pset4/resize Cóż, jeśli chcesz zobaczyć na przykład nagłówki Large.bmp (w bardziej przyjaznej dla użytkownika formie niż pozwala na to xxd), musisz uruchomić następujące polecenie: ~cs50/pset4/peek large.bmp Jeszcze lepiej, jeśli chcesz porównać swoje nagłówki z nagłówkami plików asystenta CS50. Możesz uruchamiać polecenia w katalogu ~/workspace/pset4/bmp (zastanów się, co robi każde polecenie). Jeśli użyłeś malloc , pamiętaj, aby użyć darmowego , aby zapobiec wyciekom pamięci. Spróbuj użyć valgrind , aby sprawdzić, czy nie ma wycieków. ./resize 4 small.bmp student.bmp
~cs50/pset4/resize 4 small.bmp staff.bmp
~cs50/pset4/peek student.bmp staff.bmp

Jak zdecydować?

  • Otwórz plik, który musimy powiększyć, a także utwórz i otwórz nowy plik, w którym zostanie zapisany powiększony obraz;

  • zaktualizować informacje nagłówka pliku wyjściowego. Ponieważ nasz obraz jest w formacie BMP i zmieniamy jego rozmiar, musimy zapisać nagłówek nowego pliku z nowymi wymiarami. Co się zmieni? Rozmiar pliku, a także rozmiar obrazu - jego szerokość i wysokość.

Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 11Jeśli spojrzymy na opis nagłówka, zobaczymy zmienną biSizeImage . Wskazuje całkowity rozmiar obrazu w bajtach, biWidth to szerokość obrazu minus wyrównanie, biHeight to wysokość. Zmienne te znajdują się w strukturach BITMAPFILEHEADER i BITMAPINFOHEADER. Można je znaleźć otwierając plik bmp.h. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 12Opis struktury BITMAPINFOHEADER zawiera listę zmiennych. Aby zapisać tytuł pliku wyjściowego, należy zmienić wartości wysokości i szerokości. Ale istnieje również szansa, że ​​później będziesz potrzebować oryginalnej wysokości i szerokości oryginalnego pliku. Dlatego lepiej zachować oba. Uważaj na nazwy zmiennych, aby przypadkowo nie zapisać błędnych danych w nagłówku pliku wyjściowego.
  • Czytamy wychodzący plik linia po linii, piksel po pikselu. Aby to zrobić, ponownie skorzystamy z naszej biblioteki plików I/O i funkcji fread. Pobiera wskaźnik do struktury, która będzie zawierać odczytane bajty, rozmiar pojedynczego elementu, który będziemy czytać, liczbę takich elementów oraz wskaźnik do pliku, z którego będziemy czytać.

    Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 13
  • Zwiększamy każdą linię poziomo zgodnie z określoną skalą i zapisujemy wynik do pliku wyjściowego.

    Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 14

    Jak piszemy pliki? Mamy funkcję fwrite, do której przekazujemy wskaźnik do struktury, w której znajdują się dane do zapisania do pliku, wielkość elementu, ich liczbę oraz wskaźnik do pliku wyjściowego. Do uporządkowania pętli możemy użyć znanej nam już pętli for .

    Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 15
  • Wypełnić luki! Jeśli liczba pikseli w linii nie jest wielokrotnością czterech, musimy dodać „wyrównanie” - zero bajtów. Będziemy potrzebować wzoru do obliczenia rozmiaru wyrównania. Aby zapisać bajty zerowe w pliku wyjściowym, możesz użyć funkcji fputc, przekazując jej znak, który chcesz zapisać, oraz wskaźnik do pliku wyjściowego.

    Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 16

    Teraz, gdy rozciągnęliśmy ciąg w poziomie i dodaliśmy wyrównanie do pliku wyjściowego, musimy przesunąć bieżącą pozycję w pliku wyjściowym, ponieważ musimy przeskoczyć wyrównanie.

    Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 17
  • Zwiększ rozmiar w pionie. To bardziej skomplikowane, ale możemy użyć przykładowego kodu z copy.c (copy.c otwiera plik wyjściowy, zapisuje nagłówek do pliku wyjściowego, odczytuje obraz z pliku źródłowego linia po linii, piksel po pikselu i zapisuje je do pliku wyjściowego). Na tej podstawie pierwszą rzeczą, którą możesz zrobić, to uruchomić następujące polecenie: cp copy.c resize.c

    Rozciągnięcie obrazu w pionie oznacza kilkukrotne skopiowanie każdej linii. Można to zrobić na kilka różnych sposobów. Na przykład przy użyciu przepisywania, gdy zapisujemy wszystkie piksele jednej linii w pamięci i zapisujemy tę linię do pliku wyjściowego w pętli tyle razy, ile potrzeba. Inną metodą jest ponowne kopiowanie: po wczytaniu linii z pliku wychodzącego, zapisaniu jej do pliku wyjściowego i wyrównaniu, funkcja fseek wraca na początek linii w pliku wychodzącym i powtarza wszystko jeszcze kilka razy.

    Harvard CS50: Zadania w tygodniu 4 (wykłady 9 i 10) – 18
  • odzyskiwać

    W oczekiwaniu na publikację problemową z tygodnia 4. ostatnie kilka dni spędziłem na przeglądaniu zdjęć zapisanych moim aparatem cyfrowym w formacie JPEG na karcie pamięci CompactFlash (CF) o pojemności 1 GB. Proszę, nie mów mi, że zamiast tego spędziłem ostatnie kilka dni na Facebooku. Niestety moje umiejętności obsługi komputera pozostawiają wiele do życzenia i nieświadomie przez przypadek usunęłam wszystkie zdjęcia! Na szczęście w świecie komputerów „usunięty” zwykle nie oznacza „zabity”. Mój komputer twierdzi, że karta pamięci jest teraz pusta, ale wiem, że kłamie. Zadanie: Napisz program w ~/workspace/pset4/jpg/recover.c, który odzyska te zdjęcia. Hmmm. OK, oto jeszcze jedno wyjaśnienie. Chociaż format JPEG jest bardziej złożony niż BMP, JPEG zawiera „podpisy”, czyli wzorce bajtów, które pomagają odróżnić go od innych formatów plików. Większość plików JPEG zaczyna się od następujących trzech bajtów: 0xff 0xd8 0xff Od pierwszego do trzeciego bajtu, od lewej do prawej. Czwarty bajt będzie najprawdopodobniej jedną z następujących kombinacji: 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,0xe8, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef. Innymi słowy, pierwsze cztery bity czwartego bajtu pliku JPEG to 1110. Jest prawdopodobne, że jeśli znajdziesz jeden z tych wzorów na dysku, na którym przechowywane były zdjęcia (np. na mojej karcie pamięci), będzie to początek pliku JPEG. Oczywiście możesz natknąć się na to, na którym dysku, wyłącznie przez przypadek; odzyskiwania danych nie można nazwać nauką ścisłą.

    Jak zdecydować

    1. Otwórz plik z zawartością karty pamięci.

    2. Znajdź początek pliku JPEG. Wszystkie pliki na tej karcie są obrazami w formacie JPEG.

    O znacznikach JPEG już wiesz: Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 19ważne (i miłe) jest wiedzieć, że każdy plik JPEG jest przechowywany w pamięci jako pojedynczy blok, a same pliki następują jeden po drugim. Narysujmy schematyczną mapę pamięci. Każdy prostokąt to blok o długości 512 bajtów. Szare prostokąty to obszary, w których nie ma plików JPEG; gwiazdki wskazują początek pliku JPEG. Uważamy, że nie mamy szarych bloków pomiędzy plikami. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 20Jak odczytać te dane, te 512 bajtów, aby porównać ich początek z nagłówkiem JPEG? Możemy skorzystać ze znanej nam już funkcji fread, która pobiera wskaźnik do struktury danych, w której zostaną zapisane czytane bajty, a także rozmiar odczytywanego elementu, liczbę takich elementów oraz wskaźnik do pliku, z którego odczytujemy dane. Harvard CS50: Zadania z czwartego tygodnia (wykłady 9 i 10) – 21Chcemy odczytać 512 bajtów i zapisać je w buforze. Będzie to wskaźnik &data, a wskaźnik inptr wskaże otwarty plik z zawartością karty pamięci. Wróćmy zatem do struktury naszego pliku, w którym zapisujemy
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION