Kendi kendini görüntüleyen görüntü [kapalı]


11

Arka fon

Kendiliğinden açılan .ZIPdosyalar var. Genellikle uzantıları vardır .EXE(ve ayıklanacak dosyayı yürüterek), ancak bunları yeniden adlandırırken .ZIP, dosyayı bazı ZIP ayıklama yazılımıyla açabilirsiniz.

(Bu, .EXEdosyalar belirli bir üstbilgi gerektirdiğinden, ancak .ZIPdosyalar belirli bir treyler gerektirdiğinden mümkündür, bu nedenle hem .EXEüstbilgi hem de .ZIPtreyler içeren bir dosya oluşturmak mümkündür .)

Senin görevin:

"Kendini görüntüleyen" görüntü dosyaları oluşturan bir program oluşturun:

  • Program girdi olarak 64x64 resim (en az 4 renk desteklenecektir) ve çıktı olarak bazı "birleşik" dosya alır
  • Programın çıktı dosyası, yaygın resim izleyicileri tarafından resim dosyası olarak tanınacaktır.
  • Çıktı dosyasını resim görüntüleyici ile açarken, giriş görüntüsü görüntülenecektir
  • Çıktı dosyası ayrıca herhangi bir işletim sistemi veya bilgisayar türü için yürütülebilir dosya olarak tanınacaktır

    (Yaygın olmayan bir işletim sistemi veya bilgisayar için bir dosya oluşturulursa, açık kaynaklı bir PC öykünücüsü varsa iyi olur. Ancak, bu gerekli değildir.)

  • Çıktı dosyası yürütülürken, giriş görüntüsü de görüntülenecektir
  • Dosyanın yeniden adlandırılması (örneğin, .PNG- arasındaki .COM) gerekebilir
  • Programın ve çıktı dosyasının aynı işletim sisteminde çalışması gerekmez; program örneğin bir Windows programı ve Commodore C64 üzerinde çalıştırılabilecek çıktı dosyaları olabilir.

Kazanan kriter

  • En küçük çıktı dosyasını üreten program kazanır
  • Çıktı dosyasının boyutu giriş görüntüsüne göre değişirse (örneğin, program görüntüyü sıkıştırdığı için), program tarafından oluşturulan ve 4 renge kadar 64x64 görüntüyü temsil eden mümkün olan en büyük çıktı dosyası

Bu arada

StackOverflow bu soruyu okurken aşağıdaki programlama bulmaca için bir fikir vardı .


Kazanan koşul etiketlerini ekledim (metagolf ile birlikte kod meydan okuma - en kısa çıktı). Giriş 64x64 resmine gelince, bazı örnek resimleriniz var mı? Ayrıca, bakıldığında görüntünün kendisinin aynı olması gerekir mi? Veya çıktı görüntüsü ve girdi görüntüsü farklı olabilir mi? Daha somut olmak için: diyelim ki .exezorluğun bir kısmı için bir çeşit kod ekliyoruz ve bunu olarak .pnggörüntülerken bu .exe-koduna dayalı değiştirilmiş pikseller var . Hala .pnggörüntüleyebildiğimiz sürece buna izin veriliyor mu? Çıktı görüntüsünün de en az 4 rengi olması gerekir mi?
Kevin Cruijssen

2
"Ortak resim görüntüleyiciyi" nasıl tanımlarsınız? Örneğin, HTML "kodu" bulunan bir internet tarayıcısı sayılır mı?
Jo King

@KevinCruijssen Görüntü dosyası olarak yorumlandığında, çıktı dosyası giriş dosyasıyla aynı görüntüyü temsil etmelidir: Piksel cinsinden aynı genişlik ve yükseklik ve her piksel aynı renge sahip olacaktır. Dosya formatları tam olarak aynı renk paletini desteklemiyorsa, her pikselin renkleri mümkün olduğunca yakın olmalıdır. Aynı şey yürütülebilir dosya olarak yorumlanan dosya için de geçerlidir. Çıktı dosyası bir "tam ekran" programını temsil ediyorsa, görüntüyü ekranda herhangi bir yerde görüntüleyebilir (ortalanmış, sol üst kenar, ...) veya tam ekran boyutuna genişletebilir.
Martin Rosenau

1
@JoKing "Yaygın görüntü izleyicileri tarafından tanınır", dosya biçiminin önceden yüklenmiş yazılım (HTML gibi) bulunan çoğu bilgisayar tarafından okunabileceği veya çok sayıda kullanıcının dosyayı görüntülemek için ücretsiz bir araç indirebileceği anlamına gelir ( PDF gibi). Ben HTML + JavaScript kodu, ancak, "resim görüntüleyici" gerektiği gibi görülebilir söyleyebilirim değil kodu çalıştırmak! Dolayısıyla, bir web tarayıcısının bir "resim görüntüleyici" olduğunu söyleyebiliriz, ancak bu durumda HTML "kod" değildir. Veya HTML + JS'nin "kod" olduğunu söyleyebilirsiniz, ancak bu durumda web tarayıcısı bir "resim görüntüleyici" değildir.
Martin Rosenau

2
Böyle ilginç bir sorunun kapalı olduğunu görmek üzücü. Anladığım kadarıyla, bir soruyu yeniden açmadan önce herhangi bir endişe giderilmelidir. Yorumlardaki ana şey, belirsiz olmak için yeterince puslu olan "ortak resim görüntüleyici" terimidir ve görüntü, yürürlükteki kodun varlığıyla değiştirilmeyen bir durumda (@ KevinCruijssen'in endişesine göre) görüntülenmeye açıktır. . Bu endişeleri ele alan bir düzenleme yeterli olur mu? (Ben "dört renk dört renk" belirsizliği anlamıyorum itiraf ediyorum.)
gastropner

Yanıtlar:


5

8086 MS-DOS .COM dosyası / BMP, çıktı dosyası boyutu = 2192 bayt

Encoder

Kodlayıcı C ile yazılır. İki argüman alır: Girdi dosyası ve çıktı dosyası. Giriş dosyası 64x64 RAW RGB görüntüsüdür (yani sadece 4096 RGB üçlüsüdür). Renk sayısı 4 ile sınırlıdır, böylece palet mümkün olduğunca kısa olabilir. Yaptıklarında çok basittir; sadece bir palet oluşturur, piksel çiftlerini baytlara paketler ve önceden hazırlanmış üstbilgiler ve kod çözücü programı ile yapıştırır.

#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;
}

Çıktı dosyası

Çıktı dosyası .COM olarak yeniden adlandırılabilen ve DOS ortamında çalıştırılabilen bir BMP dosyasıdır. Yürütme üzerine, 13h video moduna geçecek ve görüntüyü gösterecektir.

Bir BMP dosyası, görüntü verilerinin dosyada nerede başladığını gösteren ImageOffset alanını içeren ilk başlık BITMAPFILEHEADER'a sahiptir. Bundan sonra BITMAPINFOHEADER çeşitli kod çözme / kodlama bilgileri, ardından bir palet kullanılırsa gelir. ImageOffset, herhangi bir üstbilginin sonunu aşan bir değere sahip olabilir, bu da kod çözücünün oturması için bir boşluk oluşturmamızı sağlar.

BITMAPFILEHEADER
BITMAPINFOHEADER
PALETTE
<gap>
IMAGE DATA

Başka bir sorun, kod çözücüye girmektir. BITMAPFILEHEADER ve BITMAPINFOHEADER, yasal makine kodu olduklarından (kurtarılamayan bir durum üretmeyen) emin olmak için kullanılabilir, ancak palet daha karmaşıktır. Elbette paleti yapay olarak daha uzun yapabilir ve makine kodunu oraya koyabiliriz, ancak bunun yerine biXPelsPerMeter ve biYPelsPerMeter alanlarını, kodun düzgün hizalanmasını sağlamak için ikincisini ve kod çözücüye atlamayı seçtim. Bu alanların elbette içlerinde çöp olacaktır, ancak test ettiğim herhangi bir görüntü görüntüleyici görüntünün iyi olduğunu gösterir. Yine de yazdırmak tuhaf sonuçlar doğurabilir.

Bildiğim kadarıyla standart uyumlu.

JMPTalimatlar BITMAPFILEHEADER içindeki ayrılmış alanlardan birine yerleştirilirse daha kısa bir dosya oluşturulabilir . Bu, görüntü yüksekliğini 64 yerine -64 olarak depolamamıza izin verir, bu da BMP dosyalarının büyülü harikalar diyarında görüntü verilerinin doğru şekilde saklandığı anlamına gelir ve bu da basitleştirilmiş bir kod çözücüye izin verir.

şifre çözücü

Kod çözücüde belirli bir hile yok. Palet kodlayıcı tarafından doldurulur ve burada kukla değerlerle gösterilir. Bir tuşa basıldığında DOS'a dönmezse biraz daha kısa olabilir, ancak onsuz eğlenceli bir test değildi. Gerektiğini düşünüyorsanız, jmp $birkaç bayt kaydetmek için son üç talimatı değiştirebilirsiniz . (İsterseniz dosya başlıklarını güncellemeyi unutmayın!)

BMP paletleri , sıfırlarla doldurulmuş BGR ( RGB değil ) üçüzleri olarak saklar . Bu, VGA paletini ayarlamayı normalden daha can sıkıcı hale getirir. BMP'lerin baş aşağı saklanması sadece lezzete (ve boyuta) katkıda bulunur.

NASM tarzında listelenmiştir:

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:

Güzel. Ben de çift BMP / MS-DOS COM düşünüyordum; Bir hafta içinde cevap olmasaydı uygulardım. Ancak, 10K'dan çok daha fazlasına ihtiyacım olacaktı: Kayıtların sıfır başlatıldığını varsaymadım, dosya ofseti 2'ye bir atlama talimatı yerleştirirdim. Ve bu alan BMP dosyalarında "dosya boyutu" olarak yorumlandığından, "Dosya boyutu" alanının doğru dosya boyutunu temsil ettiğinden emin olmak için BMP dosyasını "kukla" baytlarla doldurmak zorunda kalacağım.
Martin Rosenau

@MartinRosenau Aslında zorunda değil ben genellikle (gereğince yapmak kayıt değerlerinden bazılarını farz fysnet.net/yourhelp.htm başlıkları kayıtlarını clobber beri) ve necessating PSP hatta ilk bayt, int 0x20üzerinde ret.
gastropner
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.