def _run_transform(self, target_fp, image_request, kdu_cmd, fifo_fp): try: # Start the kdu shellout. Blocks until the pipe is empty kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=self.env) with open(fifo_fp, 'rb') as f: # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image finally: stdoutdata, stderrdata = kdu_expand_proc.communicate() kdu_exit = kdu_expand_proc.returncode if kdu_exit != 0: map(logger.error, stderrdata) unlink(fifo_fp) if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = cStringIO.StringIO( image_request.info.color_profile_bytes) im = profileToProfile(im, emb_profile, self.srgb_profile_fp) self._derive_with_pil(im, target_fp, image_request, crop=False)
def test_png_rotate_has_alpha_transparency(self): ident = 'test.png' rotate = '45' request_path = '/%s/full/full/%s/default.png' % (ident, rotate) resp = self.client.get(request_path) self.assertEqual(resp.status_code, 200) image = None bytes = StringIO(resp.data) p = Parser() p.feed(bytes.read()) # all in one gulp! image = p.close() bytes.close() # Get the alpha channel as an itertools.imap alpha = self.get_alpha_channel(image) # Instantiate transparency as False transparency = False # Loop on the alpha channel and see if we have a value of # 0 which means there's a transparent pixel there if alpha != None: for i in alpha: if i == 0: transparency = True self.assertTrue(transparency)
def _run_transform(self, target_fp, image_request, image_info, kdu_cmd, fifo_fp): try: # Start the kdu shellout. Blocks until the pipe is empty kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=self.env) with open(fifo_fp, 'rb') as f: # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image finally: _, stderrdata = kdu_expand_proc.communicate() kdu_exit = kdu_expand_proc.returncode if kdu_exit != 0: map(logger.error, stderrdata) unlink(fifo_fp) try: if self.map_profile_to_srgb and image_info.color_profile_bytes: emb_profile = BytesIO(image_info.color_profile_bytes) im = self._map_im_profile_to_srgb(im, emb_profile) except PyCMSError as err: logger.warn('Error converting %r to sRGB: %r', im, err) self._derive_with_pil( im=im, target_fp=target_fp, image_request=image_request, image_info=image_info, crop=False )
def transform(self, src_fp, target_fp, image_request): # opj writes to this: fifo_fp = self._make_tmp_fp() # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s', mkfifo_call) resp = subprocess.check_call(mkfifo_call, shell=True) if resp != 0: logger.error('Problem with mkfifo') # how to handle CalledProcessError; would have to be a 500? # opj_decompress command i = '-i "%s"' % (src_fp, ) o = '-o %s' % (fifo_fp, ) region_arg = self._region_to_opj_arg(image_request.region_param) reg = '-d %s' % (region_arg, ) if region_arg else '' reduce_arg = self._scales_to_reduce_arg(image_request) red = '-r %s' % (reduce_arg, ) if reduce_arg else '' opj_cmd = ' '.join((self.opj_decompress, i, reg, red, o)) logger.debug('Calling: %s', opj_cmd) # Start the shellout. Blocks until the pipe is empty # TODO: If this command hangs, the server never returns. # Surely that can't be right! with open(devnull, 'w') as fnull: opj_decompress_proc = subprocess.Popen(opj_cmd, shell=True, bufsize=-1, stderr=fnull, stdout=fnull, env=self.env) with open(fifo_fp, 'rb') as f: # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish opj opj_exit = opj_decompress_proc.wait() if opj_exit != 0: map(logger.error, opj_decompress_proc.stderr) unlink(fifo_fp) try: if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = BytesIO(image_request.info.color_profile_bytes) im = self._map_im_profile_to_srgb(im, emb_profile) except PyCMSError as err: logger.warn('Error converting %r to sRGB: %r', im, err) self._derive_with_pil(im, target_fp, image_request, crop=False)
def transform(self, src_fp, target_fp, image_request): # kdu writes to this: fifo_fp = self._make_tmp_fp() # kdu command #q = '-quiet' t = '-num_threads %s' % (self.num_threads,) i = '-i "%s"' % (src_fp,) o = '-o %s' % (fifo_fp,) reduce_arg = self._scales_to_reduce_arg(image_request) red = '-reduce %s' % (reduce_arg,) if reduce_arg else '' region_arg = self._region_to_kdu_arg(image_request.region_param) reg = '-region %s' % (region_arg,) if region_arg else '' #kdu_cmd = ' '.join((self.kdu_expand,q,i,t,reg,red,o)) kdu_cmd = 'LD_LIBRARY_PATH=/opt/kakadu/current/apps/make ' + ' '.join((self.kdu_expand,i,t,reg,red,o)) # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s' % (mkfifo_call,)) resp = subprocess.check_call(mkfifo_call, shell=True) try: # Start the kdu shellout. Blocks until the pipe is empty logger.debug('Calling: %s' % (kdu_cmd,)) kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=self.env) f = open(fifo_fp, 'rb') logger.debug('Opened %s' % fifo_fp) # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, kdu_expand_proc.stderr) if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = cStringIO.StringIO(image_request.info.color_profile_bytes) im = profileToProfile(im, emb_profile, self.srgb_profile_fp) self._derive_with_pil(im, target_fp, image_request, crop=False) except: raise finally: kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, map(string.strip, kdu_expand_proc.stderr)) unlink(fifo_fp)
def _init_fs(self, fs): kwargs = super(UploadImage, self)._init_fs(fs) parser = ImageParser() for chunk in read_chunks(fs.file): parser.feed(chunk) self.image = parser.close() return kwargs
def transform(self, src_fp, target_fp, image_request): # opj writes to this: fifo_fp = self._make_tmp_fp() # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s' % (mkfifo_call, )) resp = subprocess.check_call(mkfifo_call, shell=True) if resp != 0: logger.error('Problem with mkfifo') # how to handle CalledProcessError; would have to be a 500? # opj_decompress command i = '-i "%s"' % (src_fp, ) o = '-o %s' % (fifo_fp, ) region_arg = self._region_to_opj_arg(image_request.region_param) reg = '-d %s' % (region_arg, ) if region_arg else '' reduce_arg = self._scales_to_reduce_arg(image_request) red = '-r %s' % (reduce_arg, ) if reduce_arg else '' opj_cmd = ' '.join((self.opj_decompress, i, reg, red, o)) logger.debug('Calling: %s' % (opj_cmd, )) # Start the shellout. Blocks until the pipe is empty with open(devnull, 'w') as fnull: opj_decompress_proc = subprocess.Popen(opj_cmd, shell=True, bufsize=-1, stderr=fnull, stdout=fnull, env=self.env) f = open(fifo_fp, 'rb') logger.debug('Opened %s' % fifo_fp) # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish opj opj_exit = opj_decompress_proc.wait() if opj_exit != 0: map(logger.error, opj_decompress_proc.stderr) unlink(fifo_fp) if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = cStringIO.StringIO( image_request.info.color_profile_bytes) im = profileToProfile(im, emb_profile, self.srgb_profile_fp) self._derive_with_pil(im, target_fp, image_request, crop=False)
def transform(self, src_fp, target_fp, image_request): self._check_format(image_request) # kdu writes to this: fifo_fp = JP2_Transformer._make_tmp_fp(self.tmp_dp, 'bmp') # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s' % (mkfifo_call,)) resp = subprocess.check_call(mkfifo_call, shell=True) if resp == 0: logger.debug('OK') # how to handle CalledProcessError; would have to be a 500? # kdu command q = '-quiet' i = '-i %s' % (src_fp,) o = '-o %s' % (fifo_fp,) region_arg = self._region_to_kdu(image_request.region_param) # kdu can do the rotation if it's a multiple of 90: if int(image_request.rotation_param.uri_value) % 90 == 0: rotate_downstream = False kdu_rotation_arg = self._rotation_to_kdu(image_request.rotation_param) kdu_cmd = ' '.join((self.kdu_expand,q,i,region_arg,kdu_rotation_arg,o)) else: rotate_downstream = True kdu_cmd = ' '.join((self.kdu_expand,q,i,region_arg,o)) logger.debug('Calling: %s' % (kdu_cmd,)) # Start the kdu shellout. Blocks until the pipe is emptied kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=self.env) f = open(fifo_fp, 'rb') logger.debug('Opened %s' % fifo_fp) # read from the named pipe # itertools.takewhile() ? p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, kdu_expand_proc.stderr) unlink(fifo_fp) JP2_Transformer._derive_with_pil(im, target_fp, image_request, rotate=rotate_downstream)
def transform(self, src_fp, target_fp, image_request): # opj writes to this: fifo_fp = self._make_tmp_fp() # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s' % (mkfifo_call,)) resp = subprocess.check_call(mkfifo_call, shell=True) if resp != 0: logger.error('Problem with mkfifo') # how to handle CalledProcessError; would have to be a 500? # opj_decompress command i = '-i "%s"' % (src_fp,) o = '-o %s' % (fifo_fp,) region_arg = self._region_to_opj_arg(image_request.region_param) reg = '-d %s' % (region_arg,) if region_arg else '' reduce_arg = self._scales_to_reduce_arg(image_request) red = '-r %s' % (reduce_arg,) if reduce_arg else '' opj_cmd = ' '.join((self.opj_decompress,i,reg,red,o)) logger.debug(fifo_fp) logger.debug('Calling: %s' % (opj_cmd,)) logger.debug(fifo_fp) # Start the shellout. Blocks until the pipe is empty with open(devnull, 'w') as fnull: logger.debug('opening devnull') opj_decompress_proc = subprocess.Popen(opj_cmd, shell=True, bufsize=-1, stderr=fnull, stdout=fnull, env=self.env) logger.debug('opening fifo') f = open(fifo_fp, 'rb') logger.debug('Opened %s' % fifo_fp) # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish opj opj_exit = opj_decompress_proc.wait() if opj_exit != 0: map(logger.error, opj_decompress_proc.stderr) unlink(fifo_fp) if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = cStringIO.StringIO(image_request.info.color_profile_bytes) im = profileToProfile(im, emb_profile, self.srgb_profile_fp) self._derive_with_pil(im, target_fp, image_request, crop=False)
def import_image(cls, file_path): image_parser = Parser() f = open(file_path, 'rb') while True: buf = f.read(8192) if buf: image_parser.feed(buf) continue break image_parser.close() im_hash = cls.hash_image(f) if cls.objects.filter(hash=im_hash).exists(): print "Skipping duplicate (%s)" % im_hash else: cls.objects.create( image=File(f), hash=im_hash, )
def import_image(cls, file_path): image_parser = Parser() f = open(file_path, 'rb') while True: buf = f.read(8192) if buf: image_parser.feed(buf) continue break image_parser.close() im_hash = cls.hash_image(f) if cls.objects.filter(hash = im_hash).exists(): print "Skipping duplicate (%s)"%im_hash else: cls.objects.create( image = File(f), hash = im_hash, )
def __init__(self, **kw): object.__init__(self) [self.__setattr__(k, kw[k]) for k in page.keys] quietFns = {False: (self._prnfn, self._nlfn), True: (nopfn, nopfn)} self.prnfn, self.nlfn = quietFns[self.quiet] if self.contents: parser = Parser() parser.feed(kw["infile"]) self.orig = parser.close() else: self.orig = Image.open(self.infile) self.img = self._prepare() self.frames = self._getFrames()
def mk_tile_subproc(): opj_bin = '/usr/local/bin/opj_decompress' opj_lib = '/usr/local/lib/libopenjp2.so' pipe_o = '/tmp/mypipe.bmp' out_jpg = '/tmp/test.jpg' mkfifo_cmd = '/usr/bin/mkfifo %s' % (pipe_o, ) rmfifo_cmd = '/bin/rm %s' % (pipe_o, ) i = '../tests/img/01/02/0001.jp2' r = 2 # reduce # d = '256,256,512,512' d = '0,0,256,256' opj_cmd = '%s -i %s -o %s -d %s -r %s' % (opj_bin, i, pipe_o, d, r) # make a named pipe mkfifo_resp = subprocess.check_call(mkfifo_cmd, shell=True) if mkfifo_resp != 0: sys.stderr.write('mkfifo not OK\n') # write opj_decompress's output to the named pipe opj_proc = subprocess.Popen(opj_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env={'LD_LIBRARY_PATH': opj_lib}) # open the named pipe and parse the stream im = None with open(pipe_o, 'rb') as f: p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # finish opj opj_exit = opj_proc.wait() if opj_exit != 0: map(sys.stderr.write, opj_proc.stderr) else: # opj was successful, save to a jpg # map(sys.stdout.write, opj_proc.stdout) im.save(out_jpg, quality=95) # remove the named pipe rmfifo_resp = subprocess.check_call(rmfifo_cmd, shell=True) if rmfifo_resp != 0: sys.stderr.write('rm fifo not OK\n')
def generate_exemplar(grammar, **kwargs): """ Using CFDG, creates an exemplar from the provided grammar, retrieves the image data, and returns the image data Available kwargs: 'maxshapes': maximum number of shapes 'width': width, in pixels, of image 'height': height, in pixels, of image :return: Exemplar instance """ commandstr = "cfdg" # process keyword arguments if 'maxshapes' in kwargs: commandstr += " -m {0}".format(kwargs['maxshapes']) else: commandstr += " -m {0}".format(MAX_SHAPES) if 'width' in kwargs: commandstr += " -w {0}".format(kwargs['width']) if 'height' in kwargs: commandstr += " -h {0}".format(kwargs['height']) # specify to cfdg that grammar file will come from stdin commandstr += " -" # run cfdg, passing in grammar.body as the input try: cfdg_proccess = proc.Popen(commandstr, shell=True, stdin=proc.PIPE, stdout=proc.PIPE) comm = cfdg_proccess.communicate(input=clean_body(grammar)) cfdg_output = comm[0] if cfdg_output == '': raise Exception("CFDG output is empty.") except Exception as e: print("Error using CFDG to parse grammar '{0}'".format(grammar.name)) raise e # parse output of cfdg into an image file, ready to save try: p = Parser() p.feed(cfdg_output) image = p.close() except IOError as e: print("Error parsing CFDG output for grammar '{0}' into an image file".format(grammar.name)) raise e ex = Exemplar(image=image) return ex
def mk_tile_subproc(): opj_bin = '/usr/local/bin/opj_decompress' opj_lib = '/usr/local/lib/libopenjp2.so' pipe_o = '/tmp/mypipe.bmp' out_jpg = '/tmp/test.jpg' mkfifo_cmd = '/usr/bin/mkfifo %s' % (pipe_o,) rmfifo_cmd = '/bin/rm %s' % (pipe_o,) i = '../tests/img/01/02/0001.jp2' r = 2 # reduce # d = '256,256,512,512' d = '0,0,256,256' opj_cmd = '%s -i %s -o %s -d %s -r %s' % (opj_bin, i, pipe_o, d, r) # make a named pipe mkfifo_resp = subprocess.check_call(mkfifo_cmd, shell=True) if mkfifo_resp != 0: sys.stderr.write('mkfifo not OK\n') # write opj_decompress's output to the named pipe opj_proc = subprocess.Popen(opj_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env={ 'LD_LIBRARY_PATH' : opj_lib }) # open the named pipe and parse the stream im = None with open(pipe_o, 'rb') as f: p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # finish opj opj_exit = opj_proc.wait() if opj_exit != 0: map(sys.stderr.write, opj_proc.stderr) else: # opj was successful, save to a jpg # map(sys.stdout.write, opj_proc.stdout) im.save(out_jpg, quality=95) # remove the named pipe rmfifo_resp = subprocess.check_call(rmfifo_cmd, shell=True) if rmfifo_resp != 0: sys.stderr.write('rm fifo not OK\n')
def test_allows_jp2_upsample(self): # Makes a request rather than building everything from scratch ident = self.test_jp2_color_id request_path = '/%s/full/pct:110/0/default.jpg' % (ident, ) resp = self.client.get(request_path) self.assertEqual(resp.status_code, 200) image = None bytes = StringIO(resp.data) p = Parser() p.feed(bytes.read()) # all in one gulp! image = p.close() bytes.close() expected_dims = tuple(int(d * 1.10) for d in self.test_jp2_color_dims) self.assertEqual(expected_dims, image.size)
def test_allows_jp2_upsample(self): # Makes a request rather than building everything from scratch ident = self.test_jp2_color_id request_path = '/%s/full/pct:110/0/default.jpg' % (ident,) resp = self.client.get(request_path) self.assertEqual(resp.status_code, 200) image = None bytes = StringIO(resp.data) p = Parser() p.feed(bytes.read()) # all in one gulp! image = p.close() bytes.close() expected_dims = tuple(int(d*1.10) for d in self.test_jp2_color_dims) self.assertEqual(expected_dims, image.size)
class InterceptingProxyClient(ProxyClient): def __init__(self, *args, **kwargs): ProxyClient.__init__(self, *args, **kwargs) self.image_parser = None def handleHeader(self, key, value): if key == "Content-Type" and value in ["image/jpeg", "image/gif", "image/png"]: self.image_parser = Parser() if key == "Content-Length" and self.image_parser: pass else: ProxyClient.handleHeader(self, key, value) def handleEndHeaders(self): if self.image_parser: pass #Need to calculate and send Content-Length first else: ProxyClient.handleEndHeaders(self) def handleResponsePart(self, buffer): if self.image_parser: self.image_parser.feed(buffer) else: ProxyClient.handleResponsePart(self, buffer) def handleResponseEnd(self): if self.image_parser: image = self.image_parser.close() try: format = image.format image = image.rotate(180) s = StringIO() image.save(s, format) buffer = s.getvalue() except: buffer = "" ProxyClient.handleHeader(self, "Content-Length", len(buffer)) ProxyClient.handleEndHeaders(self) ProxyClient.handleResponsePart(self, buffer) ProxyClient.handleResponseEnd(self)
def __init__(self, **kw): """A page object. Valid keyword parameters: startRow (default:0): Which row to start analyzing from. This is typically used for analyzing the first page of a comic where some top part of the page contains the title (which we need to skip) lignore, rignore (default:0 for both): Scanned pages might have some non-white color on one or both of the edges which interfere with gutter detection. These paramters tell the gutter detection algorithm to adjust the left boundary by lignore and right boundary by rignore when locating gutters contents (default: True): True => "infile" is a string consisting of page contents False => "infile" is a string holding the name of the page file to open infile: A String holding page contents or the page file name (depending on the contents parameter) pgNum (default:1): Page number (used when processing a whole book) quiet: Don't print any status messages debug: Enable debug prints fwidth, fheight: Minimum width (height resp) of a frame""" object.__init__(self) [self.__setattr__(k, kw[k]) for k in page.keys] quietFns = {False: (self._prnfn, self._nlfn), True: (nopfn, nopfn)} self.prnfn, self.nlfn = quietFns[self.quiet] if self.contents: parser = Parser() parser.feed(kw["infile"]) self.orig = parser.close() else: self.orig = Image.open(self.infile) self.img = self._prepare() self.frames = self._getFrames()
def transform(self, src_fp, target_fp, image_request): # kdu writes to this: fifo_fp = self._make_tmp_fp() # kdu command q = '-quiet' t = '-num_threads %s' % (self.num_threads, ) i = '-i "%s"' % (src_fp, ) o = '-o %s' % (fifo_fp, ) reduce_arg = self._scales_to_reduce_arg(image_request) red = '-reduce %s' % (reduce_arg, ) if reduce_arg else '' region_arg = self._region_to_kdu_arg(image_request.region_param) reg = '-region %s' % (region_arg, ) if region_arg else '' kdu_cmd = ' '.join((self.kdu_expand, q, i, t, reg, red, o)) # make the named pipe mkfifo_call = '%s %s' % (self.mkfifo, fifo_fp) logger.debug('Calling %s' % (mkfifo_call, )) resp = subprocess.check_call(mkfifo_call, shell=True) try: # Start the kdu shellout. Blocks until the pipe is empty logger.debug('Calling: %s' % (kdu_cmd, )) kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=self.env) f = open(fifo_fp, 'rb') logger.debug('Opened %s' % fifo_fp) # read from the named pipe p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, kdu_expand_proc.stderr) if self.map_profile_to_srgb and image_request.info.color_profile_bytes: # i.e. is not None emb_profile = cStringIO.StringIO( image_request.info.color_profile_bytes) im = profileToProfile(im, emb_profile, self.srgb_profile_fp) self._derive_with_pil(im, target_fp, image_request, crop=False) except: raise finally: kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, map(string.strip, kdu_expand_proc.stderr)) unlink(fifo_fp)
kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env={'LD_LIBRARY_PATH': LIB_KDU}) # open the named pipe and parse the stream with open(pipe_fp, 'rb') as f: p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(sys.stderr.write, kdu_expand_proc.stderr) else: # if kdu was successful, save to a jpg map(sys.stdout.write, kdu_expand_proc.stdout) im = im.resize((719, 900), resample=Image.ANTIALIAS) im.save(OUT_JPG, quality=95) # remove the named pipe rmfifo_resp = subprocess.check_call(rmfifo_cmd, shell=True) if rmfifo_resp == 0: print 'rm fifo OK'
def get_reduced_image_from_kdu(jp2, size): # This is basically like an IIIF op /full/!size,size/0/default.jpg # uses kdu via fifo as per Loris # returns PIL image object print 'making new pillow image for derivs at size', size im = None # extract the smallest possible resolution as the starting point for our transform ops req_w, req_h = confine(jp2.width, jp2.height, size, size) # mostly taken from transforms.py in Loris, but we want to return a Pillow image # color profile stuff has been removed for now n = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) fifo_fp = os.path.join(TMP_DIR, n + '.bmp') # kdu command q = '' # '-quiet' t = '-num_threads 4' i = '-i "%s"' % (jp2.path,) o = '-o %s' % (fifo_fp,) reduce_arg = scales_to_reduce_arg(jp2, size) red = '-reduce %s' % (reduce_arg,) if reduce_arg else '' # kdu_expand -usage: # -reduce <discard levels> # Set the number of highest resolution levels to be discarded. The image # resolution is effectively divided by 2 to the power of the number of # discarded levels. kdu_cmd = ' '.join((KDU_EXPAND,q,i,t,red,o)) # make the named pipe mkfifo_call = '%s %s' % (MKFIFO, fifo_fp) print 'Calling %s' % (mkfifo_call,) resp = subprocess.check_call(mkfifo_call, shell=True) expand_env = { 'LD_LIBRARY_PATH': KDU_LIB, 'PATH': KDU_EXPAND } try: # Start the kdu shellout. Blocks until the pipe is empty print 'Calling: %s' % (kdu_cmd,) print '########### kdu ###############' kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=expand_env) f = open(fifo_fp, 'rb') print 'Opened %s' % fifo_fp # read from the named pipe into PIL p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: print 'KDU ERROR' for e in kdu_expand_proc.stderr: print e imw, imh = im.size print 'we now have a PIL image %s x %s' % (imw, imh) if imw != req_w or imh != req_h: im = im.resize((req_w, req_h), resample=Image.ANTIALIAS) except: raise finally: kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(logger.error, map(string.strip, kdu_expand_proc.stderr)) os.unlink(fifo_fp) return im
print 'mkfifo OK' # write kdu_expand's output to the named pipe kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env={ 'LD_LIBRARY_PATH' : LIB_KDU }) # open the named pipe and parse the stream with open(pipe_fp, 'rb') as f: p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: map(sys.stderr.write, kdu_expand_proc.stderr) else: # if kdu was successful, save to a jpg map(sys.stdout.write, kdu_expand_proc.stdout) im = im.resize((719,900), resample=Image.ANTIALIAS) im.save(OUT_JPG, quality=95) # remove the named pipe rmfifo_resp = subprocess.check_call(rmfifo_cmd, shell=True) if rmfifo_resp == 0: print 'rm fifo OK'
def get_reduced_image_from_kdu(jp2, size): # This is basically like an IIIF op /full/!size,size/0/default.jpg # uses kdu via fifo as per Loris # returns PIL image object print 'making new pillow image for derivs at size', size im = None # extract the smallest possible resolution as the starting point for our transform ops req_w, req_h = confine(jp2.width, jp2.height, size, size) # mostly taken from transforms.py in Loris, but we want to return a Pillow image # color profile stuff has been removed for now n = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) fifo_fp = os.path.join(TMP_DIR, n + '.bmp') # kdu command q = '' # '-quiet' t = '-num_threads 4' i = '-i "%s"' % (jp2.path,) o = '-o %s' % (fifo_fp,) reduce_arg = scales_to_reduce_arg(jp2, size) red = '-reduce %s' % (reduce_arg,) if reduce_arg else '' # kdu_expand -usage: # -reduce <discard levels> # Set the number of highest resolution levels to be discarded. The image # resolution is effectively divided by 2 to the power of the number of # discarded levels. kdu_cmd = ' '.join((KDU_EXPAND, q, i, t, red, o)) # make the named pipe mkfifo_call = '%s %s' % (MKFIFO, fifo_fp) print 'Calling %s' % (mkfifo_call,) resp = subprocess.check_call(mkfifo_call, shell=True) expand_env = { 'LD_LIBRARY_PATH': KDU_LIB, 'PATH': KDU_EXPAND } try: # Start the kdu shellout. Blocks until the pipe is empty print 'Calling: %s' % (kdu_cmd,) print '########### kdu ###############' kdu_expand_proc = subprocess.Popen(kdu_cmd, shell=True, bufsize=-1, stderr=subprocess.PIPE, env=expand_env) f = open(fifo_fp, 'rb') print 'Opened %s' % fifo_fp # read from the named pipe into PIL p = Parser() while True: s = f.read(1024) if not s: break p.feed(s) im = p.close() # a PIL.Image # finish kdu kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: print 'KDU ERROR' for e in kdu_expand_proc.stderr: print e if im.mode != "RGB": im = im.convert("RGB") imw, imh = im.size print 'we now have a PIL image %s x %s' % (imw, imh) if imw != req_w or imh != req_h: im = im.resize((req_w, req_h), resample=Image.ANTIALIAS) except: raise finally: kdu_exit = kdu_expand_proc.wait() if kdu_exit != 0: # TODO : add logging! # map(logger.error, map(string.strip, kdu_expand_proc.stderr)) pass os.unlink(fifo_fp) return im