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
Ukurannya 180 byte dan opsi -pdiperlukan (+1). Skornya kemudian 181.
Argumen diberikan melalui STDIN dalam garis, dipisahkan oleh spasi, warna sebagai nilai hex (16 karakter) dan jumlah piksel untuk lebar / tinggi, misalnya:
echo "FFFF00FF 200" | perl -p solidpng.pl >yellow200.png

Ukuran file adalah 832 byte. Gambar berukuran maksimal (n = 999) dengan warna yang sama memiliki 6834 byte (jauh di bawah 10 MB).
Solusinya menggunakan dua perpustakaan:
use Digest::CRC crc32; untuk nilai CRC32 di ujung chunk.
use IO::Compress::Deflate deflate; untuk mengompres data gambar.
Kedua perpustakaan tidak terkait dengan gambar.
Tidak Disatukan:
# 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');
Suntingan
use IO::Compress::Deflate':all';diganti oleh use Compress::Zlib;. Yang terakhir memang mengekspor fungsi deflate compresssecara default. Fungsi tidak memerlukan referensi sebagai argumen dan juga mengembalikan hasilnya secara langsung. Itu memungkinkan untuk menyingkirkan variabel $o.
Terima kasih atas jawaban Michael :
Terima kasih atas komentar VadimR dengan banyak tips:
use String::CRC32;lebih pendek dari use Digest::CRC crc32;.
y///c-4lebih pendek dari -4+y///c.
- Baris pemindaian sekarang dibangun oleh templat
CH*dengan pengulangan dalam nilai.
- Penghapusan
$idengan menggunakan referensi nilai.
- Kata-kata telanjang alih-alih string untuk tipe chunk.
- Opsi sekarang dibaca dengan mencocokkan jalur input STDIN (opsi
-p) dengan mencocokkan pemisah ruang / /. Kemudian opsi pertama ada $`dan argumen kedua masuk $'.
- Pilihan
-pjuga mencetak secara otomatis $_.
"\cZ"lebih pendek dari "\x1a".
Kompresi yang lebih baik
Dengan mengorbankan ukuran kode, data gambar dapat dikompresi lebih lanjut, jika penyaringan diterapkan.
Ukuran file tanpa filter untuk FFFF0FF 200: 832 bytes
Filter Sub(perbedaan piksel horizontal): 560 byte
$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
Saring Subuntuk baris pertama dan Upuntuk baris lainnya: 590 byte
$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);
Pertama tanpa filter baris, lalu filter Up: 586 bytes
$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);
Juga Compress::Zlibbisa disetel; tingkat kompresi tertinggi dapat diatur dengan opsi tambahan untuk tingkat kompresi berfungsi compressdengan biaya dua byte:
compress ..., 9;
Ukuran file misalnya yellow200.pngtanpa penyaringan menurun dari 832 byte menjadi 472 byte. Diterapkan pada contoh dengan Subfilter, ukuran file menyusut dari 560 byte menjadi 445 byte ( pngcrush -brutetidak dapat memampatkan lebih lanjut).
999x999file memiliki lebih dari 30720 piksel, sehingga tampaknya saling bertentangan.