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
El tamaño es de 180 bytes y -p
se necesita la opción (+1). La puntuación es entonces 181.
Los argumentos se proporcionan a través de STDIN en una línea, separados por un espacio, el color como valor hexadecimal (16 caracteres) y el número de píxeles para ancho / alto, por ejemplo:
echo "FFFF00FF 200" | perl -p solidpng.pl >yellow200.png
El tamaño del archivo es de 832 bytes. La imagen de tamaño máximo (n = 999) con el mismo color tiene 6834 bytes (muy por debajo de 10 MB).
La solución usa dos bibliotecas:
use Digest::CRC crc32;
para los valores CRC32 en el fragmento finaliza.
use IO::Compress::Deflate deflate;
para comprimir los datos de la imagen.
Ambas bibliotecas no están relacionadas con las imágenes.
Sin golf:
# 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');
Ediciones
use IO::Compress::Deflate':all';
se sustituye por use Compress::Zlib;
. Este último exporta la función desinflar compress
por defecto. La función no necesita referencias como argumentos y también devuelve el resultado directamente. Eso permite deshacerse de la variable $o
.
Gracias por la respuesta de Michael :
Gracias por el comentario de VadimR con muchos consejos:
use String::CRC32;
es más corto que use Digest::CRC crc32;
.
y///c-4
es más corto que -4+y///c
.
- La línea de exploración ahora está construida por la plantilla
CH*
con la repetición en el valor.
- Eliminación de
$i
mediante el uso de una referencia de valor.
- Palabras desnudas en lugar de cadenas para los tipos de fragmentos.
- Las opciones ahora se leen haciendo coincidir una línea de entrada STDIN (opción
-p
) con la coincidencia del separador de espacio / /
. Entonces $`
entra la primera opción y entra el segundo argumento $'
.
- La opción
-p
también imprime automáticamente $_
.
"\cZ"
es más corto que "\x1a"
.
Mejor compresión
A costa del tamaño del código, los datos de la imagen pueden comprimirse aún más, si se aplica el filtrado.
Tamaño de archivo sin filtrar para FFFF0FF
200
: 832 bytes
Filtro Sub
(diferencias de píxeles horizontales): 560 bytes
$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
Filtro Sub
para la primera línea y Up
para las líneas restantes: 590 bytes
$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);
Primera línea sin filtrar, luego filtro 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);
También Compress::Zlib
se puede sintonizar; El nivel de compresión más alto se puede establecer mediante una opción adicional para el nivel de compresión en función compress
a un costo de dos bytes:
compress ..., 9;
El tamaño del archivo de ejemplo yellow200.png
sin filtrado disminuye de 832 bytes a 472 bytes. Aplicado al ejemplo con Sub
filtro, el tamaño del archivo se reduce de 560 bytes a 445 bytes ( pngcrush -brute
no se puede comprimir más).
999x999
archivo tiene más de 30720 píxeles, por lo que parece contradictorio.