JavaRush /Java Blog /Random-IT /Harvard CS50: Compiti della settimana 4 (lezioni 9 e 10)
Masha
Livello 41

Harvard CS50: Compiti della settimana 4 (lezioni 9 e 10)

Pubblicato nel gruppo Random-IT
Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 1

Preparazione per il lavoro

Come sempre, prima apri una finestra di terminale ed esegui il comando. update50 per assicurarti che la tua applicazione sia già aggiornata. Prima di iniziare, segui questo cd ~ / workspace wget http://cdn.cs50.net/2015/fall/psets/4/pset4/pset4.zip per scaricare un archivio ZIP di questa attività. Ora se esegui ls vedrai che hai un file chiamato pset4.zip nella tua directory ~/workspace . Estrailo utilizzando il comando: Se esegui unzip pset4.zip nuovamente il comando ls , vedrai che è apparsa un'altra directory. Ora puoi eliminare il file zip come mostrato di seguito: rm -f pset4.zip Apriamo la directory pset4 cd pset4 , eseguiamo ls e assicuriamoci che la directory contenga bmp / jpg / questions.txt

whodunit o "Chi ha fatto questo?"

Se hai mai visto il desktop predefinito di Windows XP (https://en.wikipedia.org/wiki/Bliss_(image)) (colline e cielo blu), allora hai visto BMP. Nelle pagine web, molto probabilmente hai visto le GIF. Hai guardato le foto digitali? Quindi, abbiamo avuto la gioia di vedere JPEG. Se hai mai fatto uno screenshot su un Mac, molto probabilmente hai visto un PNG. Leggi su Internet i formati BMP, GIF, JPEG, PNG e rispondi a queste domande:
  1. Quanti colori supporta ciascun formato?

  2. Quale formato supporta l'animazione?

  3. Qual è la differenza tra compressione con perdita e senza perdita?

  4. Quale di questi formati utilizza la compressione con perdita?

A chi parla inglese si consiglia di fare riferimento all'articolo del MIT . Se lo studi (o trovi altre risorse su Internet sull'archiviazione di file su dischi e file system), puoi rispondere alle seguenti domande:
  1. Cosa succede dal punto di vista tecnico quando un file viene eliminato in un file system FAT?

  2. Cosa si può fare per garantire (con un'alta probabilità) che i file cancellati non possano essere recuperati?

E ora passiamo alla nostra storia, che sfocia dolcemente nel primo compito della quarta settimana. Benvenuti a Palazzo Tudor! Il proprietario della tenuta, il signor John Boddy, ci ha improvvisamente lasciato, vittima di un oscuro gioco. Per scoprire cosa è successo, devi definire whodunit . Sfortunatamente per te (anche se ancora più sfortunatamente per Mr. Boddy), l'unica prova che hai è il file BMP a 24 bit indizio.bmp . È il suo contenuto che vedi di seguito. Il signor Boddy è riuscito a crearlo e salvarlo sul suo computer nei suoi ultimi istanti. Il file contiene un'immagine di giallo nascosta tra il rumore rosso . Ora devi lavorare sulla soluzione come un vero specialista tecnico. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 2Ma prima, alcune informazioni. Probabilmente è più semplice pensare a un'immagine come a una griglia di pixel (punti, cioè), ciascuno dei quali può avere un colore specifico. Per impostare il colore di un punto in un'immagine in bianco e nero, abbiamo bisogno di 1 bit. 0 può rappresentare il nero e 1 può rappresentare il bianco come mostrato nell'immagine qui sotto. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 3Quindi, le immagini rappresentate in questo modo sono semplicemente una mappa di bit (bitmap o bitmap, come si dice in inglese o slang). Con il bianco e nero tutto è il più semplice possibile, ma per ottenere immagini a colori abbiamo solo bisogno di più bit per pixel. Un formato file (come GIF) che supporta il "colore a 8 bit" utilizza 8 bit per pixel. Un formato file (ad esempio BMP, JPG, PNG) che supporta il "colore a 24 bit" utilizza 24 bit per pixel (BMP supporta effettivamente colori a 1, 4, 8, 16, 24 e 32 bit) . Nel BMP a 24 bit utilizzato da Mr. Boddy, sono necessari 8 bit per indicare la quantità di rosso, la stessa quantità per il verde e ancora 8 bit per indicare la quantità di blu in ciascun pixel. Se hai mai sentito parlare di colori RGB , è proprio questo (R=rosso, G=verde, B=blu). Se i valori R, G e B di alcuni pixel in BMP sono, ad esempio, 0xff, 0x00 e 0x00 in formato esadecimale, allora il pixel sarà rosso puro, poiché 0xff (altrimenti noto come 255 in decimale) significa "molto rosso " in quel momento 0x00 e 0x00 significano rispettivamente "nessun verde" e "blu anche zeri". Dato come ci appare rossa l'immagine BMP del signor Boddy, è intuitivo che il "compartimento" rosso abbia un valore chiaramente maggiore rispetto ai "compartimenti" rosso e blu. Tuttavia, non tutti i pixel sono rossi; alcuni sono chiaramente di colore diverso. A proposito, in HTML e CSS (il linguaggio di markup e i fogli di stile che lo aiutano, utilizzati per creare pagine web), i modelli di colore sono disposti allo stesso modo. Se interessato, controlla il link: https://ru.wikipedia.org/wiki/Colors_HTMLper ulteriori dettagli. Ora affrontiamo il problema in modo più tecnico. Ricordiamo che un file è semplicemente una sequenza di bit disposti in un certo ordine. Un file BMP a 24 bit è una sequenza di bit, ogni 24 dei quali (beh, quasi) determinano il colore di quale pixel. Oltre ai dati sul colore, un file BMP contiene anche metadati, ovvero informazioni sulla larghezza e sull'altezza dell'immagine. Questi metadati vengono memorizzati all'inizio del file sotto forma di due strutture dati comunemente chiamate "header" (da non confondere con i file header C). La prima di queste intestazioni è BITMAPFILEHEADER, che è lunga 14 byte (o 14*8 bit). La seconda intestazione è BITMAPINFOHEADER (lunga 40 byte). Dopo queste intestazioni c'è la bitmap: un array di byte, le cui triplette rappresentano il colore del pixel (1, 4 e 16 bit in BMP, ma non 24 o 32, hanno un'intestazione aggiuntiva subito dopo BITMAPINFOHEADER. Si chiama l'array RGBQUAD, che definisce il "valore di intensità" per ciascuno dei colori nella tavolozza). Tuttavia, BMP memorizza queste triplette al contrario (potremmo dire come BGR), con 8 bit per il blu, 8 bit per il verde e 8 bit per il rosso. A proposito, alcuni BMP memorizzano anche l'intera bitmap al contrario, a partire dalla riga superiore dell'immagine alla fine del file BMP. Nel nostro compito, abbiamo salvato la VMR come descritto qui, prima la riga superiore dell'immagine, poi quelle inferiori. In altre parole, abbiamo trasformato un emoji a un bit in uno a 24 bit sostituendo il nero con il rosso. Un BMP a 24 bit memorizzerà questa bitmap, dove 0000ff rappresenta il rosso e ffffff rappresenta il bianco; abbiamo evidenziato in rosso tutte le istanze di 0000ff. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 4Poiché abbiamo presentato questi frammenti da sinistra a destra, dall'alto al basso, puoi vedere la faccina rossa in queste lettere se ti allontani leggermente dal monitor. Ricordiamo che una cifra nel sistema numerico esadecimale rappresenta 4 bit. Di conseguenza, ffffff in esadecimale significa in realtà 1111111111111111111111111 in binario. Ora rallenta e non andare oltre finché non sei sicuro di aver capito perché 0000ff rappresenta un pixel rosso in un file BMP a 24 bit. Nella finestra IDE CS50, espandere (ad esempio, facendo clic sul piccolo triangolo) la cartella pset4 e in essa - bmp . In questa cartella troverai smiley.bmp , fai doppio clic sul file e lì troverai una piccola faccina da 8x8 pixel. Nel menu a discesa, modifica la scala dell'immagine, diciamo dal 100% al 400%, questo ti permetterà di vedere una versione più grande, ma allo stesso tempo più “sfocata” dell'emoticon. Anche se in realtà questa stessa immagine non dovrebbe risultare sfocata anche se ingrandita. È solo che l'IDE CS50 sta cercando di farti un favore (nello stile della serie CIA) uniformando l'immagine (sfocando visivamente i bordi). Ecco come apparirà la nostra faccina se la ingrandiamo senza smussare: Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 5I pixel si sono trasformati in grandi quadrati. Continuiamo. Nel terminale vai a ~/workspace/pset4/bmp . Pensiamo che tu ricordi già come farlo. Esaminiamo i byte allocati in smiley.bmp . Questo può essere fatto utilizzando l'editor esadecimale della riga di comando, il programma xxd . Per eseguirlo, esegui il comando: xxd -c 24 -g 3 -s 54 smiley.bmp Dovresti vedere quanto mostrato di seguito; Abbiamo nuovamente evidenziato in rosso tutte le istanze di 0000ff. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 6Nell'immagine nella colonna più a sinistra puoi vedere gli indirizzi nel file, che equivalgono all'offset dal primo byte del file. Tutti sono indicati nel sistema numerico esadecimale. Se convertiamo l'esadecimale 00000036 in decimale, otteniamo 54. Quindi stai guardando il 54esimo byte di smiley.bmp . Ricordiamo che nei file BMP a 24 bit, i primi 14 + 40 = 54 byte sono pieni di metadati. Quindi, se vuoi vedere i metadati, esegui il seguente comando: xxd -c 24 -g 3 smiley.bmp Se smiley.bmp contiene caratteri ASCII , li vedremo nella colonna più a destra in xxd invece di tutti quei punti. Quindi, lo smiley è un BMP a 24 bit (ogni pixel è rappresentato da 24 ÷ 8 = 3 byte) con una dimensione (risoluzione) di 8x8 pixel. Ogni riga (o "Scanline" come viene chiamata) occupa quindi (8 pixel) x (3 byte per pixel) = 24 byte. Questo numero è un multiplo di quattro e questo è importante perché il file BMP viene memorizzato in modo leggermente diverso se il numero di byte nella riga non è un multiplo di quattro. Quindi, in small.bmp, un altro file BMP a 24 bit nella nostra cartella, puoi vedere un riquadro verde di 3x3 pixel. Se lo apri in un visualizzatore di immagini, vedrai che assomiglia all'immagine mostrata sotto, solo di dimensioni più piccole. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 7Ogni riga in small.bmp occupa quindi (3 pixel) × (3 byte per pixel) = 9 byte, che non è un multiplo di 4. Per ottenere una lunghezza di riga che sia multiplo di 4, viene riempita con zeri aggiuntivi: tra 0 e 3 byte riempiamo ogni riga in formato BMP a 24 bit (puoi indovinare perché?). Per small.bmp , sono necessari 3 byte di zeri, poiché (3 pixel) x (3 byte per pixel) + (3 byte di riempimento) = 12 byte, che in realtà è un multiplo di 4. Per "vedere" questo riempimento, Fai quanto segue. xxd -c 12 -g 3 -s 54 small.bmp Tieni presente che utilizziamo un valore diverso per -c rispetto a smiley.bmp , quindi xxd questa volta restituisce solo 4 colonne (3 per il quadrato verde e 1 per il riempimento). Per chiarezza, abbiamo evidenziato tutte le istanze di 00ff00 in verde. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 8Per contrasto, utilizziamo xxd per il file large.bmp . Sembra esattamente uguale a small.bmp, solo la sua risoluzione è 12x12 pixel, cioè quattro volte più grande. Esegui il comando seguente. Potrebbe essere necessario espandere la finestra per evitare il trasferimento. xxd -c 36 -g 3 -s 54 large.bmp Vedrai qualcosa del genere: Harvard CS50: Compiti della settimana 4 (lezioni 9 e 10) - 9Nota: non ci sono digressioni in questo BMP! Dopotutto, (12 pixel) × (3 byte per pixel) = 36 byte, e questo è un multiplo di 4. L'editor esadecimale xxd ci ha mostrato i byte nei nostri file BMP. Come possiamo ottenerli a livello di programmazione? In copy.c c'è un programma il cui unico scopo nella vita è creare una copia del BMP, pezzo per pezzo. Sì, puoi usare cp per questo . Tuttavia, CP non sarà in grado di aiutare il signor Boddy. Speriamo che copy.c faccia questo, quindi eccoci qui: ./copy smiley.bmp copy.bmp se ora esegui ls (con il flag appropriato), vedrai che smiley.bmp e copy.bmp hanno effettivamente la stessa dimensione. Controlliamo ancora se questo è effettivamente vero? diff smiley.bmp copy.bmp Se questo comando non visualizza nulla sullo schermo, significa che i file sono effettivamente identici (importante: alcuni programmi, come Photoshop, includono zeri finali alla fine di alcuni VMP. La nostra versione di copia li scarta, quindi non farlo preoccupatevi se, copiando altri BMP che avete scaricato o creato per testare, la copia sarà di qualche byte più piccola dell'originale). È possibile aprire entrambi i file nel visualizzatore di immagini di Ristretto (fare doppio clic) per confermarlo visivamente. Ma diff fa questo confronto byte per byte, quindi la sua visione è più nitida della tua! Come è stata creata questa copia? Si scopre che copy.c è correlato a bmp.h . Assicuriamoci: apri bmp.h. Lì vedrai le definizioni effettive delle intestazioni che abbiamo già menzionato, adattate dalle implementazioni di Microsoft. Inoltre, questo file definisce i tipi di dati BYTE, DWORD, LONG e WORD, che sono i tipi di dati tipicamente presenti nel mondo della programmazione Win32 (ovvero Windows). Nota che questi sono essenzialmente alias per primitive con cui (si spera) hai già familiarità. Risulta che BITMAPFILEHEADER e BITMAPINFOHEADER utilizzavano questi tipi. Questo file definisce anche una struttura chiamata RGBTRIPLE. Esso “incapsula” tre byte: uno blu, uno verde e uno rosso (questo è l'ordine in cui cercheremo le triplette RGB sul disco). In che modo sono utili queste strutture? Per ricapitolare, un file è semplicemente una sequenza di byte (o, in ultima analisi, bit) sul disco. Tuttavia, questi byte vengono generalmente ordinati in modo che i primi rappresentino qualcosa, i successivi rappresentino qualcos'altro e così via. I "formati" dei file esistono perché abbiamo standard, o regole, che definiscono cosa significano i byte. Ora possiamo semplicemente leggere il file dal disco alla RAM come un grande array di byte. E ricordiamo che il byte in posizione [i] rappresenta una cosa, mentre il byte in posizione [j] è un'altra cosa. Ma perché non dare un nome ad alcuni di questi byte in modo da poterli recuperare più facilmente dalla memoria? Questo è esattamente ciò in cui ci aiutano le strutture in bmp.h. Invece di pensare a un file come a una lunga sequenza di byte, lo vediamo suddiviso in blocchi più comprensibili: sequenze di strutture. Ricordiamo che smiley.bmp ha una risoluzione di 8x8 pixel, quindi occupa 14 + 40 + (8 × 8) × 3 = 246 byte su disco (puoi verificarlo utilizzando il comando ls). Ecco come appare sul disco secondo Microsoft: Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 10Possiamo vedere che l'ordine è importante quando si tratta di membri di strutture. Il byte 57 è rgbtBlue (non, ad esempio, rgbtRed) perché rgbtBlue è definito prima in RGBTRIPLE. A proposito, il nostro utilizzo dell'attributo imballato garantisce che clang non tenti di "allineare a parola" i membri (con l'indirizzo del primo byte di ciascun membro che è un multiplo di 4), in modo da non ritrovarci con buchi le nostre strutture che non esistono affatto sul disco. Andiamo avanti. Trova gli URL che corrispondono a BITMAPFILEHEADER e BITMAPINFOHEADER, come indicato nei commenti in bmp.h. Attenzione, ottimo momento: stai iniziando a utilizzare MSDN (Microsoft Developer Network)! Invece di scorrere ulteriormente copy.c , rispondi ad alcune domande per capire come funziona il codice. Come sempre, il comando man è il tuo vero amico, e ora anche MSDN. Se non conosci le risposte, cerca su Google e pensaci. È anche possibile fare riferimento al file stdio.h su https://reference.cs50.net/.
  1. Imposta un punto di interruzione nella riga principale (facendo clic a sinistra del righello con i numeri della riga principale).

  2. In una scheda del terminale , vai su ~/workspace/pset4/bmp e compila copy.c nel programma di copia utilizzando make.

  3. Esegui debug50 copy smiley.bmp copy.bmp , questo aprirà il pannello del debugger sulla destra.

  4. Segui il programma passo dopo passo utilizzando il pannello a destra. Nota bf e bi . In ~/workspace/pset4/questions.txt , rispondi alle domande:

  • Cos'è stdint.h ?

  • Qual è lo scopo di utilizzare uint8_t , uint32_t , int32_t e uint16_t in un programma?

  • Quanti byte contengono rispettivamente BYTE , DWORD , LONG e WORD (presupponendo un'architettura a 32 bit)?

  • Quali (ASCII, decimale o esadecimale) dovrebbero essere i primi due byte di un file BMP? (i byte iniziali, utilizzati per identificare il formato del file (con alta probabilità) sono spesso chiamati "numeri magici").
  • Qual è la differenza tra bfSize e biSize?

  • Cosa significa una biHeight negativa?

  • Quale campo in BITMAPINFOHEADER definisce la profondità del colore in BMP (ovvero bit per pixel)?

  • Perché la funzione fopen può restituire NULL in copy.c 37?

  • Perché il terzo argomento di fread nel nostro codice è uguale a 1?

  • Quale valore in copy.c 70 definisce il riempimento se bi.biWidth è 3?

  • Cosa fa fseek?

  • Cos'è SEEK_CUR?

Torniamo al signor Boddy. Esercizio:

Scrivi un programma chiamato whodunit in un file chiamato whodunit.c che mostri il disegno di Mr. Boddy. Hmmmm, cosa? Come per la copia, il programma deve accettare esattamente due argomenti della riga di comando e, se esegui il programma come mostrato di seguito, il risultato verrà memorizzato in verdict.bmp, in cui il disegno di Mr. Boddy non sarà rumoroso. ./whodunit clue.bmp verdict.b Ti suggeriamo di iniziare a risolvere questo mistero eseguendo il comando seguente. cp copy.c whodunit.c Potresti rimanere stupito da quante righe di codice devi scrivere per aiutare il signor Boddy. Non c'è nulla di inutile nascosto in smiley.bmp , quindi sentiti libero di testare il programma su questo file. È piccolo e puoi confrontare l'output del tuo programma e l'output di xxd durante lo sviluppo (o forse c'è qualcosa nascosto in smiley.bmp ? In realtà no). A proposito, questo problema può essere risolto in diversi modi. Una volta identificato il disegno del signor Boddy, riposerà in pace. Poiché whodunit può essere implementato in più modi, non sarai in grado di verificare la correttezza delle implementazioni con check50 . E lascia che ti rovini il divertimento, ma anche per il problema del giallo non è disponibile la soluzione degli assistenti . Infine, nel file In ~/workspace/pset4/questions.txt , rispondi alla seguente domanda: Whodunit? //ктоэтосделал?

ridimensionare

Bene, ora - il prossimo test! Scriviamo un programma chiamato resize in resize.c . Ridimensionerà un'immagine BMP a 24 bit non compressa in passaggi di n. L'applicazione deve accettare esattamente tre argomenti della riga di comando, di cui il primo (n) è un numero intero non maggiore di 100, il secondo è il nome del file che verrà modificato e il terzo è il nome della versione salvata del file modificato. file. Usage: ./resize n infile outfile Con un programma del genere, potremmo creare large.bmp da small.bmp ridimensionando quest'ultimo di 4 (ovvero moltiplicando sia la larghezza che l'altezza per 4), come mostrato di seguito. ./resize 4 small.bmp large.bmp Per semplicità, puoi avviare l'attività copiando nuovamente copy.c e nominando la copia resize.c . Ma prima chiediti e rispondi a queste domande: cosa significa modificare la dimensione BMP (puoi supporre che n volte la dimensione del file non superi 232 - 1) . Determina quali campi in BITMAPFILEHEADER e BITMAPINFOHEADER devi modificare. Valuta se è necessario aggiungere o rimuovere i campi delle linee di scansione . E sì, sii grato che non ti stiamo chiedendo di considerare tutti i possibili valori di n da 0 a 1! (anche se, se sei interessato, questo è un problema tratto dal libro di un hacker ;)). Tuttavia, assumiamo che per n = 1 il programma funzionerà correttamente e il file di output outfile avrà le stesse dimensioni dell'infile originale. Vuoi controllare il programma utilizzando check50? Digita il seguente comando: check50 2015.fall.pset4.resize bmp.h resize.c Vuoi giocare con l'implementazione dell'applicazione fatta dagli assistenti CS50? Esegui quanto segue: ~cs50/pset4/resize Bene, se vuoi vedere, ad esempio, le intestazioni large.bmp (in una forma più user-friendly rispetto a quella consentita da xxd), devi eseguire il seguente comando: ~cs50/pset4/peek large.bmp Ancora meglio, se vuoi confrontare i tuoi headers con le intestazioni dei file dell'assistente CS50. Puoi eseguire comandi nella directory ~/workspace/pset4/bmp (pensa a cosa fa ciascun comando). Se hai utilizzato malloc , assicurati di utilizzare free per evitare perdite di memoria. Prova a utilizzare valgrind per verificare la presenza di perdite. ./resize 4 small.bmp student.bmp
~cs50/pset4/resize 4 small.bmp staff.bmp
~cs50/pset4/peek student.bmp staff.bmp

Come decidere?

  • Apriamo il file che dobbiamo ingrandire e creiamo e apriamo anche un nuovo file in cui verrà registrata l'immagine ingrandita;

  • aggiornare le informazioni sull'intestazione per il file di output. Dato che la nostra immagine è in formato BMP e ne stiamo modificando le dimensioni, dobbiamo scrivere l'intestazione del nuovo file con le nuove dimensioni. Cosa cambierà? La dimensione del file, così come la dimensione dell'immagine: larghezza e altezza.

Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 11Se guardiamo la descrizione dell'intestazione, vedremo la variabile biSizeImage . Indica la dimensione totale dell'immagine in byte, biWidth è la larghezza dell'immagine meno l'allineamento, biHeight è l'altezza. Queste variabili si trovano nelle strutture BITMAPFILEHEADER e BITMAPINFOHEADER. Puoi trovarli se apri il file bmp.h. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 12La descrizione della struttura BITMAPINFOHEADER contiene un elenco di variabili. Per scrivere il titolo del file di output, dovrai modificare i valori di altezza e larghezza. Ma c'è anche la possibilità che in seguito avrai bisogno dell'altezza e della larghezza originali del file originale. Pertanto è meglio mantenerli entrambi. Fai attenzione ai nomi delle variabili in modo da non scrivere accidentalmente dati errati nell'intestazione del file di output.
  • Leggiamo il file in uscita, riga per riga, pixel per pixel. Per fare ciò, ci rivolgiamo nuovamente alla nostra libreria I/O di file e alla funzione fread. Ci vuole un puntatore ad una struttura che conterrà i byte letti, la dimensione del singolo elemento che andremo a leggere, il numero di tali elementi, ed un puntatore al file da cui leggeremo.

    Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 13
  • Aumentiamo ogni riga orizzontalmente in base alla scala specificata e scriviamo il risultato nel file di output.

    Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 14

    Come scriviamo i file? Abbiamo una funzione fwrite, alla quale passiamo un indicatore alla struttura in cui si trovano i dati da scrivere nel file, la dimensione degli elementi, il loro numero e un puntatore al file di output. Per organizzare il ciclo possiamo utilizzare il ciclo for che già conosciamo .

    Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 15
  • Riempi gli spazi vuoti! Se il numero di pixel in una riga non è multiplo di quattro, dobbiamo aggiungere "allineamento" - zero byte. Avremo bisogno di una formula per calcolare la dimensione dell'allineamento. Per scrivere byte nulli su un file di output, puoi utilizzare la funzione fputc, passandole il carattere che vuoi scrivere e un puntatore al file di output.

    Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 16

    Ora che abbiamo allungato la corda orizzontalmente e aggiunto un allineamento al file di output, dobbiamo spostare la posizione corrente nel file di output perché dobbiamo saltare oltre l'allineamento.

    Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 17
  • Aumenta la dimensione verticale. È più complicato, ma possiamo usare il codice di esempio da copy.c (copy.c apre il file di output, scrive un'intestazione nel file di output, legge l'immagine dal file sorgente riga per riga, pixel per pixel, e la scrive al file di output). Sulla base di ciò, la prima cosa che puoi fare è eseguire il seguente comando: cp copy.c resize.c

    Allungare verticalmente un'immagine significa copiare ogni riga più volte. Esistono diversi modi per farlo. Ad esempio, utilizzando la riscrittura, quando salviamo tutti i pixel di una riga in memoria e scriviamo questa riga nel file di output in un ciclo tutte le volte necessarie. Un altro metodo è la ricopia: dopo aver letto una riga dal file in uscita, averla scritta nel file di output e averla allineata, riportare la funzione fseek all'inizio della riga nel file in uscita e ripetere tutto più volte.

    Harvard CS50: Compiti della settimana 4 (lezioni 9 e 10) - 18
  • recuperare

    In previsione del documento problematico della settimana 4, ho passato gli ultimi giorni a guardare le foto salvate in formato JPEG dalla mia fotocamera digitale su una scheda di memoria CompactFlash (CF) da 1 GB. Per favore, non dirmi che in realtà ho passato gli ultimi giorni invece su Facebook. Purtroppo le mie competenze informatiche lasciano molto a desiderare e, senza saperlo, ho cancellato per sbaglio tutte le foto! Fortunatamente, nel mondo dei computer, "eliminato" di solito non equivale a "ucciso". Il mio computer insiste sul fatto che la scheda di memoria ora è vuota, ma so che sta mentendo. Compito: scrivere un programma in ~/workspace/pset4/jpg/recover.c che recupererà queste foto. Hmm. Ok, ecco un altro chiarimento. Sebbene il formato JPEG sia più complesso del BMP, il formato JPEG è dotato di "firme", ovvero schemi di byte che aiutano a distinguerlo da altri formati di file. La maggior parte dei file JPEG iniziano con i seguenti tre byte: 0xff 0xd8 0xff dal primo byte al terzo, da sinistra a destra. Il quarto byte sarà molto probabilmente una delle seguenti combinazioni: 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,0xe8, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef. In altre parole, i primi quattro bit del quarto byte di un file JPEG sono 1110. È probabile che, se trovi uno di questi modelli sull'unità in cui sono state archiviate le foto (come la mia scheda di memoria), questo sarà l'inizio del file JPEG. Naturalmente, potresti riscontrare questo su quale disco per puro caso; il recupero dei dati non può essere definito una scienza esatta.

    Come decidere

    1. Apri il file con il contenuto della memory card.

    2. Trova l'inizio del file JPEG. Tutti i file su questa scheda sono immagini in formato JPEG.

    Conosci già i marcatori JPEG: Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 19è importante (e bello) sapere che ogni file JPEG viene archiviato in memoria come un singolo blocco e che i file stessi si susseguono uno dopo l'altro. Disegniamo una mappa schematica della memoria. Ogni rettangolo è un blocco lungo 512 byte. I rettangoli grigi sono aree in cui non sono presenti file JPEG; gli asterischi indicano l'inizio del file JPEG. Riteniamo di non avere blocchi grigi tra i file. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 20Come leggiamo questi dati, questi 512 byte, per confrontarne l'inizio con l'intestazione JPEG? Possiamo utilizzare la funzione fread , a noi già familiare, che prende un puntatore alla struttura dati in cui verranno scritti i byte letti, nonché la dimensione dell'elemento che viene letto, il numero di tali elementi e un puntatore al file da cui stiamo leggendo i dati. Harvard CS50: Compiti della quarta settimana (lezioni 9 e 10) - 21Vogliamo leggere 512 byte e memorizzarli in un buffer. Questo sarà il puntatore &data e il puntatore inptr punterà al file aperto con il contenuto della scheda di memoria. Torniamo quindi alla struttura del nostro file in cui salviamo
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION