Avoid dots in white spaces with custom halftone screensets - ghostscript

I am trying to set up custom angle/frequency halftone screensets with ghostscript and ran into a peculiar problem. The resulting output contains black dots where there should be none.
As a reproducer I found this code:
%!PS-Adobe-2.0
% Sample code to explore the different screen and spot functions
% Written by Bruce Barnett
% Inspired by Michael Thorne
% PostScript Language Journal Vol 1, Number 4
%
%
% define some abbreviations
/l /lineto load def
/m /moveto load def
/rl /rlineto load def
/rm /rmoveto load def
/sg /setgray load def
/sh /show load def
/slw /setlinewidth load def
/st /stroke load def
/tr /translate load def
% and some places to store some information
/str 300 string def % define a string
/ss 50 def % defines square size
/fountstring 256 string def
% print a fountain
/PrintFountain {
% create a string containing values from 0 to 255
0 1 255 {fountstring exch dup put } for
% scale a 1 by 1 image to the size that will spread across the page
% first number is the width, second the height
600 45 scale
% construct/transform the image
256 1 8 [256 0 0 1 0 0] {fountstring} image
} bind def
% Print a tinted box
/TintBox { %define a tinted box, size (ss by ss)
tint 100 div sg
newpath
0 0 m
ss 0 l
ss ss l
0 ss l
closepath fill
} def
/LabelBox { % define a procedure to label a box
10 ss 2 div m % move to (10, ss/2)
lettercolor sg % select color
tint 3 string cvs sh
(% grey) sh
} def
/NextLine {-1 ss mul 10 mul -1 ss mul tr} def % goto next line
/NextLoc {ss 0 tr} def % goto next location (or place for a square)
/PrintMatrix { % define a procedure to print a row of squares
% if at the end of the row, go to the next line
% else - go to the next location
/tint exch def
TintBox % draw the box
LabelBox % add the label
/count count 1 add def % increase the count by one
count 11 lt { % move to next spot
NextLoc
} {
NextLine /count 0 def
} ifelse
} def
% show details of layout (Halftone, etc.)
/ShowDetails {
/str 300 string def
100 750 m
(Spot Procedure Name= ) show
/SpotFunctionName load show % => freq angle
currentscreen % => freq angle proc
pop % ignore procedure
( Angle= ) show
str cvs show % => freq
( Frequency= ) show
str cvs show
} bind def
% A procedure to set the screen angle
% and remember the name of the function
% so we can print it
/ScreenSet { % set screen function
% ang freq /spot_function ScreenSet
dup str cvs /SpotFunctionName exch def
load setscreen
} bind def
/PrintPage {
% also remember time to print page
/time_start usertime def
ShowDetails % prints the halftone screen
gsave % save the graphic state
ss ss 10 mul tr
0 0 m
/count 0 def
/lettercolor 1 def % select white letters
0 1 10 {PrintMatrix} for
10 1 20 {PrintMatrix} for
20 1 30 {PrintMatrix} for
30 1 40 {PrintMatrix} for
40 1 50 {PrintMatrix} for
/lettercolor 0 def % change to black letters
50 1 60 {PrintMatrix} for
60 1 70 {PrintMatrix} for
70 1 80 {PrintMatrix} for
80 1 90 {PrintMatrix} for
90 1 100 {PrintMatrix} for
grestore %restore graphic state
gsave % save it again, for the fountain
PrintFountain
grestore % restore
0 sg
% now print the elapsed time
100 775 m (elapsed time (milliseconds) = ) show
usertime time_start sub str cvs show
showpage % print the page
} bind def
% Here are the different spot functions
% These are suggested by Adobe
/spot_round { % simple round
dup mul exch dup mul add 1 exch sub
} def
% Inverted Round
/spot_iround {
dup mul exch dup mul add 1 sub
} def
% Euclidean Composite
/spot_euclid { % default on many new PS printers
abs exch abs 2 copy add 1 gt {
1 sub dup mul exch 1 sub dup mul add 1 sub
} {
dup mul exch dup mul add 1 exch sub
} ifelse
} def
% Rhomboid
/spot_rhomboid { % Rhomboid
abs exch abs .8 mul add 2 div
} def
% Line
/spot_line {
exch pop abs 1 exch sub
} def
% Diamond
/spot_diamond {
abs exch abs 2 copy add .75 le
{
dup mul exch dup mul add 1 exch sub
} {
2 copy add 1.25 le {
.85 mul add 1 exch sub
} {
1 sub dup mul exch 1 sub dup mul add 1 sub
} ifelse
} ifelse
} def
% Inverted Elliptical
/spot_iellipt {
dup mul .9 mul exch dup mul add 1 sub
} def
/spot_rb { % another from the "Red Book"
180 mul cos exch 180 mul cos add 2 div
} def
/spot_line { % simple line
pop
} def
/spot_line2 { % simple line going the other way
exch pop
} def
% End of definitions, now to print
% Use 8 point Helvetica
8 /Helvetica-Bold findfont exch scalefont setfont
% each "PrintPage" prints one test page
% Print 5 test pages or different screens
% using the same spot function
53 45 /spot_euclid ScreenSet PrintPage
75 0 /spot_euclid ScreenSet PrintPage
83 56 /spot_euclid ScreenSet PrintPage
106 45 /spot_euclid ScreenSet PrintPage
150 0 /spot_euclid ScreenSet PrintPage
% Now print 10 other spot functions, same screen
53 45 /spot_round ScreenSet PrintPage
53 45 /spot_iround ScreenSet PrintPage
53 45 /spot_euclid ScreenSet PrintPage
53 45 /spot_rhomboid ScreenSet PrintPage
53 45 /spot_line ScreenSet PrintPage
53 45 /spot_diamond ScreenSet PrintPage
53 45 /spot_iellipt ScreenSet PrintPage
53 45 /spot_rb ScreenSet PrintPage
53 45 /spot_linea ScreenSet PrintPage
53 45 /spot_lineb ScreenSet PrintPage
% I think you get the idea.....
% end of file
with gs -r1440 -sOutputFile=test%d.tif -sDEVICE=tiffsep1 -f example1.gs I get in test5(black).tif (spot_euclid freq=150) following patterns in progression from white to (near) black:
Where are these dots coming from and how to avoid them? I noticed that the dots within the white are gone at 720 but I need 1440 for my application.
I already looked around and found people with similar problems but no solution. This comment assumes that the white is not clean but that does not explain why the non white parts contain those dots.
EDIT: Smaller reproducer
I noticed that this behavior is also reproducible with a smaller example and stock ghostscript spot function:
<< /PageSize [10 10] >> setpagedevice
0.75 0.5 0 0 setcmykcolor
newpath 0 0 moveto 10 0 lineto 10 10 lineto 0 10 lineto closepath fill
showpage
quit
Running this with gs -r300 -dDITHERPPI=20 -sOutputFile=test%d.tif -sDEVICE=tiffsep1 -f test.gs I get the following output tifs for CMYK channels:
Cyan:
Magenta:
Yellow:
Black:
And for 600 DPI I also get dots in the empty channels:
Cyan:
Magenta:
Yellow:
Black:
I used low dither PPI to make the problem more visible but even in default settings, the points are there.

As noted by #KenS this was a bug in ghostscript that has been resolved.

Related

How to reclassify images in Matlab?

I am attempting to reclassify continuous data to categorical data using Matlab. The following script takes a 4-band (Red, Green, Blue, nIR) aerial image and calculates the normalized difference vegetation index (i.e. a vegetation index showing healthy green vegetation). The script then rescales the values from (-1 to 1) to (0 - 255). This is the matrix I am trying to reclassify in the third section of the script %% Reclassify Imag1 matrix. I am attempting to use conditional statements to perform the reclassification, although this may be the wrong approach. The reclassification step in the script does not have any apparent effect.
How can I reclassify continuous values (0 - 255) to categorical values (1, 2, 3, 4) on a cell by cell basis?
file = 'F:\path\to\naip\image\4112107_ne.tif';
[Z R] = geotiffread(file);
outputdir = 'F:\temp\';
%% Make NDVI calculations
NIR = im2single(Z(:,:,4));
red = im2single(Z(:,:,3));
ndvi = (NIR - red) ./ (NIR + red);
ndvi = double(ndvi);
%% Stretch NDVI to 0-255 and convert to 8-bit unsigned integer
ndvi = floor((ndvi + 1) * 128); % [-1 1] -> [0 256]
ndvi(ndvi < 0) = 0; % not really necessary, just in case & for symmetry
ndvi(ndvi > 255) = 255; % in case the original value was exactly 1
Imag1 = uint8(ndvi);
%% Reclassify Imag1 matrix
if (150 <= Imag1)
Imag1 = 1;
elseif (150 > Imag1) & (140 < Imag1)
Imag1 = 2;
elseif (140 > Imag1) & (130 < Imag1)
Imag1 = 3;
elseif (130 >= Imag1)
Imag1 = 4;
end
%% Write the results to disk
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'reclass_ndvi' '.tif'];
geotiffwrite(outfilename, Imag1, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag)
disp('Processing complete')
Try this:
Imag1 = [ 62 41 169 118 210;
133 158 96 149 110;
211 200 84 194 29;
209 16 15 146 28;
95 144 13 249 170];
Imag1(find(Imag1 <= 130)) = 4;
Imag1(find(Imag1 >= 150)) = 1;
Imag1(find(Imag1 > 140)) = 2;
Imag1(find(Imag1 > 130)) = 3;
Result:
Imag1 =
62 41 169 118 210
133 158 96 149 110
211 200 84 194 29
209 16 15 146 28
95 144 13 249 170
Imag1 =
4 4 1 4 1
3 1 4 2 4
1 1 4 1 4
1 4 4 2 4
4 2 4 1 1
I can go into the logic in detail if you like, but I wanted to confirm that this gives your expected results first.
Some updates based on comments on the follow-up question to eliminate the unnecessary find and make the code more robust and independent of execution order.
Imag2 = zeros(size(Imag1));
Imag2(Imag1 >= 150) = 1;
Imag2((Imag1 > 140) & (Imag1 < 150)) = 2;
Imag2((Imag1 > 130) & (Imag1 < 141)) = 3;
Imag2(Imag1 <= 130) = 4;
Note that the results are now in Imag2 instead of overwriting Imag1.

Fastest way to find the sign of different square

Given an image I and two matrices m_1 ;m_2 (same size with I). The function f is defined as:
Because my goal design wants to get the sign of f . Hence, the function f can rewritten as following:
I think that second formula is faster than first formula because: It
can ignore the square term
It can compute the sign directly, instead of two steps in first equation: compute the f and check sign.
Do you agree with me? Do you have another faster formula for f
I =[16 23 11 42 10
11 21 22 24 30
16 22 154 155 156
25 28 145 151 156
11 38 147 144 153];
m1 =[0 0 0 0 0
0 0 22 11 0
0 23 34 56 0
0 56 0 0 0
0 11 0 0 0];
m2 =[0 0 0 0 0
0 0 12 11 0
0 22 111 156 0
0 32 0 0 0
0 12 0 0 0];
The ouput f is
f =[1 1 1 1 1
1 1 -1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1]
I implemented the first way, but I did not finish the second way by matlab. Could you check help me the second way and compare it
UPDATE: I would like to add code of chepyle and Divakar to make clearly question. Note that both of them give the same result as above f
function compare()
I =[16 23 11 42 10
11 21 22 24 30
16 22 154 155 156
25 28 145 151 156
11 38 147 144 153];
m1 =[0 0 0 0 0
0 0 22 11 0
0 23 34 56 0
0 56 0 0 0
0 11 0 0 0];
m2 =[0 0 0 0 0
0 0 12 11 0
0 22 111 156 0
0 32 0 0 0
0 12 0 0 0];
function f=first_way()
f=sign((I-m1).^2-(I-m2).^2);
f(f==0)=1;
end
function f= second_way()
f = double(abs(I-m1) >= abs(I-m2));
f(f==0) = -1;
end
function f= third_way()
v1=abs(I-m1);
v2=abs(I-m2);
f= int8(v1>v2) + -1*int8(v1<v2); % need to convert to int from logical
f(f==0) = 1;
end
disp(['First way : ' num2str(timeit(#first_way))])
disp(['Second way: ' num2str(timeit(#second_way))])
disp(['Third way : ' num2str(timeit(#third_way))])
end
First way : 1.2897e-05
Second way: 1.9381e-05
Third way : 2.0077e-05
This seems to be comparable and might be a wee bit faster at times than the original approach -
f = sign(abs(I-m1) - abs(I-m2)) + sign(abs(m1-m2)) + ...
sign(abs(2*I-m1-m2)) - 1 -sign(abs(2*I-m1-m2) + abs(m1-m2))
Benchmarking Code
%// Create random inputs
N = 5000;
I = randi(1000,N,N);
m1 = randi(1000,N,N);
m2 = randi(1000,N,N);
num_iter = 20; %// Number of iterations for all approaches
%// Warm up tic/toc.
for k = 1:100000
tic(); elapsed = toc();
end
disp('------------------------- With Original Approach')
tic
for iter = 1:num_iter
out1 = sign((I-m1).^2-(I-m2).^2);
out1(out1==0)=-1;
end
toc, clear out1
disp('------------------------- With Proposed Approach')
tic
for iter = 1:num_iter
out2 = sign(abs(I-m1) - abs(I-m2)) + sign(abs(m1-m2)) + ...
sign(abs(2*I-m1-m2)) - 1 -sign(abs(2*I-m1-m2) + abs(m1-m2));
end
toc
Results
------------------------- With Original Approach
Elapsed time is 1.751966 seconds.
------------------------- With Proposed Approach
Elapsed time is 1.681263 seconds.
There is a problem with the accuracy of second formula, but for the sake of comparison, here's how I would implement it in matlab, along with a third approach to avoid squaring and the sign() function, inline with your intent. Note that the matlab's matrix and sign functions are pretty well optimized, the second and third approaches are both slower.
function compare()
I =[16 23 11 42 10
11 21 22 24 30
16 22 154 155 156
25 28 145 151 156
11 38 147 144 153];
m1 =[0 0 0 0 0
0 0 22 11 0
0 23 34 56 0
0 56 0 0 0
0 11 0 0 0];
m2 =[0 0 0 0 0
0 0 12 11 0
0 22 111 156 0
0 32 0 0 0
0 12 0 0 0];
function f=first_way()
f=sign((I-m1).^2-(I-m2).^2);
end
function f= second_way()
v1=(I-m1);
v2=(I-m2);
f= int8(v1<=0 & v2>0) + -1* int8(v1>0 & v2<=0);
end
function f= third_way()
v1=abs(I-m1);
v2=abs(I-m2);
f= int8(v1>v2) + -1*int8(v1<v2); % need to convert to int from logical
end
disp(['First way : ' num2str(timeit(#first_way))])
disp(['Second way: ' num2str(timeit(#second_way))])
disp(['Third way : ' num2str(timeit(#third_way))])
end
The output:
First way : 9.4226e-06
Second way: 1.2247e-05
Third way : 1.1546e-05

JPEG compression implementation in MATLAB

I'm working on an implementation of the JPEG compression algorithm in MATLAB. I've run into some issues when computing the discrete cosine transform(DCT) of the 8x8 image blocks(T = H * F * H_transposed, H is the matrix containing the DCT coefficients of an 8x8 matrix, generated with dctmtx(8) and F is an 8x8 image block). The code is bellow:
jpegCompress.m
function y = jpegCompress(x, quality)
% y = jpegCompress(x, quality) compresses an image X based on 8 x 8 DCT
% transforms, coefficient quantization and Huffman symbol coding. Input
% quality determines the amount of information that is lost and compression achieved. y is the encoding structure containing fields:
% y.size size of x
% y.numblocks number of 8 x 8 encoded blocks
% y.quality quality factor as percent
% y.huffman Huffman coding structure
narginchk(1, 2); % check number of input arguments
if ~ismatrix(x) || ~isreal(x) || ~ isnumeric(x) || ~ isa(x, 'uint8')
error('The input must be a uint8 image.');
end
if nargin < 2
quality = 1; % default value for quality
end
if quality <= 0
error('Input parameter QUALITY must be greater than zero.');
end
m = [16 11 10 16 24 40 51 61 % default JPEG normalizing array
12 12 14 19 26 58 60 55 % and zig-zag reordering pattern
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99] * quality;
order = [1 9 2 3 10 17 25 18 11 4 5 12 19 26 33 ...
41 34 27 20 13 6 7 14 21 28 35 42 49 57 50 ...
43 36 29 22 15 8 16 23 30 37 44 51 58 59 52 ...
45 38 31 24 32 39 46 53 60 61 54 47 40 48 55 ...
62 63 56 64];
[xm, xn] = size(x); % retrieve size of input image
x = double(x) - 128; % level shift input
t = dctmtx(8); % compute 8 x 8 DCT matrix
% Compute DCTs pf 8 x 8 blocks and quantize coefficients
y = blkproc(x, [8 8], 'P1 * x * P2', t, t');
y = blkproc(y, [8 8], 'round(x ./ P1)', m); % <== nearly all elements from y are zero after this step
y = im2col(y, [8 8], 'distinct'); % break 8 x 8 blocks into columns
xb = size(y, 2); % get number of blocks
y = y(order, :); % reorder column elements
eob = max(x(:)) + 1; % create end-of-block symbol
r = zeros(numel(y) + size(y, 2), 1);
count = 0;
for j = 1:xb % process one block(one column) at a time
i = find(y(:, j), 1, 'last'); % find last non-zero element
if isempty(i) % check if there are no non-zero values
i = 0;
end
p = count + 1;
q = p + i;
r(p:q) = [y(1:i, j); eob]; % truncate trailing zeros, add eob
count = count + i + 1; % and add to output vector
end
r((count + 1):end) = []; % delete unused portion of r
y = struct;
y.size = uint16([xm xn]);
y.numblocks = uint16(xb);
y.quality = uint16(quality * 100);
y.huffman = mat2huff(r);
mat2huff is implemented as:
mat2huff.m
function y = mat2huff(x)
%MAT2HUFF Huffman encodes a matrix.
% Y = mat2huff(X) Huffman encodes matrix X using symbol
% probabilities in unit-width histogram bins between X's minimum
% and maximum value s. The encoded data is returned as a structure
% Y :
% Y.code the Huffman - encoded values of X, stored in
% a uint16 vector. The other fields of Y contain
% additional decoding information , including :
% Y.min the minimum value of X plus 32768
% Y.size the size of X
% Y.hist the histogram of X
%
% If X is logical, uintB, uint16 ,uint32 ,intB ,int16, or double,
% with integer values, it can be input directly to MAT2HUF F. The
% minimum value of X must be representable as an int16.
%
% If X is double with non - integer values --- for example, an image
% with values between O and 1 --- first scale X to an appropriate
% integer range before the call.For example, use Y
% MAT2HUFF (255 * X) for 256 gray level encoding.
%
% NOTE : The number of Huffman code words is round(max(X(:)))
% round (min(X(:)))+1. You may need to scale input X to generate
% codes of reasonable length. The maximum row or column dimension
% of X is 65535.
if ~ismatrix(x) || ~isreal(x) || (~isnumeric(x) && ~islogical(x))
error('X must be a 2-D real numeric or logical matrix.');
end
% Store the size of input x.
y.size = uint32(size(x));
% Find the range of x values
% by +32768 as a uint16.
x = round(double(x));
xmin = min(x(:));
xmax = max(x(:));
pmin = double(int16(xmin));
pmin = uint16(pmin+32768);
y.min = pmin;
% Compute the input histogram between xmin and xmax with unit
% width bins , scale to uint16 , and store.
x = x(:)';
h = histc(x, xmin:xmax);
if max(h) > 65535
h = 65535 * h / max(h);
end
h = uint16(h);
y.hist = h;
% Code the input mat rix and store t h e r e s u lt .
map = huffman(double(h)); % Make Huffman code map
hx = map(x(:) - xmin + 1); % Map image
hx = char(hx)'; % Convert to char array
hx = hx(:)';
hx(hx == ' ') = [ ]; % Remove blanks
ysize = ceil(length(hx) / 16); % Compute encoded size
hx16 = repmat('0', 1, ysize * 16); % Pre-allocate modulo-16 vector
hx16(1:length(hx)) = hx; % Make hx modulo-16 in length
hx16 = reshape(hx16, 16, ysize); % Reshape to 16-character words
hx16 = hx16' - '0'; % Convert binary string to decimal
twos = pow2(15 : - 1 : 0);
y.code = uint16(sum(hx16 .* twos(ones(ysize ,1), :), 2))';
Why is the block processing step generating mostly null values?
It is likely that multiplying the Quantization values you have by four is causing the DCT coefficients to go to zero.

Remove images from PDF

I read Create a tiff with only text and no images from a postscript file with ghostscript and try to use KenS`s answer.
But this method remove only "black" images - image contain data only in black channel (PDF has colorspace CMYK). How can i remove all images in my case?
This does a better job, but its incomplete. It doesn't deal with images using multiple data sources for example. Its essentially untested, except that I did test your smaller file (pages.pdf) by using ps2write to convert to PostScript and then the PostScript program below, and teh pdfwrite device, to convert back to PDF.
One of the first things you will notice is that almost all the text has vanished from your document. That's because the fonts you are using are bitmap fonts, and the program can't tell the difference between a bitmap representing a character, and any other kind of bitmap. For this file you can solve that by removing the definition of imagemask because all the characters use imagemask, and the other images use 'image'.
I have a sneaky suspicion the formatting of the program is going to get messed up here :-(
8<------------------------------8<--------------------------8<-------------------------
%!
%
% numbytes -file- ConsumeFileData -
%
/ConsumeFileData {
userdict begin
/DataString 256 string def
/DataFile exch def
/BytesToRead exch def
%(BytesToRead = ) print BytesToRead ==
mark
{
DataFile DataString readstring { % read bytes
/BytesToRead BytesToRead 256 sub def % not EOF subtract 256 from required amount.
%(Read 256 bytes) ==
%(BytesToRead now = ) print BytesToRead ==
} {
length
%(Read ) print dup 256 string cvs print (bytes) ==
BytesToRead exch sub /BytesToRead exch def % Reached EOF, subtract length read froom required amount
%(BytesToRead now = ) print BytesToRead ==
exit % and exit loop
} ifelse
} loop
%BytesToRead ==
BytesToRead 0 gt {
(Ran out of image data reading from DataSource\n) ==
} if
cleartomark
end
} bind def
%
% numbytes -proc- ConsumeProcData -
%
/ConsumeProcData {
userdict begin
/DataProc exch def
/BytesToRead exch def
{
DataProc exec % returns a string
length BytesToRead exch sub % subtract # bytes read
/BytesToRead exch def
BytesToRead 0 le {
exit % exit when read enough
} if
} loop
end
} bind def
/image {
(image) ==
dup type /dicttype eq {
dup /MultipleDataSources known {
dup /MultipleDataSources get {
(Can't handle image with multiple sources!) ==
} if
} if
dup /Width get % stack = -dict- width
exch dup /BitsPerComponent get % stack = width -dict- bpc
exch dup /Decode get % stack = width bpc -dict- decode
length 2 div % decode = 2 * num components
exch 4 1 roll % stack = -dict- width bpc ncomps
mul mul % stack = -dict- width*bpc*ncomps
7 add cvi 8 idiv % stack = -dict- width(bytes)
exch dup /Height get % stack = width -dict- height
exch /DataSource get % stack = width height DataSource
3 1 roll % stack = DataSource width height
mul % stack = DataSource widht*height
exch % stack = size DataSource
} {
5 -1 roll
pop % throw away matrix
mul mul % bits/sample*width*height
7 add cvi 8 idiv % size in bytes of data floor(bits+7 / 8)
exch % stack = size DataSource
} ifelse
dup type /filetype eq {
ConsumeFileData
} {
dup type /arraytype eq or
1 index type /packedarraytype eq or {
ConsumeProcData
} {
pop pop % Remove DataSource and size
} ifelse
} ifelse
} bind def
/imagemask {
(imagemask)==
dup type /dicttype eq {
dup /MultipleDataSources known {
dup /MultipleDataSources get {
(Can't handle imagemask with multiple sources!) ==
} if
} if
dup /Width get % stack = -dict- width
7 add cvi 8 idiv % size in bytes of width floor(bits+7 / 8)
exch dup /Height get % stack = width -dict- height
exch /DataSource get % stack = width height DataSource
3 1 roll % stack = DataSource width height
mul % stack = DataSource width*height
exch % stack = size DataSource
} {
5 -1 roll
pop % throw away matrix
mul mul % bits/sample*width*height
7 add cvi 8 idiv % size in bytes of data floor(bits+7 / 8)
exch % stack = size DataSource
} ifelse
dup type /filetype eq {
ConsumeFileData
} {
dup type /arraytype eq or
1 index type /packedarraytype eq or {
ConsumeProcData
} {
pop pop % Remove DataSource and size
} ifelse
} ifelse
} bind def
/colorimage {
(colorimage)==
dup 1 ne {
1 index
{
(Can't handle colorimage with multiple sources!) ==
} if
} {
exch pop % get rid of 'multi'
% stack: w h bpc m d ncomp
3 -1 roll pop % stack: w h bpc d ncomp
exch 5 -1 roll % stack d w h bpc ncomp
mul mul mul % stack: d w*h*bpc*ncomp
7 add cvi 8 idiv exch % stack: bytes datasource
} ifelse
dup type /filetype eq {
ConsumeFileData
} {
dup type /arraytype eq or
1 index type /packedarraytype eq or {
ConsumeProcData
} {
pop pop % Remove DataSource and size
} ifelse
} ifelse
} bind def
That technique should work for images in any colour, because the image operator is used for both colour and monochrome images. Unless your file uses the obselete level 1.5 'colorimage' operator. I can't recall if I redefined that operator in the example, if not then yuo can redefine it in a similar fashion.
In fact I see that I offered redefinitions for image, colorimage and imagemask, so all image types should be elided. Perhaps you could share an example ?

Generating random points to build a procedural line

I want to randomly generate points. Well at least there should be a limitation on the y-axis. Later I connect the points to a line which should proceed in a simple animation. You can imagine this as a random walk of a drunken person, going uphill and downhill.
This sounds very simple. I searched around the web and found that this could be accomplished using the markov chain. I think this idea is really interesting.
You can create the first state of your scene by yourself and pass this state as input to the markov chain algorithm. The algorithm randomly changes this state and creates a walk.
However I cannot find any example of that algorithm and no source code. I just found an applet that demonstrates the markov chain algorithm: http://www.probability.ca/jeff/java/unif.html
Please suggest some code. Any other ideas how to accomplish this are appreciated too.
I painted an example
So I want the line to proceed in a similar way. There are valleys, slopes ... they are random but the randomness still apply to the initial state of the line. This is why I found makrov chain so interesting here: http://www.suite101.com/content/implementing-markov-chains-a24146
Here's some code in Lua:
absstepmax = 25
ymin = -100
ymax = 100
x = 0
y = 5
for i = 1, 20 do
y = y + (math.random(2*absstepmax) - absstepmax - 1)
y = math.max(ymin, math.min(ymax, y))
x = x + 5
print (x,y)
end
absstepmax limits the size of a y step per iteration
ymin and ymax limit the extent of y
There is no bias in the example, i.e., y can change symmetrically up or down. If you want your "drunk" tending more "downhill" you can change the offset after the call to random from absstepmax - 1 to absstepmax - 5 or whatever bias you like.
In this example, the x step is fixed. You may make this random as well using the same mechanisms.
Here are some sample runs:
> absstepmax = 25
> ymin = -100
> ymax = 100
> x = 0
> y = 5
> for i = 1, 20 do
>> y = y + (math.random(2*absstepmax) - absstepmax - 1)
>> y = math.max(ymin, math.min(ymax, y))
>> x = x + 5
>> print (x,y)
>> end
5 4
10 22
15 37
20 39
25 50
30 40
35 21
40 22
45 12
50 16
55 16
60 12
65 -1
70 -8
75 -14
80 -17
85 -19
90 -25
95 -37
100 -59
> absstepmax = 25
> ymin = -100
> ymax = 100
> x = 0
> y = 5
> for i = 1, 20 do
>> y = y + (math.random(2*absstepmax) - absstepmax - 1)
>> y = math.max(ymin, math.min(ymax, y))
>> x = x + 5
>> print (x,y)
>> end
5 -2
10 -15
15 -7
20 1
25 1
30 12
35 23
40 45
45 43
50 65
55 56
60 54
65 54
70 62
75 57
80 62
85 86
90 68
95 76
100 68
>
Painted result added from OP:

Resources