PDF cropping image almost correctly - image

I've inherited some code that hand-rolls PDF files. One of the things this code does, is that a large image is inserted into the PDF as a resource, and then pieces of that image are cropped in the PDF command stream and drawn separately.
For example, if the large image is 1000 x 400 pixels, the code draws a chunk extracted from the top left of the large image ((0, 0) to (250, 200)) and then next to that draws another chunk extracted from the top middle of the large image ((250, 0), (500, 200)) (in this post I'm describing the crop coordinates using standard image coordinate system with origin in top-left).
The way the code does this, is to create a secondary XObject that just draws the large image, scaled and offset appropriately. So to extract the image from ((250, 0) to (500, 200)) it defines a new XObject like this:
/Type/XObject /Subtype/Form /FormType 1 /Name/Img4 /BBox [0 0 1 1] /Matrix [1 0 0 1 0 0] /Length 26/Resources << /XObject << /img3 23 0 R >> >>
4 0 0 2 1 1 cm
/img3 Do
(obviously I've cut out a lot of PDF, don't worry, it works so the PDF you don't see is basically correct)
Which, if I understand it correctly, takes the XObject of the original image (which is a 1 x 1 square), makes it 4 times bigger in the x-direction and 2 times bigger in the y-direction, offsets it by 1 in both x and y, and now the portion of the image we want appears in the XObject rectangle of ((0, 0), (1, 1)). So the code can just draw this new XObject wherever it wants, and gets the cropped portion of the large image.
This basically works correctly, but of course in the real world the large image is 656 x 656, and the pieces being extracted are 308 x 120 and 40 x 120 so the numbers aren't quite as nice.
If I look at the resulting PDF at high magnification (1600%) in Adobe Acrobat Reader, it's perfect. All the pixels exactly where they should be.
The problem I'm running into, is that at lower magnification (200%), I end up with this strange offset where the 2 images abut:
For this example, the transform matrix that does the cropping is:
2.12987 0 0 5.46667 -0 -4.46667 cm
which seems like it should be enough digits of precision, but even if I increase the precision:
2.1298701 0 0 5.4666667 -0 -4.4666667 cm
the exact same problem happens.
It looks like Adobe Reader is truncating the precision somewhere in its calculations.
Any idea why this is happening, and how I can get around it?

Related

Is using multiple halftone screens on the same page allowed in postscript 3?

I am working with a postscript file that uses sethalftone several times on the same page. On my printer I get the expected results but when using ghostscript, the whole page is rendered with the same screen. I reduced it down to this example:
%!PS-Adobe-3.0
<< /PageSize [99 33] >> setpagedevice
/size 33 def
/rect {
newpath
0 0 moveto
size 0 lineto
size size lineto
0 size lineto
closepath
fill
} def
0.5 0.5 0.5 0.5 setcmykcolor
rect
<< /HalftoneType 1 /Frequency 100 /Angle 60 /SpotFunction { pop } >> sethalftone
size 0 translate
rect
<< /HalftoneType 1 /Frequency 100 /Angle 45 /SpotFunction { pop } >> sethalftone
size 0 translate
rect
showpage
For which gs -dNOPAUSE -dBATCH -r600 -sDEVICE=tiffsep1 -sOutputFile=test%d.tif test.ps (version 9.52) gives me the following channel images (its the same for all channels):
When moving the first sethalftone before the first rect command, I get these channel images, which contain artifacts and still have the same halftone:
Obviously, there is some sort of memory corruption in the halftone buffer.
Setting only one halftone at the beginning (before the default has been used) works fine.
So my question from the title remains: Is it allowed to use multiple different halftones on the same page in postscript?
PS: When separating each rectangle and halftone onto its own page, I still get the memory corruptions but the halftones seem to be applied differently.
You can change halftone at any point in the course of a PostScript program. It need not be at the start of a page or start of a program.

pdf images position and scaling

I have some images in a pdf document, they are singular images saved in the pdf, but then are rebuilt together. I have to rebuild the entire image, but I don't understand something...so, the extract in the pdf is:
Q
q
cm:36.442 0 0 88.32 71.94 462.56
Do:/Im1
Q
q
cm:54.92 0 0 88.32 106.962 462.56
Do:/Im5
Q
q
cm:20.018 0 0 88.32 160.342 462.56
Do:/Im10
Im1 is 71x206 pixels, Im2 is 107x206 and Im3 is 39x706.
I don't understand how to apply the x scale factor to the single images, it seems they are xscaled, but if I calculate they don't appears one beside the other, as it should be.
In addition, if, knowing nothing of pdf, I merge these images all together, the union image results not aligned. Anyone could explain me better? Thank you

Turn black pixel on the first image to white if it is also black on a second co-located image

I have 2 co-located images, both created in a similar way and both have the size of 7,221 x 119 pixels.
I want to write a logic like this:
If the R,G,B values of a certain pixel (called it x) in image 1 = 0,0,0 (black) And the R,G,B values of pixel x in image 2 = 0,0,0 (black) then change the R,G,B values of pixel x in image 1 to 255,255,255 (white), Else no change.
How can I do this in either Matlab or Python?
You should be able to do this in python with the Pillow package. You need to load the two pixels, check if all the color channels are 0 and if so make them 255, then save the image again. In Python 0 is interpreted as False, so not any(vals) will be True when vals includes only zeros.
from PIL import Image
im1 = Image.open("image1.jpg")
im2 = Image.open("image2.jpg")
pixel = (0, 0)
newcolor = (255,)*3
if not any(im1.getpixel(pixel)) and not any(im2.getpixel(pixel)):
im1.putpixel(pixel, newcolor)
im1.save('image1conv.jpg')
Note that not any(im1.getpixel(pixel)) and not any(im2.getpixel(pixel)) could be rewritten as not any(im1.getpixel(pixel) + im2.getpixel(pixel)), but I think the first way has clearer logic.

Overlay data on image file aligning with grid lines

My aim is to plot an image file in MATLAB and aligning it as closely to the ticks from the image then overlay data points. The image file was screen captured from a pdf report (link below). The data is loglog. The image file axis has lower and upper bounds of.
xstart 1e-2 to xend 1e5 % frequency and
ystart 1e-7 yo yend 1e-1 % amplitude
I would like to plot the following data values on top of the image
frequency = [1 3 10 30 100 300 1000 3000 10000];
amplitude = [7e-3 8e-4 1.3e-4 4e-5 2e-5 1.8e-5 1.7e-5 1.65e-5 1.6e-5];
(Or any vector values I get from computation for example vector "B" as a function of frequency vector "f")
The issue I have is the .pdf image has grid lines. As a consequence misaligning data points and making it look unaesthetic with axis labels.Thanks
image file
I think it's best to align the log ticks as closely as possible with the image file. Below is my code. I haven't worked out how to align the tick axis with the image exactly yet (when zoomed in), (i'm sure you can do this manually, but if there is an elegant image process mathematical method would be nice).
imgInputlf = imread('RMIT_Input_Noise_Lowf.png');
[nrows,ncols,dim]=size(imgInputlf);
figure(1)
f = logspace(-2,5,ncols);
amp=logspace(-7,-1,nrows);
xrng=[min(f) max(f)];yrng=[min(amp) max(amp)];
imagesc(xrng,yrng,imgInputlf)
ax1=gca;
set(ax1,'YTickLabel', [], 'XTickLabel', []) % remove pixel ticklabels
set(findobj(gcf, 'type','axes'), 'Visible','off')
Freq = [1 3 10 30 100 300 1000 3000 10000]; % data
Amp = [7e-3 8e-4 1.3e-4 4e-5 2e-5 1.8e-5 1.7e-5 1.65e-5 1.6e-5]; %data
ax2 = axes('Position',get(ax1,'Position'),'Color','none','YScale', 'log','XScale','log'); %color=none to make the image visible
ylim(yrng)
xlim(xrng)
hold on
loglog(Freq,Amp,'k','LineWidth',4) % plot data end

MATLAB imresize increases image size on disc on downscaling to half

I was trying to downscale a .png image using imresize by 0.5 which was originally 25 kB. However, on saving the scaled image using imwrite, the size of the saved image becomes 52 kB.
The following is the image and the commands:
image=imread('image0001.png');
B = imresize(image, 0.5);
imwrite(B,'img0001.png','png');
This also happens if the resolution is specified as follows:
B = imresize(image, [400 300]);
What is the reason for this? It seems to work fine when scaled to 0.15.
The reason is that imresize uses bicubic interpolation, thus producing additional pixel values. Your original image is small since it has small number of unique pixel values. After interpolation the number will increase, thus increasing the file size.
To preserve the number of unique values you can use: B = imresize(image, 0.5, 'nearest');. You can check it as follows:
image=imread('image0001.png');
B = imresize(image, 0.5);
numel(unique(image)); % gives 18
numel(unique(B)); % gives 256
with new interpolation:
image=imread('image0001.png');
B = imresize(image, 0.5, 'nearest');
numel(unique(image)); % gives 18
numel(unique(B)); % gives 18
Saving B now should produce smaller size.

Resources