From 11f239c6e507bdec9c6b56b3c97736ac899a0e79 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 10 May 2016 15:40:33 +0530 Subject: [PATCH] Remove ImageMagick --- src/calibre/utils/imageops/imageops.cpp | 79 + src/calibre/utils/imageops/imageops.h | 3 + src/calibre/utils/imageops/imageops.sip | 21 + src/calibre/utils/img.py | 82 +- src/calibre/utils/magick/__init__.py | 280 +-- src/calibre/utils/magick/draw.py | 217 +-- src/calibre/utils/magick/generate.py | 73 - src/calibre/utils/magick/legacy.py | 166 ++ src/calibre/utils/magick/magick.c | 1693 ------------------- src/calibre/utils/magick/magick_constants.h | 344 ---- 10 files changed, 351 insertions(+), 2607 deletions(-) delete mode 100644 src/calibre/utils/magick/generate.py create mode 100644 src/calibre/utils/magick/legacy.py delete mode 100644 src/calibre/utils/magick/magick.c delete mode 100644 src/calibre/utils/magick/magick_constants.h diff --git a/src/calibre/utils/imageops/imageops.cpp b/src/calibre/utils/imageops/imageops.cpp index be01f84b03..52f68f1ff4 100644 --- a/src/calibre/utils/imageops/imageops.cpp +++ b/src/calibre/utils/imageops/imageops.cpp @@ -863,3 +863,82 @@ QImage oil_paint(const QImage &image, const float radius, const bool high_qualit return(buffer); } // }}} + +bool has_transparent_pixels(const QImage &image) { // {{{ + QImage img(image); + QImage::Format fmt = img.format(); + if (!img.hasAlphaChannel()) return false; + if (fmt != QImage::Format_ARGB32 && fmt != QImage::Format_ARGB32_Premultiplied) { + img = img.convertToFormat(QImage::Format_ARGB32); + if (img.isNull()) throw std::bad_alloc(); + } + int w = image.width(), h = image.height(); + for (int r = 0; r < h; r++) { + const QRgb *line = reinterpret_cast(img.constScanLine(r)); + for (int c = 0; c < w; c++) { + if (qAlpha(*(line + c)) != 0xff) return true; + } + } + return false; +} // }}} + +QImage set_opacity(const QImage &image, double alpha) { // {{{ + QImage img(image); + QImage::Format fmt = img.format(); + if (fmt != QImage::Format_ARGB32) { + img = img.convertToFormat(QImage::Format_ARGB32); + if (img.isNull()) throw std::bad_alloc(); + } + int w = image.width(), h = image.height(); + for (int r = 0; r < h; r++) { + QRgb *line = reinterpret_cast(img.scanLine(r)); + for (int c = 0; c < w; c++) { + QRgb pixel = *(line + c); + *(line + c) = qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel) * alpha); + } + } + return img; +} // }}} + +QImage texture_image(const QImage &image, const QImage &texturei) { // {{{ + QImage canvas(image); + QImage texture(texturei); + if (texture.isNull()) throw std::out_of_range("Cannot use null texture image"); + if (canvas.isNull()) throw std::out_of_range("Cannot use null canvas image"); + + ENSURE32(canvas); ENSURE32(texture); + int x = 0, y = 0, cw = canvas.width(), ch = canvas.height(), tw = texture.width(), th = texture.height(); + const bool overwrite = !texturei.hasAlphaChannel(); + + if (!overwrite) { + if (texture.format() != QImage::Format_ARGB32_Premultiplied) { + texture = texture.convertToFormat(QImage::Format_ARGB32_Premultiplied); + if (texture.isNull()) throw std::bad_alloc(); + } + } + + while (y < ch) { + int ylimit = MIN(th, ch - y); + x = 0; + while (x < cw) { + for (int r = 0; r < ylimit; r++) { + const QRgb *src = reinterpret_cast(texture.constScanLine(r)); + QRgb *dest = reinterpret_cast(canvas.scanLine(r + y)) + x; + int xlimit = MIN(tw, cw - x); + if (overwrite) { + memcpy(dest, src, xlimit * sizeof(QRgb)); + } else { + for (int c = 0; c < xlimit; c++) { + // See the overlay function() for an explanation of the alpha blending code below + QRgb s = src[c]; + if (s >= 0xff000000) dest[c] = s; + else if (s != 0) dest[c] = s + BYTE_MUL(dest[c], qAlpha(~s)); + } + } + } + x += tw; + } + y += th; + } + return canvas; +} // }}} diff --git a/src/calibre/utils/imageops/imageops.h b/src/calibre/utils/imageops/imageops.h index 6d9a3539a3..1b5a0ed56d 100644 --- a/src/calibre/utils/imageops/imageops.h +++ b/src/calibre/utils/imageops/imageops.h @@ -19,6 +19,9 @@ void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned in QImage normalize(const QImage &image); QImage oil_paint(const QImage &image, const float radius=-1, const bool high_quality=true); QImage quantize(const QImage &image, unsigned int maximum_colors, bool dither, const QVector &palette); +bool has_transparent_pixels(const QImage &image); +QImage set_opacity(const QImage &image, double alpha); +QImage texture_image(const QImage &image, const QImage &texturei); class ScopedGILRelease { public: diff --git a/src/calibre/utils/imageops/imageops.sip b/src/calibre/utils/imageops/imageops.sip index f2e4c9af06..ed72af2b3c 100644 --- a/src/calibre/utils/imageops/imageops.sip +++ b/src/calibre/utils/imageops/imageops.sip @@ -78,3 +78,24 @@ QImage quantize(const QImage &image, unsigned int maximum_colors, bool dither, c sipRes = new QImage(quantize(*a0, a1, a2, *a3)); IMAGEOPS_SUFFIX %End + +bool has_transparent_pixels(const QImage &image); +%MethodCode + IMAGEOPS_PREFIX + sipRes = has_transparent_pixels(*a0); + IMAGEOPS_SUFFIX +%End + +QImage set_opacity(const QImage &image, double alpha); +%MethodCode + IMAGEOPS_PREFIX + sipRes = new QImage(set_opacity(*a0, a1)); + IMAGEOPS_SUFFIX +%End + +QImage texture_image(const QImage &image, const QImage &texturei); +%MethodCode + IMAGEOPS_PREFIX + sipRes = new QImage(texture_image(*a0, *a1)); + IMAGEOPS_SUFFIX +%End diff --git a/src/calibre/utils/img.py b/src/calibre/utils/img.py index 9a9867fe71..23c730e2e6 100644 --- a/src/calibre/utils/img.py +++ b/src/calibre/utils/img.py @@ -27,18 +27,8 @@ def get_exe_path(name): return name return os.path.join(base, name) -_qimage_pixel_map = None - -def get_pixel_map(): - ' Get the order of pixels in QImage (RGBA or BGRA usually) ' - global _qimage_pixel_map - if _qimage_pixel_map is None: - i = QImage(1, 1, QImage.Format_ARGB32) - i.fill(QColor(0, 1, 2, 3)) - raw = bytearray(i.constBits().asstring(4)) - _qimage_pixel_map = {c:raw.index(x) for c, x in zip('RGBA', b'\x00\x01\x02\x03')} - _qimage_pixel_map = ''.join(sorted(_qimage_pixel_map, key=_qimage_pixel_map.get)) - return _qimage_pixel_map +def null_image(): + return QImage() def image_from_data(data): if isinstance(data, QImage): @@ -48,6 +38,21 @@ def image_from_data(data): raise NotImage('Not a valid image') return i +def image_from_path(path): + with lopen(path, 'rb') as f: + return image_from_data(f.read()) + +def image_from_x(x): + if isinstance(x, type('')): + return image_from_path(x) + if hasattr(x, 'read'): + return image_from_data(x.read()) + if isinstance(x, (bytes, QImage)): + return image_from_data(x) + if isinstance(x, bytearray): + return image_from_data(bytes(x)) + raise TypeError('Unknown image src type: %s' % type(x)) + def image_and_format_from_data(data): ba = QByteArray(data) buf = QBuffer(ba) @@ -62,10 +67,10 @@ def add_borders_to_image(img, left=0, top=0, right=0, bottom=0, border_color='#f return img canvas = QImage(img.width() + left + right, img.height() + top + bottom, QImage.Format_RGB32) canvas.fill(QColor(border_color)) - overlay(img, canvas, left, top) + overlay_image(img, canvas, left, top) return canvas -def overlay(img, canvas=None, left=0, top=0): +def overlay_image(img, canvas=None, left=0, top=0): if canvas is None: canvas = QImage(img.size(), QImage.Format_RGB32) canvas.fill(Qt.white) @@ -85,7 +90,7 @@ def overlay(img, canvas=None, left=0, top=0): def blend_image(img, bgcolor='#ffffff'): canvas = QImage(img.size(), QImage.Format_RGB32) canvas.fill(QColor(bgcolor)) - overlay(img, canvas) + overlay_image(img, canvas) return canvas def image_to_data(img, compression_quality=95, fmt='JPEG', png_compression_level=9, jpeg_optimized=True, jpeg_progressive=False): @@ -119,6 +124,12 @@ def image_to_data(img, compression_quality=95, fmt='JPEG', png_compression_level raise ValueError('Failed to export image as ' + fmt + ' with error: ' + w.errorString()) return ba.data() +def save_image(img, path, **kw): + fmt = path.rpartition('.')[-1] + kw['fmt'] = kw.get('fmt', fmt) + with lopen(path, 'wb') as f: + f.write(image_to_data(image_from_data(img), **kw)) + def resize_image(img, width, height): return img.scaled(int(width), int(height), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) @@ -174,10 +185,18 @@ def normalize_format_name(fmt): def grayscale_image(img): if imageops is not None: - return imageops.grayscale(img) + return imageops.grayscale(image_from_data(img)) return img -def save_cover_data_to(data, path=None, bgcolor='#ffffff', resize_to=None, compression_quality=90, minify_to=None, grayscale=False): +def set_image_opacity(img, alpha=0.5): + ''' Change the opacity of `img`. Note that the alpha value is multiplied to + any existing alpha values, so you cannot use this function to convert a + semi-transparent image to an opaque one. For that use `blend_image()`. ''' + if imageops is None: + raise RuntimeError(imageops_err) + return imageops.set_opacity(image_from_data(img), alpha) + +def save_cover_data_to(data, path=None, bgcolor='#ffffff', resize_to=None, compression_quality=90, minify_to=None, grayscale=False, data_fmt='jpeg'): ''' Saves image in data to path, in the format specified by the path extension. Removes any transparency. If there is no transparency and no @@ -186,6 +205,7 @@ def save_cover_data_to(data, path=None, bgcolor='#ffffff', resize_to=None, compr :param data: Image data as bytestring :param path: If None img data is returned, in JPEG format + :param data_fmt: The fmt to return data in when path is None. Defaults to JPEG :param compression_quality: The quality of the image after compression. Number between 1 and 100. 1 means highest compression, 100 means no compression (lossless). @@ -197,7 +217,7 @@ def save_cover_data_to(data, path=None, bgcolor='#ffffff', resize_to=None, compr ''' img, fmt = image_and_format_from_data(data) orig_fmt = normalize_format_name(fmt) - fmt = normalize_format_name('jpeg' if path is None else os.path.splitext(path)[1][1:]) + fmt = normalize_format_name(data_fmt if path is None else os.path.splitext(path)[1][1:]) changed = fmt != orig_fmt if resize_to is not None: changed = True @@ -228,7 +248,7 @@ def blend_on_canvas(img, width, height, bgcolor='#ffffff'): w, h = nw, nh canvas = QImage(width, height, QImage.Format_RGB32) canvas.fill(QColor(bgcolor)) - overlay(img, canvas, (width - w)//2, (height - h)//2) + overlay_image(img, canvas, (width - w)//2, (height - h)//2) return canvas class Canvas(object): @@ -245,14 +265,28 @@ class Canvas(object): def compose(self, img, x=0, y=0): img = image_from_data(img) - overlay(img, self.img, x, y) + overlay_image(img, self.img, x, y) def export(self, fmt='JPEG', compression_quality=95): return image_to_data(self.img, compression_quality=compression_quality, fmt=fmt) +def create_canvas(width, height, bgcolor='#ffffff'): + img = QImage(width, height, QImage.Format_RGB32) + img.fill(QColor(bgcolor)) + return img + def flip_image(img, horizontal=False, vertical=False): return image_from_data(img).mirrored(horizontal, vertical) +def image_has_transparent_pixels(img): + ' Return True iff the image has at least one semi-transparent pixel ' + img = image_from_data(img) + if img.isNull(): + return False + if imageops is None: + raise RuntimeError(imageops_err) + return imageops.has_transparent_pixels(img) + def rotate_image(img, degrees): t = QTransform() t.rotate(degrees) @@ -314,6 +348,14 @@ def quantize_image(img, max_colors=256, dither=True, palette=''): palette = palette.split() return imageops.quantize(img, max_colors, dither, [QColor(x).rgb() for x in palette]) +def texture_image(canvas, texture): + ' Repeatedly tile the image `texture` across and down the image `canvas` ' + if imageops is None: + raise RuntimeError(imageops_err) + if canvas.hasAlphaChannel(): + canvas = blend_image(canvas) + return imageops.texture_image(canvas, texture) + # Optimization of images {{{ def run_optimizer(file_path, cmd, as_filter=False, input_data=None): diff --git a/src/calibre/utils/magick/__init__.py b/src/calibre/utils/magick/__init__.py index d710de0824..0332e26ed5 100644 --- a/src/calibre/utils/magick/__init__.py +++ b/src/calibre/utils/magick/__init__.py @@ -5,284 +5,10 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os +from calibre.utils.magick.legacy import Image, PixelWand -from calibre.constants import plugins, filesystem_encoding -from calibre.utils.img import get_pixel_map, image_and_format_from_data - -_magick, _merr = plugins['magick'] - -if _magick is None: - raise RuntimeError('Failed to load ImageMagick: '+_merr) - -_gravity_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if - x.endswith('Gravity')]) - -_type_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if - x.endswith('Type')]) - -_colorspace_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if - x.endswith('Colorspace')]) - -def qimage_to_magick(img): - ans = Image() - ans.from_qimage(img) - return ans - -# Font metrics {{{ -class Rect(object): - - def __init__(self, left, top, right, bottom): - self.left, self.top, self.right, self.bottom = left, top, right, bottom - - def __str__(self): - return '(%s, %s) -- (%s, %s)'%(self.left, self.top, self.right, - self.bottom) - -class FontMetrics(object): - - def __init__(self, ret): - self._attrs = [] - for i, x in enumerate(('char_width', 'char_height', 'ascender', - 'descender', 'text_width', 'text_height', - 'max_horizontal_advance')): - setattr(self, x, ret[i]) - self._attrs.append(x) - self.bounding_box = Rect(ret[7], ret[8], ret[9], ret[10]) - self.x, self.y = ret[11], ret[12] - self._attrs.extend(['bounding_box', 'x', 'y']) - self._attrs = tuple(self._attrs) - - def __str__(self): - return '''FontMetrics: - char_width: %s - char_height: %s - ascender: %s - descender: %s - text_width: %s - text_height: %s - max_horizontal_advance: %s - bounding_box: %s - x: %s - y: %s - '''%tuple([getattr(self, x) for x in self._attrs]) - -# }}} - -class PixelWand(_magick.PixelWand): # {{{ - pass - -# }}} - -class DrawingWand(_magick.DrawingWand): # {{{ - - @dynamic_property - def font(self): - def fget(self): - return self.font_.decode(filesystem_encoding, 'replace').lower() - def fset(self, val): - if isinstance(val, unicode): - val = val.encode(filesystem_encoding) - self.font_ = str(val) - return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_.__doc__) - - @dynamic_property - def gravity(self): - def fget(self): - val = self.gravity_ - return _gravity_map[val] - def fset(self, val): - val = getattr(_magick, str(val)) - self.gravity_ = val - return property(fget=fget, fset=fset, doc=_magick.DrawingWand.gravity_.__doc__) - - @dynamic_property - def font_size(self): - def fget(self): - return self.font_size_ - def fset(self, val): - self.font_size_ = float(val) - return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_size_.__doc__) - - @dynamic_property - def stroke_color(self): - def fget(self): - return self.stroke_color_.color - def fset(self, val): - col = PixelWand() - col.color = unicode(val) - self.stroke_color_ = col - return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_size_.__doc__) - - @dynamic_property - def fill_color(self): - def fget(self): - return self.fill_color_.color - def fset(self, val): - col = PixelWand() - col.color = unicode(val) - self.fill_color_ = col - return property(fget=fget, fset=fset, doc=_magick.DrawingWand.font_size_.__doc__) - -# }}} - -class Image(_magick.Image): # {{{ - - read_format = None - - @property - def clone(self): - ans = Image() - ans.copy(self) - return ans - - def from_qimage(self, img): - from PyQt5.Qt import QImage - fmt = get_pixel_map() - if not img.hasAlphaChannel(): - if img.format() != img.Format_RGB32: - img = img.convertToFormat(QImage.Format_RGB32) - fmt = fmt.replace('A', 'P') - else: - if img.format() != img.Format_ARGB32: - img = img.convertToFormat(QImage.Format_ARGB32) - raw = img.constBits().ascapsule() - self.constitute(img.width(), img.height(), fmt, raw) - - def to_qimage(self): - from PyQt5.Qt import QImage, QByteArray - fmt = get_pixel_map() - # ImageMagick can only output raw data in some formats that can be - # read into QImage directly, if the QImage format is not one of those, use - # PNG - if fmt in {'RGBA', 'BGRA'}: - w, h = self.size - self.depth = 8 # QImage expects 8bpp - raw = self.export(fmt) - i = QImage(raw, w, h, QImage.Format_ARGB32) - del raw # According to the documentation, raw is supposed to not be deleted, but it works, so make it explicit - return i - else: - raw = self.export('PNG') - return QImage.fromData(QByteArray(raw), 'PNG') - - def load(self, data): - if not data: - raise ValueError('Cannot open image from empty data string') - img, self.read_format = image_and_format_from_data(data) - self.from_qimage(img) - - def open(self, path_or_file): - data = path_or_file - if hasattr(data, 'read'): - data = data.read() - else: - with lopen(data, 'rb') as f: - data = f.read() - if not data: - raise ValueError('%r is an empty file'%path_or_file) - self.load(data) - - @dynamic_property - def format(self): - def fget(self): - if self.format_ is None: - return self.read_format - return self.format_.decode('utf-8', 'ignore').lower() - def fset(self, val): - self.format_ = str(val) - return property(fget=fget, fset=fset, doc=_magick.Image.format_.__doc__) - - @dynamic_property - def type(self): - def fget(self): - return _type_map[self.type_] - def fset(self, val): - val = getattr(_magick, str(val)) - self.type_ = val - return property(fget=fget, fset=fset, doc=_magick.Image.type_.__doc__) - - @dynamic_property - def colorspace(self): - def fget(self): - return _colorspace_map[self.colorspace_] - def fset(self, val): - val = getattr(_magick, str(val)) - self.colorspace_ = val - return property(fget=fget, fset=fset, doc=_magick.Image.type_.__doc__) - - @dynamic_property - def size(self): - def fget(self): - return self.size_ - def fset(self, val): - filter = 'CatromFilter' - if len(val) > 2: - filter = val[2] - filter = int(getattr(_magick, filter)) - blur = 1.0 - if len(val) > 3: - blur = float(val[3]) - self.size_ = (int(val[0]), int(val[1]), filter, blur) - return property(fget=fget, fset=fset, doc=_magick.Image.size_.__doc__) - - def save(self, path, format=None): - if format is None: - ext = os.path.splitext(path)[1] - if len(ext) < 2: - raise ValueError('No format specified') - format = ext[1:] - format = format.upper() - - with lopen(path, 'wb') as f: - f.write(self.export(format)) - - def compose(self, img, left=0, top=0, operation='OverCompositeOp'): - op = getattr(_magick, operation) - bounds = self.size - if left < 0 or top < 0 or left >= bounds[0] or top >= bounds[1]: - raise ValueError('left and/or top out of bounds') - _magick.Image.compose(self, img, int(left), int(top), op) - - def compare(self, img, metric='RootMeanSquaredErrorMetric'): - return _magick.Image.compare(self, img, getattr(_magick, metric)) - - def font_metrics(self, drawing_wand, text): - if isinstance(text, unicode): - text = text.encode('UTF-8') - return FontMetrics(_magick.Image.font_metrics(self, drawing_wand, text)) - - def annotate(self, drawing_wand, x, y, angle, text): - if isinstance(text, unicode): - text = text.encode('UTF-8') - return _magick.Image.annotate(self, drawing_wand, x, y, angle, text) - - def distort(self, method, arguments, bestfit): - method = getattr(_magick, method) - arguments = [float(x) for x in arguments] - _magick.Image.distort(self, method, arguments, bestfit) - - def rotate(self, background_pixel_wand, degrees): - _magick.Image.rotate(self, background_pixel_wand, float(degrees)) - - def quantize(self, number_colors, colorspace='RGBColorspace', treedepth=0, dither=True, - measure_error=False): - colorspace = getattr(_magick, colorspace) - _magick.Image.quantize(self, number_colors, colorspace, treedepth, dither, - measure_error) - - def identify(self, data): - img, fmt = image_and_format_from_data(data) - return img.width(), img.height(), fmt - - def trim(self, fuzz): - try: - _magick.Image.remove_border(self, fuzz) - except AttributeError: - _magick.Image.trim(self, fuzz) - - -# }}} +if False: + PixelWand def create_canvas(width, height, bgcolor='#ffffff'): canvas = Image() diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 58d96aa307..e7ef1c65fa 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -7,10 +7,10 @@ __docformat__ = 'restructuredtext en' import os -from calibre.utils.magick import Image, DrawingWand, create_canvas -from calibre.constants import __appname__, __version__ -from calibre.utils.config import tweaks -from calibre import fit_image, force_unicode +from calibre.utils.magick import Image, create_canvas +from calibre.utils.img import save_cover_data_to as _save_cover_data_to, image_to_data, add_borders_to_image as abti +from calibre.utils.imghdr import identify as _identify +from calibre import fit_image def _data_to_image(data): if isinstance(data, Image): @@ -40,12 +40,6 @@ def minify_image(data, minify_to=(1200, 1600), preserve_aspect_ratio=True): img.size = (nwidth, nheight) return img -def normalize_format_name(fmt): - fmt = fmt.lower() - if fmt == 'jpeg': - fmt = 'jpg' - return fmt - def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, return_data=False, compression_quality=90, minify_to=None, grayscale=False): @@ -67,50 +61,13 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, tweak is used. ''' - changed = False - img = _data_to_image(data) - orig_fmt = normalize_format_name(img.format) fmt = os.path.splitext(path)[1] - fmt = normalize_format_name(fmt[1:]) - - if grayscale: - img.type = "GrayscaleType" - changed = True - - if resize_to is not None: - img.size = (resize_to[0], resize_to[1]) - changed = True - owidth, oheight = img.size - nwidth, nheight = tweaks['maximum_cover_size'] if minify_to is None else minify_to - scaled, nwidth, nheight = fit_image(owidth, oheight, nwidth, nheight) - if scaled: - img.size = (nwidth, nheight) - changed = True - if img.has_transparent_pixels(): - canvas = create_canvas(img.size[0], img.size[1], bgcolor) - canvas.compose(img) - img = canvas - changed = True - - if not changed: - changed = fmt != orig_fmt - - ret = None if return_data: - ret = data - if changed or isinstance(ret, Image): - if hasattr(img, 'set_compression_quality') and fmt == 'jpg': - img.set_compression_quality(compression_quality) - ret = img.export(fmt) - else: - if changed or isinstance(ret, Image): - if hasattr(img, 'set_compression_quality') and fmt == 'jpg': - img.set_compression_quality(compression_quality) - img.save(path) - else: - with lopen(path, 'wb') as f: - f.write(data) - return ret + path = None + if isinstance(data, Image): + data = Image.img + return _save_cover_data_to( + data, path, bgcolor=bgcolor, resize_to=resize_to, compression_quality=compression_quality, minify_to=minify_to, grayscale=grayscale, data_fmt=fmt) def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg', preserve_aspect_ratio=True, compression_quality=70): @@ -131,9 +88,8 @@ def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg', img.size = (nwidth, nheight) canvas = create_canvas(img.size[0], img.size[1], bgcolor) canvas.compose(img) - if fmt == 'jpg': - canvas.set_compression_quality(compression_quality) - return (canvas.size[0], canvas.size[1], canvas.export(fmt)) + data = image_to_data(canvas.img, compression_quality=compression_quality) + return (canvas.size[0], canvas.size[1], data) def identify_data(data): ''' @@ -141,8 +97,8 @@ def identify_data(data): (width, height, format) or raises an Exception if data is not an image. ''' - img = Image() - return img.identify(data) + fmt, width, height = _identify(data) + return width, height, fmt def identify(path): ''' @@ -151,149 +107,10 @@ def identify(path): or raises an Exception. ''' with lopen(path, 'rb') as f: - data = f.read() - return identify_data(data) + fmt, width, height = _identify(f) + return width, height, fmt def add_borders_to_image(img_data, left=0, top=0, right=0, bottom=0, border_color='#ffffff', fmt='jpg'): - img = Image() - img.load(img_data) - lwidth, lheight = img.size - canvas = create_canvas(lwidth+left+right, lheight+top+bottom, - border_color) - canvas.compose(img, left, top) - return canvas.export(fmt) - -def create_text_wand(font_size, font_path=None): - ans = DrawingWand() - if font_path is not None: - ans.font = font_path - ans.font_size = font_size - ans.gravity = 'CenterGravity' - ans.text_alias = True - return ans - -def create_text_arc(text, font_size, font=None, bgcolor='#ffffff'): - if isinstance(text, unicode): - text = text.encode('utf-8') - - canvas = create_canvas(300, 300, bgcolor) - - tw = create_text_wand(font_size, font_path=font) - m = canvas.font_metrics(tw, text) - canvas = create_canvas(int(m.text_width)+20, int(m.text_height*3.5), bgcolor) - canvas.annotate(tw, 0, 0, 0, text) - canvas.distort("ArcDistortion", [120], True) - canvas.trim(0) - return canvas - -def _get_line(img, dw, tokens, line_width): - line, rest = tokens, [] - while True: - m = img.font_metrics(dw, ' '.join(line)) - width = m.text_width - if width < line_width: - return line, rest - rest = line[-1:] + rest - line = line[:-1] - -def annotate_img(img, dw, left, top, rotate, text, - translate_from_top_left=True): - if isinstance(text, unicode): - text = text.encode('utf-8') - if translate_from_top_left: - m = img.font_metrics(dw, text) - img_width, img_height = img.size - left = left - img_width/2. + m.text_width/2. - top = top - img_height/2. + m.text_height/2. - img.annotate(dw, left, top, rotate, text) - -def draw_centered_line(img, dw, line, top): - m = img.font_metrics(dw, line) - width, height = m.text_width, m.text_height - img_width = img.size[0] - left = max(int((img_width - width)/2.), 0) - annotate_img(img, dw, left, top, 0, line) - return top + height - -def draw_centered_text(img, dw, text, top, margin=10): - img_width = img.size[0] - tokens = text.split(' ') - while tokens: - line, tokens = _get_line(img, dw, tokens, img_width-2*margin) - if not line: - # Could not fit the first token on the line - line = tokens[:1] - tokens = tokens[1:] - bottom = draw_centered_line(img, dw, ' '.join(line), top) - top = bottom - return top - -class TextLine(object): - - def __init__(self, text, font_size, bottom_margin=30, font_path=None): - self.text, self.font_size, = text, font_size - self.bottom_margin = bottom_margin - if font_path is None: - if not isinstance(text, unicode): - text = force_unicode(text) - from calibre.utils.fonts.utils import get_font_for_text - fd = get_font_for_text(text) - if fd is not None: - from calibre.ptempfile import PersistentTemporaryFile - pt = PersistentTemporaryFile('.ttf') - pt.write(fd) - pt.close() - font_path = pt.name - self.font_path = font_path - - def __repr__(self): - return u'TextLine:%r:%f'%(self.text, self.font_size) - - -def create_cover_page(top_lines, logo_path, width=590, height=750, - bgcolor='#ffffff', output_format='jpg', texture_data=None, - texture_opacity=1.0): - ''' - Create the standard calibre cover page and return it as a byte string in - the specified output_format. - ''' - canvas = create_canvas(width, height, bgcolor) - if texture_data and hasattr(canvas, 'texture'): - texture = Image() - texture.load(texture_data) - texture.set_opacity(texture_opacity) - canvas.texture(texture) - - bottom = 10 - for line in top_lines: - twand = create_text_wand(line.font_size, font_path=line.font_path) - bottom = draw_centered_text(canvas, twand, line.text, bottom) - bottom += line.bottom_margin - bottom -= top_lines[-1].bottom_margin - - foot_font = P('fonts/liberation/LiberationMono-Regular.ttf') - vanity = create_text_arc(__appname__ + ' ' + __version__, 24, - font=foot_font, bgcolor='#00000000') - lwidth, lheight = vanity.size - left = int(max(0, (width - lwidth)/2.)) - top = height - lheight - 10 - canvas.compose(vanity, left, top) - - available = (width, int(top - bottom)-20) - if available[1] > 40: - logo = Image() - logo.open(logo_path) - lwidth, lheight = logo.size - scaled, lwidth, lheight = fit_image(lwidth, lheight, *available) - if scaled: - logo.size = (lwidth, lheight) - left = int(max(0, (width - lwidth)/2.)) - top = bottom+10 - extra = int((available[1] - lheight)/2.0) - if extra > 0: - top += extra - canvas.compose(logo, left, top) - - return canvas.export(output_format) - + img = abti(img_data, left=left, top=top, right=right, bottom=bottom, border_color=border_color) + return image_to_data(img, fmt=fmt) diff --git a/src/calibre/utils/magick/generate.py b/src/calibre/utils/magick/generate.py deleted file mode 100644 index 186c6b89ee..0000000000 --- a/src/calibre/utils/magick/generate.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python2 -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2010, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -import os, textwrap, re, subprocess - -INC = '/usr/include/ImageMagick-6' - -''' -Various constants defined in the ImageMagick header files. Note that -they are defined as actual numeric constants rather than symbolic names to -ensure that the extension can be compiled against older versions of ImageMagick -than the one this script is run against. -''' - -def parse_enums(f): - print '\nParsing:', f - raw = open(os.path.join(INC, f)).read() - raw = re.sub(r'(?s)/\*.*?\*/', '', raw) - raw = re.sub('#.*', '', raw) - - for enum in re.findall(r'typedef\s+enum\s+\{([^}]+)', raw): - enum = re.sub(r'(?s)/\*.*?\*/', '', enum) - for x in enum.splitlines(): - e = x.split(',')[0].strip().split(' ')[0] - if e: - val = get_value(e) - print e, val - yield e, val - -def get_value(const): - t = ''' - #define MAGICKCORE_QUANTUM_DEPTH 16 - #define MAGICKCORE_HDRI_ENABLE 0 - #include - #include - int main(int argc, char **argv) { - printf("%%d", %s); - return 0; - } - '''%const - with open('/tmp/ig.c','wb') as f: - f.write(t) - subprocess.check_call(['gcc', '-I'+INC, '/tmp/ig.c', '-o', '/tmp/ig', '-lMagickWand-6.Q16']) - return int(subprocess.Popen(["/tmp/ig"], - stdout=subprocess.PIPE).communicate()[0].strip()) - - -def main(): - constants = [] - for x in ('resample', 'image', 'draw', 'distort', 'composite', 'geometry', - 'colorspace', 'compare', 'compress'): - constants += list(parse_enums('magick/%s.h'%x)) - base = os.path.dirname(__file__) - constants = [ - 'PyModule_AddIntConstant(m, "{0}", {1});'.format(c, v) for c, v in - constants] - raw = textwrap.dedent('''\ - // Generated by generate.py - - static void magick_add_module_constants(PyObject *m) { - %s - } - ''')%'\n '.join(constants) - with open(os.path.join(base, 'magick_constants.h'), 'wb') as f: - f.write(raw) - - -if __name__ == '__main__': - main() diff --git a/src/calibre/utils/magick/legacy.py b/src/calibre/utils/magick/legacy.py new file mode 100644 index 0000000000..3b2de77043 --- /dev/null +++ b/src/calibre/utils/magick/legacy.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python2 +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2016, Kovid Goyal + +from __future__ import (unicode_literals, division, absolute_import, + print_function) +import os +from io import BytesIO + +from calibre.utils.img import ( + image_and_format_from_data, clone_image, null_image, resize_image, + overlay_image, rotate_image, quantize_image, remove_borders_from_image, + add_borders_to_image, gaussian_blur_image, create_canvas, despeckle_image, + image_to_data, flip_image, image_has_transparent_pixels, set_image_opacity, + gaussian_sharpen_image, texture_image +) +from calibre.utils.imghdr import identify + +class PixelWand(object): + + def __init__(self): + self.color = '#ffffff' + +class Image(object): + + def __init__(self): + self.read_format = None + self.write_format = None + self.img = null_image() + + @property + def clone(self): + ans = Image() + ans.img = clone_image(self.img) + ans.read_format = self.read_format + ans.write_format = self.write_format + return ans + + def open(self, path_or_file): + if hasattr(path_or_file, 'read'): + self.load(path_or_file.read()) + else: + with lopen(path_or_file, 'rb') as f: + self.load(f.read()) + + def load(self, data): + if not data: + raise ValueError('No image data present') + self.img, self.read_format = image_and_format_from_data(data) + read = load + + def from_qimage(self, img): + self.img = clone_image(img) + + def to_qimage(self): + return clone_image(self.img) + + @dynamic_property + def format(self): + def fget(self): + return self.write_format or self.read_format + def fset(self, val): + self.write_format = val + return property(fget=fget, fset=fset) + + @dynamic_property + def colorspace(self): + def fget(self): + return 'RGBColorspace' + def fset(self, val): + raise NotImplementedError('Changing image colorspace is not supported') + return property(fget=fget, fset=fset) + + @dynamic_property + def size(self): + def fget(self): + return self.img.width(), self.img.height() + def fset(self, val): + w, h = val[:2] + self.img = resize_image(self.img, w, h) + return property(fget=fget, fset=fset) + + def save(self, path, format=None): + if format is None: + ext = os.path.splitext(path)[1] + if len(ext) < 2: + raise ValueError('No format specified') + format = ext[1:] + format = format.upper() + + with lopen(path, 'wb') as f: + f.write(self.export(format)) + + def compose(self, img, left=0, top=0, operation='OverCompositeOp'): + bounds = self.size + if left < 0 or top < 0 or left >= bounds[0] or top >= bounds[1]: + raise ValueError('left and/or top out of bounds') + self.img = overlay_image(img.img, self.img, left=left, top=top) + + def rotate(self, background_pixel_wand, degrees): + self.img = rotate_image(self.img, degrees) + + def quantize(self, number_colors, colorspace='RGBColorspace', treedepth=0, dither=True, measure_error=False): + self.img = quantize_image(self.img, max_colors=number_colors, dither=dither) + + def identify(self, data): + fmt, width, height = identify(data) + return width, height, fmt + + def remove_border(self, fuzz=None): + if fuzz is not None and fuzz < 0 or fuzz > 255: + fuzz = None + self.img = remove_borders_from_image(self.img, fuzz) + trim = remove_border + + def add_border(self, pixel_wand, dx, dy): + self.img = add_borders_to_image(self.img, left=dx, top=dy, right=dx, bottom=dy, border_color=pixel_wand.color) + + def blur(self, radius=-1, sigma=3.0): + self.img = gaussian_blur_image(self.img, radius, sigma) + + def copy(self, img): + self.img = clone_image(img.img) + + def create_canvas(self, width, height, background_pixel_wand): + self.img = create_canvas(width, height, background_pixel_wand) + + def despeckle(self): + self.img = despeckle_image(self.img) + + def export(self, fmt='JPEG'): + if fmt.lower() == 'gif': + data = image_to_data(self.img, fmt='PNG', png_compression_level=0) + from PIL import Image + i = Image.open(data) + buf = BytesIO() + i.save(buf, 'gif') + return buf.getvalue() + return image_to_data(self.img, fmt=fmt) + + def flip(self, vertical=True): + self.img = flip_image(self.img, horizontal=not vertical, vertical=vertical) + + def has_transparent_pixels(self): + return image_has_transparent_pixels(self.img) + + def set_border_color(self, *args, **kw): + pass # no-op + + def set_compression_quality(self, *args, **kw): + pass # no-op + + def set_opacity(self, alpha=0.5): + self.img = set_image_opacity(self.img, alpha) + + def set_page(self, *args, **kw): + pass # no-op + + def sharpen(self, radius=0, sigma=3): + self.img = gaussian_sharpen_image(self.img, radius, sigma) + + def texture(self, img): + self.img = texture_image(self.img, img.img) + + def thumbnail(self, width, height): + self.img = resize_image(self.img, width, height) diff --git a/src/calibre/utils/magick/magick.c b/src/calibre/utils/magick/magick.c deleted file mode 100644 index d367582265..0000000000 --- a/src/calibre/utils/magick/magick.c +++ /dev/null @@ -1,1693 +0,0 @@ -#define UNICODE -#define PY_SSIZE_T_CLEAN -#include -#include - -#include "magick_constants.h" - -// Ensure that the underlying MagickWand has not been deleted -#define NULL_CHECK(x) if(self->wand == NULL) {PyErr_SetString(PyExc_ValueError, "Underlying ImageMagick Wand has been destroyed"); return x; } -#define MAX(x, y) ((x > y) ? x: y) -#define ABS(x) ((x < 0) ? -x : x) -#define SQUARE(x) x*x - -// magick_set_exception {{{ -PyObject* magick_set_exception(MagickWand *wand) { - ExceptionType ext; - char *desc = MagickGetException(wand, &ext); - PyErr_SetString(PyExc_Exception, desc); - MagickClearException(wand); - desc = MagickRelinquishMemory(desc); - return NULL; -} - -PyObject* pw_iterator_set_exception(PixelIterator *pi) { - ExceptionType ext; - char *desc = PixelGetIteratorException(pi, &ext); - PyErr_SetString(PyExc_Exception, desc); - PixelClearIteratorException(pi); - desc = MagickRelinquishMemory(desc); - return NULL; -} -// }}} - -// PixelWand object definition {{{ -typedef struct { - PyObject_HEAD - // Type-specific fields go here. - PixelWand *wand; - -} magick_PixelWand; - -static void -magick_PixelWand_dealloc(magick_PixelWand* self) -{ - if (self->wand != NULL) self->wand = DestroyPixelWand(self->wand); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -magick_PixelWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - magick_PixelWand *self; - - self = (magick_PixelWand *)type->tp_alloc(type, 0); - if (self != NULL) { - self->wand = NewPixelWand(); - if (self->wand == NULL || self->wand < 0) { - PyErr_SetString(PyExc_Exception, "Failed to allocate wand."); - self->wand = NULL; - Py_DECREF(self); - return NULL; - } - } - - return (PyObject *)self; -} - -// PixelWand.color {{{ -static PyObject * -magick_PixelWand_color_getter(magick_PixelWand *self, void *closure) { - const char *fp; - NULL_CHECK(NULL); - fp = PixelGetColorAsNormalizedString(self->wand); - return Py_BuildValue("s", fp); -} - -static int -magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closure) { - char *fmt; - - NULL_CHECK(-1); - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete PixelWand color"); - return -1; - } - - fmt = PyString_AsString(val); - if (fmt == NULL) return -1; - - if (!PixelSetColor(self->wand, fmt)) { - PyErr_SetString(PyExc_ValueError, "Unknown color"); - return -1; - } - - return 0; -} - -// }}} - -// PixelWand.destroy {{{ - -static PyObject * -magick_PixelWand_destroy(magick_PixelWand *self, PyObject *args) { - NULL_CHECK(NULL) - self->wand = DestroyPixelWand(self->wand); - Py_RETURN_NONE; -} -// }}} - -// PixelWand attr list {{{ -static PyMethodDef magick_PixelWand_methods[] = { - {"destroy", (PyCFunction)magick_PixelWand_destroy, METH_VARARGS, - "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, - - {NULL} /* Sentinel */ -}; - -static PyGetSetDef magick_PixelWand_getsetters[] = { - {(char *)"color", - (getter)magick_PixelWand_color_getter, (setter)magick_PixelWand_color_setter, - (char *)"PixelWand color. ImageMagick color specification.", - NULL}, - - {NULL} /* Sentinel */ -}; - -// }}} - -static PyTypeObject magick_PixelWandType = { // {{{ - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "magick.PixelWand", /*tp_name*/ - sizeof(magick_PixelWand), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)magick_PixelWand_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "PixelWand", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - magick_PixelWand_methods, /* tp_methods */ - 0, /* tp_members */ - magick_PixelWand_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - magick_PixelWand_new, /* tp_new */ -}; // }}} - - -// }}} - -// DrawingWand object definition {{{ -typedef struct { - PyObject_HEAD - // Type-specific fields go here. - DrawingWand *wand; - -} magick_DrawingWand; - -static void -magick_DrawingWand_dealloc(magick_DrawingWand* self) -{ - if (self->wand != NULL) self->wand = DestroyDrawingWand(self->wand); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -magick_DrawingWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - magick_DrawingWand *self; - - self = (magick_DrawingWand *)type->tp_alloc(type, 0); - if (self != NULL) { - self->wand = NewDrawingWand(); - if (self->wand == NULL || self->wand < 0) { - PyErr_SetString(PyExc_Exception, "Failed to allocate wand."); - self->wand = NULL; - Py_DECREF(self); - return NULL; - } - } - - return (PyObject *)self; -} - -// DrawingWand.destroy {{{ - -static PyObject * -magick_DrawingWand_destroy(magick_DrawingWand *self, PyObject *args) { - NULL_CHECK(NULL) - self->wand = DestroyDrawingWand(self->wand); - Py_RETURN_NONE; -} -// }}} - -// DrawingWand.font {{{ -static PyObject * -magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) { - const char *fp; - NULL_CHECK(NULL); - fp = DrawGetFont(self->wand); - return Py_BuildValue("s", fp); -} - -static int -magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - char *fmt; - NULL_CHECK(-1); - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand font"); - return -1; - } - - fmt = PyString_AsString(val); - if (fmt == NULL) return -1; - - if (!DrawSetFont(self->wand, fmt)) { - PyErr_SetString(PyExc_ValueError, "Unknown font"); - return -1; - } - - return 0; -} - -// }}} - -// DrawingWand.font_size {{{ -static PyObject * -magick_DrawingWand_fontsize_getter(magick_DrawingWand *self, void *closure) { - NULL_CHECK(NULL) - return Py_BuildValue("d", DrawGetFontSize(self->wand)); -} - -static int -magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - NULL_CHECK(-1) - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fontsize"); - return -1; - } - - if (!PyFloat_Check(val)) { - PyErr_SetString(PyExc_TypeError, "Font size must be a float"); - return -1; - } - - DrawSetFontSize(self->wand, PyFloat_AsDouble(val)); - - return 0; -} - -// }}} - -// DrawingWand.stroke_color {{{ -static PyObject * -magick_DrawingWand_stroke_color_getter(magick_DrawingWand *self, void *closure) { - magick_PixelWand *pw; - PixelWand *wand; - - NULL_CHECK(NULL) - wand = NewPixelWand(); - - if (wand == NULL) return PyErr_NoMemory(); - DrawGetStrokeColor(self->wand, wand); - - pw = (magick_PixelWand*) magick_PixelWandType.tp_alloc(&magick_PixelWandType, 0); - if (pw == NULL) return PyErr_NoMemory(); - pw->wand = wand; - return Py_BuildValue("O", (PyObject *)pw); -} - -static int -magick_DrawingWand_stroke_color_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - magick_PixelWand *pw; - - NULL_CHECK(-1) - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand stroke color"); - return -1; - } - - - pw = (magick_PixelWand*)val; - if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return -1; } - - DrawSetStrokeColor(self->wand, pw->wand); - - return 0; -} - -// }}} - -// DrawingWand.fill_color {{{ -static PyObject * -magick_DrawingWand_fill_color_getter(magick_DrawingWand *self, void *closure) { - magick_PixelWand *pw; - PixelWand *wand; - - NULL_CHECK(NULL) - wand = NewPixelWand(); - - if (wand == NULL) return PyErr_NoMemory(); - DrawGetFillColor(self->wand, wand); - - pw = (magick_PixelWand*) magick_PixelWandType.tp_alloc(&magick_PixelWandType, 0); - if (pw == NULL) return PyErr_NoMemory(); - pw->wand = wand; - return Py_BuildValue("O", (PyObject *)pw); -} - -static int -magick_DrawingWand_fill_color_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - magick_PixelWand *pw; - - NULL_CHECK(-1) - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fill color"); - return -1; - } - - - pw = (magick_PixelWand*)val; - if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return -1; } - - DrawSetFillColor(self->wand, pw->wand); - - return 0; -} - -// }}} - -// DrawingWand.text_antialias {{{ -static PyObject * -magick_DrawingWand_textantialias_getter(magick_DrawingWand *self, void *closure) { - NULL_CHECK(NULL); - if (DrawGetTextAntialias(self->wand)) Py_RETURN_TRUE; - Py_RETURN_FALSE; -} - -static int -magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - NULL_CHECK(-1); - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand textantialias"); - return -1; - } - DrawSetTextAntialias(self->wand, (MagickBooleanType)PyObject_IsTrue(val)); - - return 0; -} - -// }}} - -// DrawingWand.gravity {{{ -static PyObject * -magick_DrawingWand_gravity_getter(magick_DrawingWand *self, void *closure) { - NULL_CHECK(NULL); - return Py_BuildValue("n", DrawGetGravity(self->wand)); -} - -static int -magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void *closure) { - int grav; - - NULL_CHECK(-1); - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand gravity"); - return -1; - } - - if (!PyInt_Check(val)) { - PyErr_SetString(PyExc_TypeError, "Gravity must be an integer"); - return -1; - } - - grav = (int)PyInt_AS_LONG(val); - - DrawSetGravity(self->wand, grav); - - return 0; -} - -// }}} - -// DrawingWand attr list {{{ -static PyMethodDef magick_DrawingWand_methods[] = { - {"destroy", (PyCFunction)magick_DrawingWand_destroy, METH_VARARGS, - "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, - - {NULL} /* Sentinel */ -}; - -static PyGetSetDef magick_DrawingWand_getsetters[] = { - {(char *)"font_", - (getter)magick_DrawingWand_font_getter, (setter)magick_DrawingWand_font_setter, - (char *)"DrawingWand font path. Absolute path to font file.", - NULL}, - - {(char *)"font_size_", - (getter)magick_DrawingWand_fontsize_getter, (setter)magick_DrawingWand_fontsize_setter, - (char *)"DrawingWand fontsize", - NULL}, - - {(char *)"stroke_color_", - (getter)magick_DrawingWand_stroke_color_getter, (setter)magick_DrawingWand_stroke_color_setter, - (char *)"DrawingWand stroke color", - NULL}, - - {(char *)"fill_color_", - (getter)magick_DrawingWand_fill_color_getter, (setter)magick_DrawingWand_fill_color_setter, - (char *)"DrawingWand fill color", - NULL}, - - {(char *)"text_antialias", - (getter)magick_DrawingWand_textantialias_getter, (setter)magick_DrawingWand_textantialias_setter, - (char *)"DrawingWand text antialias", - NULL}, - - {(char *)"gravity_", - (getter)magick_DrawingWand_gravity_getter, (setter)magick_DrawingWand_gravity_setter, - (char *)"DrawingWand gravity", - NULL}, - - {NULL} /* Sentinel */ -}; - -// }}} - -static PyTypeObject magick_DrawingWandType = { // {{{ - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "magick.DrawingWand", /*tp_name*/ - sizeof(magick_DrawingWand), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)magick_DrawingWand_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "DrawingWand", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - magick_DrawingWand_methods, /* tp_methods */ - 0, /* tp_members */ - magick_DrawingWand_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - magick_DrawingWand_new, /* tp_new */ -}; // }}} - - -// }}} - -// Image object definition {{{ -typedef struct { - PyObject_HEAD - // Type-specific fields go here. - MagickWand *wand; - -} magick_Image; - -// Method declarations {{{ -static PyObject* magick_Image_compose(magick_Image *self, PyObject *args); -static PyObject* magick_Image_compare(magick_Image *self, PyObject *args); -static PyObject* magick_Image_copy(magick_Image *self, PyObject *args); -static PyObject* magick_Image_texture(magick_Image *self, PyObject *args); -// }}} - -static void -magick_Image_dealloc(magick_Image* self) -{ - if (self->wand != NULL) self->wand = DestroyMagickWand(self->wand); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -magick_Image_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - magick_Image *self; - - self = (magick_Image *)type->tp_alloc(type, 0); - if (self != NULL) { - self->wand = NewMagickWand(); - if (self->wand == NULL || self->wand < 0) { - PyErr_SetString(PyExc_Exception, "Failed to allocate wand."); - self->wand = NULL; - Py_DECREF(self); - return NULL; - } - } - - return (PyObject *)self; -} - -// Image.constitute {{{ -static PyObject * -magick_Image_constitute(magick_Image *self, PyObject *args) { - const char *map = NULL; - unsigned int width = 0, height = 0; - PyObject *capsule = NULL; - MagickBooleanType res = MagickFalse; - void *data = NULL; - - NULL_CHECK(NULL) - if (!PyArg_ParseTuple(args, "IIsO", &width, &height, &map, &capsule)) return NULL; - - if (!PyCapsule_CheckExact(capsule)) { - PyErr_SetString(PyExc_TypeError, "data is not a capsule object"); - return NULL; - } - - data = PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule)); - if (data == NULL) return NULL; - - res = MagickConstituteImage(self->wand, (size_t)width, (size_t)height, map, CharPixel, data); - - if (!res) - return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} - -// }}} - -// Image.load {{{ -static PyObject * -magick_Image_load(magick_Image *self, PyObject *args) { - const char *data; - Py_ssize_t dlen; - MagickBooleanType res; - - NULL_CHECK(NULL) - if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL; - - res = MagickReadImageBlob(self->wand, data, dlen); - - if (!res) - return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} - -// }}} - -// Image.identify {{{ -static PyObject * -magick_Image_identify(magick_Image *self, PyObject *args) { - const char *data; - Py_ssize_t dlen; - MagickBooleanType res; - - NULL_CHECK(NULL) - if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL; - - res = MagickPingImageBlob(self->wand, data, dlen); - - if (!res) - return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} - -// }}} - -// Image.open {{{ -static PyObject * -magick_Image_read(magick_Image *self, PyObject *args) { - const char *data; - MagickBooleanType res; - - NULL_CHECK(NULL) - if (!PyArg_ParseTuple(args, "s", &data)) return NULL; - - res = MagickReadImage(self->wand, data); - - if (!res) - return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} - -// }}} - -// Image.create_canvas {{{ -static PyObject * -magick_Image_create_canvas(magick_Image *self, PyObject *args) -{ - Py_ssize_t width, height; - char *bgcolor; - PixelWand *pw; - MagickBooleanType res = MagickFalse; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "nns", &width, &height, &bgcolor)) return NULL; - - pw = NewPixelWand(); - if (pw == NULL) return PyErr_NoMemory(); - PixelSetColor(pw, bgcolor); - res = MagickNewImage(self->wand, width, height, pw); - pw = DestroyPixelWand(pw); - if (!res) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.font_metrics {{{ - -static PyObject * -magick_Image_font_metrics(magick_Image *self, PyObject *args) { - char *text; - PyObject *dw_, *ans, *m; - Py_ssize_t i; - DrawingWand *dw; - double *metrics; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!s", &magick_DrawingWandType, &dw_, &text)) return NULL; - dw = ((magick_DrawingWand*)dw_)->wand; - if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; } - ans = PyTuple_New(13); - if (ans == NULL) return PyErr_NoMemory(); - - metrics = MagickQueryFontMetrics(self->wand, dw, text); - - for (i = 0; i < 13; i++) { - m = PyFloat_FromDouble(metrics[i]); - if (m == NULL) { return PyErr_NoMemory(); } - PyTuple_SET_ITEM(ans, i, m); - } - - return ans; -} -// }}} - -// Image.annotate {{{ - -static PyObject * -magick_Image_annotate(magick_Image *self, PyObject *args) { - char *text; - PyObject *dw_; - DrawingWand *dw; - double x, y, angle; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!ddds", &magick_DrawingWandType, &dw_, &x, &y, &angle, &text)) return NULL; - dw = ((magick_DrawingWand*)dw_)->wand; - if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; } - - if (!MagickAnnotateImage(self->wand, dw, x, y, angle, text)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.export {{{ - -static PyObject * -magick_Image_export(magick_Image *self, PyObject *args) { - char *fmt; - unsigned char *data; - PyObject *ans; - size_t len = 0; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "s", &fmt)) return NULL; - - if (!MagickSetFormat(self->wand, fmt)) { - PyErr_SetString(PyExc_ValueError, "Unknown image format"); - return NULL; - } - - data = MagickGetImageBlob(self->wand, &len); - - if (data == NULL || len < 1) - return magick_set_exception(self->wand); - - ans = Py_BuildValue("s#", data, len); - data = MagickRelinquishMemory(data); - - return ans; -} -// }}} - -// Image.size {{{ -static PyObject * -magick_Image_size_getter(magick_Image *self, void *closure) { - size_t width, height; - NULL_CHECK(NULL) - - width = MagickGetImageWidth(self->wand); - height = MagickGetImageHeight(self->wand); - return Py_BuildValue("nn", width, height); -} - -static int -magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) { - Py_ssize_t width, height; - int filter; - double blur; - MagickBooleanType res; - - NULL_CHECK(-1) - - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete image size"); - return -1; - } - - if (!PySequence_Check(val) || PySequence_Length(val) < 4) { - PyErr_SetString(PyExc_TypeError, "Must use at least a 4 element sequence to set size"); - return -1; - } - - if (!PyInt_Check(PySequence_ITEM(val, 2))) { - PyErr_SetString(PyExc_TypeError, "Filter must be an integer"); - return -1; - } - - - width = PyInt_AsSsize_t(PySequence_ITEM(val, 0)); - height = PyInt_AsSsize_t(PySequence_ITEM(val, 1)); - filter = (int)PyInt_AS_LONG(PySequence_ITEM(val, 2)); - blur = PyFloat_AsDouble(PySequence_ITEM(val, 3)); - - if (PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Width, height, filter or blur not a number"); - return -1; - } - - if ( filter <= UndefinedFilter || filter >= SentinelFilter) { - PyErr_SetString(PyExc_ValueError, "Invalid filter"); - return -1; - } - - res = MagickResizeImage(self->wand, width, height, filter, blur); - - if (!res) { - magick_set_exception(self->wand); - return -1; - } - - return 0; - -} -// }}} - -// Image.format {{{ -static PyObject * -magick_Image_format_getter(magick_Image *self, void *closure) { - const char *fmt; - NULL_CHECK(NULL) - - fmt = MagickGetImageFormat(self->wand); - return Py_BuildValue("s", fmt); -} - -static int -magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) { - char *fmt; - NULL_CHECK(-1) - - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete image format"); - return -1; - } - - fmt = PyString_AsString(val); - if (fmt == NULL) return -1; - - if (!MagickSetImageFormat(self->wand, fmt)) { - PyErr_SetString(PyExc_ValueError, "Unknown image format"); - return -1; - } - - return 0; -} - -// }}} - -// Image.distort {{{ - -static PyObject * -magick_Image_distort(magick_Image *self, PyObject *args) { - int method; - Py_ssize_t i, number; - PyObject *bestfit, *argv, *t; - MagickBooleanType res; - double *arguments = NULL; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "iOO", &method, &argv, &bestfit)) return NULL; - - if (!PySequence_Check(argv)) { PyErr_SetString(PyExc_TypeError, "arguments must be a sequence"); return NULL; } - - number = PySequence_Length(argv); - if (number > 0) { - arguments = (double *)PyMem_Malloc(sizeof(double) * number); - if (arguments == NULL) return PyErr_NoMemory(); - for (i = 0; i < number; i++) { - t = PySequence_ITEM(argv, i); - if (t == NULL || !PyFloat_Check(t)) { PyErr_SetString(PyExc_TypeError, "Arguments must all be floats"); PyMem_Free(arguments); return NULL; } - arguments[i] = PyFloat_AsDouble(t); - } - } - - res = MagickDistortImage(self->wand, method, number, arguments, PyObject_IsTrue(bestfit)); - if (arguments != NULL) PyMem_Free(arguments); - - if (!res) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.trim {{{ - -static PyObject * -magick_Image_trim(magick_Image *self, PyObject *args) { - double fuzz; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL; - - if (!MagickTrimImage(self->wand, fuzz)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.remove_border {{{ - -static size_t -magick_find_border(PixelIterator *pi, double fuzz, size_t img_width, double *reds, PixelWand** (*next)(PixelIterator*, size_t*)) { - size_t band = 0, width = 0, c = 0; - double *greens = NULL, *blues = NULL, red_average, green_average, blue_average, distance, first_row[3] = {0.0, 0.0, 0.0}; - PixelWand **pixels = NULL; - - greens = reds + img_width + 1; blues = greens + img_width + 1; - - while ( (pixels = next(pi, &width)) != NULL ) { - red_average = 0; green_average = 0; blue_average = 0; - for (c = 0; c < width; c++) { - reds[c] = PixelGetRed(pixels[c]); greens[c] = PixelGetGreen(pixels[c]); blues[c] = PixelGetBlue(pixels[c]); - /* PixelGetHSL(pixels[c], reds + c, greens + c, blues + c); */ - red_average += reds[c]; green_average += greens[c]; blue_average += blues[c]; - } - red_average /= MAX(1, width); green_average /= MAX(1, width); blue_average /= MAX(1, width); - distance = 0; - for (c = 0; c < width && distance < fuzz; c++) - distance = MAX(distance, SQUARE((reds[c] - red_average)) + SQUARE((greens[c] - green_average)) + SQUARE((blues[c] - blue_average))); - if (distance > fuzz) break; // row is not homogeneous - if (band == 0) {first_row[0] = red_average; first_row[1] = blue_average; first_row[2] = green_average; } - else { - distance = SQUARE((first_row[0] - red_average)) + SQUARE((first_row[1] - green_average)) + SQUARE((first_row[2] - blue_average)); - if (distance > fuzz) break; // this row's average color is far from the previous rows average color - } - band += 1; - } - return band; -} - -static PyObject * -magick_Image_remove_border(magick_Image *self, PyObject *args) { - double fuzz, *buf = NULL; - PixelIterator *pi = NULL; - size_t width, height, iwidth, iheight; - size_t top_band = 0, bottom_band = 0, left_band = 0, right_band = 0; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL; - fuzz /= 255; - - height = iwidth = MagickGetImageHeight(self->wand); - width = iheight = MagickGetImageWidth(self->wand); - buf = PyMem_New(double, 3*(MAX(width, height)+1)); - pi = NewPixelIterator(self->wand); - if (buf == NULL || pi == NULL) { PyErr_NoMemory(); goto end; } - top_band = magick_find_border(pi, fuzz, width, buf, &PixelGetNextIteratorRow); - if (top_band >= height) goto end; - PixelSetLastIteratorRow(pi); - bottom_band = magick_find_border(pi, fuzz, width, buf, &PixelGetPreviousIteratorRow); - if (bottom_band >= height) goto end; - if (!MagickTransposeImage(self->wand)) { magick_set_exception(self->wand); goto end; } - pi = DestroyPixelIterator(pi); - pi = NewPixelIterator(self->wand); - if (pi == NULL) { PyErr_NoMemory(); goto end; } - left_band = magick_find_border(pi, fuzz, iwidth, buf, &PixelGetNextIteratorRow); - if (left_band >= iheight) goto end; - PixelSetLastIteratorRow(pi); - right_band = magick_find_border(pi, fuzz, iwidth, buf, &PixelGetPreviousIteratorRow); - if (right_band >= iheight) goto end; - if (!MagickTransposeImage(self->wand)) { magick_set_exception(self->wand); goto end; } - if (!MagickCropImage(self->wand, width - left_band - right_band, height - top_band - bottom_band, left_band, top_band)) { magick_set_exception(self->wand); goto end; } -end: - if (pi != NULL) pi = DestroyPixelIterator(pi); - if (buf != NULL) PyMem_Free(buf); - if (PyErr_Occurred() != NULL) return NULL; - - return Py_BuildValue("kkkk", left_band, top_band, right_band, bottom_band); -} -// }}} - -// Image.thumbnail {{{ - -static PyObject * -magick_Image_thumbnail(magick_Image *self, PyObject *args) { - Py_ssize_t width, height; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "nn", &width, &height)) return NULL; - - if (!MagickThumbnailImage(self->wand, width, height)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.crop {{{ - -static PyObject * -magick_Image_crop(magick_Image *self, PyObject *args) { - Py_ssize_t width, height, x, y; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return NULL; - - if (!MagickCropImage(self->wand, width, height, x, y)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.set_border_color {{{ - -static PyObject * -magick_Image_set_border_color(magick_Image *self, PyObject *args) { - PyObject *obj; - magick_PixelWand *pw; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!", &magick_PixelWandType, &obj)) return NULL; - pw = (magick_PixelWand*)obj; - if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } - - if (!MagickSetImageBorderColor(self->wand, pw->wand)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.rotate {{{ - -static PyObject * -magick_Image_rotate(magick_Image *self, PyObject *args) { - PyObject *obj; - magick_PixelWand *pw; - double degrees; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!d", &magick_PixelWandType, &obj, °rees)) return NULL; - pw = (magick_PixelWand*)obj; - if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } - - if (!MagickRotateImage(self->wand, pw->wand, degrees)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.flip {{{ - -static PyObject * -magick_Image_flip(magick_Image *self, PyObject *args) { - PyObject *obj = NULL; - MagickBooleanType ret = 0; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "|O", &obj)) return NULL; - ret = (obj != NULL && PyObject_IsTrue(obj)) ? MagickFlopImage(self->wand) : MagickFlipImage(self->wand); - if (!ret) { PyErr_SetString(PyExc_ValueError, "Failed to flip image"); return NULL; } - - Py_RETURN_NONE; -} -// }}} - -// Image.set_page {{{ - -static PyObject * -magick_Image_set_page(magick_Image *self, PyObject *args) { - Py_ssize_t width, height, x, y; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return NULL; - - if (!MagickSetImagePage(self->wand, width, height, x, y)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.set_compression_quality {{{ - -static PyObject * -magick_Image_set_compression_quality(magick_Image *self, PyObject *args) { - Py_ssize_t quality; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "n", &quality)) return NULL; - - if (!MagickSetImageCompressionQuality(self->wand, quality)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.has_transparent_pixels {{{ - -static PyObject * -magick_Image_has_transparent_pixels(magick_Image *self, PyObject *args) { - PixelIterator *pi = NULL; - PixelWand **pixels = NULL; - int found = 0; - size_t r, c, width, height; - double alpha; - - NULL_CHECK(NULL) - - height = MagickGetImageHeight(self->wand); - pi = NewPixelIterator(self->wand); - - for (r = 0; r < height; r++) { - pixels = PixelGetNextIteratorRow(pi, &width); - for (c = 0; c < width; c++) { - alpha = PixelGetAlpha(pixels[c]); - if (alpha < 1.00) { - found = 1; - c = width; r = height; - } - } - } - pi = DestroyPixelIterator(pi); - if (found) Py_RETURN_TRUE; - Py_RETURN_FALSE; -} -// }}} - -// Image.normalize {{{ - -static PyObject * -magick_Image_normalize(magick_Image *self, PyObject *args) { - NULL_CHECK(NULL) - - if (!MagickNormalizeImage(self->wand)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.add_border {{{ - -static PyObject * -magick_Image_add_border(magick_Image *self, PyObject *args) { - Py_ssize_t dx, dy; - PyObject *obj; - magick_PixelWand *pw; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!nn", &magick_PixelWandType, &obj, &dx, &dy)) return NULL; - pw = (magick_PixelWand*)obj; - if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } - - if (!MagickBorderImage(self->wand, pw->wand, dx, dy)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.sharpen {{{ - -static PyObject * -magick_Image_sharpen(magick_Image *self, PyObject *args) { - double radius, sigma; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "dd", &radius, &sigma)) return NULL; - - if (!MagickSharpenImage(self->wand, radius, sigma)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.blur {{{ - -static PyObject * -magick_Image_blur(magick_Image *self, PyObject *args) { - double radius, sigma; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "dd", &radius, &sigma)) return NULL; - - if (!MagickBlurImage(self->wand, radius, sigma)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.quantize {{{ - -static PyObject * -magick_Image_quantize(magick_Image *self, PyObject *args) { - Py_ssize_t number_colors, treedepth; - int colorspace; - PyObject *dither, *measure_error; - - NULL_CHECK(NULL) - - - if (!PyArg_ParseTuple(args, "ninOO", &number_colors, &colorspace, &treedepth, &dither, &measure_error)) return NULL; - - if (!MagickQuantizeImage(self->wand, number_colors, colorspace, treedepth, PyObject_IsTrue(dither), PyObject_IsTrue(measure_error))) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.despeckle {{{ - -static PyObject * -magick_Image_despeckle(magick_Image *self, PyObject *args) { - NULL_CHECK(NULL) - - if (!MagickDespeckleImage(self->wand)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.type {{{ -static PyObject * -magick_Image_type_getter(magick_Image *self, void *closure) { - NULL_CHECK(NULL) - - return Py_BuildValue("n", MagickGetImageType(self->wand)); -} - -static int -magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) { - int type; - - NULL_CHECK(-1) - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete image type"); - return -1; - } - - if (!PyInt_Check(val)) { - PyErr_SetString(PyExc_TypeError, "Type must be an integer"); - return -1; - } - - type = (int)PyInt_AS_LONG(val); - if (!MagickSetImageType(self->wand, type)) { - PyErr_SetString(PyExc_ValueError, "Unknown image type"); - return -1; - } - - return 0; -} - -// }}} - -// Image.depth {{{ -static PyObject * -magick_Image_depth_getter(magick_Image *self, void *closure) { - NULL_CHECK(NULL) - - return Py_BuildValue("n", MagickGetImageDepth(self->wand)); -} - -static int -magick_Image_depth_setter(magick_Image *self, PyObject *val, void *closure) { - size_t depth; - - NULL_CHECK(-1) - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete image depth"); - return -1; - } - - if (!PyInt_Check(val)) { - PyErr_SetString(PyExc_TypeError, "Depth must be an integer"); - return -1; - } - - depth = (size_t)PyInt_AsSsize_t(val); - if (!MagickSetImageDepth(self->wand, depth)) { - PyErr_Format(PyExc_ValueError, "Could not set image depth to %lu", depth); - return -1; - } - - return 0; -} - -// }}} - -// Image.destroy {{{ - -static PyObject * -magick_Image_destroy(magick_Image *self, PyObject *args) { - NULL_CHECK(NULL) - self->wand = DestroyMagickWand(self->wand); - Py_RETURN_NONE; -} -// }}} - -// Image.set_opacity {{{ - -static PyObject * -magick_Image_set_opacity(magick_Image *self, PyObject *args) { - double opacity; - NULL_CHECK(NULL) - - - if (!PyArg_ParseTuple(args, "d", &opacity)) return NULL; - - if (!MagickSetImageOpacity(self->wand, opacity)) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.colorspace {{{ -static PyObject * -magick_Image_colorspace_getter(magick_Image *self, void *closure) { - NULL_CHECK(NULL) - - return Py_BuildValue("i", MagickGetImageColorspace(self->wand)); -} - -static int -magick_Image_colorspace_setter(magick_Image *self, PyObject *val, void *closure) { - int cs = RGBColorspace; - - NULL_CHECK(-1) - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete image colorspace"); - return -1; - } - - if (!PyInt_Check(val)) { - PyErr_SetString(PyExc_TypeError, "Colorspace must be an integer"); - return -1; - } - - cs = (int)PyInt_AS_LONG(val); - if (!MagickSetImageColorspace(self->wand, cs)) { - PyErr_Format(PyExc_ValueError, "Could not set image colorspace to %d", cs); - return -1; - } - - return 0; -} - -// }}} - -// Image attr list {{{ -static PyMethodDef magick_Image_methods[] = { - {"destroy", (PyCFunction)magick_Image_destroy, METH_VARARGS, - "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, - - {"identify", (PyCFunction)magick_Image_identify, METH_VARARGS, - "Identify an image from a byte buffer (string)" - }, - - {"constitute", (PyCFunction)magick_Image_constitute, METH_VARARGS, - "constitute(width, height, map, data) -> Create an image from raw (A)RGB data. map should be 'ARGB' or 'PRGB' or whatever is needed for data. data must be a PyCapsule object." - }, - - {"load", (PyCFunction)magick_Image_load, METH_VARARGS, - "Load an image from a byte buffer (string)" - }, - - {"read", (PyCFunction)magick_Image_read, METH_VARARGS, - "Read image from path. Path must be a bytestring in the filesystem encoding" - }, - - {"export", (PyCFunction)magick_Image_export, METH_VARARGS, - "export(format) -> bytestring\n\n Export the image as the specified format" - }, - - {"create_canvas", (PyCFunction)magick_Image_create_canvas, METH_VARARGS, - "create_canvas(width, height, bgcolor)\n\n" - "Create a blank canvas\n" - "bgcolor should be an ImageMagick color specification (string)" - }, - - {"compose", (PyCFunction)magick_Image_compose, METH_VARARGS, - "compose(img, left, top, op) \n\n Compose img using operation op at (left, top)" - }, - - {"compare", (PyCFunction)magick_Image_compare, METH_VARARGS, - "compose(img, metric) \n\n Compare images using the specified metric. (One of AbsoluteErrorMetric, MeanAbsoluteErrorMetric, MeanErrorPerPixelMetric, MeanSquaredErrorMetric, PeakAbsoluteErrorMetric, PeakSignalToNoiseRatioMetric, RootMeanSquaredErrorMetric, NormalizedCrossCorrelationErrorMetric, FuzzErrorMetric)" - }, - - {"texture", (PyCFunction)magick_Image_texture, METH_VARARGS, - "texture(img)) \n\n Repeatedly tile img across and down the canvas." - }, - - {"set_opacity", (PyCFunction)magick_Image_set_opacity, METH_VARARGS, - "set_opacity(opacity)) \n\n Set the opacity of this image (between 0.0 - transparent and 1.0 - opaque)" - }, - - {"copy", (PyCFunction)magick_Image_copy, METH_VARARGS, - "copy(img) \n\n Copy img to self." - }, - - {"font_metrics", (PyCFunction)magick_Image_font_metrics, METH_VARARGS, - "font_metrics(drawing_wand, text) \n\n Return font metrics for specified drawing wand and text." - }, - - {"annotate", (PyCFunction)magick_Image_annotate, METH_VARARGS, - "annotate(drawing_wand, x, y, angle, text) \n\n Annotate image with text." - }, - - {"distort", (PyCFunction)magick_Image_distort, METH_VARARGS, - "distort(method, arguments, best_fit) \n\n Distort image." - }, - - {"trim", (PyCFunction)magick_Image_trim, METH_VARARGS, - "trim(fuzz) \n\n Trim image." - }, - - {"remove_border", (PyCFunction)magick_Image_remove_border, METH_VARARGS, - "remove_border(fuzz) \n\n Try to detect and remove borders from the image, better than the ImageMagick trim() method. Detects rows of the same color at each image edge. Where color similarity testing is based on the fuzz factor (a number between 0 and 255). Returns the number of columns/rows removed from the left, top, right and bottom edges of the image." - }, - - {"crop", (PyCFunction)magick_Image_crop, METH_VARARGS, - "crop(width, height, x, y) \n\n Crop image." - }, - - {"set_page", (PyCFunction)magick_Image_set_page, METH_VARARGS, - "set_page(width, height, x, y) \n\n Sets the page geometry of the image." - }, - - {"set_compression_quality", (PyCFunction)magick_Image_set_compression_quality, METH_VARARGS, - "set_compression_quality(quality) \n\n Sets the compression quality when exporting the image." - }, - - {"has_transparent_pixels", (PyCFunction)magick_Image_has_transparent_pixels, METH_VARARGS, - "has_transparent_pixels() \n\n Returns True iff image has a (semi-) transparent pixel" - }, - - {"thumbnail", (PyCFunction)magick_Image_thumbnail, METH_VARARGS, - "thumbnail(width, height) \n\n Convert to a thumbnail of specified size." - }, - - {"set_border_color", (PyCFunction)magick_Image_set_border_color, METH_VARARGS, - "set_border_color(pixel_wand) \n\n Set border color to the specified PixelWand." - }, - - {"rotate", (PyCFunction)magick_Image_rotate, METH_VARARGS, - "rotate(background_pixel_wand, degrees) \n\n Rotate image by specified degrees." - }, - {"flip", (PyCFunction)magick_Image_flip, METH_VARARGS, - "flip(horizontal=False) \n\n Flip image about a vertical axis. If horizontal is True, flip about horizontal axis instead." - }, - - - {"normalize", (PyCFunction)magick_Image_normalize, METH_VARARGS, - "normalize() \n\n enhances the contrast of a color image by adjusting the pixels color to span the entire range of colors available." - }, - - {"add_border", (PyCFunction)magick_Image_add_border, METH_VARARGS, - "add_border(pixel_wand, width, height) \n\n surrounds the image with a border of the color defined by the bordercolor pixel wand." - }, - - {"sharpen", (PyCFunction)magick_Image_sharpen, METH_VARARGS, - "sharpen(radius, sigma) \n\n sharpens an image. We convolve the image with a Gaussian operator of the given radius and standard deviation (sigma). For reasonable results, the radius should be larger than sigma. Use a radius of 0 and MagickSharpenImage() selects a suitable radius for you." - }, - - {"blur", (PyCFunction)magick_Image_blur, METH_VARARGS, - "blur(radius, sigma) \n\n blurs an image. We convolve the image with a Gaussian operator of the given radius and standard deviation (sigma). For reasonable results, the radius should be larger than sigma. Use a radius of 0 and MagickBlurImage() selects a suitable radius for you." - }, - - {"despeckle", (PyCFunction)magick_Image_despeckle, METH_VARARGS, - "despeckle() \n\n reduces the speckle noise in an image while preserving the edges of the original image." - }, - - {"quantize", (PyCFunction)magick_Image_quantize, METH_VARARGS, - "quantize(number_colors, colorspace, treedepth, dither, measure_error) \n\n analyzes the colors within a reference image and chooses a fixed number of colors to represent the image. The goal of the algorithm is to minimize the color difference between the input and output image while minimizing the processing time." - }, - - {NULL} /* Sentinel */ -}; - -static PyGetSetDef magick_Image_getsetters[] = { - {(char *)"size_", - (getter)magick_Image_size_getter, (setter)magick_Image_size_setter, - (char *)"Image size (width, height). When setting pass in (width, height, filter, blur). See MagickResizeImage docs.", - NULL}, - - {(char *)"format_", - (getter)magick_Image_format_getter, (setter)magick_Image_format_setter, - (char *)"Image format", - NULL}, - - {(char *)"type_", - (getter)magick_Image_type_getter, (setter)magick_Image_type_setter, - (char *)"the image type: UndefinedType, BilevelType, GrayscaleType, GrayscaleMatteType, PaletteType, PaletteMatteType, TrueColorType, TrueColorMatteType, ColorSeparationType, ColorSeparationMatteType, or OptimizeType.", - NULL}, - - {(char *)"depth", - (getter)magick_Image_depth_getter, (setter)magick_Image_depth_setter, - (char *)"the image depth.", - NULL}, - - {(char *)"colorspace_", - (getter)magick_Image_colorspace_getter, (setter)magick_Image_colorspace_setter, - (char *)"the image colorspace.", - NULL}, - - {NULL} /* Sentinel */ -}; - -// }}} - - -static PyTypeObject magick_ImageType = { // {{{ - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "magick.Image", /*tp_name*/ - sizeof(magick_Image), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)magick_Image_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "Images", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - magick_Image_methods, /* tp_methods */ - 0, /* tp_members */ - magick_Image_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - magick_Image_new, /* tp_new */ -}; // }}} - -// Image.compose {{{ -static PyObject * -magick_Image_compose(magick_Image *self, PyObject *args) -{ - PyObject *img, *op_; - ssize_t left, top; - CompositeOperator op; - magick_Image *src; - MagickBooleanType res = MagickFalse; - - NULL_CHECK(NULL) - - - if (!PyArg_ParseTuple(args, "O!nnO", &magick_ImageType, &img, &left, &top, &op_)) return NULL; - src = (magick_Image*)img; - if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} - - op = (CompositeOperator)PyInt_AsSsize_t(op_); - if (PyErr_Occurred() || op <= UndefinedCompositeOp) { - PyErr_SetString(PyExc_TypeError, "Invalid composite operator"); - return NULL; - } - - res = MagickCompositeImage(self->wand, src->wand, op, left, top); - - if (!res) return magick_set_exception(self->wand); - - Py_RETURN_NONE; -} -// }}} - -// Image.compare {{{ -static PyObject * -magick_Image_compare(magick_Image *self, PyObject *args) -{ - PyObject *img; - MetricType metric; - magick_Image *src; - double distortion = 0; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!i", &magick_ImageType, &img, &metric)) return NULL; - src = (magick_Image*)img; - if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} - - MagickCompareImages(self->wand, src->wand, metric, &distortion); - return Py_BuildValue("d", distortion); -} -// }}} - -// Image.clone {{{ -static PyObject * -magick_Image_copy(magick_Image *self, PyObject *args) -{ - PyObject *img; - magick_Image *src; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!", &magick_ImageType, &img)) return NULL; - src = (magick_Image*)img; - if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} - self->wand = DestroyMagickWand(self->wand); - self->wand = CloneMagickWand(src->wand); - if (self->wand == NULL) { return PyErr_NoMemory(); } - - Py_RETURN_NONE; -} -// }}} - -// Image.texture {{{ -static PyObject * -magick_Image_texture(magick_Image *self, PyObject *args) { - PyObject *img; - magick_Image *texture; - - NULL_CHECK(NULL) - - if (!PyArg_ParseTuple(args, "O!", &magick_ImageType, &img)) return NULL; - texture = (magick_Image*)img; - if (!IsMagickWand(texture->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} - - self->wand = MagickTextureImage(self->wand, texture->wand); - - Py_RETURN_NONE; -} - -// }}} - -// Module functions {{{ - -static PyObject * -magick_genesis(PyObject *self, PyObject *args) -{ - MagickWandGenesis(); - Py_RETURN_NONE; -} - -static PyObject * -magick_terminus(PyObject *self, PyObject *args) -{ - MagickWandTerminus(); - Py_RETURN_NONE; -} - - -static PyMethodDef magick_methods[] = { - {"genesis", magick_genesis, METH_VARARGS, - "genesis()\n\n" - "Initializes ImageMagick.\n" - "Must be called before any other use of this module is made. " - }, - - {"terminus", magick_terminus, METH_VARARGS, - "terminus()\n\n" - "Cleans up ImageMagick memory structures.\n" - "Must be called after you are done using this module. You can call genesis() again after this to resume using the module." - }, - - - {NULL} /* Sentinel */ -}; -// }}} - -// }}} - -// Module initialization {{{ -PyMODINIT_FUNC -initmagick(void) -{ - PyObject* m; - - if (PyType_Ready(&magick_ImageType) < 0) - return; - if (PyType_Ready(&magick_DrawingWandType) < 0) - return; - if (PyType_Ready(&magick_PixelWandType) < 0) - return; - - m = Py_InitModule3("magick", magick_methods, - "Wrapper for the ImageMagick imaging library"); - - Py_INCREF(&magick_ImageType); - PyModule_AddObject(m, "Image", (PyObject *)&magick_ImageType); - Py_INCREF(&magick_DrawingWandType); - PyModule_AddObject(m, "DrawingWand", (PyObject *)&magick_DrawingWandType); - Py_INCREF(&magick_PixelWandType); - PyModule_AddObject(m, "PixelWand", (PyObject *)&magick_PixelWandType); - - magick_add_module_constants(m); - MagickWandGenesis(); -} -// }}} - diff --git a/src/calibre/utils/magick/magick_constants.h b/src/calibre/utils/magick/magick_constants.h deleted file mode 100644 index 95c41def92..0000000000 --- a/src/calibre/utils/magick/magick_constants.h +++ /dev/null @@ -1,344 +0,0 @@ -// Generated by generate.py - -static void magick_add_module_constants(PyObject *m) { - PyModule_AddIntConstant(m, "UndefinedFilter", 0); - PyModule_AddIntConstant(m, "PointFilter", 1); - PyModule_AddIntConstant(m, "BoxFilter", 2); - PyModule_AddIntConstant(m, "TriangleFilter", 3); - PyModule_AddIntConstant(m, "HermiteFilter", 4); - PyModule_AddIntConstant(m, "HanningFilter", 5); - PyModule_AddIntConstant(m, "HammingFilter", 6); - PyModule_AddIntConstant(m, "BlackmanFilter", 7); - PyModule_AddIntConstant(m, "GaussianFilter", 8); - PyModule_AddIntConstant(m, "QuadraticFilter", 9); - PyModule_AddIntConstant(m, "CubicFilter", 10); - PyModule_AddIntConstant(m, "CatromFilter", 11); - PyModule_AddIntConstant(m, "MitchellFilter", 12); - PyModule_AddIntConstant(m, "JincFilter", 13); - PyModule_AddIntConstant(m, "SincFilter", 14); - PyModule_AddIntConstant(m, "SincFastFilter", 15); - PyModule_AddIntConstant(m, "KaiserFilter", 16); - PyModule_AddIntConstant(m, "WelshFilter", 17); - PyModule_AddIntConstant(m, "ParzenFilter", 18); - PyModule_AddIntConstant(m, "BohmanFilter", 19); - PyModule_AddIntConstant(m, "BartlettFilter", 20); - PyModule_AddIntConstant(m, "LagrangeFilter", 21); - PyModule_AddIntConstant(m, "LanczosFilter", 22); - PyModule_AddIntConstant(m, "LanczosSharpFilter", 23); - PyModule_AddIntConstant(m, "Lanczos2Filter", 24); - PyModule_AddIntConstant(m, "Lanczos2SharpFilter", 25); - PyModule_AddIntConstant(m, "RobidouxFilter", 26); - PyModule_AddIntConstant(m, "RobidouxSharpFilter", 27); - PyModule_AddIntConstant(m, "CosineFilter", 28); - PyModule_AddIntConstant(m, "SplineFilter", 29); - PyModule_AddIntConstant(m, "LanczosRadiusFilter", 30); - PyModule_AddIntConstant(m, "SentinelFilter", 31); - PyModule_AddIntConstant(m, "UndefinedAlphaChannel", 0); - PyModule_AddIntConstant(m, "ActivateAlphaChannel", 1); - PyModule_AddIntConstant(m, "BackgroundAlphaChannel", 2); - PyModule_AddIntConstant(m, "CopyAlphaChannel", 3); - PyModule_AddIntConstant(m, "DeactivateAlphaChannel", 4); - PyModule_AddIntConstant(m, "ExtractAlphaChannel", 5); - PyModule_AddIntConstant(m, "OpaqueAlphaChannel", 6); - PyModule_AddIntConstant(m, "ResetAlphaChannel", 7); - PyModule_AddIntConstant(m, "SetAlphaChannel", 8); - PyModule_AddIntConstant(m, "ShapeAlphaChannel", 9); - PyModule_AddIntConstant(m, "TransparentAlphaChannel", 10); - PyModule_AddIntConstant(m, "FlattenAlphaChannel", 11); - PyModule_AddIntConstant(m, "RemoveAlphaChannel", 12); - PyModule_AddIntConstant(m, "UndefinedType", 0); - PyModule_AddIntConstant(m, "BilevelType", 1); - PyModule_AddIntConstant(m, "GrayscaleType", 2); - PyModule_AddIntConstant(m, "GrayscaleMatteType", 3); - PyModule_AddIntConstant(m, "PaletteType", 4); - PyModule_AddIntConstant(m, "PaletteMatteType", 5); - PyModule_AddIntConstant(m, "TrueColorType", 6); - PyModule_AddIntConstant(m, "TrueColorMatteType", 7); - PyModule_AddIntConstant(m, "ColorSeparationType", 8); - PyModule_AddIntConstant(m, "ColorSeparationMatteType", 9); - PyModule_AddIntConstant(m, "OptimizeType", 10); - PyModule_AddIntConstant(m, "PaletteBilevelMatteType", 11); - PyModule_AddIntConstant(m, "UndefinedInterlace", 0); - PyModule_AddIntConstant(m, "NoInterlace", 1); - PyModule_AddIntConstant(m, "LineInterlace", 2); - PyModule_AddIntConstant(m, "PlaneInterlace", 3); - PyModule_AddIntConstant(m, "PartitionInterlace", 4); - PyModule_AddIntConstant(m, "GIFInterlace", 5); - PyModule_AddIntConstant(m, "JPEGInterlace", 6); - PyModule_AddIntConstant(m, "PNGInterlace", 7); - PyModule_AddIntConstant(m, "UndefinedOrientation", 0); - PyModule_AddIntConstant(m, "TopLeftOrientation", 1); - PyModule_AddIntConstant(m, "TopRightOrientation", 2); - PyModule_AddIntConstant(m, "BottomRightOrientation", 3); - PyModule_AddIntConstant(m, "BottomLeftOrientation", 4); - PyModule_AddIntConstant(m, "LeftTopOrientation", 5); - PyModule_AddIntConstant(m, "RightTopOrientation", 6); - PyModule_AddIntConstant(m, "RightBottomOrientation", 7); - PyModule_AddIntConstant(m, "LeftBottomOrientation", 8); - PyModule_AddIntConstant(m, "UndefinedResolution", 0); - PyModule_AddIntConstant(m, "PixelsPerInchResolution", 1); - PyModule_AddIntConstant(m, "PixelsPerCentimeterResolution", 2); - PyModule_AddIntConstant(m, "UndefinedTransmitType", 0); - PyModule_AddIntConstant(m, "FileTransmitType", 1); - PyModule_AddIntConstant(m, "BlobTransmitType", 2); - PyModule_AddIntConstant(m, "StreamTransmitType", 3); - PyModule_AddIntConstant(m, "ImageTransmitType", 4); - PyModule_AddIntConstant(m, "UndefinedAlign", 0); - PyModule_AddIntConstant(m, "LeftAlign", 1); - PyModule_AddIntConstant(m, "CenterAlign", 2); - PyModule_AddIntConstant(m, "RightAlign", 3); - PyModule_AddIntConstant(m, "UndefinedPathUnits", 0); - PyModule_AddIntConstant(m, "UserSpace", 1); - PyModule_AddIntConstant(m, "UserSpaceOnUse", 2); - PyModule_AddIntConstant(m, "ObjectBoundingBox", 3); - PyModule_AddIntConstant(m, "UndefinedDecoration", 0); - PyModule_AddIntConstant(m, "NoDecoration", 1); - PyModule_AddIntConstant(m, "UnderlineDecoration", 2); - PyModule_AddIntConstant(m, "OverlineDecoration", 3); - PyModule_AddIntConstant(m, "LineThroughDecoration", 4); - PyModule_AddIntConstant(m, "UndefinedDirection", 0); - PyModule_AddIntConstant(m, "RightToLeftDirection", 1); - PyModule_AddIntConstant(m, "LeftToRightDirection", 2); - PyModule_AddIntConstant(m, "UndefinedRule", 0); - PyModule_AddIntConstant(m, "EvenOddRule", 1); - PyModule_AddIntConstant(m, "NonZeroRule", 2); - PyModule_AddIntConstant(m, "UndefinedGradient", 0); - PyModule_AddIntConstant(m, "LinearGradient", 1); - PyModule_AddIntConstant(m, "RadialGradient", 2); - PyModule_AddIntConstant(m, "UndefinedCap", 0); - PyModule_AddIntConstant(m, "ButtCap", 1); - PyModule_AddIntConstant(m, "RoundCap", 2); - PyModule_AddIntConstant(m, "SquareCap", 3); - PyModule_AddIntConstant(m, "UndefinedJoin", 0); - PyModule_AddIntConstant(m, "MiterJoin", 1); - PyModule_AddIntConstant(m, "RoundJoin", 2); - PyModule_AddIntConstant(m, "BevelJoin", 3); - PyModule_AddIntConstant(m, "UndefinedMethod", 0); - PyModule_AddIntConstant(m, "PointMethod", 1); - PyModule_AddIntConstant(m, "ReplaceMethod", 2); - PyModule_AddIntConstant(m, "FloodfillMethod", 3); - PyModule_AddIntConstant(m, "FillToBorderMethod", 4); - PyModule_AddIntConstant(m, "ResetMethod", 5); - PyModule_AddIntConstant(m, "UndefinedPrimitive", 0); - PyModule_AddIntConstant(m, "PointPrimitive", 1); - PyModule_AddIntConstant(m, "LinePrimitive", 2); - PyModule_AddIntConstant(m, "RectanglePrimitive", 3); - PyModule_AddIntConstant(m, "RoundRectanglePrimitive", 4); - PyModule_AddIntConstant(m, "ArcPrimitive", 5); - PyModule_AddIntConstant(m, "EllipsePrimitive", 6); - PyModule_AddIntConstant(m, "CirclePrimitive", 7); - PyModule_AddIntConstant(m, "PolylinePrimitive", 8); - PyModule_AddIntConstant(m, "PolygonPrimitive", 9); - PyModule_AddIntConstant(m, "BezierPrimitive", 10); - PyModule_AddIntConstant(m, "ColorPrimitive", 11); - PyModule_AddIntConstant(m, "MattePrimitive", 12); - PyModule_AddIntConstant(m, "TextPrimitive", 13); - PyModule_AddIntConstant(m, "ImagePrimitive", 14); - PyModule_AddIntConstant(m, "PathPrimitive", 15); - PyModule_AddIntConstant(m, "UndefinedReference", 0); - PyModule_AddIntConstant(m, "GradientReference", 1); - PyModule_AddIntConstant(m, "UndefinedSpread", 0); - PyModule_AddIntConstant(m, "PadSpread", 1); - PyModule_AddIntConstant(m, "ReflectSpread", 2); - PyModule_AddIntConstant(m, "RepeatSpread", 3); - PyModule_AddIntConstant(m, "UndefinedDistortion", 0); - PyModule_AddIntConstant(m, "AffineDistortion", 1); - PyModule_AddIntConstant(m, "AffineProjectionDistortion", 2); - PyModule_AddIntConstant(m, "ScaleRotateTranslateDistortion", 3); - PyModule_AddIntConstant(m, "PerspectiveDistortion", 4); - PyModule_AddIntConstant(m, "PerspectiveProjectionDistortion", 5); - PyModule_AddIntConstant(m, "BilinearForwardDistortion", 6); - PyModule_AddIntConstant(m, "BilinearDistortion", 6); - PyModule_AddIntConstant(m, "BilinearReverseDistortion", 7); - PyModule_AddIntConstant(m, "PolynomialDistortion", 8); - PyModule_AddIntConstant(m, "ArcDistortion", 9); - PyModule_AddIntConstant(m, "PolarDistortion", 10); - PyModule_AddIntConstant(m, "DePolarDistortion", 11); - PyModule_AddIntConstant(m, "Cylinder2PlaneDistortion", 12); - PyModule_AddIntConstant(m, "Plane2CylinderDistortion", 13); - PyModule_AddIntConstant(m, "BarrelDistortion", 14); - PyModule_AddIntConstant(m, "BarrelInverseDistortion", 15); - PyModule_AddIntConstant(m, "ShepardsDistortion", 16); - PyModule_AddIntConstant(m, "ResizeDistortion", 17); - PyModule_AddIntConstant(m, "SentinelDistortion", 18); - PyModule_AddIntConstant(m, "UndefinedColorInterpolate", 0); - PyModule_AddIntConstant(m, "BarycentricColorInterpolate", 1); - PyModule_AddIntConstant(m, "BilinearColorInterpolate", 7); - PyModule_AddIntConstant(m, "PolynomialColorInterpolate", 8); - PyModule_AddIntConstant(m, "ShepardsColorInterpolate", 16); - PyModule_AddIntConstant(m, "VoronoiColorInterpolate", 18); - PyModule_AddIntConstant(m, "InverseColorInterpolate", 19); - PyModule_AddIntConstant(m, "UndefinedCompositeOp", 0); - PyModule_AddIntConstant(m, "NoCompositeOp", 1); - PyModule_AddIntConstant(m, "ModulusAddCompositeOp", 2); - PyModule_AddIntConstant(m, "AtopCompositeOp", 3); - PyModule_AddIntConstant(m, "BlendCompositeOp", 4); - PyModule_AddIntConstant(m, "BumpmapCompositeOp", 5); - PyModule_AddIntConstant(m, "ChangeMaskCompositeOp", 6); - PyModule_AddIntConstant(m, "ClearCompositeOp", 7); - PyModule_AddIntConstant(m, "ColorBurnCompositeOp", 8); - PyModule_AddIntConstant(m, "ColorDodgeCompositeOp", 9); - PyModule_AddIntConstant(m, "ColorizeCompositeOp", 10); - PyModule_AddIntConstant(m, "CopyBlackCompositeOp", 11); - PyModule_AddIntConstant(m, "CopyBlueCompositeOp", 12); - PyModule_AddIntConstant(m, "CopyCompositeOp", 13); - PyModule_AddIntConstant(m, "CopyCyanCompositeOp", 14); - PyModule_AddIntConstant(m, "CopyGreenCompositeOp", 15); - PyModule_AddIntConstant(m, "CopyMagentaCompositeOp", 16); - PyModule_AddIntConstant(m, "CopyOpacityCompositeOp", 17); - PyModule_AddIntConstant(m, "CopyRedCompositeOp", 18); - PyModule_AddIntConstant(m, "CopyYellowCompositeOp", 19); - PyModule_AddIntConstant(m, "DarkenCompositeOp", 20); - PyModule_AddIntConstant(m, "DstAtopCompositeOp", 21); - PyModule_AddIntConstant(m, "DstCompositeOp", 22); - PyModule_AddIntConstant(m, "DstInCompositeOp", 23); - PyModule_AddIntConstant(m, "DstOutCompositeOp", 24); - PyModule_AddIntConstant(m, "DstOverCompositeOp", 25); - PyModule_AddIntConstant(m, "DifferenceCompositeOp", 26); - PyModule_AddIntConstant(m, "DisplaceCompositeOp", 27); - PyModule_AddIntConstant(m, "DissolveCompositeOp", 28); - PyModule_AddIntConstant(m, "ExclusionCompositeOp", 29); - PyModule_AddIntConstant(m, "HardLightCompositeOp", 30); - PyModule_AddIntConstant(m, "HueCompositeOp", 31); - PyModule_AddIntConstant(m, "InCompositeOp", 32); - PyModule_AddIntConstant(m, "LightenCompositeOp", 33); - PyModule_AddIntConstant(m, "LinearLightCompositeOp", 34); - PyModule_AddIntConstant(m, "LuminizeCompositeOp", 35); - PyModule_AddIntConstant(m, "MinusDstCompositeOp", 36); - PyModule_AddIntConstant(m, "ModulateCompositeOp", 37); - PyModule_AddIntConstant(m, "MultiplyCompositeOp", 38); - PyModule_AddIntConstant(m, "OutCompositeOp", 39); - PyModule_AddIntConstant(m, "OverCompositeOp", 40); - PyModule_AddIntConstant(m, "OverlayCompositeOp", 41); - PyModule_AddIntConstant(m, "PlusCompositeOp", 42); - PyModule_AddIntConstant(m, "ReplaceCompositeOp", 43); - PyModule_AddIntConstant(m, "SaturateCompositeOp", 44); - PyModule_AddIntConstant(m, "ScreenCompositeOp", 45); - PyModule_AddIntConstant(m, "SoftLightCompositeOp", 46); - PyModule_AddIntConstant(m, "SrcAtopCompositeOp", 47); - PyModule_AddIntConstant(m, "SrcCompositeOp", 48); - PyModule_AddIntConstant(m, "SrcInCompositeOp", 49); - PyModule_AddIntConstant(m, "SrcOutCompositeOp", 50); - PyModule_AddIntConstant(m, "SrcOverCompositeOp", 51); - PyModule_AddIntConstant(m, "ModulusSubtractCompositeOp", 52); - PyModule_AddIntConstant(m, "ThresholdCompositeOp", 53); - PyModule_AddIntConstant(m, "XorCompositeOp", 54); - PyModule_AddIntConstant(m, "DivideDstCompositeOp", 55); - PyModule_AddIntConstant(m, "DistortCompositeOp", 56); - PyModule_AddIntConstant(m, "BlurCompositeOp", 57); - PyModule_AddIntConstant(m, "PegtopLightCompositeOp", 58); - PyModule_AddIntConstant(m, "VividLightCompositeOp", 59); - PyModule_AddIntConstant(m, "PinLightCompositeOp", 60); - PyModule_AddIntConstant(m, "LinearDodgeCompositeOp", 61); - PyModule_AddIntConstant(m, "LinearBurnCompositeOp", 62); - PyModule_AddIntConstant(m, "MathematicsCompositeOp", 63); - PyModule_AddIntConstant(m, "DivideSrcCompositeOp", 64); - PyModule_AddIntConstant(m, "MinusSrcCompositeOp", 65); - PyModule_AddIntConstant(m, "DarkenIntensityCompositeOp", 66); - PyModule_AddIntConstant(m, "LightenIntensityCompositeOp", 67); - PyModule_AddIntConstant(m, "NoValue", 0); - PyModule_AddIntConstant(m, "XValue", 1); - PyModule_AddIntConstant(m, "XiValue", 1); - PyModule_AddIntConstant(m, "YValue", 2); - PyModule_AddIntConstant(m, "PsiValue", 2); - PyModule_AddIntConstant(m, "WidthValue", 4); - PyModule_AddIntConstant(m, "RhoValue", 4); - PyModule_AddIntConstant(m, "HeightValue", 8); - PyModule_AddIntConstant(m, "SigmaValue", 8); - PyModule_AddIntConstant(m, "ChiValue", 16); - PyModule_AddIntConstant(m, "XiNegative", 32); - PyModule_AddIntConstant(m, "XNegative", 32); - PyModule_AddIntConstant(m, "PsiNegative", 64); - PyModule_AddIntConstant(m, "YNegative", 64); - PyModule_AddIntConstant(m, "ChiNegative", 128); - PyModule_AddIntConstant(m, "PercentValue", 4096); - PyModule_AddIntConstant(m, "AspectValue", 8192); - PyModule_AddIntConstant(m, "NormalizeValue", 8192); - PyModule_AddIntConstant(m, "LessValue", 16384); - PyModule_AddIntConstant(m, "GreaterValue", 32768); - PyModule_AddIntConstant(m, "MinimumValue", 65536); - PyModule_AddIntConstant(m, "CorrelateNormalizeValue", 65536); - PyModule_AddIntConstant(m, "AreaValue", 131072); - PyModule_AddIntConstant(m, "DecimalValue", 262144); - PyModule_AddIntConstant(m, "SeparatorValue", 524288); - PyModule_AddIntConstant(m, "AllValues", 2147483647); - PyModule_AddIntConstant(m, "UndefinedGravity", 0); - PyModule_AddIntConstant(m, "ForgetGravity", 0); - PyModule_AddIntConstant(m, "NorthWestGravity", 1); - PyModule_AddIntConstant(m, "NorthGravity", 2); - PyModule_AddIntConstant(m, "NorthEastGravity", 3); - PyModule_AddIntConstant(m, "WestGravity", 4); - PyModule_AddIntConstant(m, "CenterGravity", 5); - PyModule_AddIntConstant(m, "EastGravity", 6); - PyModule_AddIntConstant(m, "SouthWestGravity", 7); - PyModule_AddIntConstant(m, "SouthGravity", 8); - PyModule_AddIntConstant(m, "SouthEastGravity", 9); - PyModule_AddIntConstant(m, "StaticGravity", 10); - PyModule_AddIntConstant(m, "UndefinedColorspace", 0); - PyModule_AddIntConstant(m, "RGBColorspace", 1); - PyModule_AddIntConstant(m, "GRAYColorspace", 2); - PyModule_AddIntConstant(m, "TransparentColorspace", 3); - PyModule_AddIntConstant(m, "OHTAColorspace", 4); - PyModule_AddIntConstant(m, "LabColorspace", 5); - PyModule_AddIntConstant(m, "XYZColorspace", 6); - PyModule_AddIntConstant(m, "YCbCrColorspace", 7); - PyModule_AddIntConstant(m, "YCCColorspace", 8); - PyModule_AddIntConstant(m, "YIQColorspace", 9); - PyModule_AddIntConstant(m, "YPbPrColorspace", 10); - PyModule_AddIntConstant(m, "YUVColorspace", 11); - PyModule_AddIntConstant(m, "CMYKColorspace", 12); - PyModule_AddIntConstant(m, "sRGBColorspace", 13); - PyModule_AddIntConstant(m, "HSBColorspace", 14); - PyModule_AddIntConstant(m, "HSLColorspace", 15); - PyModule_AddIntConstant(m, "HWBColorspace", 16); - PyModule_AddIntConstant(m, "Rec601LumaColorspace", 17); - PyModule_AddIntConstant(m, "Rec601YCbCrColorspace", 18); - PyModule_AddIntConstant(m, "Rec709LumaColorspace", 19); - PyModule_AddIntConstant(m, "Rec709YCbCrColorspace", 20); - PyModule_AddIntConstant(m, "LogColorspace", 21); - PyModule_AddIntConstant(m, "CMYColorspace", 22); - PyModule_AddIntConstant(m, "LuvColorspace", 23); - PyModule_AddIntConstant(m, "HCLColorspace", 24); - PyModule_AddIntConstant(m, "LCHColorspace", 25); - PyModule_AddIntConstant(m, "LMSColorspace", 26); - PyModule_AddIntConstant(m, "LCHabColorspace", 27); - PyModule_AddIntConstant(m, "LCHuvColorspace", 28); - PyModule_AddIntConstant(m, "scRGBColorspace", 29); - PyModule_AddIntConstant(m, "HSIColorspace", 30); - PyModule_AddIntConstant(m, "HSVColorspace", 31); - PyModule_AddIntConstant(m, "HCLpColorspace", 32); - PyModule_AddIntConstant(m, "YDbDrColorspace", 33); - PyModule_AddIntConstant(m, "UndefinedMetric", 0); - PyModule_AddIntConstant(m, "AbsoluteErrorMetric", 1); - PyModule_AddIntConstant(m, "MeanAbsoluteErrorMetric", 2); - PyModule_AddIntConstant(m, "MeanErrorPerPixelMetric", 3); - PyModule_AddIntConstant(m, "MeanSquaredErrorMetric", 4); - PyModule_AddIntConstant(m, "PeakAbsoluteErrorMetric", 5); - PyModule_AddIntConstant(m, "PeakSignalToNoiseRatioMetric", 6); - PyModule_AddIntConstant(m, "RootMeanSquaredErrorMetric", 7); - PyModule_AddIntConstant(m, "NormalizedCrossCorrelationErrorMetric", 8); - PyModule_AddIntConstant(m, "FuzzErrorMetric", 9); - PyModule_AddIntConstant(m, "UndefinedErrorMetric", 0); - PyModule_AddIntConstant(m, "UndefinedCompression", 0); - PyModule_AddIntConstant(m, "NoCompression", 1); - PyModule_AddIntConstant(m, "BZipCompression", 2); - PyModule_AddIntConstant(m, "DXT1Compression", 3); - PyModule_AddIntConstant(m, "DXT3Compression", 4); - PyModule_AddIntConstant(m, "DXT5Compression", 5); - PyModule_AddIntConstant(m, "FaxCompression", 6); - PyModule_AddIntConstant(m, "Group4Compression", 7); - PyModule_AddIntConstant(m, "JPEGCompression", 8); - PyModule_AddIntConstant(m, "JPEG2000Compression", 9); - PyModule_AddIntConstant(m, "LosslessJPEGCompression", 10); - PyModule_AddIntConstant(m, "LZWCompression", 11); - PyModule_AddIntConstant(m, "RLECompression", 12); - PyModule_AddIntConstant(m, "ZipCompression", 13); - PyModule_AddIntConstant(m, "ZipSCompression", 14); - PyModule_AddIntConstant(m, "PizCompression", 15); - PyModule_AddIntConstant(m, "Pxr24Compression", 16); - PyModule_AddIntConstant(m, "B44Compression", 17); - PyModule_AddIntConstant(m, "B44ACompression", 18); - PyModule_AddIntConstant(m, "LZMACompression", 19); - PyModule_AddIntConstant(m, "JBIG1Compression", 20); - PyModule_AddIntConstant(m, "JBIG2Compression", 21); -}