0

I'm trying to figure out how to swap an image that is embedded in an .eps file with a jpeg. My "template" .eps file contains several sections that look this, each representing a different image:

Adobe_AGM_Image/AGMIMG_fl cf /ASCII85Decode fl /RunLengthDecode filter ddf
<<
/T 1
/W 4773 
/H 273 
/M[4773 0 0 -273 0 273 ]
/BC 8 
/D[0 1 0 1 0 1 0 1 ]
/DS [
[AGMIMG_fl 4773 string /rs cvx /pop cvx] cvx
[AGMIMG_fl 4773 string /rs cvx /pop cvx] cvx
[AGMIMG_fl 4773 string /rs cvx /pop cvx] cvx
[AGMIMG_fl 4773 string /rs cvx /pop cvx] cvx
]
/O 3
>>
%%BeginBinary: 1
img
[image data]~>

%%EndBinary

From what I've been able to determine, the image file is ASCII85 encoded, but I haven't been able to figure out a way to encode a jpeg image such that I could swap it out.

To clarify the situation, I have both the .eps and the original files. ASCII85 decoding the image blocks in the .eps doesn't match the information in the jpegs, and visa versa.

[updated]

My ultimate goal is to create a .eps with layers and without using adobe's scripting language. We create finals for our customers that we then need to add to the template (the .eps file) our printer gave us. All of the finals should be the same and contain the same color scheme (CMYK).

In the .eps file, one of the layers (which Adobe Illustrator can read) contains the artwork that needs to print; the other layer contains cut lines in a "spot color" that the printer uses as instructions for their cutting machine. My goal is to automate the templating process so that we don't need to manually create the .eps files for the printer.

A simple find/replace seemed to be the simplest way to achieve my goal, but I am not married to that idea. Image libraries such as imagemagick, graphicsmagick, and pillow have all failed me to date.

[updated]

As requested, here is an image of the template: printer template There are four distinct black images, which as you would guess meet at the midpoint between the cut lines. During the "templating process" (perhaps a poor choice of words) we take the artwork generated for our clients - the finals - and position it where the black images are. The entire process is manual, tedious, and should be possible to automate - that is what I am attempting to do.

jobu1342
  • 150
  • 7
  • OK so the cutter will be, as you say, in a spot colour which will be defined as a /Separation colour space. But because this is a PostScript program, it may not obviously be defined that way. I'm afraid I still don't know what you mean by the 'templating process' and what it is you hope to automate, probably because I don't really understand what you mean by a 'final'. Perhaps some pictures would help, or some demonstration files. Normally you wouldn't add content to an EPS you would embed the EPS inside a PostScript program. – KenS Jan 07 '20 at 19:23
  • Updated the question to include an example image and further clarified the process - hopefully that answers your question! – jobu1342 Jan 07 '20 at 19:55
  • OK I'll tack my answer on to my previous answer, because its kind of large. – KenS Jan 08 '20 at 08:19

1 Answers1

2

Realistically you shouldn't try to replace the image.

PostScript is a programming language and unless all the EPS files you ever plan to handle are produced by the same application, and to be realistic exactly the same version of that application, then the exact semantics of the program may vary. If the semantics vary then search and replace will fail.

The section you have supplied is incomplete, it looks like it's a 4 colour image in CMYK space (because it has 4 procedures to read the data, and what's probably a Decode array has 8 elements) but there is no attempt to set the colour space, nor do you know the CTM in force. Scaling a different image to fit into the same area would be difficult unless it has the same number of rows and columns.

The image data is not simply ASCII85 encoded, it is also run-length encoded (ascii85 applied after run-length encoding), and the data is supplied as interleaved rasters. A line of Cyan followed by a line of Magenta, followed by a line of Yellow and a line of blacK. In order for an image application to read this you will have to read a set of 4 rasters, undo the ascii85 encoding, and then undo the run-length encoding, then take samples individually from each raster and interleave them to produce 4 lines of CMYKCMYKCMYK... data. (Note that very few image applications can handle CMYK data at all).

In order to replace the image data, and assuming the replacement is precisely the same dimensions, you would need to decode the image data into image samples (i.e. undo the JPEG compression). Break it up into C, M, Y, K planes, run length encode the planes, then ascii85 encode each raster, then write the image data a raster line at a time.

If there are any differences in the colour space, dimensions, bits per component or encoding then you would also need to replace the section of program which reads the image data and massages it into a form suitable for passing to the interpreter, and that's going to be a large task requiring you to learn the PostScript programming language.

The 'img' procedure (which will be defined earlier in the program) takes the dictionary data and either turns it into an image dictionary to be supplied to the PostScript image operator or turns it into equivalent level 1 operands to be supplied to the image operator if the interpreter is extremely old and only supports level 1.

In general, the only way to handle EPS files is to use a full PostScript interpreter, such as Ghostscript (as used by ImageMagick and, I presume GraphicsMagick). Because you really need to interpret the program. You can make limited changes to programs which conform to the EPS specification, but wholesale replacement of image data is not one of the intended purposes.

I don't know what you mean by 'layers'. There is no concept of layers in PostScript, which is because it's a page description language; there is no need for a 'layer'. Perhaps if you could explain what you want to achieve it might be possible to offer a different solution.

Additional

OK so the 'normal' way to proceed in this sort of situation is for the PostScript with the 'template' to be generated such that it includes the content from your customers.

Ordinarily the customer content would be supplied as EPS (might be PDF these days), the tool to create the output for the printer would generate PostScript (not EPS, a full PostScript program) and would embed the EPS in the program. That's the point of EPS, you include it in a PostScript program.

EPS files are not really editable and not intended to be altered, in fact altering them potentially invalidates the BoundingBox information. The only way to understand what the PostScript program does is to interpret it, which is why trying to search and replace is not really a future-proof solution.

I'm also a little concerned that you seem to be using JPEG compressed images in a print environment! JPEG is (ordinarily) a lossy compression method, so a JPEG compressed image will have artefacts, I'd ordinarily consider it unsuitable for the kind of process you seem to be implying here.

Now I can see several ways to approach the problem which don't involve editing the EPS file. Assuming you know the size and position of each of the 'boxes' in the EPS, and your customer content is in EPS format, you simply concatenate the files together, generating positional information as required.

PostScript has an opaque imaging model, that means that if you start with the 'template' and then set up the CTM correctly, you can include an entire EPS file in such a way that when rendered it exactly covers the area you want to replace.

To do this you need to know the precise size and location which the EPS should cover (I'm assuming you know this) and the exact area covered by the EPS, you get that from the %%BoundingBox comment of the EPS file. It's then a trivial matter to add scale and translate operations so that the EPS is correctly sized an positioned.

Here's a skeleton of what I mean:

%!PS

%!PS-Adobe-2.0 EPSF-1.2
%%Creator: Adobe Illustrator
%%Title: Template
%%BoundingBox: 0 0 612 792
....
....
%%EOF

% execute a save of the graphics state so the EPS doesn't change anything
gsave

% Reposition customer EPS file to first location in the template
% and scale it up (Lets pretend the first slot is at x=0, y=200
% and we need to double the size of the EPS so it fits.
0 200 moveto
2 2 scale

%!PS-Adobe-2.0 EPSF-1.2
%%Creator: Adobe Illustrator
%%Title: customer content file #1
%%BoundingBox: 0 0 100 100
....
....
%%EOF

% Now execute a grestore so everythgin goes back to the state it was in
% before we ran the EPS
grestore

% Repeat for each EPS file

showpage

I'm assuming that your customer content is supplied as EPS and not as image (bitmap) data. If it really is a JPEG image then you can write PostScript code to include the JPEG in place of the EPS in the code above.

I'm hazy on how your existing process works, it's not obvious to me what your manual process for positioning the client content is.

halfer
  • 19,824
  • 17
  • 99
  • 186
KenS
  • 30,202
  • 3
  • 34
  • 51
  • Thanks for the explanation, Ken. We use Adobe Illustrator, and it recognizes layers in the eps file (like photoshop) - presumably it can do that because of the flexible nature of the eps file. It sounds like this _could_ work for us, if I learn a lot about image processing. I'm not sure ghostscript can do what we need (i.e. maintain the layers). – jobu1342 Jan 07 '20 at 17:01
  • I've updated my goal in the question - hopefully does a better job explaining what I want to achieve. – jobu1342 Jan 07 '20 at 17:14
  • I doubt if Illustrator recogises 'layers' in the EPS. What it probably does is save the Illustrator native file in the EPS as comments. Then when you open the EPS it actually throws away the PostScript and just uses its native file. – KenS Jan 07 '20 at 19:20
  • I've been playing around with your template for a while now, and it looks promising, except that the `moveto` command isn't repositioning cursor for following eps documents. They consistently draw at the bottom of the document (0, 0) regardless of the values I use for `moveto`, positive or negative. – jobu1342 Jan 08 '20 at 19:27
  • D'oh, yeah, the values are absolute in the EPS file so you need to use translate instead of moveto. Sorry, not thinking there. What translate does is move the origin (0,0) from the bottom left to somewhere else, so all the co-ordinates in the following EPS become relative to the new position, rather than relative to the bottom left of the media. – KenS Jan 09 '20 at 08:06
  • This is working! I still have (one last?) problem though. The image (at least in IrfanView) aspect ratio is portrait when I start the document with `%!PS`. Through the process of elimination I discovered that if I start the document with `%!PS-Adobe-3.1 EPSF-3.0` it renders correctly. Can I just do that, or is there anything I should be aware of? – jobu1342 Jan 09 '20 at 17:26
  • Yes. That's just a comment, which means 'something' is reading the comment and acting upon it, you haven't (I don't think) said what you are using to process the PostScript (i'd be amazed if IrfanView can render PostScript natively, it may be using Ghostsc ipt), but in order to get the media size correct your PostScript should do a <> setpagedevice. I presume you can get x and y from the BoundingBox of the EPS file, or you just know already what it should be. Its best to set this rather than relying on an unknown processor reading it from the comments in an embedded EPS file. – KenS Jan 09 '20 at 19:57