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
La taille est de 180 octets et une option -p
est nécessaire (+1). Le score est alors de 181.
Les arguments sont donnés via STDIN dans une ligne, séparés par un espace, la couleur en valeur hexadécimale (16 caractères) et le nombre de pixels pour la largeur / hauteur, par exemple:
echo "FFFF00FF 200" | perl -p solidpng.pl >yellow200.png
La taille du fichier est de 832 octets. L'image de taille maximale (n = 999) avec la même couleur a 6834 octets (bien en dessous de 10 Mo).
La solution utilise deux bibliothèques:
use Digest::CRC crc32;
pour les valeurs CRC32 aux extrémités du bloc.
use IO::Compress::Deflate deflate;
pour compresser les données d'image.
Les deux bibliothèques ne sont pas liées aux images.
Non 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');
Modifications
use IO::Compress::Deflate':all';
est remplacé par use Compress::Zlib;
. Ce dernier exporte la fonction de dégonflage compress
par défaut. La fonction n'a pas besoin de références comme arguments et renvoie également le résultat directement. Cela permet de se débarrasser des variables $o
.
Merci pour la réponse de Michael :
Merci pour le commentaire de VadimR avec beaucoup de conseils:
use String::CRC32;
est plus court que use Digest::CRC crc32;
.
y///c-4
est plus court que -4+y///c
.
- La ligne de balayage est maintenant construite par le modèle
CH*
avec la répétition dans la valeur.
- Suppression de
$i
en utilisant une référence de valeur.
- Mots nus au lieu de chaînes pour les types de blocs.
- Les options sont désormais lues en faisant correspondre une ligne d'entrée STDIN (option
-p
) avec une correspondance avec le séparateur d'espace / /
. Ensuite, la première option est entrée $`
et le deuxième argument est entré $'
.
- L'option
-p
imprime également automatiquement $_
.
"\cZ"
est plus court que "\x1a"
.
Meilleure compression
Au prix de la taille du code, les données d'image peuvent être encore compressées si un filtrage est appliqué.
Taille de fichier non filtrée pour FFFF0FF
200
: 832 octets
Filtre Sub
(différences de pixels horizontales): 560 octets
$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
Filtre Sub
pour la première ligne et Up
pour les lignes restantes: 590 octets
$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);
Première ligne non filtrée, puis filtre Up
: 586 octets
$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);
Compress::Zlib
Peut également être réglé; le niveau de compression le plus élevé peut être défini par une option supplémentaire pour le niveau de compression en fonction compress
au prix de deux octets:
compress ..., 9;
La taille de fichier de l'exemple yellow200.png
sans filtrage passe de 832 octets à 472 octets. Appliquée à l'exemple avec Sub
filtre, la taille du fichier passe de 560 octets à 445 octets ( pngcrush -brute
impossible de compresser davantage).
999x999
fichier a plus de 30720 pixels, ce qui semble contradictoire.