처음부터 단색 PNG 출력


11

입력 :는 RGBA 육각 색 c(예. FFFF00FF) 및 정수> 0 <(1000) n(예. 200).

출력 : 원시는 PNG 파일의 출력은 이미지 뷰어에서 파일에 저장하고 열 때 같은 것을 바이트 n에 의해 n컬러로 채워진 이미지가 c표시됩니다.

사양 : 프로그램이 정확하게 출력해야 합니다 :

  • PNG 헤더 ( 89504E470D0A1A0A16 진수)
  • IHDR이러한 사양을 포함 하는 청크 :
    • 너비 : 이전 입력 n
    • 높이 : 이전 입력 n
    • 비트 심도 : 8( RGBA)
    • 색상 유형 : 6(알파와 트루 컬러)
    • 압축 방법 : 0
    • 필터 방법 : 0
    • 인터레이스 방식 : 0
  • IDAT이미지 데이터를 포함하는 하나 이상의 청크 (이전에 입력 된 컬러의 실선 이미지 c); 압축되거나 압축되지 않을 수 있습니다
  • IEND화상 최종 청크

추가 정보는 Wikipedia , W3 사이트 또는 Google 검색을 통해 제공됩니다.

제한 사항 :

  • 어떤 종류의 이미지에도 작동하도록 설계된 이미지 라이브러리 또는 함수를 사용할 수 없습니다.
  • 프로그램은 3 분 이내에 실행되어야하며 모든 입력에 대해 10MB 미만의 파일을 출력해야합니다 (위생성 검사).
  • 이것은 이므로 바이트 단위의 가장 짧은 코드가 이길 것입니다!

파일이 완전히 압축되지 않았을 수 있지만 모든 입력에 대해 30kB 미만이어야합니다. 999x999즉 자기 모순 보인다 있도록 파일이 이상 30,720 픽셀을 가지고 있습니다.
피터 테일러

@PeterTaylor Hm, 어떤 이유로 30KB가 충분하다고 생각했습니다. 내가 무슨 생각을했는지 모르겠다. (그리고 나는 당신이 압축을 사용하거나 사용하지 않을 수 있다고 말했지만 당신이 원하는 어느 쪽이든)
손잡이

폭 : 4 바이트 높이 : 4 바이트 비트 깊이 : 1 바이트 색상 유형 : 1 바이트 압축 방법 : 1 바이트 필터 방법 : 1 바이트 인터레이스 방법 : 1 바이트
technosaurus

@technosaurus ... 음, 뭐?
Doorknob

1
귀하의 예가 올바르지 않습니다 : 비트 깊이 : 8 (RRGGBBAA). 비트 깊이 8은 (RRGGBBAA)가 아닌 (RGBA)입니다.
Glenn Randers-Pehrson

답변:


6

펄, 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

크기는 180 바이트이며 옵션 -p이 필요합니다 (+1). 그런 다음 점수는 181입니다.

인수는 STDIN을 통해 한 줄에 공백, 16 진수 값 (16 자)으로 색상 및 너비 / 높이에 대한 픽셀 수로 구분됩니다. 예 :

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

yellow200.png

파일 크기는 832 바이트입니다. 동일한 색상의 최대 크기 이미지 (n = 999)는 6834 바이트 (10MB 미만)입니다.

이 솔루션은 두 개의 라이브러리를 사용합니다.

  • use Digest::CRC crc32; 청크 끝에서 CRC32 값의 경우.
  • use IO::Compress::Deflate deflate; 이미지 데이터를 압축합니다.

두 라이브러리 모두 이미지와 관련이 없습니다.

언 골프 드 :

# 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');

편집

  • use IO::Compress::Deflate':all';로 대체되었습니다 use Compress::Zlib;. 후자는 compress기본적으로 수축 기능 을 내 보냅니다 . 이 함수는 인수로 참조가 필요하지 않으며 결과를 직접 반환합니다. 변수를 제거 할 수 있습니다 $o.

Michael의 답변에 감사드립니다 .

  • 기능 k: 함수 의 첫 번째 pack템플릿 Na*N을 사용하여 호출을 제거 할 수 있습니다 pack.

  • packNNCV4 개의 값이있는 템플릿 은 NNC3n6 개의 값으로 최적화 됩니다.

많은 팁과 함께 VadimR의 의견에 감사드립니다 .

  • use String::CRC32;보다 짧습니다 use Digest::CRC crc32;.
  • y///c-4보다 짧습니다 -4+y///c.
  • 스캔 라인은 이제 CH*값이 반복되는 템플릿 으로 구성됩니다 .
  • $i값 참조를 사용하여 제거
  • 청크 유형의 문자열 대신 맨손으로 단어를 표시하십시오.
  • STDIN 입력 라인 (옵션 -p)을 공백 구분 기호와 일치시켜 옵션을 읽습니다 / /. 그런 다음 첫 번째 옵션은 in $`이고 두 번째 인수는 in $'입니다.
  • 옵션 -p도 자동으로 인쇄합니다 $_.
  • "\cZ"보다 짧습니다 "\x1a".

더 나은 압축

필터링이 적용되는 경우, 코드 크기의 비용으로 이미지 데이터를 추가로 압축 할 수 있습니다.

  • 필터링되지 않은 파일 크기 FFFF0FF 200: 832 bytes

  • 필터 Sub(가로 픽셀 차이) : 560 바이트

    $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첫 번째 행과 Up나머지 행에 대한 필터 : 590 바이트

    $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);
    
  • 필터링되지 않은 첫 번째 줄 다음 필터링 Up: 586 바이트

    $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조정할 수 있습니다. 최고 압축 수준 compress은 2 바이트의 비용으로 작동 중인 압축 수준에 대한 추가 옵션으로 설정할 수 있습니다 .

    compress ..., 9;

    yellow200.png필터링하지 않은 예제 파일 크기는 832 바이트에서 472 바이트로 줄어 듭니다. Sub필터 를 사용한 예에 적용 하면 파일 크기가 560 바이트에서 445 바이트로 줄어 듭니다 ( pngcrush -brute더 이상 압축 할 수 없음).


좋은 답변 (항상 그렇듯이)하지만 골프는 더 나아갈 수 있습니다-나는 202, + 1을 얻습니다 -p. 마이클의 대답 통찰력 (이외에 NA*NNNCV템플릿) - String::CRC32기본적으로 수출, y///c-4OK입니다 CH*템플릿, $i사라질, \cZ, barewords은 OK입니다, -p그리고 / /;prematch 및 postmatch에 배치합니다 인수. 내가 뭔가를 놓치고 점수가 200 이하로 떨어질 수 있는지 궁금합니다.
user2846289

1
@VadimR : 유용한 팁을 주셔서 감사합니다. 나는 그것을 사용하여 골프를 더 할 수 있었고 use Compress::Zlib;200보다 ≈ 10 % 낮았다.
Heiko

5

PHP 214

저는 PHP 전문가가 아니며 골프를 할 수있는 곳이 있습니다. 팁을 환영합니다.

<?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");

PNG 파일을 생성하십시오.

php png.php 20 FFFF00FF > output.png

base64 스트림 생성 (브라우저 주소 표시 줄에 결과 붙여 넣기)

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

언 골프 버전 :

<?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");

지금은 214입니다. 그리고 골프 버전과 골프 이외의 버전 모두에서 올바른 이미지를 얻을 수는 없지만 PHP 경험이 없으므로 다른 사람에게도 효과가 있으면 잘못하고 있습니다.
user2846289

1
@VadimR, 그렇습니다. 214. 맞습니다. 확인한 결과 생성 된 이미지가 유효합니다.
Michael M.

나를 위해 (PHP 5.4.27.0으로 테스트) 이미지가 4 바이트 짧습니다. 수축 된 데이터에 adler-32를 추가해서는 안됩니까? IE와 Chrome은 이미지를 그대로 표시하고 FF는 아닙니다. 이 이미지에서는 다른 앱도 다르게 작동합니다.
user2846289 12

4

파이썬, 252 바이트

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")

이 스크립트는 argv에서 입력을받습니다. 다음과 같이 명령 행에서이 스크립트를 실행하십시오.python 27086.py deadbeef 999

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.