Exemple #1
0
def test_cropped_canvas_fixing():
    img = builtins.rose.resized((200, 200))
    dim = Size(50, 50).at((25, 25))
    cropped = img.cropped(dim)

    assert cropped.size == dim.size
    assert cropped[0].canvas == dim.at(origin)
Exemple #2
0
def test_multi_frame_resize():
    """ImageMagick doesn't handle resizing correctly when a virtual canvas is
    involved.  Make sure we fixed it.
    """

    img = get_image('anim_bgnd.gif')

    # Original dimensions
    assert img.size == Size(100, 100)
    assert img[0].size == Size(32, 32)
    assert img[0].canvas.position == Vector(5, 10)
    assert img[1].size == Size(32, 32)
    assert img[1].canvas.position == Vector(35, 30)
    assert img[2].size == Size(32, 32)
    assert img[2].canvas.position == Vector(62, 50)
    assert img[3].size == Size(32, 32)
    assert img[3].canvas.position == Vector(10, 55)

    img = img.resized(img.size * 0.5)

    # Resized dimensions -- reduced by half
    assert img.size == Size(50, 50)
    assert img[0].size == Size(16, 16)
    assert img[0].canvas.position == Vector(3, 5)
    assert img[1].size == Size(16, 16)
    assert img[1].canvas.position == Vector(18, 15)
    assert img[2].size == Size(16, 16)
    assert img[2].canvas.position == Vector(31, 25)
    assert img[3].size == Size(16, 16)
    assert img[3].canvas.position == Vector(5, 28)
Exemple #3
0
def test_cropped_canvas_fixing_large_crop():
    size = Size(20, 20)
    img = builtins.rose.resized(size)
    dim = Size(50, 50).at((-25, -25))
    cropped = img.cropped(dim)

    assert cropped.size == size
    assert cropped[0].canvas == size.at(origin)
Exemple #4
0
def check_original_dimensions(img):
    assert img.size == Size(100, 100)
    assert img[0].size == Size(32, 32)
    assert img[0].canvas.position == Vector(5, 10)
    assert img[1].size == Size(32, 32)
    assert img[1].canvas.position == Vector(35, 30)
    assert img[2].size == Size(32, 32)
    assert img[2].canvas.position == Vector(62, 50)
    assert img[3].size == Size(32, 32)
    assert img[3].canvas.position == Vector(10, 55)
Exemple #5
0
    def tiled(self, size):
        size = Size.coerce(size)

        new = Image.new(size)

        # TODO this returns a bool?
        lib.TextureImage(new._stack, self._frame)
        magick_raise(self._frame.exception)

        return new
Exemple #6
0
    def tiled(self, size):
        size = Size.coerce(size)

        new = Image.new(size)

        # TODO this returns a bool?
        lib.TextureImage(new._stack, self._frame)
        magick_raise(self._frame.exception)

        return new
Exemple #7
0
    def size(self):
        """The image dimensions, as a `Size`.  Empty images have zero size.

        Some image formats support a canvas offset, in which case this value
        may not match the actual drawable area.  See `ImageFrame.canvas`.

        Note that multi-frame images don't have a notion of intrinsic size for
        the entire image, though particular formats may enforce that every
        frame be the same size.  If the image has multiple frames, this returns
        the size of the first frame, which is in line with most image-handling
        software.
        """

        if self._frames:
            _frame = self._frames[0]._frame
            # Note that this doesn't use .rows/.columns, as those are the size
            # of the pixel area.  The "page" is the size of the canvas, which
            # is the size of the image itself.
            # TODO the canvas might be different between different frames!  see
            # if this happens on load, try to preserve it with operations
            return Size(_frame.page.width, _frame.page.height)
        else:
            return Size(0, 0)
Exemple #8
0
    def new(cls, size, fill=None):
        """Create a new image (with one frame) of the given size."""
        size = Size.coerce(size)

        image_info = blank_image_info()
        magick_pixel = blank_magick_pixel()

        if fill is None:
            # TODO need a way to explicitly create a certain color
            fill = RGBColor(0., 0., 0., 0.)

        fill._populate_magick_pixel(magick_pixel)

        ptr = lib.NewMagickImage(image_info, size.width, size.height, magick_pixel)
        magick_raise(ptr.exception)

        return cls(ptr)
Exemple #9
0
    def new(cls, size, fill=None):
        """Create a new image (with one frame) of the given size."""
        size = Size.coerce(size)

        image_info = blank_image_info()
        magick_pixel = blank_magick_pixel()

        if fill is None:
            # TODO need a way to explicitly create a certain color
            fill = RGBColor(0., 0., 0., 0.)

        fill._populate_magick_pixel(magick_pixel)

        ptr = lib.NewMagickImage(image_info, size.width, size.height,
                                 magick_pixel)
        magick_raise(ptr.exception)

        return cls(ptr)
Exemple #10
0
def test_crop_miss(ctx):
    img = builtins.rose.cropped(Size(40, 30).at((90, 60)),
                                preserve_canvas=True)
    ctx.compare(img, 'crop_miss.miff')
Exemple #11
0
def test_crop_all(ctx):
    img = builtins.rose.cropped(Size(90, 60).at((-10, -10)),
                                preserve_canvas=True)
    ctx.compare(img, 'crop_all.miff')
Exemple #12
0
def test_crop(ctx):
    img = builtins.rose.cropped(Size(40, 30).at((10, 10)),
                                preserve_canvas=True)
    ctx.compare(img, 'crop.miff')
Exemple #13
0
    def resized(self, size, filter=None):
        size = Size.coerce(size)

        # TODO allow picking a filter
        # TODO allow messing with blur?

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

        if filter == "box":
            c_filter = lib.BoxFilter
        else:
            c_filter = lib.UndefinedFilter

        target_width = size.width
        target_height = size.height
        ratio_width = target_width / (self._stack.page.width or self._stack.columns)
        ratio_height = target_height / (self._stack.page.height or self._stack.rows)

        while p:
            # Alrighty, so.  ResizeImage takes the given size as the new size
            # of the FRAME, rather than the CANVAS, which is almost certainly
            # not what anyone expects.  So do the math to fix this manually,
            # converting from canvas size to frame size.
            frame_width = int(p.columns * ratio_width + 0.5)
            frame_height = int(p.rows * ratio_height + 0.5)

            # ImageMagick, brilliant as it is, does not scale non-linear colorspaces
            # correctly. This definitely affects sRGB (see Issue-23) and may affect
            # other colorspaces. The "helpful" solution is to preconvert to linear RGB,
            # and postconvert to the original value. See also:
            # http://www.imagemagick.org/script/color-management.php

            inputImage = p
            with magick_try() as exc:
                # Assume ImageMagick will do the dumbest possible thing to non-RGB spaces.
                # TODO: But maybe we can trust it a bit more?
                if p.colorspace != lib.RGBColorspace:
                    inputImage = lib.CloneImage(p, 0, 0, 0, exc.ptr)
                    lib.TransformImageColorspace(inputImage, lib.RGBColorspace)

                if c_filter == lib.BoxFilter:
                    # Use the faster ScaleImage in this special case
                    new_frame = lib.ScaleImage(inputImage, frame_width, frame_height, exc.ptr)
                else:
                    new_frame = lib.ResizeImage(inputImage, frame_width, frame_height, c_filter, 1.0, exc.ptr)

                if new_frame.colorspace != p.colorspace:
                    lib.TransformImageColorspace(new_frame, p.colorspace)

            if inputImage != p:
                lib.DestroyImage(inputImage)

            # TODO how do i do this correctly etc?  will it ever be non-null??
            # except Exception:
            #    lib.DestroyImage(new_frame)

            # ImageMagick uses new_size/old_size to compute the resized frame's
            # position.  But new_size has already been rounded, so for small
            # frames in a large image, the double rounding error can place the
            # new frame a noticable distance from where one might expect.  Fix
            # the canvas manually, too.
            new_frame.page.width = target_width
            new_frame.page.height = target_height
            new_frame.page.x = int(p.page.x * ratio_width + 0.5)
            new_frame.page.y = int(p.page.y * ratio_height + 0.5)

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

        return type(self)(new_stack_ptr[0])
Exemple #14
0
 def size(self):
     """Size of the frame, as a `Size`.  Shortcut for `frame.canvas.size`.
     """
     return Size(self._frame.columns, self._frame.rows)
Exemple #15
0
    def resized(self, size, filter=None):
        size = Size.coerce(size)

        # TODO allow picking a filter
        # TODO allow messing with blur?

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

        if filter == 'box':
            c_filter = lib.BoxFilter
        else:
            c_filter = lib.UndefinedFilter

        target_width = size.width
        target_height = size.height
        ratio_width = target_width / (self._stack.page.width
                                      or self._stack.columns)
        ratio_height = target_height / (self._stack.page.height
                                        or self._stack.rows)

        while p:
            # Alrighty, so.  ResizeImage takes the given size as the new size
            # of the FRAME, rather than the CANVAS, which is almost certainly
            # not what anyone expects.  So do the math to fix this manually,
            # converting from canvas size to frame size.
            frame_width = int(p.columns * ratio_width + 0.5)
            frame_height = int(p.rows * ratio_height + 0.5)

            # ImageMagick, brilliant as it is, does not scale non-linear colorspaces
            # correctly. This definitely affects sRGB (see Issue-23) and may affect
            # other colorspaces. The "helpful" solution is to preconvert to linear RGB,
            # and postconvert to the original value. See also:
            # http://www.imagemagick.org/script/color-management.php

            inputImage = p
            with magick_try() as exc:
                # Assume ImageMagick will do the dumbest possible thing to non-RGB spaces.
                # TODO: But maybe we can trust it a bit more?
                if p.colorspace != lib.RGBColorspace:
                    inputImage = lib.CloneImage(p, 0, 0, 0, exc.ptr)
                    lib.TransformImageColorspace(inputImage, lib.RGBColorspace)

                if c_filter == lib.BoxFilter:
                    # Use the faster ScaleImage in this special case
                    new_frame = lib.ScaleImage(inputImage, frame_width,
                                               frame_height, exc.ptr)
                else:
                    new_frame = lib.ResizeImage(inputImage, frame_width,
                                                frame_height, c_filter, 1.0,
                                                exc.ptr)

                if new_frame.colorspace != p.colorspace:
                    lib.TransformImageColorspace(new_frame, p.colorspace)

            if inputImage != p:
                lib.DestroyImage(inputImage)

            # TODO how do i do this correctly etc?  will it ever be non-null??
            #except Exception:
            #    lib.DestroyImage(new_frame)

            # ImageMagick uses new_size/old_size to compute the resized frame's
            # position.  But new_size has already been rounded, so for small
            # frames in a large image, the double rounding error can place the
            # new frame a noticable distance from where one might expect.  Fix
            # the canvas manually, too.
            new_frame.page.width = target_width
            new_frame.page.height = target_height
            new_frame.page.x = int(p.page.x * ratio_width + 0.5)
            new_frame.page.y = int(p.page.y * ratio_height + 0.5)

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

        return type(self)(new_stack_ptr[0])
Exemple #16
0
    def resized(self, size, filter=None):
        size = Size.coerce(size)

        # TODO allow picking a filter
        # TODO allow messing with blur?

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

        if filter == 'box':
            c_filter = lib.BoxFilter
        else:
            c_filter = lib.UndefinedFilter

        target_width = size.width
        target_height = size.height
        ratio_width = target_width / (self._stack.page.width or self._stack.columns)
        ratio_height = target_height / (self._stack.page.height or self._stack.rows)

        while p:
            # Alrighty, so.  ResizeImage takes the given size as the new size
            # of the FRAME, rather than the CANVAS, which is almost certainly
            # not what anyone expects.  So do the math to fix this manually,
            # converting from canvas size to frame size.
            frame_width = int(p.columns * ratio_width + 0.5)
            frame_height = int(p.rows * ratio_height + 0.5)

            # Imagemagick seems to consider sRGB (nonlinear) to be the default colorspace
            # for images without colorspace information. In doing so, it might mangle colors
            # during some operations which expect a linear colorspace. It also seems to prefer
            # sRGB as output, rather than using the input colorspace.
            # See also:
            # http://www.imagemagick.org/script/color-management.php

            inputImage = p
            with magick_try() as exc:
                if c_filter == lib.BoxFilter:
                    # Use the faster ScaleImage in this special case
                    new_frame = lib.ScaleImage(
                        inputImage, frame_width, frame_height, exc.ptr)
                else:
                    new_frame = lib.ResizeImage(
                        inputImage, frame_width, frame_height,
                        c_filter, 1.0, exc.ptr)

                if new_frame.colorspace != p.colorspace and p.colorspace != lib.UndefinedColorspace:
                    lib.TransformImageColorspace(new_frame, p.colorspace)

            if inputImage != p:
                lib.DestroyImage(inputImage)

            # TODO how do i do this correctly etc?  will it ever be non-null??
            #except Exception:
            #    lib.DestroyImage(new_frame)

            # ImageMagick uses new_size/old_size to compute the resized frame's
            # position.  But new_size has already been rounded, so for small
            # frames in a large image, the double rounding error can place the
            # new frame a noticable distance from where one might expect.  Fix
            # the canvas manually, too.
            new_frame.page.width = target_width
            new_frame.page.height = target_height
            new_frame.page.x = int(p.page.x * ratio_width + 0.5)
            new_frame.page.y = int(p.page.y * ratio_height + 0.5)

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

        return type(self)(new_stack_ptr[0])
Exemple #17
0
def test_rose_pixel(ctx):
    img = builtins.rose
    img = img.cropped(Size(1, 1).at((40, 30)))
    img = img.resized((100, 100), filter='box')
    ctx.compare(img, 'canvas_pick.miff')