JavaRush /จาวาบล็อก /Random-TH /Harvard CS50: การบ้านสัปดาห์ที่ 4 (การบรรยายที่ 9 และ 10)...
Masha
ระดับ

Harvard CS50: การบ้านสัปดาห์ที่ 4 (การบรรยายที่ 9 และ 10)

เผยแพร่ในกลุ่ม
Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 1

การเตรียมงาน

เช่นเคย ก่อนอื่นให้เปิดหน้าต่างเทอร์มินัลแล้วรันคำสั่ง update50 เพื่อให้แน่ใจว่าใบสมัครของคุณเป็นข้อมูลล่าสุดอยู่แล้ว ก่อนที่คุณจะเริ่มต้น ให้ปฏิบัติตามสิ่งนี้ cd ~ / workspace wget http://cdn.cs50.net/2015/fall/psets/4/pset4/pset4.zip เพื่อดาวน์โหลดไฟล์ ZIP ของงานนี้ ตอนนี้ถ้าคุณรันls คุณ จะเห็นว่ามีไฟล์ชื่อpset4.zipอยู่ใน ไดเร็กทอรี ~/workspace ของคุณ แยกออกโดยใช้คำสั่ง: หากคุณรันคำสั่ง lsunzip pset4.zip อีกครั้งคุณจะเห็นว่ามีไดเร็กทอรีอื่นปรากฏขึ้น ตอนนี้คุณสามารถลบไฟล์ zip ได้ตามที่แสดงด้านล่าง: มาเปิด ไดเร็กทอรี pset4 รันlsและตรวจสอบให้แน่ใจว่าไดเร็กทอรีมี rm -f pset4.zip cd pset4bmp / jpg / questions.txt

whodunit หรือ "ใครทำสิ่งนี้"

หากคุณเคยเห็นเดสก์ท็อป Windows XP เริ่มต้น (https://en.wikipedia.org/wiki/Bliss_(image)) (เนินเขาและท้องฟ้าสีคราม) แสดงว่าคุณเคยเห็น BMP แล้ว บนหน้าเว็บ คุณน่าจะเคยเห็น GIF มาก่อน คุณเคยดูภาพถ่ายดิจิทัลหรือไม่? ดังนั้นเราจึงมีความสุขที่ได้เห็น JPEG หากคุณเคยจับภาพหน้าจอบน Mac คุณน่าจะเคยเห็น PNG อ่านบนอินเทอร์เน็ตเกี่ยวกับรูปแบบ BMP, GIF, JPEG, PNG และตอบคำถามเหล่านี้:
  1. แต่ละรูปแบบรองรับกี่สี?

  2. รูปแบบใดที่รองรับแอนิเมชั่น?

  3. การบีบอัดแบบ lossy และ lossless แตกต่างกันอย่างไร?

  4. รูปแบบใดต่อไปนี้ใช้การบีบอัดแบบสูญเสียข้อมูล

ผู้ที่พูดภาษา อังกฤษควรอ่านบทความจากMIT หากคุณศึกษา (หรือค้นหาแหล่งข้อมูลอื่นบนอินเทอร์เน็ตเกี่ยวกับการจัดเก็บไฟล์บนดิสก์และระบบไฟล์) คุณสามารถตอบคำถามต่อไปนี้:
  1. จะเกิดอะไรขึ้นจากมุมมองทางเทคนิคเมื่อไฟล์ถูกลบในระบบไฟล์ FAT

  2. สิ่งที่สามารถทำได้เพื่อให้แน่ใจว่า (มีความเป็นไปได้สูง) ว่าไฟล์ที่ถูกลบไม่สามารถกู้คืนได้?

และตอนนี้ - มาถึงเรื่องราวของเราซึ่งไหลเข้าสู่งานแรกของสัปดาห์ที่สี่อย่างราบรื่น ยินดีต้อนรับสู่คฤหาสน์ทูดอร์! คุณจอห์น บอดดี้ เจ้าของอสังหาริมทรัพย์ จู่ๆ ก็ทิ้งเราไป โดยตกเป็นเหยื่อของเกมที่ไม่ชัดเจน หากต้องการทราบว่าเกิดอะไรขึ้น คุณต้องกำหนดwhodunit น่าเสียดายสำหรับคุณ (แต่น่าเสียดายยิ่งกว่านั้นสำหรับ Mr. Boddy) หลักฐานเดียวที่คุณมีคือไฟล์ BMP 24 บิตclue.bmp เป็นเนื้อหาที่คุณเห็นด้านล่าง คุณ Boddy สามารถสร้างและบันทึกมันลงในคอมพิวเตอร์ของเขาในช่วงเวลาสุดท้ายของเขา ไฟล์นี้มี ภาพ หน่วยสืบสวน ที่ซ่อนอยู่ท่ามกลางสัญญาณรบกวนสี แดง ตอนนี้คุณต้องทำงานเกี่ยวกับโซลูชันเหมือนผู้เชี่ยวชาญด้านเทคนิคจริงๆ Harvard CS50: การมอบหมายงานสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 2แต่ก่อนอื่นข้อมูลบางอย่าง อาจเป็นวิธีที่ง่ายที่สุดที่จะคิดว่ารูปภาพเป็นตารางพิกเซล (นั่นคือจุด) ซึ่งแต่ละภาพสามารถเป็นสีเฉพาะได้ ในการตั้งค่าสีของจุดในภาพขาวดำ เราจำเป็นต้องมี 1 บิต 0 แทนสีดำได้ และ 1 แทนสีขาวได้ ดังภาพด้านล่าง Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 3ดังนั้น รูปภาพที่แสดงในลักษณะนี้จึงเป็นเพียงแผนผังของบิต (บิตแมปหรือบิตแมป ตามที่กล่าวไว้ในภาษาอังกฤษหรือคำสแลง) เมื่อใช้ขาวดำ ทุกอย่างจะเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ แต่เพื่อให้ได้ภาพสี เราแค่ต้องการบิตต่อพิกเซลเพิ่มขึ้น รูปแบบไฟล์ (เช่น GIF) ที่รองรับ "สี 8 บิต" จะใช้ 8 บิตต่อพิกเซล รูปแบบไฟล์ (เช่น BMP, JPG, PNG) ที่รองรับ "สี 24 บิต" จะใช้ 24 บิตต่อพิกเซล (จริงๆ แล้ว BMP รองรับสี 1-, 4-, 8-, 16-, 24- และ 32 บิต) . ใน BMP 24 บิตที่ Mr. Boddy ใช้ จะใช้เวลา 8 บิตเพื่อระบุปริมาณสีแดง จำนวนเท่ากันสำหรับสีเขียว และอีกครั้ง 8 บิตเพื่อระบุปริมาณสีน้ำเงินในแต่ละพิกเซล หากคุณเคยได้ยินเกี่ยวกับ สี RGBนี่คือสีนั้น (R=แดง, G=เขียว, B=น้ำเงิน) หากค่า R, G และ B ของพิกเซลบางพิกเซลใน BMP คือ 0xff, 0x00 และ 0x00 ในรูปแบบเลขฐานสิบหก พิกเซลดังกล่าวจะเป็นสีแดงล้วน เนื่องจาก 0xff (หรือเรียกอีกอย่างว่า 255 ในรูปทศนิยม) หมายถึง "สีแดงจำนวนมาก " ในขณะนั้น 0x00 และ 0x00 หมายถึง "ไม่มีสีเขียว" และ "สีน้ำเงินยังเป็นศูนย์" ตามลำดับ เมื่อพิจารณาว่าภาพ BMP ของ Mr. Boddy สีแดงปรากฏต่อเราเพียงใด จึงเป็นเรื่องง่ายที่ "ช่อง" สีแดงจะมีค่ามากกว่า "ช่อง" สีแดงและสีน้ำเงินอย่างชัดเจน อย่างไรก็ตาม ไม่ใช่ว่าทุกพิกเซลจะเป็นสีแดง บางพิกเซลก็มีสีที่แตกต่างกันอย่างชัดเจน อย่างไรก็ตามใน HTML และ CSS (ภาษามาร์กอัปและสไตล์ชีตที่ช่วยซึ่งใช้ในการสร้างหน้าเว็บ) โมเดลสีจะถูกจัดเรียงในลักษณะเดียวกัน หากสนใจลองดูลิงค์: https://ru.wikipedia.org/wiki/Colors_HTMLสำหรับรายละเอียดเพิ่มเติม ตอนนี้เรามาดูปัญหาทางเทคนิคกันดีกว่า โปรดจำไว้ว่าไฟล์เป็นเพียงลำดับของบิตที่จัดเรียงตามลำดับบางอย่าง ไฟล์ BMP 24 บิตคือลำดับของบิต ซึ่งทุกๆ 24 บิต (เกือบ) จะเป็นตัวกำหนดสีของพิกเซล นอกจากข้อมูลสีแล้ว ไฟล์ BMP ยังมีข้อมูลเมตา - ข้อมูลเกี่ยวกับความกว้างและความสูงของรูปภาพ ข้อมูลเมตานี้ถูกเก็บไว้ที่จุดเริ่มต้นของไฟล์ในรูปแบบของโครงสร้างข้อมูลสองโครงสร้างที่เรียกกันทั่วไปว่า "ส่วนหัว" (เพื่อไม่ให้สับสนกับไฟล์ส่วนหัว C) ส่วนหัวแรกของเหล่านี้คือ BITMAPFILEHEADER ซึ่งมีความยาว 14 ไบต์ (หรือ 14*8 บิต) ส่วนหัวที่สองคือ BITMAPINFOHEADER (ยาว 40 ไบต์) หลังจากส่วนหัวเหล่านี้มาบิตแมป: อาร์เรย์ของไบต์, แฝดสามซึ่งแสดงถึงสีของพิกเซล (1, 4 และ 16 บิตใน BMP แต่ไม่ใช่ 24 หรือ 32 พวกเขามีส่วนหัวเพิ่มเติมหลังจาก BITMAPINFOHEADER เรียกว่า อาร์เรย์ RGBQUAD ซึ่งกำหนด "ค่าความเข้ม" สำหรับแต่ละสีในจานสี) อย่างไรก็ตาม BMP จะจัดเก็บแฝดสามเหล่านี้ในแบบย้อนกลับ (เราอาจพูดได้เช่น BGR) โดยมี 8 บิตสำหรับสีน้ำเงิน 8 บิตสำหรับสีเขียว และ 8 บิตสำหรับสีแดง อย่างไรก็ตาม BMP บางตัวยังจัดเก็บบิตแมปทั้งหมดไปข้างหลัง โดยเริ่มจากบรรทัดบนสุดของรูปภาพที่ส่วนท้ายของไฟล์ BMP ในงานของเรา เราได้บันทึก VMR ตามที่อธิบายไว้ที่นี่ แถวบนสุดของรูปภาพก่อน จากนั้นจึงบันทึกแถวล่างสุด กล่าวอีกนัยหนึ่ง เราเปลี่ยนอีโมจิหนึ่งบิตให้เป็นอีโมจิ 24 บิตโดยแทนที่สีดำด้วยสีแดง BMP 24 บิตจะจัดเก็บบิตแมปนี้ โดยที่ 0000ff แทนสีแดง และ ffffff แทนสีขาว เราได้เน้นอินสแตนซ์ทั้งหมดของ 0000ff เป็นสีแดง Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 4เนื่องจากเรานำเสนอบิตเหล่านี้จากซ้ายไปขวา จากบนลงล่าง คุณสามารถเห็นหน้ายิ้มสีแดงในตัวอักษรเหล่านี้ได้หากคุณขยับออกห่างจากจอภาพเล็กน้อย โปรดจำไว้ว่าตัวเลขในระบบเลขฐานสิบหกแทน 4 บิต ดังนั้น ffffff ในเลขฐานสิบหกจึงหมายถึง 11111111111111111111111111 ในไบนารี่ ตอนนี้ ช้าลงหน่อย และอย่าไปไกลกว่านั้นจนกว่าคุณจะแน่ใจว่าคุณเข้าใจว่าทำไม 0000ff ถึงแสดงพิกเซลสีแดงในไฟล์ BMP 24 บิต ในหน้าต่าง CS50 IDE ให้ขยาย (เช่นโดยคลิกที่สามเหลี่ยมเล็ก ๆ ) โฟลเดอร์ pset4และในนั้น - bmp . ในโฟลเดอร์นี้ คุณจะพบsmiley.bmpดับเบิลคลิกที่ไฟล์ และคุณจะพบสไมลี่เล็กๆ ขนาด 8x8 พิกเซลอยู่ที่นั่น ในเมนูแบบเลื่อนลง ให้เปลี่ยนขนาดภาพ เช่น จาก 100% เป็น 400% ซึ่งจะช่วยให้คุณเห็นอิโมติคอนเวอร์ชันที่ใหญ่ขึ้น แต่ในขณะเดียวกันก็ "เบลอ" มากขึ้น แม้ว่าในความเป็นจริงภาพเดียวกันนี้ไม่ควรเบลอแม้ว่าจะขยายใหญ่ก็ตาม เป็นเพียงว่า CS50 IDE พยายามช่วยเหลือคุณ (ในรูปแบบของซีรีส์ CIA) โดยการปรับภาพให้เรียบ (เบลอขอบด้วยสายตา) สไมลี่ของเราจะมีลักษณะเช่นนี้หากเราขยายมันโดยไม่ทำให้เรียบ: Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 5พิกเซลกลายเป็นสี่เหลี่ยมขนาดใหญ่ มาต่อกันเลย ในเทอร์มินัลไปที่~/workspace/pset4/ bmp เราคิดว่าคุณจำวิธีการทำเช่นนี้ได้แล้ว มาตรวจสอบไบต์ที่จัดสรรในsmiley.bmp ซึ่งสามารถทำได้โดยใช้โปรแกรมแก้ไขฐานสิบหกบรรทัดคำสั่งโปรแกรมxxd หากต้องการเรียกใช้ให้รันคำสั่ง: xxd -c 24 -g 3 -s 54 smiley.bmp คุณควรเห็นสิ่งที่แสดงด้านล่าง เราได้เน้นสีแดงอีกครั้งทุกกรณีของ 0000ff Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 6ในรูปภาพในคอลัมน์ซ้ายสุด คุณจะเห็นที่อยู่ในไฟล์ ซึ่งเทียบเท่ากับออฟเซ็ตจากไบต์แรกของไฟล์ ทั้งหมดถูกกำหนดไว้ในระบบเลขฐานสิบหก ถ้าเราแปลงเลข ฐานสิบหก 00000036 เป็นทศนิยม เราจะได้ 54 ดังนั้นคุณกำลังดูไบต์ที่ 54 จากsmiley.bmp โปรดจำไว้ว่าในไฟล์ BMP 24 บิต 14 + 40 = 54 ไบต์แรกจะถูกเติมด้วยข้อมูลเมตา ดังนั้นหากคุณต้องการดูข้อมูลเมตา ให้รันคำสั่งต่อไปนี้: xxd -c 24 -g 3 smiley.bmp หากsmiley.bmpมีอักขระ ASCIIเราจะเห็นอักขระเหล่านั้นในคอลัมน์ขวาสุดในหน่วย xxd แทนที่จะเป็นจุดทั้งหมด ดังนั้น สไมลี่จึงเป็น BMP 24 บิต (แต่ละพิกเซลแทนด้วย 24 ÷ 8 = 3 ไบต์) โดยมีขนาด (ความละเอียด) 8x8 พิกเซล แต่ละบรรทัด (หรือ "สแกนไลน์" ตามที่เรียกว่า) จึงใช้ (8 พิกเซล) x (3 ไบต์ต่อพิกเซล) = 24 ไบต์ จำนวนนี้คือผลคูณของสี่ และเป็นสิ่งสำคัญเนื่องจากไฟล์ BMP จะถูกจัดเก็บแตกต่างออกไปเล็กน้อยหากจำนวนไบต์ในบรรทัดไม่ใช่ผลคูณของสี่ ดังนั้น ใน Small.bmp ซึ่งเป็นไฟล์ BMP 24 บิตอีกไฟล์ในโฟลเดอร์ของเรา คุณจะเห็นกล่องพิกเซลสีเขียวขนาด 3x3 หากคุณเปิดมันในโปรแกรมดูรูปภาพ คุณจะเห็นว่ามันคล้ายกับภาพที่แสดงด้านล่าง แต่มีขนาดเล็กกว่าเท่านั้น Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 7แต่ละบรรทัดในsmall.bmpจึงใช้พื้นที่ (3 พิกเซล) × (3 ไบต์ต่อพิกเซล) = 9 ไบต์ ซึ่งไม่ใช่ผลคูณของ 4 หากต้องการรับความยาวของบรรทัดที่เป็นผลคูณของ 4 บรรทัดนั้นจะถูกเติมด้วยศูนย์เพิ่มเติม: ระหว่าง 0 ถึง 3 ไบต์ เราเติมแต่ละบรรทัดในรูปแบบ BMP 24 บิต (คุณเดาได้ไหมว่าทำไมถึงเป็นเช่นนั้น) สำหรับsmall.bmpจำเป็นต้องมีศูนย์ 3 ไบต์ เนื่องจาก (3 พิกเซล) x (3 ไบต์ต่อพิกเซล) + (ช่องว่างภายใน 3 ไบต์) = 12 ไบต์ ซึ่งก็คือผลคูณของ 4 จริงๆ หากต้องการ "ดู" ช่องว่างภายในนี้ ทำสิ่งต่อไปนี้ xxd -c 12 -g 3 -s 54 small.bmp โปรดทราบว่าเราใช้ค่าที่แตกต่างกันสำหรับ-cมากกว่ากับsmiley.bmpดังนั้น xxd จึงส่งออกเพียง 4 คอลัมน์ในครั้งนี้ (3 สำหรับสี่เหลี่ยมสีเขียวและ 1 สำหรับช่องว่างภายใน) เพื่อความชัดเจน เราได้เน้นอินสแตนซ์ทั้งหมดของ 00ff00 เป็นสีเขียว Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 8ในทางตรงกันข้าม ลองใช้ xxd สำหรับไฟล์large.bmp มันดูเหมือนกับsmall.bmp ทุกประการมีเพียงความละเอียดเท่านั้นคือ 12x12 พิกเซล ซึ่งก็คือใหญ่กว่าสี่เท่า รันคำสั่งด้านล่าง คุณอาจต้องขยายหน้าต่างเพื่อหลีกเลี่ยงการถ่ายโอน xxd -c 36 -g 3 -s 54 large.bmp คุณจะเห็นข้อความดังนี้: Harvard CS50: การบ้านสัปดาห์ที่ 4 (การบรรยายที่ 9 และ 10) - 9โปรดทราบว่า BMP นี้ไม่มีการถดถอย! ท้ายที่สุดแล้ว (12 พิกเซล) × (3 ไบต์ต่อพิกเซล) = 36 ไบต์ และนี่คือผลคูณของ 4 โปรแกรมแก้ไข xxd hex แสดงจำนวนไบต์ในไฟล์ BMP ของเรา เราจะรับพวกมันโดยทางโปรแกรมได้อย่างไร? ในcopy.cมีโปรแกรมหนึ่งที่มีวัตถุประสงค์ในชีวิตเพียงอย่างเดียวคือการสร้างสำเนาของ BMP ทีละชิ้น ใช่ คุณสามารถใช้cp สำหรับสิ่ง นี้ อย่างไรก็ตามซีพีไม่สามารถช่วยเหลือคุณบอดดี้ได้ หวังว่าcopy.cจะทำสิ่งนี้ ลุยเลย: ./copy smiley.bmp copy.bmp หากคุณเรียกใช้ls (ด้วยแฟล็กที่เหมาะสม) คุณจะเห็นว่าsmiley.bmpและcopy.bmpมีขนาดเท่ากันจริงๆ มาตรวจสอบอีกครั้งว่าจริงหรือไม่? diff smiley.bmp copy.bmp หากคำสั่งนี้ไม่แสดงสิ่งใดบนหน้าจอ แสดงว่าไฟล์นั้นเหมือนกันทุกประการ (สำคัญ: บางโปรแกรม เช่น Photoshop มีเลขศูนย์ต่อท้ายที่ส่วนท้ายของ VMP บางรายการ เวอร์ชันสำเนาของเราจะละทิ้งมัน ดังนั้นอย่า กังวลว่าในกรณีที่คัดลอก BMP อื่นๆ ที่คุณดาวน์โหลดหรือสร้างขึ้นเพื่อการทดสอบ สำเนาจะมีขนาดเล็กกว่าต้นฉบับสองสามไบต์) คุณสามารถเปิดทั้งสองไฟล์ในโปรแกรมดูรูปภาพของ Ristretto (ดับเบิลคลิก) เพื่อยืนยันสิ่งนี้ด้วยสายตา แต่การเปรียบเทียบนี้ต่างกันทีละไบต์ ดังนั้นการมองเห็นของเธอจึงคมชัดกว่าของคุณ! สำเนานี้ถูกสร้างขึ้นมาอย่างไร? ปรากฎว่าcopy.c เกี่ยวข้องกับbmp.h มาตรวจสอบให้แน่ใจกัน: เปิดbmp.h. คุณจะเห็นคำจำกัดความที่แท้จริงของส่วนหัวที่เราได้กล่าวไปแล้ว ซึ่งดัดแปลงมาจากการใช้งานของ Microsoft นอกจากนี้ ไฟล์นี้ยังกำหนดประเภทข้อมูล BYTE, DWORD, LONG และ WORD ซึ่งเป็นประเภทข้อมูลที่พบโดยทั่วไปในโลกของการเขียนโปรแกรม Win32 (เช่น Windows) โปรดทราบว่าสิ่งเหล่านี้เป็นนามแฝงโดยพื้นฐานสำหรับคำดั้งเดิมที่คุณ (หวังว่า) คุ้นเคยอยู่แล้ว ปรากฎว่า BITMAPFILEHEADER และ BITMAPINFOHEADER กำลังใช้ประเภทเหล่านี้ ไฟล์นี้ยังกำหนดโครงสร้างที่เรียกว่า RGBTRIPLE มัน "ห่อหุ้ม" สามไบต์: หนึ่งสีน้ำเงิน, หนึ่งสีเขียวและหนึ่งสีแดง (นี่คือลำดับที่เราจะค้นหา RGB triplets บนดิสก์) โครงสร้างเหล่านี้มีประโยชน์อย่างไร? สรุป ไฟล์เป็นเพียงลำดับของไบต์ (หรือบิตสุดท้าย) บนดิสก์ อย่างไรก็ตาม โดยปกติแล้วไบต์เหล่านี้จะถูกเรียงลำดับเพื่อให้สองสามไบต์แรกแทนบางสิ่ง จากนั้นสองสามไบต์ถัดไปแทนสิ่งอื่น และอื่นๆ ไฟล์ "รูปแบบ" มีอยู่เพราะเรามีมาตรฐานหรือกฎเกณฑ์ที่กำหนดว่าไบต์หมายถึงอะไร ตอนนี้เราสามารถอ่านไฟล์จากดิสก์ลงใน RAM ในรูปแบบอาร์เรย์ไบต์ขนาดใหญ่ได้ และเราจำได้ว่าไบต์ที่ตำแหน่ง [i] เป็นตัวแทนสิ่งหนึ่ง ในขณะที่ไบต์ที่ตำแหน่ง [j] เป็นอย่างอื่น แต่ทำไมไม่ระบุชื่อไบต์เหล่านี้บางส่วนเพื่อให้เราสามารถดึงข้อมูลจากหน่วยความจำได้ง่ายขึ้น นี่คือสิ่งที่โครงสร้างใน bmp.h ช่วยเราจริงๆ แทนที่จะคิดว่าไฟล์เป็นลำดับไบต์ยาวๆ ลำดับเดียว เราจะเห็นว่าไฟล์แบ่งออกเป็นบล็อกที่เข้าใจได้มากขึ้น นั่นก็คือ ลำดับของโครงสร้าง จำได้ว่าsmiley.bmpมีความละเอียด 8x8 พิกเซล ดังนั้นจึงใช้พื้นที่ 14 + 40 + (8 × 8) × 3 = 246 ไบต์บนดิสก์ (คุณสามารถตรวจสอบได้โดยใช้คำสั่ง ls) ต่อไปนี้คือลักษณะที่ปรากฏบนดิสก์ตามข้อมูลของ Microsoft: Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 10เราจะเห็นว่าลำดับนั้นมีความสำคัญเมื่อพูดถึงสมาชิกของโครงสร้าง ไบต์ 57 คือ rgbtBlue (ไม่ใช่พูด rgbtRed) เนื่องจาก rgbtBlue ถูกกำหนดไว้ใน RGBTRIPLE ก่อน อย่างไรก็ตาม การใช้แอ็ตทริบิวต์ที่แพ็คของเราทำให้มั่นใจได้ว่าเสียงดังกราวจะไม่พยายาม "จัดเรียงคำ" สมาชิก (โดยที่อยู่ของไบต์แรกของสมาชิกแต่ละคนเป็นผลคูณของ 4) เพื่อที่เราจะได้ไม่จบลงด้วยช่องโหว่ใน โครงสร้างของเราที่ไม่มีอยู่บนดิสก์เลย เดินหน้าต่อไป ค้นหา URL ที่ตรงกับ BITMAPFILEHEADER และ BITMAPINFOHEADER ตามความคิดเห็นใน bmp.h โปรดทราบ ช่วงเวลาที่ยอดเยี่ยม: คุณเริ่มใช้ MSDN (Microsoft Developer Network)! แทนที่จะเลื่อนดูผ่านcopy.c เพิ่มเติม ให้ตอบคำถามสองสามข้อเพื่อทำความเข้าใจวิธีการทำงานของโค้ด เช่นเคย คำสั่ง man คือเพื่อนแท้ของคุณ และตอนนี้ก็รวมถึง MSDN ด้วย ถ้าไม่รู้คำตอบก็ Google แล้วลองคิดดู คุณยังสามารถอ้างถึงไฟล์ stdio.h ได้ที่ https://reference.cs50.net/
  1. ตั้งค่าเบรกพอยต์ใน main (โดยคลิกทางด้านซ้ายของไม้บรรทัดที่มีหมายเลขบรรทัดหลัก)

  2. ในแท็ เทอร์มินัล ให้ไปที่~/workspace/pset4/bmpและคอมไพล์ copy.c ลงในโปรแกรมคัดลอกโดยใช้ make

  3. เรียกใช้debug50 copy smiley.bmp copy.bmpซึ่งจะเปิดแผงดีบักเกอร์ทางด้านขวา

  4. เดินผ่านโปรแกรมทีละขั้นตอนโดยใช้แผงทางด้านขวา หมายเหตุbfและbi _ ใน~/workspace/pset4/questions.txtให้ตอบคำถาม:

  • stdint.hคืออะไร?

  • จุดประสงค์ของการใช้uint8_t , uint32_t , int32_tและuint16_tในโปรแกรมคืออะไร?

  • BYTE , DWORD , LONGและWORD มี กี่ไบต์ตามลำดับ (สมมติว่าสถาปัตยกรรม 32 บิต)

  • สองไบต์แรกของไฟล์ BMP ควรเป็นอย่างไร (ASCII, ทศนิยมหรือฐานสิบหก) (ไบต์นำซึ่งใช้ในการระบุรูปแบบไฟล์ (ที่มีความน่าจะเป็นสูง) มักเรียกว่า "ตัวเลขมหัศจรรย์")
  • bfSize และ biSize แตกต่างกันอย่างไร

  • BiHeight ที่เป็นลบหมายถึงอะไร

  • ฟิลด์ใดใน BITMAPINFOHEADER กำหนดความลึกของสีใน BMP (เช่น บิตต่อพิกเซล)

  • เหตุใดฟังก์ชัน fopen จึงสามารถส่งคืน NULL ใน copy.c 37 ได้

  • เหตุใดอาร์กิวเมนต์ที่สามที่ต้องอ่านในโค้ดของเราจึงเท่ากับ 1

  • ค่าใดใน copy.c 70 กำหนดช่องว่างภายในถ้า bi.biWidth คือ 3

  • fseek ทำอะไร?

  • SEEK_CUR คืออะไร?

กลับไปหาคุณบ๊อดดี้ ออกกำลังกาย:

เขียนโปรแกรมชื่อwhodunitในไฟล์ชื่อwhodunit.cที่แสดงภาพวาดของ Mr. Boddy อืม อะไรนะ? เช่นเดียวกับการคัดลอก โปรแกรมจะต้องรับอาร์กิวเมนต์บรรทัดคำสั่งสองตัวพอดี และหากคุณรันโปรแกรมตามที่แสดงด้านล่าง ผลลัพธ์จะถูกเก็บไว้ใน verdict.bmp ซึ่งรูปวาดของ Mr. Boddy จะไม่ส่งเสียงดัง ./whodunit clue.bmp verdict.b เราขอแนะนำให้คุณเริ่มไขปริศนานี้ด้วยการรันคำสั่งด้านล่าง cp copy.c whodunit.c คุณอาจประหลาดใจกับจำนวนโค้ดที่คุณต้องเขียนเพื่อช่วย Mr. Boddy ไม่มีอะไรที่ไม่จำเป็นซ่อนอยู่ ในsmiley.bmpดังนั้นอย่าลังเลที่จะทดสอบโปรแกรมในไฟล์นี้ มันมีขนาดเล็ก และคุณสามารถเปรียบเทียบผลลัพธ์ของโปรแกรมของคุณกับผลลัพธ์ของ xxd ในระหว่างการพัฒนาได้ (หรืออาจมีบางอย่างซ่อนอยู่ในsmiley.bmpจริง ๆ แล้วไม่มี) อย่างไรก็ตามปัญหานี้สามารถแก้ไขได้หลายวิธี เมื่อคุณระบุภาพวาดของคุณบอดดี้ได้แล้ว เขาจะพักผ่อนอย่างสงบ เนื่องจากwhodunitสามารถนำไปใช้ได้หลายวิธี คุณจะไม่สามารถตรวจสอบความถูกต้องของการใช้งานด้วยcheck50ได้ และปล่อยให้มันเสียความ สนุกของคุณ แต่วิธีแก้ปัญหาของผู้ช่วยก็ไม่สามารถใช้ได้สำหรับ ปัญหา การสืบสวน สุดท้ายนี้ ในไฟล์In ~/workspace/pset4/questions.txtให้ตอบคำถามต่อไปนี้: Whodunit? //ктоэтосделал?

ปรับขนาด

ตอนนี้ - การทดสอบครั้งต่อไป! มาเขียนโปรแกรมชื่อ resizeใน resize.c กันดีกว่า มันจะปรับขนาดอิมเมจ BMP 24 บิตที่ไม่มีการบีบอัดในขั้นตอนที่ n แอปพลิเคชันของคุณต้องยอมรับอาร์กิวเมนต์บรรทัดคำสั่งสามรายการเท่านั้น โดยอาร์กิวเมนต์แรก (n) เป็นจำนวนเต็มไม่เกิน 100 อาร์กิวเมนต์ที่สองเป็นชื่อของไฟล์ที่จะได้รับการแก้ไข และตัวที่สามเป็นชื่อของเวอร์ชันที่บันทึกไว้ของเวอร์ชันแก้ไข ไฟล์. Usage: ./resize n infile outfile ด้วยโปรแกรมดังกล่าว เราสามารถสร้าง large.bmp จาก small.bmp โดยการปรับขนาดอันหลังด้วย 4 (เช่น คูณทั้งความกว้างและความสูงด้วย 4) ดังที่แสดงด้านล่าง เพื่อความง่าย คุณสามารถเริ่มงานได้ด้วยการคัดลอก copy.c./resize 4 small.bmp large.bmp อีกครั้งและตั้งชื่อสำเนาresize.c แต่ก่อนอื่น ให้ถามตัวเองและตอบคำถามเหล่านี้: การเปลี่ยนขนาด BMP หมายความว่าอย่างไร (คุณสามารถสรุปได้ว่า n คูณขนาดไฟล์จะไม่เกิน 232 - 1 ) กำหนดเขตข้อมูลใน BITMAPFILEHEADER และ BITMAPINFOHEADER ที่คุณต้องการเปลี่ยนแปลง พิจารณาว่าคุณจำเป็นต้องเพิ่มหรือลบฟิลด์scanlines และใช่ จงขอบคุณที่เราไม่ได้ขอให้คุณพิจารณาค่าที่เป็นไปได้ทั้งหมดของ n จาก 0 ถึง 1! (แม้ว่าหากคุณสนใจ นี่เป็นปัญหาจากหนังสือของแฮ็กเกอร์ ;)) อย่างไรก็ตาม เราถือว่าสำหรับ n = 1 โปรแกรมจะทำงานได้อย่างถูกต้อง และoutfile ของไฟล์เอาต์พุต จะมีขนาดเท่ากับ infile ดั้งเดิม คุณต้องการตรวจสอบโปรแกรมโดยใช้ check50 หรือไม่? พิมพ์คำสั่งต่อไปนี้: check50 2015.fall.pset4.resize bmp.h resize.c คุณต้องการเล่นกับการใช้งานแอปพลิเคชันที่สร้างโดยผู้ช่วย CS50 หรือไม่? เรียกใช้สิ่งต่อไปนี้: หากคุณต้องการดูส่วนหัว large.bmp ~cs50/pset4/resize เช่น(ในรูปแบบที่ใช้งานง่ายกว่าที่ xxd อนุญาต) คุณต้องเรียกใช้คำสั่งต่อไปนี้: ดียิ่งขึ้นถ้าคุณต้องการเปรียบเทียบของคุณ ส่วนหัวที่มีส่วนหัวของไฟล์ผู้ช่วย CS50 คุณสามารถรันคำสั่งภายใน ไดเร็กทอรี ~/workspace/pset4/bmp ของคุณ ได้ (ลองนึกถึงว่าแต่ละคำสั่งทำอะไรได้บ้าง) หากคุณใช้ mallocต้องแน่ใจว่าใช้ freeเพื่อป้องกันหน่วยความจำรั่ว ลองใช้ valgrindเพื่อตรวจสอบรอยรั่ว ~cs50/pset4/peek large.bmp ./resize 4 small.bmp student.bmp
~cs50/pset4/resize 4 small.bmp staff.bmp
~cs50/pset4/peek student.bmp staff.bmp

จะตัดสินใจอย่างไร?

  • เปิดไฟล์ที่เราต้องการขยายและสร้างและเปิดไฟล์ใหม่ที่จะบันทึกภาพที่ขยายใหญ่ขึ้น

  • อัปเดตข้อมูลส่วนหัวสำหรับไฟล์เอาต์พุต เนื่องจากรูปภาพของเราอยู่ในรูปแบบ BMP และเรากำลังเปลี่ยนขนาด เราจึงต้องเขียนส่วนหัวของไฟล์ใหม่ด้วยขนาดใหม่ อะไรจะเปลี่ยนไป? ขนาดไฟล์ รวมถึงขนาดภาพ - ความกว้างและความสูง

Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 11หากเราดูคำอธิบายส่วนหัว เราจะเห็นตัวแปร biSizeImage โดยระบุขนาดรวมของรูปภาพเป็นไบต์ biWidthคือความกว้างของรูปภาพลบการจัดตำแหน่ง biHeightคือความสูง ตัวแปรเหล่านี้จะอยู่ในโครงสร้าง BITMAPFILEHEADER และ BITMAPINFOHEADER คุณสามารถค้นหาได้หาก คุณ เปิด ไฟล์ bmp.h Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 12คำอธิบายของโครงสร้าง BITMAPINFOHEADER ประกอบด้วยรายการของตัวแปร หากต้องการเขียนชื่อเรื่องของไฟล์เอาต์พุต คุณจะต้องเปลี่ยนค่าความสูงและความกว้าง แต่ยังมีโอกาสที่คุณจะต้องใช้ความสูงและความกว้างดั้งเดิมของไฟล์ต้นฉบับในภายหลัง ดังนั้นจึงควรเก็บทั้งสองอย่างไว้จะดีกว่า ระวังชื่อตัวแปรเพื่อไม่ให้คุณเขียนข้อมูลที่ผิดพลาดในส่วนหัวของไฟล์เอาต์พุตโดยไม่ตั้งใจ
  • เราอ่านไฟล์ขาออกทีละบรรทัด พิกเซลต่อพิกเซล ในการดำเนินการนี้ เราจะหันไปใช้ไลบรารีไฟล์ I/O และฟังก์ชัน fread อีกครั้ง มันจะนำตัวชี้ไปยังโครงสร้างที่จะมีไบต์ที่อ่าน ขนาดขององค์ประกอบเดี่ยวที่เราจะอ่าน จำนวนขององค์ประกอบดังกล่าว และตัวชี้ไปยังไฟล์ที่เราจะอ่าน

    Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 13
  • เราเพิ่มแต่ละบรรทัดในแนวนอนตามมาตราส่วนที่ระบุ และเขียนผลลัพธ์ลงในไฟล์เอาต์พุต

    Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 14

    เราจะเขียนไฟล์ได้อย่างไร? เรามีฟังก์ชัน fwrite ซึ่งเราจะส่งตัวบ่งชี้ไปยังโครงสร้างที่มีข้อมูลที่จะเขียนลงในไฟล์ขนาดขององค์ประกอบหมายเลขและตัวชี้ไปยังไฟล์เอาต์พุต ในการจัดระเบียบลูป เราสามารถใช้for loop ที่เราคุ้นเคยอยู่ แล้ว

    Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 15
  • เติมคำลงในช่องว่าง! หากจำนวนพิกเซลในบรรทัดไม่เป็นผลคูณของสี่ เราต้องเพิ่ม "การจัดตำแหน่ง" - ศูนย์ไบต์ เราจะต้องมีสูตรในการคำนวณขนาดการจัดตำแหน่ง หากต้องการเขียนไบต์ว่างไปยังไฟล์เอาต์พุต คุณสามารถใช้ฟังก์ชัน fputc โดยส่งอักขระที่คุณต้องการเขียนและตัวชี้ไปยังไฟล์เอาต์พุต

    Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 16

    ตอนนี้เราได้ขยายสตริงในแนวนอนและเพิ่มการจัดตำแหน่งให้กับไฟล์เอาต์พุตแล้ว เราจำเป็นต้องย้ายตำแหน่งปัจจุบันในไฟล์เอาต์พุตเนื่องจากเราจำเป็นต้องข้ามข้ามการจัดตำแหน่ง

    Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 17
  • เพิ่มขนาดแนวตั้ง มันซับซ้อนกว่า แต่เราสามารถใช้โค้ดตัวอย่างจากcopy.cได้ (copy.c เปิดไฟล์เอาต์พุต เขียนส่วนหัวไปยังไฟล์เอาต์พุต อ่านรูปภาพจากไฟล์ต้นฉบับทีละบรรทัด พิกเซลต่อพิกเซล และเขียนมัน ไปยังไฟล์เอาต์พุต) จากสิ่งนี้ สิ่งแรกที่คุณสามารถทำได้คือรันคำสั่งต่อไปนี้: cp copy.c resize.c

    การยืดภาพในแนวตั้งหมายถึงการคัดลอกแต่ละบรรทัดหลายครั้ง มีหลายวิธีในการทำเช่นนี้ ตัวอย่างเช่น เมื่อใช้การเขียนใหม่ เมื่อเราบันทึกพิกเซลทั้งหมดของบรรทัดเดียวในหน่วยความจำ และเขียนบรรทัดนี้ลงในไฟล์เอาต์พุตแบบวนซ้ำได้บ่อยเท่าที่ต้องการ อีกวิธีหนึ่งคือการคัดลอกใหม่: หลังจากอ่านบรรทัดจากไฟล์ขาออกแล้ว เขียนลงในไฟล์เอาต์พุตและจัดตำแหน่ง ให้ส่งคืนฟังก์ชัน fseek กลับไปที่จุดเริ่มต้นของบรรทัดในไฟล์ขาออก และทำซ้ำทุกอย่างอีกครั้งหลาย ๆ ครั้ง

    Harvard CS50: การบ้านสัปดาห์ที่ 4 (การบรรยายที่ 9 และ 10) - 18
  • ฟื้นตัว

    เพื่อเตรียมพร้อมสำหรับรายงานปัญหาของสัปดาห์ที่ 4 ฉันใช้เวลาสองสามวันที่ผ่านมาดูภาพที่บันทึกในรูปแบบ JPEG โดยกล้องดิจิตอลของฉันในการ์ดหน่วยความจำ CompactFlash (CF) ขนาด 1 GB โปรดอย่าบอกฉันว่าฉันใช้เวลาสองสามวันที่ผ่านมาบน Facebook แทน น่าเสียดายที่ทักษะการใช้คอมพิวเตอร์ของฉันยังเหลือความต้องการอีกมาก และฉันก็ลบรูปภาพทั้งหมดโดยไม่รู้ตัว! โชคดีที่ในโลกคอมพิวเตอร์ การ "ลบ" มักจะไม่เท่ากับ "ถูกฆ่า" คอมพิวเตอร์ของฉันยืนยันว่าขณะนี้การ์ดหน่วยความจำว่างเปล่า แต่ฉันรู้ว่าการ์ดนั้นโกหก งานที่ได้รับมอบหมาย: เขียนโปรแกรมใน ~/workspace/pset4/jpg/recover.c ที่จะกู้คืนรูปภาพเหล่านี้ อืม. เอาล่ะ นี่คืออีกหนึ่งคำชี้แจง แม้ว่ารูปแบบ JPEG จะซับซ้อนกว่า BMP แต่ JPEG ก็มีรูปแบบไบต์ "ลายเซ็น" ที่ช่วยแยกความแตกต่างจากรูปแบบไฟล์อื่นๆ ไฟล์ JPEG ส่วนใหญ่เริ่มต้นด้วยสามไบต์ต่อไปนี้: 0xff 0xd8 0xff จากไบต์แรกไปที่สาม จากซ้ายไปขวา ไบต์ที่สี่มักจะเป็นหนึ่งในชุดค่าผสมต่อไปนี้: 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,0xe8, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef กล่าวอีกนัยหนึ่ง สี่บิตแรกของไบต์ที่สี่ของไฟล์ JPEG คือ 1110 มีโอกาสที่หากคุณพบรูปแบบใดรูปแบบหนึ่งเหล่านี้บนไดรฟ์ที่เก็บรูปภาพไว้ (เช่น การ์ดหน่วยความจำของฉัน) นี่จะเป็นจุดเริ่มต้นของไฟล์ JPEG แน่นอนคุณอาจพบสิ่งนี้โดยบังเอิญบนดิสก์ใด ๆ การกู้คืนข้อมูลไม่สามารถเรียกได้ว่าเป็นวิทยาศาสตร์ที่แน่นอน

    ตัดสินใจอย่างไร

    1. เปิดไฟล์ที่มีเนื้อหาอยู่ในการ์ดหน่วยความจำ

    2. ค้นหาจุดเริ่มต้นของไฟล์ JPEG ไฟล์ทั้งหมดในการ์ดใบนี้เป็นภาพในรูปแบบ JPEG

    คุณรู้เกี่ยวกับเครื่องหมาย JPEG อยู่แล้ว: Harvard CS50: การบ้านสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 19เป็นสิ่งสำคัญ (และดี) ที่จะรู้ว่าไฟล์ JPEG แต่ละไฟล์ถูกจัดเก็บไว้ในหน่วยความจำเป็นบล็อกเดียว และไฟล์ต่างๆ จะติดตามกัน มาวาดแผนที่หน่วยความจำแบบแผนผังกันดีกว่า แต่ละสี่เหลี่ยมมีความยาวบล็อก 512 ไบต์ สี่เหลี่ยมสีเทาคือพื้นที่ที่ไม่มีไฟล์ JPEG เครื่องหมายดอกจันหมายถึงจุดเริ่มต้นของไฟล์ JPEG เราเชื่อว่าเราไม่มีบล็อกสีเทาระหว่างไฟล์ Harvard CS50: การบ้านสัปดาห์ที่สี่ (การบรรยายที่ 9 และ 10) - 20เราจะอ่านข้อมูลนี้ขนาด 512 ไบต์เหล่านี้เพื่อเปรียบเทียบจุดเริ่มต้นของข้อมูลกับส่วนหัวของ JPEG ได้อย่างไร เราสามารถใช้ ฟังก์ชัน freadซึ่งเราคุ้นเคยอยู่แล้ว ซึ่งจะนำตัวชี้ไปยังโครงสร้างข้อมูลที่ไบต์การอ่านจะถูกเขียน เช่นเดียวกับขนาดขององค์ประกอบที่กำลังอ่าน จำนวนขององค์ประกอบดังกล่าว และ ตัวชี้ไปยังไฟล์ที่เรากำลังอ่านข้อมูล Harvard CS50: การมอบหมายสัปดาห์ที่สี่ (บรรยายที่ 9 และ 10) - 21เราต้องการอ่าน 512 ไบต์และเก็บไว้ในบัฟเฟอร์ นี่จะเป็นตัวชี้ &data และตัวชี้ inptr จะชี้ไปที่ไฟล์ที่เปิดอยู่พร้อมกับเนื้อหาของการ์ดหน่วยความจำ กลับไปที่โครงสร้างของไฟล์ที่เราบันทึก
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION