#!/usr/bin/perl -w use strict; use constant SIZE => 128; use constant SCALE => SIZE / 1024; if( -t STDOUT ) { die "Giving up early because stdout is a tty\n"; } # Edge definition (bezier curve control points in absolute coordinates). my @shapes = ( [ [667,676], [688,740],[706,829],[760,852], [814,875],[855,755],[834,708], [813,661],[733,625],[667,676] ], [ [182,764], [113,753],[108,886],[182,936], [251,982],[373,931],[348,881], [324,834],[251,775],[182,764] ], [ [293,406], [404,499],[491,500],[664,573], [837,646],[938,501],[897,433], [832,326],[879,290],[793,144], [746,64],[620,38],[534,76], [394,138],[364,79],[280,122], [180,173],[171,304],[293,406] ], [ [290,764], [260,780],[250,803],[238,830], [249,840],[262,848],[275,854], [288,824],[302,805],[331,805], [331,795],[313,764],[290,764] ], [ [638,753], [647,768],[658,775],[671,775], [654,779],[631,779],[608,779], [615,770],[625,760],[638,753] ], [ [671,775], [684,775],[699,769],[718,756], [726,768],[732,780],[738,793], [654,842],[641,814],[608,779], [620,776],[658,775],[671,775] ], [ [279,288], [248,300],[283,384],[339,432], [312,484],[162,610],[290,764], [290,785],[303,805],[331,805], [344,805],[360,808],[380,816], [563,887],[822,659],[653,599], [659,587],[663,578],[668,564], [477,482],[436,227],[279,288] ], ); # Output image buffer. my $image = chr(0) x (SIZE * SIZE); # Interpolate between two values. sub interpolate($$$) { my ($a, $b, $t) = @_; return $a + ($b - $a) * $t; } # Syntactic sugar. sub min($$) { my ($a, $b) = @_; return $a < $b ? $a : $b; } sub max($$) { my ($a, $b) = @_; return $a > $b ? $a : $b; } # Draw filled shape by scanlines. sub draw_scanlines($@) { my ($color, @points) = @_; my @ranges = (); for(my $i = 0; $i < SIZE; $i++) { push @ranges, [undef, undef]; } # Collect ranges. for(my $i = 0; $i + 3 < scalar @points; $i += 3) { my $x0 = SCALE * $points[$i][0]; my $x1 = SCALE * $points[$i + 1][0]; my $x2 = SCALE * $points[$i + 2][0]; my $x3 = SCALE * $points[$i + 3][0]; my $y0 = SCALE * $points[$i][1]; my $y1 = SCALE * $points[$i + 1][1]; my $y2 = SCALE * $points[$i + 2][1]; my $y3 = SCALE * $points[$i + 3][1]; for(my $j = 0; $j < SIZE * 2; $j++) { my $t = $j / (SIZE * 2); my $x = interpolate(interpolate(interpolate($x0, $x1, $t), interpolate($x1, $x2, $t), $t), interpolate(interpolate($x1, $x2, $t), interpolate($x2, $x3, $t), $t), $t); my $y = interpolate(interpolate(interpolate($y0, $y1, $t), interpolate($y1, $y2, $t), $t), interpolate(interpolate($y1, $y2, $t), interpolate($y2, $y3, $t), $t), $t); my $ix = int($x); my $iy = int($y); if( $ix >= 0 && $ix < SIZE && $iy >= 0 && $iy < SIZE ) { if( defined($ranges[$iy][0]) ) { $ranges[$iy][0] = min($ranges[$iy][0], $ix); $ranges[$iy][1] = max($ranges[$iy][1], $ix); } else { $ranges[$iy][0] = $ranges[$iy][1] = $ix; } } } } # Draw scanlines. for(my $y = 0; $y < SIZE; $y++) { if( defined($ranges[$y][0]) ) { if( $color == 0xff ) { # Draw solid scanline. my $w = $ranges[$y][1] - $ranges[$y][0] + 1; substr($image, $y * SIZE + $ranges[$y][0], $w) = chr(0xff) x $w; } else { # Draw shaded scanline. for(my $x = $ranges[$y][0]; $x <= $ranges[$y][1]; $x++) { next if (($x + $y) & 1) == 0; substr($image, $y * SIZE + $x, 1) = chr(0xff); } } } } } # Add noise to output image by flipping random pixels. sub add_noise() { for(my $y = 0; $y < SIZE - 6; $y += 6) { for(my $x = 0; $x < SIZE - 4; $x += 4) { my $p = int(rand(6)); my $q = int(rand(4)); substr($image, ($y + $p) * SIZE + $x + $q, 1) = chr(0xff ^ ord(substr($image, ($y + $p) * SIZE + $x + $q, 1))); } } } for(my $i = 0; $i < scalar @shapes; $i++) { draw_scanlines($i < 3 ? 0x7f : 0xff, @{$shapes[$i]}); } add_noise(); print "P5\n", SIZE, " ", SIZE, "\n255\n", $image;