8086 MS-DOS .COM file / BMP, ukuran file output = 2192 byte
Encoder
Encoder ditulis dalam C. Dibutuhkan dua argumen: File input dan file output. File input adalah gambar RGB RAW 64x64 (berarti hanya 4096 RGB triplet RGB). Jumlah warna dibatasi hingga 4, sehingga palet bisa sesingkat mungkin. Hal ini sangat mudah dilakukan; itu hanya membangun palet, mengemas pasangan piksel menjadi byte dan menempelkannya bersama dengan header yang dibuat sebelumnya dan program dekoder.
#include <stdio.h>
#include <stdlib.h>
#define MAXPAL 4
#define IMAGESIZE 64 * 64
int main(int argc, char **argv)
{
FILE *fin, *fout;
unsigned char *imgdata = malloc(IMAGESIZE * 3), *outdata = calloc(IMAGESIZE / 2, 1);
unsigned palette[MAXPAL] = {0};
int pal_size = 0;
if (!(fin = fopen(argv[1], "rb")))
{
fprintf(stderr, "Could not open \"%s\".\n", argv[1]);
exit(1);
}
if (!(fout = fopen(argv[2], "wb")))
{
fprintf(stderr, "Could not open \"%s\".\n", argv[2]);
exit(2);
}
fread(imgdata, 1, IMAGESIZE * 3, fin);
for (int i = 0; i < IMAGESIZE; i++)
{
// BMP saves the palette in BGR order
unsigned col = (imgdata[i * 3] << 16) | (imgdata[i * 3 + 1] << 8) | (imgdata[i * 3 + 2]), palindex;
int is_in_pal = 0;
for (int j = 0; j < pal_size; j++)
{
if (palette[j] == col)
{
palindex = j;
is_in_pal = 1;
}
}
if (!is_in_pal)
{
if (pal_size == MAXPAL)
{
fprintf(stderr, "Too many unique colours in input image.\n");
exit(3);
}
palindex = pal_size;
palette[pal_size++] = col;
}
// High nibble is left-most pixel of the pair
outdata[i / 2] |= (palindex << !(i & 1) * 4);
}
char BITMAPFILEHEADER[14] = {
0x42, 0x4D, // "BM" magic marker
0x90, 0x08, 0x00, 0x00, // FileSize
0x00, 0x00, // Reserved1
0x00, 0x00, // Reserved2
0x90, 0x00, 0x00, 0x00 // ImageOffset
};
char BITMAPINFOHEADER[40] = {
0x28, 0x00, 0x00, 0x00, // StructSize
0x40, 0x00, 0x00, 0x00, // ImageWidth
0x40, 0x00, 0x00, 0x00, // ImageHeight
0x01, 0x00, // Planes
0x04, 0x00, // BitsPerPixel
0x00, 0x00, 0x00, 0x00, // CompressionType (0 = none)
0x00, 0x00, 0x00, 0x00, // RawImagDataSize (0 is fine for non-compressed,)
0x00, 0x00, 0x00, 0x90, // HorizontalRes
// db 0, 0, 0
// nop
0xEB, 0x1A, 0x90, 0x90, // VerticalRes
// jmp Decoder
// nop
// nop
0x04, 0x00, 0x00, 0x00, // NumPaletteColours
0x00, 0x00, 0x00, 0x00, // NumImportantColours (0 = all)
};
char DECODER[74] = {
0xB8, 0x13, 0x00, 0xCD, 0x10, 0xBA, 0x00, 0xA0, 0x8E, 0xC2, 0xBA,
0xC8, 0x03, 0x31, 0xC0, 0xEE, 0x42, 0xBE, 0x38, 0x01, 0xB1, 0x04,
0xFD, 0x51, 0xB1, 0x03, 0xAC, 0xD0, 0xE8, 0xD0, 0xE8, 0xEE, 0xE2,
0xF8, 0x83, 0xC6, 0x07, 0x59, 0xE2, 0xEF, 0xFC, 0xB9, 0x00, 0x08,
0xBE, 0x90, 0x01, 0xBF, 0xC0, 0x4E, 0xAC, 0xD4, 0x10, 0x86, 0xC4,
0xAB, 0xF7, 0xC7, 0x3F, 0x00, 0x75, 0x04, 0x81, 0xEF, 0x80, 0x01,
0xE2, 0xEE, 0x31, 0xC0, 0xCD, 0x16, 0xCD, 0x20,
};
fwrite(BITMAPFILEHEADER, 1, 14, fout);
fwrite(BITMAPINFOHEADER, 1, 40, fout);
fwrite(palette, 4, 4, fout);
fwrite(DECODER, 1, 74, fout);
// BMPs are stored upside-down, because why not
for (int i = 64; i--; )
fwrite(outdata + i * 32, 1, 32, fout);
fclose(fin);
fclose(fout);
return 0;
}
Berkas keluaran
File output adalah file BMP yang dapat diubah namanya .COM dan dijalankan di lingkungan DOS. Setelah dieksekusi, itu akan berubah ke mode video 13j dan menampilkan gambar.
File BMP memiliki BITMAPFILEHEADER header pertama, yang berisi antara lain bidang ImageOffset, yang menunjukkan di mana dalam file data gambar dimulai. Setelah ini datang BITMAPINFOHEADER dengan berbagai informasi de- / encoding, diikuti oleh palet, jika digunakan. ImageOffset dapat memiliki nilai yang menunjuk di luar ujung header apa pun, memungkinkan kami untuk membuat celah bagi decoder untuk berada. Secara kasar:
BITMAPFILEHEADER
BITMAPINFOHEADER
PALETTE
<gap>
IMAGE DATA
Masalah lain adalah memasukkan decoder. BITMAPFILEHEADER dan BITMAPINFOHEADER dapat dipecahkan untuk memastikan kode mesin legal (yang tidak menghasilkan keadaan tidak dapat dipulihkan), tetapi paletnya lebih rumit. Kita tentu saja dapat membuat palet secara artifisial lebih lama, dan menempatkan kode mesin di sana, tetapi saya memilih untuk menggunakan bidang biXPelsPerMeter dan biYPelsPerMeter, yang pertama membuat kode disejajarkan dengan benar, dan yang terakhir untuk melompat ke decoder. Bidang-bidang ini tentu saja akan memiliki sampah di dalamnya, tetapi setiap penampil gambar yang saya uji dengan menampilkan gambar baik-baik saja. Mencetaknya mungkin menghasilkan hasil yang aneh.
Sejauh yang saya tahu, standar-patuh.
Seseorang dapat membuat file yang lebih pendek jika JMP
instruksi dimasukkan ke dalam salah satu bidang yang disediakan di BITMAPFILEHEADER. Ini akan memungkinkan kita untuk menyimpan ketinggian gambar sebagai -64 dan bukannya 64, yang di negeri ajaib dari file BMP berarti bahwa data gambar disimpan dengan cara yang benar, yang pada gilirannya akan memungkinkan dekoder yang disederhanakan.
Dekoder
Tidak ada trik khusus dalam dekoder. Palet diisi oleh encoder, dan ditampilkan di sini dengan nilai-nilai dummy. Ini bisa menjadi sedikit lebih pendek jika tidak kembali ke DOS saat tombol ditekan, tetapi tidak mengasyikkan pengujian tanpa itu. Jika Anda merasa harus melakukannya, Anda dapat mengganti tiga instruksi terakhir dengan jmp $
menyimpan beberapa byte. (Jangan lupa untuk memperbarui header file jika Anda melakukannya!)
BMP menyimpan palet sebagai BGR ( bukan RGB) kembar tiga, diisi dengan nol. Ini membuat pengaturan palet VGA lebih mengganggu dari biasanya. Fakta bahwa BMP disimpan terbalik hanya menambah rasa (dan ukuran).
Tercantum di sini dalam gaya NASM:
Palette:
db 0, 0, 0, 0
db 0, 0, 0, 0
db 0, 0, 0, 0
db 0, 0, 0, 0
Decoder:
; Set screen mode
mov ax, 0x13
int 0x10
mov dx, 0xa000
mov es, dx
; Prepare to set palette
mov dx, 0x3c8
xor ax, ax
out dx, al
inc dx
mov si, Palette + 2
mov cl, 4
std
pal_loop:
push cx
mov cl, 3
pal_inner:
lodsb
shr al, 1
shr al, 1
out dx, al
loop pal_inner
add si, 7
pop cx
loop pal_loop
cld
; Copy image data to video memory
mov cx, 64 * 64 / 2
mov si, ImageData
mov di, 20160
img_loop:
lodsb
aam 16
xchg al, ah
stosw
test di, 63
jnz skip
sub di, 384
skip:
loop img_loop
; Eat a keypress
xor ax, ax
int 0x16
; Return to DOS
int 0x20
ImageData:
.exe
bagian dari tantangan, dan ketika melihatnya sebagai.png
ada piksel yang dimodifikasi berdasarkan pada.exe
-kode ini . Apakah ini diizinkan selama masih.png
bisa kita lihat? Apakah gambar output juga harus memiliki setidaknya 4 warna?