예제 #1
0
def _get_formats():
    formats = dict()

    num_formats = ffi.new("size_t *")

    # Snag the list of known supported image formats
    with magick_try() as exc:
        magick_infos = ffi.gc(lib.GetMagickInfoList(b"*", num_formats, exc.ptr), lib.RelinquishMagickMemory)
        # Sometimes this call can generate an exception (such as a module not
        # being loadable) but then succeed anyway and return a useful value, in
        # which case we want to ignore the exception
        if magick_infos != ffi.NULL:
            exc.clear()

    for i in range(num_formats[0]):
        name = ffi.string(magick_infos[i].name).decode("latin-1")
        formats[name.lower()] = ImageFormat(
            name=name,
            description=ffi.string(magick_infos[i].description).decode("latin-1"),
            can_read=magick_infos[i].decoder != ffi.NULL,
            can_write=magick_infos[i].encoder != ffi.NULL,
            supports_frames=magick_infos[i].adjoin != 0,
        )

    return formats
예제 #2
0
파일: image.py 프로젝트: pombreda/sanpera
    def to_buffer(self, format=None):
        if not self._frames:
            raise EmptyImageError

        image_info = blank_image_info()
        length = ffi.new("size_t *")

        # Force writing to a single file
        image_info.adjoin = lib.MagickTrue

        # Stupid hack to fix a bug in the rgb codec
        if format == 'rgba':
            for frame in self._frames:
                frame._fix_for_rgba_codec()

        if format:
            # If the caller provided an explicit format, pass it along
            # Make sure not to overflow the char[]
            # TODO maybe just error out when this happens
            image_info.magick = format.encode('ascii')[:lib.MaxTextExtent]
        elif self._stack.magick[0] == b'\0':
            # Uhoh; no format provided and nothing given by caller
            raise MissingFormatError

        with magick_try() as exc:
            with self._link_frames(self._frames) as ptr:
                cbuf = ffi.gc(
                    lib.ImagesToBlob(image_info, ptr, length, exc.ptr),
                    lib.RelinquishMagickMemory)

        return ffi.buffer(cbuf, length[0])
예제 #3
0
파일: image.py 프로젝트: eevee/sanpera
    def to_buffer(self, format=None):
        if not self._frames:
            raise EmptyImageError

        image_info = blank_image_info()
        length = ffi.new("size_t *")

        # Force writing to a single file
        image_info.adjoin = lib.MagickTrue

        # Stupid hack to fix a bug in the rgb codec
        if format == 'rgba':
            for frame in self._frames:
                frame._fix_for_rgba_codec()

        if format:
            # If the caller provided an explicit format, pass it along
            # Make sure not to overflow the char[]
            # TODO maybe just error out when this happens
            image_info.magick = format.encode('ascii')[:lib.MaxTextExtent]
        elif self._stack.magick[0] == b'\0':
            # Uhoh; no format provided and nothing given by caller
            raise MissingFormatError

        with magick_try() as exc:
            with self._link_frames(self._frames) as ptr:
                cbuf = ffi.gc(
                    lib.ImagesToBlob(image_info, ptr, length, exc.ptr),
                    lib.RelinquishMagickMemory)

        return ffi.buffer(cbuf, length[0])
예제 #4
0
파일: draw.py 프로젝트: eevee/sanpera
    def __init__(self, frame):
        # TODO typecheck here, maybe?
        self.frame = frame

        self.draw_info = ffi.gc(
            lib.AcquireDrawInfo(),
            lib.DestroyDrawInfo)
예제 #5
0
def _get_formats():
    formats = dict()
    formats_by_mime = dict()

    num_formats = ffi.new("size_t *")

    # Snag the list of known supported image formats
    with magick_try() as exc:
        magick_infos = ffi.gc(
            lib.GetMagickInfoList(b"*", num_formats, exc.ptr),
            lib.RelinquishMagickMemory)

    for i in range(num_formats[0]):
        imageformat = ImageFormat(
            name=ffi.string(magick_infos[i].name).decode('latin-1'),
            description=ffi.string(magick_infos[i].description).decode('latin-1'),
            can_read=magick_infos[i].decoder != ffi.NULL,
            can_write=magick_infos[i].encoder != ffi.NULL,
            supports_frames=magick_infos[i].adjoin != 0,
            mime_type=ffi.string(magick_infos[i].mime_type).decode('ascii') if magick_infos[i].mime_type else None,
        )
        formats[imageformat.name.lower()] = imageformat
        formats_by_mime[imageformat.mime_type] = imageformat

    return formats, formats_by_mime
예제 #6
0
파일: image.py 프로젝트: pombreda/sanpera
    def coalesced(self):
        """Returns an image with each frame composited over previous frames."""
        with magick_try() as exc:
            new_image = ffi.gc(lib.CoalesceImages(self._stack, exc.ptr),
                               lib.DestroyImageList)

        return type(self)(new_image)
예제 #7
0
파일: image.py 프로젝트: eevee/sanpera
    def coalesced(self):
        """Returns an image with each frame composited over previous frames."""
        with magick_try() as exc:
            new_image = ffi.gc(
                lib.CoalesceImages(self._stack, exc.ptr),
                lib.DestroyImageList)

        return type(self)(new_image)
예제 #8
0
파일: filters.py 프로젝트: pombreda/sanpera
    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)
예제 #9
0
파일: image.py 프로젝트: eevee/sanpera
    def __init__(self, _raw_frame):
        # This class has ultimate ownership of each Image pointer, so do the gc
        # stuff here.
        _frame = self._frame = ffi.gc(_raw_frame, lib.DestroyImage)

        # New frames need their filenames blanked, lest ImageMagick decide
        # to ignore our pleas and write to the same file
        _frame.filename[0] = b'\0'
        # ...yeah this too
        #_frame.magick[0] = b'\0'

        # Sometimes a new image's "page" is 0x0, which is totally bogus
        if _frame.page.width == 0 or _frame.page.height == 0:
            _frame.page.width = _frame.columns
            _frame.page.height = _frame.rows
예제 #10
0
파일: image.py 프로젝트: pombreda/sanpera
    def __init__(self, _raw_frame):
        # This class has ultimate ownership of each Image pointer, so do the gc
        # stuff here.
        _frame = self._frame = ffi.gc(_raw_frame, lib.DestroyImage)

        # New frames need their filenames blanked, lest ImageMagick decide
        # to ignore our pleas and write to the same file
        _frame.filename[0] = b'\0'
        # ...yeah this too
        #_frame.magick[0] = b'\0'

        # Sometimes a new image's "page" is 0x0, which is totally bogus
        if _frame.page.width == 0 or _frame.page.height == 0:
            _frame.page.width = _frame.columns
            _frame.page.height = _frame.rows
예제 #11
0
파일: image.py 프로젝트: eevee/sanpera
    def cropped(self, rect, preserve_canvas=False):
        rectinfo = rect.to_rect_info()

        p = self._stack
        new_stack_ptr = ffi.new("Image **", ffi.NULL)

        while p:
            with magick_try() as exc:
                new_frame = lib.CropImage(p, rectinfo, exc.ptr)

                # Only GC the first frame in the stack, since the others will be
                # in the same list and thus nuked automatically
                if new_stack_ptr == ffi.NULL:
                    new_frame = ffi.gc(new_frame, lib.DestroyImageList)

            lib.AppendImageToList(new_stack_ptr, new_frame)
            p = lib.GetNextImageInList(p)

        new = type(self)(new_stack_ptr[0])

        # Repage by default after a crop; not doing this is unexpected and
        # frankly insane.  Plain old `+repage` behavior would involve nuking
        # the page entirely, but that would screw up multiple frames; instead,
        # shift the canvas for every frame so the crop region's upper left
        # corner is the new origin, and fix the dimensions so every frame fits
        # (up to the size of the crop area, though ImageMagick should never
        # return an image bigger than the crop area...  right?)
        if not preserve_canvas:
            # ImageMagick actually behaves when the crop area extends out
            # beyond the origin, so don't fix the edges in that case
            # TODO this is complex enough that i should perhaps just do it
            # myself
            left_delta = max(rect.left, 0)
            top_delta = max(rect.top, 0)
            # New canvas should be the size of the overlap between the current
            # canvas and the crop area
            new_canvas = rect.intersection(self.size.at(origin))
            new_height = new_canvas.height
            new_width = new_canvas.width
            for frame in new:
                frame._frame.page.x -= left_delta
                frame._frame.page.y -= top_delta
                frame._frame.page.height = new_height
                frame._frame.page.width = new_width

        return new
예제 #12
0
파일: image.py 프로젝트: pombreda/sanpera
    def cropped(self, rect, preserve_canvas=False):
        rectinfo = rect.to_rect_info()

        p = self._stack
        new_stack_ptr = ffi.new("Image **", ffi.NULL)

        while p:
            with magick_try() as exc:
                new_frame = lib.CropImage(p, rectinfo, exc.ptr)

                # Only GC the first frame in the stack, since the others will be
                # in the same list and thus nuked automatically
                if new_stack_ptr == ffi.NULL:
                    new_frame = ffi.gc(new_frame, lib.DestroyImageList)

            lib.AppendImageToList(new_stack_ptr, new_frame)
            p = lib.GetNextImageInList(p)

        new = type(self)(new_stack_ptr[0])

        # Repage by default after a crop; not doing this is unexpected and
        # frankly insane.  Plain old `+repage` behavior would involve nuking
        # the page entirely, but that would screw up multiple frames; instead,
        # shift the canvas for every frame so the crop region's upper left
        # corner is the new origin, and fix the dimensions so every frame fits
        # (up to the size of the crop area, though ImageMagick should never
        # return an image bigger than the crop area...  right?)
        if not preserve_canvas:
            # ImageMagick actually behaves when the crop area extends out
            # beyond the origin, so don't fix the edges in that case
            # TODO this is complex enough that i should perhaps just do it
            # myself
            left_delta = max(rect.left, 0)
            top_delta = max(rect.top, 0)
            # New canvas should be the size of the overlap between the current
            # canvas and the crop area
            new_canvas = rect.intersection(self.size.at(origin))
            new_height = new_canvas.height
            new_width = new_canvas.width
            for frame in new:
                frame._frame.page.x -= left_delta
                frame._frame.page.y -= top_delta
                frame._frame.page.height = new_height
                frame._frame.page.width = new_width

        return new
예제 #13
0
def _get_formats():
    formats = dict()

    num_formats = ffi.new("size_t *")

    # Snag the list of known supported image formats
    with magick_try() as exc:
        magick_infos = ffi.gc(
            lib.GetMagickInfoList(b"*", num_formats, exc.ptr),
            lib.RelinquishMagickMemory)

    for i in range(num_formats[0]):
        name = ffi.string(magick_infos[i].name).decode('latin-1')
        formats[name.lower()] = ImageFormat(
            name=name,
            description=ffi.string(
                magick_infos[i].description).decode('latin-1'),
            can_read=magick_infos[i].decoder != ffi.NULL,
            can_write=magick_infos[i].encoder != ffi.NULL,
            supports_frames=magick_infos[i].adjoin != 0,
        )

    return formats
예제 #14
0
 def __init__(self, frame):
     self._frame = frame
     self._ptr = ffi.gc(lib.AcquireCacheView(frame._frame),
                        _cache_view_destructor)
예제 #15
0
파일: exception.py 프로젝트: eevee/sanpera
 def __init__(self):
     self.ptr = ffi.gc(
         lib.AcquireExceptionInfo(),
         lib.DestroyExceptionInfo)
예제 #16
0
파일: image.py 프로젝트: eevee/sanpera
def blank_image_info():
    return ffi.gc(
        lib.CloneImageInfo(ffi.NULL),
        lib.DestroyImageInfo)
예제 #17
0
파일: image.py 프로젝트: pombreda/sanpera
def blank_image_info():
    return ffi.gc(lib.CloneImageInfo(ffi.NULL), lib.DestroyImageInfo)
예제 #18
0
 def __init__(self):
     self.ptr = ffi.gc(lib.AcquireExceptionInfo(), lib.DestroyExceptionInfo)
예제 #19
0
파일: pixel_view.py 프로젝트: eevee/sanpera
 def __init__(self, frame):
     self._frame = frame
     self._ptr = ffi.gc(
         lib.AcquireCacheView(frame._frame),
         _cache_view_destructor)
예제 #20
0
파일: draw.py 프로젝트: pombreda/sanpera
    def __init__(self, frame):
        # TODO typecheck here, maybe?
        self.frame = frame

        self.draw_info = ffi.gc(lib.AcquireDrawInfo(), lib.DestroyDrawInfo)