def demo_program(): filenames = sys.argv[1:] out_filename = filenames.pop() images = Image() for fn in filenames: print("Reading %s ..." % fn) #img = Image.from_filename(fn) #img = Image.from_buffer(open(fn).read()) img = Image.read(fn) print(" %lu frames" % len(img)) images.extend(img) if not images: raise IOError("Failed to read any images!") # Create a thumbnail image sequence thumbnails = images.resized((106, 80)) del img del images # Write the thumbnail image sequence to file if thumbnails: print("Writing %s ... %lu frames" % (out_filename, len(thumbnails))) open(out_filename, 'wb').write(thumbnails.to_buffer())
def unanimate(im): """ Get the non-animated version of a sanpera ``Image``. Paramters: im: A sanpera ``Image``. Returns: *im*, if it wasn't animated, or a new ``Image`` with just the first frame of *im* if it was. """ if len(im) == 1: return im ret = Image() ret.append(im[0]) return ret
def check_type(filename): """ Return True if the filename corresponds to an image file, else False. """ try: im = Image.read(filename) except SanperaError: return False else: return im.original_format in ['JPEG', 'PNG', 'GIF']
def demo_program(): filenames = sys.argv[1:] out_filename = filenames.pop() images = Image() for fn in filenames: print "Reading %s ..." % (fn, ) #img = Image.from_filename(fn) #img = Image.from_buffer(open(fn).read()) img = Image.read(open(fn)) print " %lu frames" % (len(img), ) images.extend(img) if not images: raise IOError("Failed to read any images!") # Create a thumbnail image sequence thumbnails = images.resize(106, 80) del img del images # Write the thumbnail image sequence to file if thumbnails: print "Writing %s ... %lu frames" % (out_filename, len(thumbnails)) open(out_filename, 'w').write(thumbnails.to_buffer())
def __call__(self, *frames, **kwargs): channel = kwargs.get('channel', lib.DefaultChannels) c_channel = ffi.cast('ChannelType', channel) steps = ffi.new("sanpera_evaluate_step[]", self.compiled_steps) c_frames = ffi.new("Image *[]", [f._frame for f in frames] + [ffi.NULL]) with magick_try() as exc: new_frame = ffi.gc( lib.sanpera_evaluate_filter(c_frames, steps, c_channel, exc.ptr), lib.DestroyImageList) return Image(new_frame)
def check_type(filename, secure=True): """ Return True if the filename corresponds to an image file, else False. """ if secure: try: im = Image.read(filename) except SanperaError: return False else: return im.original_format in ['JPEG', 'PNG', 'GIF'] else: return filename and filename[-4:] in [".jpg", ".png", ".gif"]
def test_pixel_iter(): """Does iterating over pixels appear to work?""" img = Image.read(util.find_image('terminal.gif')) pixel_iter = iter(img[0].pixels) white = RGBColor(1., 1., 1.) px = next(pixel_iter) assert px.point == Vector(0, 0) assert px.color == white px = next(pixel_iter) assert px.point == Vector(1, 0) assert px.color == white
def test_identify_size(): img = Image.read(util.find_image("eye.gif")) assert len(img) == 1, "one frame" assert img.original_format == "GIF", "image is a gif" # XXX this should be a magick format object assert img.size == Size(32, 32), "dimensions are 32x32" frame = img[0] assert frame.canvas.position == Vector(0, 0), "virtual canvas has no offset" assert not frame.canvas.position, "virtual canvas offset registers as false" assert frame.canvas.size == Size(32, 32), "virtual canvas is 32x32" assert frame.canvas.size == img.size, "virtual canvas size is image size" assert not frame.has_canvas, "frame isn't using a virtual canvas" assert not img.has_canvas, "image isn't using a virtual canvas"
def test_fx_navy(ctx): img = Image.new((64, 64), fill=RGBColor(0., 0., 0.)) gray = RGBColor(0.5, 0.5, 0.5) img = image_filter(lambda *a: gray)(*img, channel=Channel.blue) ctx.compare(img, 'fx_navy.miff')
def read(filename): try: return Image.read(filename) except SanperaError: log_exc(level=logging.DEBUG) raise WeasylError('imageDecodeError')
def from_string(filedata): try: return Image.from_buffer(filedata) except SanperaError: log_exc(level=logging.DEBUG) raise WeasylError('imageDecodeError')
def test_appending_to_an_empty_image(): img = Image() img.append(builtins.rose[0]) assert img.size == builtins.rose.size
def __call__(self, *frames, **kwargs): return Image(self.impl(*frames, **kwargs))
def unanimate(im): if len(im) == 1: return im ret = Image() ret.append(im[0]) return ret
def __call__(self, *frames, **kwargs): channel = kwargs.get('channel', lib.DefaultChannels) # TODO force_python should go away and this should become a wrapper for # evaluate_python # We're gonna be using this a lot, so let's cast it to a C int just # once (and get the error early if it's a bogus type) c_channel = ffi.cast('ChannelType', channel) # TODO any gc concerns in this? for f in frames: assert isinstance(f, ImageFrame) # XXX how to handle frames of different sizes? gravity? scaling? first # frame as the master? hm frame = frames[0] # TODO does this create a blank image or actually duplicate the pixels?? docs say it actually copies with (0, 0) but the code just refs the same pixel cache? # TODO could use an inplace version for, e.g. the SVG-style compose operators # TODO also might want a different sized clone! with magick_try() as exc: new_stack = lib.CloneImage(frame._frame, 0, 0, lib.MagickTrue, exc.ptr) exc.check(new_stack == ffi.NULL) # TODO: set image to full-color. # TODO: work out how this works, how different colorspaces work, and waht the ImageType has to do with anything # QUESTION: this doesn't actually do anything. how does it work? does it leave indexes populated? what happens if this isn't done? # if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse) { # InheritException(exception,&fx_image->exception); # fx_image=DestroyImage(fx_image); # return((Image *) NULL); # } out_view = lib.AcquireCacheView(new_stack) # TODO i need to be a list in_view = lib.AcquireCacheView(frame._frame) state = FilterState() for y in range(frame._frame.rows): with magick_try() as exc: q = lib.GetCacheViewAuthenticPixels(out_view, 0, y, frame._frame.columns, 1, exc.ptr) exc.check(q == ffi.NULL) # TODO is this useful who knows #fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view); for x in range(frame._frame.columns): # TODO per-channel things # TODO for usage: see line 1453 #GetMagickPixelPacket(image,&pixel); #(void) InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate, point.x,point.y,&pixel,exception); # Set up state object # TODO document that this is reused, or somethin state._color = BaseColor._from_pixel(q) ret = self.impl(state) #q.red = c_api.RoundToQuantum(<c_api.MagickRealType> ret.c_struct.red * c_api.QuantumRange) #q.green = c_api.RoundToQuantum(<c_api.MagickRealType> ret.c_struct.green * c_api.QuantumRange) #q.blue = c_api.RoundToQuantum(<c_api.MagickRealType> ret.c_struct.blue * c_api.QuantumRange) # TODO black, opacity? # TODO seems like this should apply to any set of channels, but # IM's -fx only understands RGB # TODO this is a little invasive, but given that this inner # loop runs for every f*****g pixel, i'd like to avoid method # calls as much as possible. even that rgb() can add up rgb = ret.rgb() lib.sanpera_pixel_from_doubles_channel(q, rgb._array, c_channel) # XXX this is actually black # if (((channel & IndexChannel) != 0) && (fx_image->colorspace == CMYKColorspace)) { # (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y, &alpha,exception); # SetPixelIndex(fx_indexes+x,RoundToQuantum((MagickRealType) QuantumRange*alpha)); # } q += 1 # q++ with magick_try() as exc: lib.SyncCacheViewAuthenticPixels(in_view, exc.ptr) # TODO check exception, return value # XXX destroy in_view # XXX destroy out_view s return Image(new_stack)
def from_string(filedata): try: return Image.from_buffer(filedata) except SanperaError as e: capture_exception(e, level='info') raise WeasylError('imageDecodeError') from e
def get_image(path): """Return a test data image, as an `Image` object.""" return Image.read(find_image(path))
def test_wheat(ctx): img = Image.new((100, 100), fill=RGBColor.parse('wheat')) ctx.compare(img, 'canvas_wheat.miff')
def read(filename): try: return Image.read(filename) except SanperaError as e: capture_exception(e, level='info') raise WeasylError('imageDecodeError') from e
def test_pixel_get(): """Does random pixel inspection work?""" img = Image.read(util.find_image('terminal.gif')) assert img[0].pixels[11, 6] == RGBColor(1., 0., 0.)
def compare(self, got, expected_name): expected = Image.read(os.path.join(self.tempdir, expected_name)) got.write(os.path.join(self.tempdir, 'GOT-' + expected_name), format='miff') util.assert_identical(got, expected)
def test_khaki_to_tomato(ctx): img = Image.new((100, 100), fill=RGBColor.parse('khaki')) img[0].replace_color(RGBColor.parse('khaki'), RGBColor.parse('tomato')) ctx.compare(img, 'canvas_opaque.miff')
def test_khaki(ctx): img = Image.new((100, 100), fill=RGBColor.parse('khaki')) ctx.compare(img, 'canvas_khaki.miff')