Sıfırdan sağlam bir PNG çıktısı alın


11

Giriş : Bir RGBA onaltılık renk c(ör. FFFF00FF) Ve> 0 ve <1000 n(ör. 200) Bir tam sayı .

Çıktı : Ham bir PNG dosyasının çıktısı bir görüntü izleyicide bir dosyaya kaydedilir ve açıldığında böyle bir o bayt ntarafından nrenkle dolu görüntüye cgörüntülenir.

Özellikler : Programınız tam olarak çıktı almalıdır :

  • PNG başlığı ( 89504E470D0A1A0Aonaltılı olarak)
  • IHDRbu özellikleri içeren bir yığın:
    • genişlik: önceki giriş n
    • yükseklik: önceki giriş n
    • bit derinliği: 8( RGBA)
    • renk türü: 6(alfa ile gerçek renk)
    • sıkıştırma yöntemi: 0
    • filtre yöntemi: 0
    • taramalı yöntemi: 0
  • IDATgörüntü verilerini içeren bir veya daha fazla parça (daha önce girilen rengin düz bir görüntüsü c); sıkıştırılmış veya sıkıştırılmamış olabilir
  • bir IENDgörüntü son parçası

Wikipedia'da , W3 sitesinde veya bir Google aramasıyla ilgili daha fazla bilgi bulabilirsiniz .

Kısıtlamalar :

  • Herhangi bir görüntü ile çalışmak üzere tasarlanmış görüntü kitaplıkları veya işlevleri kullanamazsınız.
  • Programınız 3 dakikadan kısa sürede çalışmalı ve tüm girişler için 10 MB'ın altında bir dosya çıkarmalıdır (akıl sağlığı kontrolü).
  • Bu , bu yüzden bayt içindeki en kısa kod kazanacak!

Dosyanın tamamen sıkıştırılmamış olabileceğini, ancak tüm girdiler için dosyanın 30 KB'ın altında olması gerektiğini söylüyorsunuz. Bir 999x999dosya 30720 pikselden fazla, bu yüzden kendinden çelişkili görünüyor.
Peter Taylor

@PeterTaylor Hm, bir nedenden dolayı 30 KB'nin fazlasıyla yeterli olduğunu düşündüm. Ne düşündüğümü bilmiyorum ... düzenlendi. (Ve sadece sıkıştırma yapabileceğinizi veya kullanamayacağınızı söyledim; hangisini istersen).
Kapı tokmağı

Genişlik: 4 bayt Yükseklik: 4 bayt Bit derinliği: 1 bayt Renk türü: 1 bayt Sıkıştırma yöntemi: 1 bayt Filtre yöntemi: 1 bayt Taramalı yöntem: 1 bayt
technosaurus

@technosaurus ... hmm, ne?
Kapı tokmağı

1
Örneğin doğru değil: bit derinliği: 8 (RRGGBBAA). Bit derinliği 8 (RGBA) değil (RRGGBBAA).
Glenn Randers-Pehrson

Yanıtlar:


6

Perl, 181

/ /;use String::CRC32;use Compress::Zlib;sub k{$_=pop;pack'Na*N',y///c-4,$_,crc32$_}$_="\x89PNG\r\n\cZ\n".k(IHDR.pack NNCV,$',$',8,6).k(IDAT.compress pack('CH*',0,$`x$')x$').k IEND

Boyut 180 bayttır ve seçenek -pgereklidir (+1). Skor 181 olur.

Bağımsız değişkenler STDIN aracılığıyla boşlukla, onaltılık değer (16 karakter) olarak renk ve genişlik / yükseklik için piksel sayısı ile ayrılmış bir satırda verilir, örneğin:

 echo "FFFF00FF 200" | perl -p solidpng.pl >yellow200.png

yellow200.png

Dosya boyutu 832 bayttır. Aynı renkteki maksimum boyutlu görüntü (n = 999) 6834 bayta (10 MB'ın altında) sahiptir.

Çözüm iki kütüphane kullanır:

  • use Digest::CRC crc32; yığın uçlarındaki CRC32 değerleri için.
  • use IO::Compress::Deflate deflate; görüntü verilerini sıkıştırmak için.

Her iki kütüphane de görüntülerle ilgili değildir.

Ungolfed:

# Perl option "-p" adds the following around the program:
#     LINE:
#     while (<>) {
#         ... # the program goes here
#     } continue {
#         print or die "-p destination: $!\n";

/ /;    # match the separator of the arguments in the input line
        # first argument, color in hex:  $`
        # second argument, width/height: $'                              #'

# load the libraries for the CRC32 fields and the data compression
use String::CRC32;
use Compress::Zlib;

# function that generates a PNG chunk:
#   N (4 bytes, big-endian: data length
#   N:                      chunk type
#   a* (binary data):       data
#   N:                      CRC32 of chunk type and data
sub k {
    $_ = pop; # chunk data including chunk type and
              # excluding length and CRC32 fields
    pack 'Na*N',
        y///c - 4,   # chunk length                                      #/
                     # netto length without length, type, and CRC32 fields
        $_,          # chunk type and data
        crc32($_)    # checksum field
}

$_ =                      # $_ is printed by option "-p".
    "\x89PNG\r\n\cZ\n"    # PNG header
        # IHDR chunk: image header with
        #   width, height,
        #   bit depth (8), color type (6),
        #   compresson method (0), filter method (0), interlace method (0)
    . k('IHDR' . pack NNCV, $', $', 8, 6)
        # IDAT chunk: image data
    . k('IDAT' .
          compress        # compress/deflate data
          pack('CH*',     # scan line with filter byte
              0,          # filter byte: None
              ($` x $')   # pixel data for one scan line                 #'`
          ) x $'          # n lines                                      #'
      )
        # IHDR chunk: image end
    . k('IEND');

Düzenlemeler

  • use IO::Compress::Deflate':all';ile değiştirilir use Compress::Zlib;. İkincisi, compressvarsayılan olarak deflate işlevini dışa aktarır . İşlev bağımsız değişken olarak başvuruya ihtiyaç duymaz ve sonucu doğrudan döndürür. Bu değişkenlerden kurtulmanızı sağlar $o.

Michael'ın cevabı için teşekkürler :

  • İşlev k: işlevindeki ilk packşablon Na*Niçin çağrı kullanılarak çağrı kaldırılabilir pack.

  • packNNCVdört değer içeren şablon , NNC3naltı değerle optimize eder .

VadimR'nin birçok ipucu içeren yorumu için teşekkürler :

  • use String::CRC32;daha kısadır use Digest::CRC crc32;.
  • y///c-4daha kısadır -4+y///c.
  • Tarama çizgisi artık şablon tarafından CH*tekrar değeri ile oluşturulur.
  • $iBir değer başvurusu kullanarak kaldırılması .
  • Öbek türleri için dizeler yerine çıplak kelimeler.
  • Seçenekler artık STDIN giriş satırını (seçenek -p) boşluk ayırıcıyla eşleştirerek okunur / /. Sonra ilk seçenek $`girilir ve ikinci argüman devreye girer $'.
  • Seçenek -payrıca otomatik olarak yazdırılır $_.
  • "\cZ"daha kısadır "\x1a".

Daha iyi sıkıştırma

Kod boyutu pahasına, filtreleme uygulanırsa görüntü verileri daha fazla sıkıştırılabilir.

  • Filtrelenmemiş dosya boyutu FFFF0FF 200: 832 bayt

  • Filtre Sub(yatay piksel farklılıkları): 560 bayt

    $i = (                            # scan line:
             "\1"                     # filter "Sub"
             . pack('H*',$c)          # first pixel in scan line
             . ("\0" x (4 * $n - 4))  # fill rest of line with zeros
          ) x $n;                     # $n scan lines
  • Subİlk satır ve Upkalan satırlar için filtre : 590 bayt

    $i = # first scan line
         "\1"                     # filter "Sub"
         . pack('H*',$c)          # first pixel in scan line
         . ("\0" x (4 * $n - 4))  # fill rest of line with zeros
         # remaining scan lines 
         . (
               "\2"               # filter "Up"  
               . "\0" x (4 * $n)  # fill rest of line with zeros
           ) x ($n - 1);
  • İlk filtrelenmemiş satır, ardından filtre Up: 586 bayt

    $i = # first scan line
         pack('H*', ("00" . ($c x $n)))  # scan line with filter byte: none
         # remaining scan lines 
         . (
               "\2"               # filter "Up"
               . "\0" x (4 * $n)  # fill rest of line with zeros
           ) x ($n - 1);
    
  • Ayrıca Compress::Zlibayarlanabilir; en yüksek sıkıştırma seviyesi compress, iki bayt pahasına işlevdeki sıkıştırma seviyesi için ek seçenekle ayarlanabilir :

    compress ..., 9;

    yellow200.pngFiltrelemeden örneğin dosya boyutu 832 bayttan 472 bayta düşer. SubFiltreli örneğe uygulandığında, dosya boyutu 560 bayttan 445 bayta küçülür ( pngcrush -brutedaha fazla sıkıştırılamaz).


Büyük cevap (her zaman olduğu gibi), ancak golf daha da ileri gidebilir - Ben 202, + 1 olsun -p. Michael'ın cevabındaki ( NA*Nve NNCVşablonlarındaki) içgörülere ek olarak , - String::CRC32varsayılan olarak dışa aktarma y///c-4tamam, CH*şablon, $igitmiş \cZ, barewordlar tamam -pve / /;argümanları başlangıç ​​ve sonrasıya yerleştirir. Ben bir şey kaçırdı ve skor 200'ün altına alabilir miyim acaba :)
user2846289

1
@VadimR: Yararlı ipuçları için çok teşekkürler. Hatta kullanarak daha da golf olabilir use Compress::Zlib;ve 200'ün altında ≈% 10 aldım.
Heiko Oberdiek

5

PHP 214

Ben PHP bir uzman değilim, golf için yer var. İpuçları bekliyoruz.

<?function c($d){echo pack("Na*N",strlen($d)-4,$d,crc32($d));}echo"\x89PNG\r\n\x1a\n";c("IHDR".pack("NNCV",$n=$argv[1],$n,8,6));c("IDATx^".gzdeflate(str_repeat("\0".str_repeat(hex2bin($argv[2]),$n),$n)));c("IEND");

Bir PNG dosyası oluşturun:

php png.php 20 FFFF00FF > output.png

Base64 akışı oluşturun (sonucu tarayıcınızın adres çubuğuna yapıştırın)

echo "data:image/png;base64,`php png.php 200 0000FFFF | base64`"

Ungolfed sürümü:

<?php 

//function used to create a PNG chunck
function chunck($data) {
  return pack("Na*N", //write a big-endian integer, a string and another integer
    strlen($data)-4,     //size of data minus the 4 char of the type
    $data,               //data
    crc32($data));       //compute CRC of data
}

//png header
echo "\x89PNG\r\n\x1a\n"; 

//IHDR chunck
echo chunck("IHDR".pack("NNCV", //2 big-endian integer, a single byte and a little-endian integer
                   $n=$argv[1], $n,
                   8, 6)); //6 also write 3 zeros (little endian integer)

//IDAT chunck
//create a binary string of the raw image, each line begin with 0 (none filter)
$d = str_repeat("\0".str_repeat(hex2bin($argv[2]),$n),$n);
echo chunck("IDATx^".
       gzdeflate($d)); //compress raw data

//IEND chunck
echo chunck("IEND");

Şimdi 214, değil mi? Ve, hem golf hem de golf olmayan sürümlerden doğru görüntü alamıyorum, ancak PHP deneyimim yok, bu yüzden herkes için çalışıyorsa, yanlış yapıyorum.
user2846289

1
@VadimR, evet 214, haklısın. Kontrol ettim, oluşturulan görüntü benim için geçerli.
Michael M.

Benim için (PHP 5.4.27.0 ile test ediyorum), görüntü 4 bayt kısa - adler-32'ye sönük verilere eklenmemeli mi? IE ve Chrome, görüntüyü olduğu gibi görüntülemekten mutluluk duyar, FF değildir. Bu uygulama ile farklı uygulamalar da farklı davranır.
user2846289

4

Python, 252 bayt

import struct,sys,zlib as Z
P=struct.pack
A=sys.argv
I=lambda i:P(">I",i)
K=lambda d:I(len(d)-4)+d+I(Z.crc32(d)&(2<<31)-1)
j=int(A[2])
print "\x89PNG\r\n\x1A\n"+K("IHDR"+P(">IIBI",j,j,8,6<<24))+K("IDAT"+Z.compress(("\0"+I(int(A[1],16))*j)*j))+K("IEND")

Bu komut dosyası argv'den girdi alır. Bu komut dosyasını komut satırından çalıştırın.python 27086.py deadbeef 999

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.