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
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
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)
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)
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])
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])
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])