OSError: Unable to locate Ghostscript on paths

While reading in an EPS file, I get the error “OSError: Unable to locate Ghostscript on paths” Here’s my code that generates the error:

   def _readImage(self, image):
               
        actual_file = image

        # Try each, and open the one that actually exists:
        if exists(CFG.image_source + image.replace(".gif", ".eps")):
            actual_file = image.replace(".gif", ".eps")
        elif exists(CFG.image_source + image.replace(".gif", ".png")):
            actual_file = image.replace(".gif", ".png")
        elif exists(CFG.image_source + image.replace(".gif", ".jpg")):
            actual_file = image.replace(".gif", ".jpg")
        elif exists(CFG.image_source + image.replace(".gif", ".jpeg")):
            actual_file = image.replace(".gif", ".jpeg")
        
        return Image.open(CFG.image_source + actual_file)

I’m trying to parse the output of a program called AdMax from Software Consulting Systems. The output file lists images with the “.gif” extension regardless of the actual extension that the image uses, so each image call has to use os.path.exists() to determine what the actual file name is.

I do believe there is a way to edit the export, but doing so might break the current export system that I’m trying to seamlessly replace, so modifications are out of the question.

Possible Fix:

1.) Download and Install GhostScript from: https://ghostscript.com/releases/gsdnld.html

2.) Import EpsImagePlugin from PIL:

from PIL import EpsImagePlugin

3.) Configure your path to Ghostscript. I found mine in “C:\Program Files\gs\gs9.56.1\bin\gswin64c.exe”

EpsImagePlugin.gs_windows_binary = r'C:\Program Files\gs\gs9.56.1\bin\gswin64c.exe'

That worked like a charm for me. Here’s the rest of the code in case I missed something above.

Note, I’ve stopped working on this midstream, so the tail end portions of this are nowhere near complete, and some of this code has not been tested at all, not even once! Use at your own risk!

from os.path import exists
import pandas as pd
from PIL import Image
from PIL import EpsImagePlugin
import numpy as np

# Ghost script is needed on every computer that runs this script:
# Get it here: https://ghostscript.com/releases/gsdnld.html
EpsImagePlugin.gs_windows_binary =  r'C:\Program Files\gs\gs9.56.1\bin\gswin64c.exe'

# source input file is I:/_classUpload/internetWImages.txt

class CFG:
    
    image_source = "v:/new_logos_backup/"
    output_location = "i:/_classupload/python/"


class OneClassAd: 
     
    
    def __init__ (self): 
        
        # convert class variables into instance variables:
        self.ad_text = ""
        self.source_images = []
        self.ad_image = None
        self.ad_number = None
        self.class_code = None
        self.combined_full_path = None
        self.combined_image_filename = None
        
    def setClassCode(self, code):
        self.class_code = code
        
    def getClassCode(self):
        return self.class_code
        
    def setAdText(self, text):
        self.ad_text = text
        
    def getAdText(self):
        return self.ad_text
    
    def addSourceImage(self, source_image):
        self.source_images.append(source_image)
    
    def getSourceImages(self):
        return self.source_images
    
    def setAdImage(self, image):
        self.ad_image = image
    
    def getAdImage(self):
        return self.ad_image
    
    def _readImage(self, image):
        
        # So this is a bit of a mess. The exporting program can export the image in any file format that it 
        # can read, but it doesn't give us the proper extension, so all images are called 'image.gif' even
        # if they are 'image.eps'
        
        actual_file = image

        # Try each, and open the one that actually exists:
        if exists(CFG.image_source + image.replace(".gif", ".eps")):
            actual_file = image.replace(".gif", ".eps")
        elif exists(CFG.image_source + image.replace(".gif", ".png")):
            actual_file = image.replace(".gif", ".png")
        elif exists(CFG.image_source + image.replace(".gif", ".jpg")):
            actual_file = image.replace(".gif", ".jpg")
        elif exists(CFG.image_source + image.replace(".gif", ".jpeg")):
            actual_file = image.replace(".gif", ".jpeg")
        
        return Image.open(CFG.image_source + actual_file)
                
    def generateSingleImageFromList(self):
        
        if (len(self.source_images) > 0):
        
            max_width, total_height = self.determineMaxImageWidthAndHeight()

            # Create a new PIL image with the required width and height: 
            new_image = Image.new('RGB',(max_width, total_height), (250,250,250))
            
            # add each image to the combined image:
            # Start at y position 0, at the top
            current_y_pos = 0
            for image in self.source_images:
                
                img_obj = self._readImage(image)
                
                new_image.paste(img_obj, (0, current_y_pos))
                
                # increase the current_y_pos: 
                current_y_pos += img_obj.size[1]
                
            save_to = CFG.output_location + str(self.getAdNumber()) + ".png"
            new_image.save(save_to)
            return save_to
            
        else: 
            return None
        

            
    def determineMaxImageWidthAndHeight(self):
        
        max_width = 0
        total_height = 0
        
        # open each image with PIL, get the images width        
        for image in self.source_images:
            
            img_obj = self._readImage(image)
            width, height = img_obj.size
            
            if width > max_width:
                max_width = width
                
            total_height += height
            
        return (max_width, total_height)
   
    def setCombinedImageFilename(self, full_path, image_filename):
        self.combined_full_path = full_path
        self.combined_image_filename = image_filename
        
    
    def setAdNumber(self, ad_number):
        self.ad_number = ad_number

    def getAdNumber(self):
        return self.ad_number
    
    def dumpAdInfo(self):
        print("_________________________________________________________")
        print("Ad Number: " + str(self.getAdNumber()))
        print("Ad Classification: " + str(self.getClassCode()))
        print("Ad Text: " + str(self.getAdText()))
        print("Ad Images: " + str(self.getSourceImages()))

def readSource(sourceFile): 
    
    
    source_pd = pd.read_csv(sourceFile, sep='|', names = ['class_code', 'ad_text', 'images'], header=None )
    for index, row in source_pd.iterrows():
        
        this_ad = OneClassAd()
        this_ad.setAdNumber(index)
        this_ad.setClassCode(row['class_code'])
        this_ad.setAdText(row['ad_text'])
        
        
        # See if the image is a nan or not by comparing it to itself.
        # only Nans (not a number) return false equality:
        if (row['images'] == row['images']):
            
            # ignore 'newadhdr.gif' images
            if("newadhdr.gif" not in row['images']):
                
                # add each image specified to the ad, multiple images are separated with ',':
                for image in str(row['images']).split(','):
                
                    this_ad.addSourceImage(image.replace("'",""))
            
        
        this_ad.dumpAdInfo()
        this_ad.generateSingleImageFromList()    

            
# Read in the classified import file:
readSource("I:\_classUpload\internetWImages.txt")

Leave a Reply

Your email address will not be published. Required fields are marked *