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 _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 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): # 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 __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 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 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): """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)
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
# make a named pipe mkfifo_resp = subprocess.check_call(mkfifo_cmd, shell=True) if mkfifo_resp == 0: 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)