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
Kích thước là 180 byte và tùy chọn -p
là cần thiết (+1). Điểm số sau đó là 181.
Các đối số được đưa ra thông qua STDIN trong một dòng, được phân tách bằng khoảng trắng, màu dưới dạng giá trị hex (16 ký tự) và số pixel cho chiều rộng / chiều cao, ví dụ:
echo "FFFF00FF 200" | perl -p solidpng.pl >yellow200.png
Kích thước tệp là 832 byte. Hình ảnh có kích thước tối đa (n = 999) có cùng màu có 6834 byte (cách dưới 10 MB).
Giải pháp sử dụng hai thư viện:
use Digest::CRC crc32;
cho các giá trị CRC32 ở cuối chunk.
use IO::Compress::Deflate deflate;
để nén dữ liệu hình ảnh.
Cả hai thư viện không liên quan đến hình ảnh.
Ung dung:
# 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');
Chỉnh sửa
use IO::Compress::Deflate':all';
được thay thế bởi use Compress::Zlib;
. Cái sau không xuất chức năng def def compress
theo mặc định. Hàm không cần tham chiếu làm đối số và cũng trả về kết quả trực tiếp. Điều đó cho phép thoát khỏi biến $o
.
Cảm ơn câu trả lời của Michael :
Cảm ơn bình luận của VadimR với rất nhiều lời khuyên:
use String::CRC32;
ngắn hơn use Digest::CRC crc32;
.
y///c-4
ngắn hơn -4+y///c
.
- Dòng quét hiện được xây dựng bởi mẫu
CH*
với sự lặp lại trong giá trị.
- Loại bỏ
$i
bằng cách sử dụng một tham chiếu giá trị.
- Từ trần thay vì chuỗi cho các loại chunk.
- Bây giờ các tùy chọn được đọc bằng cách khớp dòng đầu vào STDIN (tùy chọn
-p
) với khớp dấu cách / /
. Sau đó, tùy chọn đầu tiên là trong $`
và đối số thứ hai đi vào $'
.
- Tùy chọn
-p
cũng tự động in $_
.
"\cZ"
ngắn hơn "\x1a"
.
Nén tốt hơn
Với chi phí kích thước mã, dữ liệu hình ảnh có thể được nén thêm, nếu lọc được áp dụng.
Kích thước tệp chưa được lọc cho FFFF0FF
200
: 832 byte
Bộ lọc Sub
(chênh lệch pixel ngang): 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
Bộ lọc Sub
cho dòng đầu tiên và Up
cho các dòng còn lại: 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);
Dòng chưa được lọc đầu tiên, sau đó lọc Up
: 586 byte
$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);
Cũng Compress::Zlib
có thể được điều chỉnh; mức nén cao nhất có thể được đặt bằng tùy chọn bổ sung cho mức nén trong hàm compress
với chi phí là hai byte:
compress ..., 9;
Kích thước tệp của ví dụ yellow200.png
mà không lọc giảm từ 832 byte xuống 472 byte. Áp dụng cho ví dụ với Sub
bộ lọc, kích thước tệp thu nhỏ từ 560 byte thành 445 byte ( pngcrush -brute
không thể nén thêm).
999x999
tệp có hơn 30720 pixel, do đó có vẻ như tự mâu thuẫn.