View difference between Paste ID: ZAuknzYw and bP4ftG4x
SHOW: | | - or go back to the newest paste.
1
#/bin/perl
2
#
3
# tst_bm16.pl - Pbairefvba ivqrb ra tvs 15 pbhyf 160k200. [ROT13]
4
#
5
# par Samuel DEVULDER, Sept 2015.
6
#
7
8
if(0) {
9
	# pour trouver les niveaux equi-repartis
10
	&init_magick;
11
12
	my(@px);
13
	for my $c (0, 100, 127, 142, 163, 179, 191, 203, 215, 223, 231, 239, 243, 247, 251, 255) {push(@px,$c,$c,$c);}
14
	my $img=&px2img(16,1, @px);
15
	my @p1 = $img->GetPixels(height=>1,normalize=>"True");
16
	$img->Set(colorspace=>$LINEAR_SPACE);
17
	my @p2 = $img->GetPixels(height=>1,normalize=>"True");
18
	for my $i (0..15) {
19
		print "$i ",$px[$i*3]," ",255*$p1[$i*3]," ",2*$p2[$i*3]," ",255*$p2[$i*3]," ", 2*$p2[$i*3],"\n";
20
	}
21
	for my $i (0..15) {
22
		print "$i ",$px[$i*3]," ",255*$p1[$i*3]," ",3*$p2[$i*3]," ",255*$p2[$i*3]," ", 3*$p2[$i*3],"\n";
23
	}
24
	
25
	# 0 163 215 255
26
	# 0 191 255
27
28
	exit;
29
}
30
31
# parametres
32
($w, $h) = (160, 100);
33
$fps     = 10;
34-
$dither  = "vac8"; #"bayer4";
34+
$dither  = "vac4"; #"bayer4";
35-
$zigzag  = 0;
35+
$zigzag  = 1;
36
$satur   = 140;
37
$max     = 245;
38
39
# fichier entree
40
$file    = $ARGV[0];
41
$name    = $file;
42
$file =~ s/\.[^\.]*$/.gif/;
43
mkdir "out";
44
$file =~ s/^.*[\/]/out\//;
45
exit if -e $file;
46-
print "$name\n";
46+
print "\n$name\n";
47
48
# dossier temporaire
49
mkdir "tmp";
50
unlink(<tmp/img*.bmp>);
51
52
open(OUT,"| ./ffmpeg -i - -v 0 -r $fps -s ${w}x${h} -an tmp/img%05d.bmp");
53
open(IN, "<$name");
54
binmode(OUT);
55
binmode(IN);
56
57
open(OUT2,"| ./ffmpeg -i - -v 0 -r 1 -s ${w}x${h} -an tmp/img%05d.bmp");
58
open(IN2, "<$name");
59
binmode(OUT2);
60
binmode(IN2);
61
62
&init_magick;
63
64
$gif = Image::Magick->new(size=>($w*2)."x".($h*2));
65
66
@mat = ([1]) if $dither eq "checker";
67
@mat = ([1,3],
68
        [4,2]) if $dither eq "bayer2";
69
@mat = ([7,8,2],
70
        [6,9,4],
71-
	[3,5,1]) if $dither eq "sam3";
71+
        [3,5,1]) if $dither eq "sam3";
72
@mat = ([3,7,4],
73
        [6,1,9],
74-
	[2,8,5]) if $dither eq "3x3";
74+
        [2,8,5]) if $dither eq "3x3";
75
@mat = ([6, 9, 7, 12],
76
        [14, 3, 15, 1],
77-
	[4,12,2,10],
77+
        [8, 11, 5, 10],
78-
	[16,8,14,6]) if $dither eq "bayer4";
78+
        [16, 2, 13, 4]) if $dither eq "vac4";
79
@mat = ([1,9,3,11],
80-
	[9,23,5,18,14],
80+
81
        [4,12,2,10],
82
        [16,8,14,6]) if $dither eq "bayer4";
83
@mat = ([21,2,16,11,6],
84
        [9,23,5,18,14],
85-
	[29,6,41,27,37,17,59,45],
85+
86-
	[61,15,53,12,62,25,33,9],
86+
87-
	[23,39,31,49,2,47,13,43],
87+
88-
	[3,52,8,22,36,58,20,56],
88+
89-
	[38,18,60,46,30,5,42,28],
89+
        [29,6,41,27,37,17,59,45],
90-
	[63,26,34,11,64,16,54,10],
90+
        [61,15,53,12,62,25,33,9],
91-
	[14,48,1,44,24,40,32,50]) if $dither eq "vac8";
91+
        [23,39,31,49,2,47,13,43],
92
        [3,52,8,22,36,58,20,56],
93
        [38,18,60,46,30,5,42,28],
94
        [63,26,34,11,64,16,54,10],
95
        [14,48,1,44,24,40,32,50]) if $dither eq "vac8";
96
97
$mat_x = 1+$#mat;
98
$mat_y = 1+$#{$mat[0]};
99
for my $a (@mat) {for my $b (@$a) {$b /= $mat_x*$mat_y+1.0;}}
100
101-
($MID31, $MID21, $MID32) = (1,3,5);
101+
102
@lin_pal = (0, 33, 54, 69, 93,115,133,152,173,188,204,220,229,237,246,255);
103
#($MID31, $MID21, $MID32) = (4,6,8);
104
#($MID31, $MID21, $MID32) = (2,4,8);
105
#($MID31, $MID21, $MID32) = (1,3,5);
106
107
if(1) {
108
	my @pc2teo = ();
109
	for my $i (1..$#teo_pal) {
110
		my($a,$b,$c) = ($teo_pal[$i-1],($teo_pal[$i-1]+$teo_pal[$i])>>1,$teo_pal[$i]);
111-
	my @tab1 = (0)x16;
111+
112-
	my @tab2 = (0)x16;
112+
113
	}
114
	
115
	my @tabR = (0)x16;
116
	my @tabG = (0)x16;
117
	my @tabB = (0)x16;
118
	$time = 1;
119
	my $run = 1;
120
	while(1) {
121
		my $name = sprintf("tmp/img%05d.bmp", $time);
122
		$expected_size = $h*(($w*3 + 3)&~3) + 54 if !$expected_size;
123
		if($expected_size != -s $name) {
124
			last unless $run;
125
			my $buf;
126
			my $read = read(IN2,$buf,4096);
127
			if($read) {
128
				syswrite OUT2, $buf, $read;
129
			} else {
130
				$run = 0;
131
				close(OUT2);
132
			}
133
		} else  {
134-
			$img->Read($name);
134+
135
			print STDERR $time++,"s\r";
136-
			
136+
137
			# lecture de l'image
138
			my $img = Image::Magick->new();
139
			my $x = $img->Read($name); die "$x, stopped $!" if $x;
140
			unlink $name;
141
142
			# on force la saturation (140%) pour avoir des couleurs plus franches
143
			$img->Modulate(saturation=>$satur);
144
			$img->Evaluate(operator=>'Multiply', value=>255/$max);
145-
				++$tab1[$pc2teo[int($px[$i]*255)]];
145+
146-
				++$tab1[$pc2teo[int($px[$i+1]*255)]];
146+
147-
				++$tab2[$pc2teo[int($px[$i+2]*255)]];
147+
			if(!defined $pal4096) {
148
				my @px;
149
				for my $r (0..15) {
150
					for my $g (0..15) {
151
						for my $b (0..15) {
152
							push(@px, $teo_pal[$r], $teo_pal[$g], $teo_pal[$b]);
153
						}
154
					}
155
				}
156
				$pal4096 = &px2img(256,16, @px);	
157
			}
158
			$img->Remap(image=>$pal4096, dither=>"true", "dither-method"=>"Floyd-Steinberg");
159-
	$tot = -$tab1[0]-$tab1[15];
159+
160-
	$acc = 0;
160+
161-
	for my $t (@tab1) {$tot += $t;}
161+
162-
	for(my $i=1; $i<16; ++$i) {
162+
163-
		$acc += $tab1[$i];
163+
164-
		if($acc*3>=$tot) {
164+
				++$tabR[$pc2teo[int($px[$i+0]*255)]];
165-
			$MID31 = $i;
165+
				++$tabG[$pc2teo[int($px[$i+1]*255)]];
166
				++$tabB[$pc2teo[int($px[$i+2]*255)]];
167
			}	
168
		}
169-
	for(my $i=$MID31+1; $i<16; ++$i) {
169+
170-
		$acc += $tab1[$i];
170+
171-
		if($acc*3>=$tot*2) {
171+
172-
			$MID32 = $i;
172+
173
	# for my $i (0..15) {
174
		# print $tab1[$i],"  ",$tab2[$i],"\n";
175
	# }
176-
	$tot = -$tab2[0]-$tab2[15];
176+
177-
	$acc = 0;
177+
178-
	for my $t (@tab2) {$tot += $t;}
178+
179-
	for(my $i=1; $i<16; ++$i) {
179+
180-
		$acc += $tab2[$i];
180+
	$tot = $acc = 0;
181-
		if($acc*2>=$tot) {
181+
	for my $t (@tabR) {$tot += $t;}
182-
			$MID21 = $i;
182+
	for(my $i=0; $i<16; ++$i) {
183
		$acc += $tabR[$i];
184
		if($acc>=$tot*.02) {
185
			$RED0 = $i;
186-
	print "$MID31 $MID21 $MID32\n";	
186+
187
		}
188
	}
189
	for(my $i=$RED0+1; $i<16; ++$i) {
190
		$acc += $tabR[$i];
191
		if($acc>=$tot*.33) {
192-
$d4 = sub {
192+
			$RED1 = $i;
193-
	my($v, $d) = @_;
193+
194-
	my($a) = $lin_pal[$MID32];
194+
195-
	return ($v-$a)/(255-$a)>=$d ? 255 : $teo_pal[$MID32] if $v>=$a;
195+
196-
	my($b) = $lin_pal[$MID31];
196+
	for(my $i=$RED1+1; $i<16; ++$i) {
197-
	return ($v-$b)/($a-$b)>=$d ? $teo_pal[$MID32] : $teo_pal[$MID31] if $v>=$b;
197+
		$acc += $tabR[$i];
198-
	return $v/$b>=$d ? $teo_pal[$MID31] : 0;
198+
		if($acc>=$tot*.66) {
199
			$RED2 = $i;
200-
$d3 = sub {
200+
201-
	my($v, $d) = @_;
201+
202-
	my($a) = $lin_pal[$MID21];
202+
203-
	return ($v-$a)/(255-$a)>=$d ? 255 : $teo_pal[$MID21] if $v>=$a;
203+
	for(my $i=$RED2+1; $i<16; ++$i) {
204-
	return $v/$a>=$d ? $teo_pal[$MID21] : 0;
204+
		$acc += $tabR[$i];
205-
};		
205+
		if($acc>=$tot*.98) {
206
			$RED3 = $i;
207
			last;
208
		}
209
	}
210
211
	$tot = $acc = 0;
212
	for my $t (@tabG) {$tot += $t;}
213
	for(my $i=0; $i<16; ++$i) {
214
		$acc += $tabG[$i];
215-
		my $read = read(IN,$buf,4096);
215+
		if($acc>=$tot*.02) {
216
			$GRN0 = $i;
217
			last;
218
		}
219
	}
220
	for(my $i=$GRN0+1; $i<16; ++$i) {
221
		$acc += $tabG[$i];
222
		if($acc>=$tot*.33) {
223
			$GRN1 = $i;
224
			last;
225
		}
226-
		sleep(5) if ($cpt%100)==0; # on fait une pause régulière pour ne pas surchauffer le processeur
226+
227
	for(my $i=$GRN1+1; $i<16; ++$i) {
228
		$acc += $tabG[$i];
229
		if($acc>=$tot*.66) {
230
			$GRN2 = $i;
231
			last;
232
		}
233
	}
234
	for(my $i=$GRN2+1; $i<16; ++$i) {
235
		$acc += $tabG[$i];
236
		if($acc>=$tot*.98) {
237
			$GRN3 = $i;
238
			last;
239
		}
240
	}
241
	
242
	$tot = $acc = 0;
243
	for my $t (@tabB) {$tot += $t;}
244
	for(my $i=0; $i<16; ++$i) {
245
		$acc += $tabB[$i];
246
		if($acc>=$tot*.02) {
247
			$BLU0 = $i;
248
			last;
249
		}
250
	}
251-
				@p = ($d4->($p[0],$d),$d4->($p[1],$d),$d3->($p[2],$d));
251+
	for(my $i=$BLU0+1; $i<16; ++$i) {
252
		$acc += $tabB[$i];
253
		if($acc>=$tot*.5) {
254
			$BLU1 = $i;
255
			last;
256
		}
257
	}
258
	for(my $i=$BLU1+1; $i<16; ++$i) {
259
		$acc += $tabB[$i];
260
		if($acc>=$tot*.98) {
261
			$BLU2 = $i;
262
			last;
263
		}
264
	}
265
	
266
	my $print = sub {
267
		my($pfx, @t) = @_;
268
		my($max, $tot) = (0,0);
269
		for my $v (@t) {$max = $v if $v>$max;$tot += $v;}
270
		for my $i (0..$#t) {print sprintf("%s%2d:%3d%% %s\n", $pfx, $i, int(100*$t[$i]/$tot), "X"x(int(50*$t[$i]/$max)));}
271
	};
272
	$print->("RED", @tabR);
273
	print "$RED0 $RED1 $RED2 $RED3\n";	
274
275
	$print->("GRN", @tabG);
276
	print "$GRN0 $GRN1 $GRN2 $GRN3\n";	
277
278
	$print->("BLU", @tabB);
279
	print "$BLU0 $BLU1 $BLU2\n";	
280
281
	unlink(<tmp/img*.bmp>);
282
}
283
284
285
$dR = sub {
286
	my($v, $d,$a,$b) = @_;
287
	
288
	($a,$b) = ($lin_pal[$RED2],$lin_pal[$RED3]);
289
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$RED3] : $teo_pal[$RED2] if $v>=$a;
290
	
291
	($a,$b) = ($lin_pal[$RED1],$a);
292
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$RED2] : $teo_pal[$RED1] if $v>=$a;
293
	
294
	($a,$b) = ($lin_pal[$RED0],$a);
295
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$RED1] : $teo_pal[$RED0];
296
};
297
$dG = sub {
298
	my($v, $d,$a,$b) = @_;
299
	
300
	($a,$b) = ($lin_pal[$GRN2],$lin_pal[$GRN3]);
301
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$GRN3] : $teo_pal[$GRN2] if $v>=$a;
302
	
303
	($a,$b) = ($lin_pal[$GRN1],$a);
304
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$GRN2] : $teo_pal[$GRN1] if $v>=$a;
305
	
306
	($a,$b) = ($lin_pal[$GRN0],$a);
307
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$GRN1] : $teo_pal[$GRN0];
308-
	open(OUT2,">/tmp/.toto2.pnm");
308+
309-
	print OUT2 "P6\n$width $height\n255\n",pack('C*', @px),"\n";
309+
$dB = sub {
310-
	close(OUT2);
310+
	my($v, $d,$a,$b) = @_;
311
	
312
	($a,$b) = ($lin_pal[$BLU1],$lin_pal[$BLU2]);
313
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$BLU2] : $teo_pal[$BLU1] if $v>=$a;
314
	
315
	($a,$b) = ($lin_pal[$BLU0],$a);
316
	return ($v-$a)/($b-$a)>=$d ? $teo_pal[$BLU1] : $teo_pal[$BLU0];
317
};
318
319
$cpt = 1;$run = 1;
320
while(1) {
321
	$name = sprintf("tmp/img%05d.bmp", $cpt);
322
	
323
	$expected_size = $h*(($w*3 + 3)&~3) + 54 if !$expected_size;
324
	if($expected_size != -s $name) {
325
		last unless $run;
326
		my $buf;
327
		my $read = read(IN,$buf,65536);
328
		if($read) {
329
			syswrite OUT, $buf, $read;
330
		} else {
331
			$run = 0;
332
			close(OUT);
333
		}
334
		
335
	} else  {
336
		# image complete!
337
		print STDERR int($cpt++/$fps),"s (",int(100*($cpt-2)/($fps*$time)),"%)\r";
338
		sleep(5) if ($cpt%500)==0; # on fait une pause régulière pour ne pas surchauffer le processeur
339
		
340
		# lecture de l'image
341
		my $img = Image::Magick->new();
342
		$img->Read($name);
343
		unlink $name;
344
		$img->Set(colorspace=>$LINEAR_SPACE);
345
		
346
		# on force la saturation (140%) pour avoir des couleurs plus franches
347
		$img->Modulate(saturation=>$satur);
348
		$img->Evaluate(operator=>'Multiply', value=>255/$max);
349
		
350
		# trammage
351
		my @px = $img->GetPixels(height=>$h, normalize=>"True");
352
		undef $img;
353
		for my $c (@px) {$c = int($c*255);}
354
		
355
		# dither
356
		my @im = (0,0,0)x($w*$h*4);
357
		for my $y (0..$h-1) {
358
			for my $x (0..$w-1) {
359
				my(@p) = splice(@px, 0, 3);
360
				my($d) = $mat[$x%$mat_x][$y%$mat_y];
361
				my($p) = ($y*$w*2 + $x)*6;
362
				
363
				@p = ($dR->($p[0],$d),$dG->($p[1],$d),$dB->($p[2],$d));
364
				
365
				if($zigzag & $x) {
366
					@im[($p,$p+2,$p+3,$p+5)] = @p[(0,2,0,2)];
367
					$p += $w*6;
368
					@im[($p+1,$p+4)]   = @p[(1,1)];
369
				} else {
370
					@im[($p+1,$p+4)]   = @p[(1,1)];
371
					$p += $w*6;
372
					@im[($p,$p+2,$p+3,$p+5)] = @p[(0,2,0,2)];
373
				}
374
			}
375
		}
376
		$img = &px2img($w*2,$h*2, @im);
377
		$img->Write("tmp/toto.png");
378
		
379
		# ajout de l'image au gif animé
380
		$img->Set(dispose=>"None");
381
		$img->Set(delay=>int(100/$fps));
382
		push(@$gif, $img);
383
		undef $img;
384
		
385
		# pas plus de 3000 imgs (5mins)
386
		last if $cpt==3000 || !$run;
387
	}
388
}
389
close(IN);
390
close(OUT);
391
392
# ecriture du fichier gif
393
$gif->Set(dispose=>"None");
394
$gif->Set(Layers=>"optimize-trans");
395
$gif->Set(delay=>int(100/$fps));
396
$gif->Write($file);
397
398
sub init_magick {
399
	eval 'use Image::Magick;';
400
	
401
	# determination de l'espace RGB lineaire
402
	my $img = Image::Magick->new(size=>"256x1", depth=>16);
403
	$img->Read('gradient:black-white');
404
	$img->Set(colorspace=>'RGB');
405
	#$img->Set(colorspace=>"Gray") unless $coul;
406
	my @px1 = $img->GetPixel(x=>128, y=>0);
407
	$img->Read('gradient:black-white');
408
	$img->Set(colorspace=>'sRGB');
409
	#$img->Set(colorspace=>"Gray") unless $coul;
410
	my @px2 = $img->GetPixel(x=>128, y=>0);
411
	my $d1 = $px1[0]-0.5; $d1=-$d1 if $d1<0;
412
	my $d2 = $px2[0]-0.5; $d2=-$d2 if $d2<0;
413
	$LINEAR_SPACE = $d1>=$d2 ? "RGB" : "sRGB";
414
	#print $px1[0], "   ",$px2[0],"    $LINEAR_SPACE\n";
415
}
416
417
sub px2img {
418
	my($width,$height,@px) = @_;
419
420
	open(OUT_2,">/tmp/.toto2.pnm");
421
	print OUT_2 "P6\n$width $height\n255\n",pack('C*', @px),"\n";
422
	close(OUT_2);
423
	my $img2 = Image::Magick->new();
424
	$img2->ReadImage("/tmp/.toto2.pnm");
425
	unlink "/tmp/.toto2.pnm";
426
  
427
	return $img2;
428
}