jpegepsascii85

Swap an image in an .eps file?


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.


Solution

  • 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.