mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
bb2d2a6641
@ -1,4 +1,5 @@
|
|||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
import re
|
||||||
|
|
||||||
class MainichiDailyITNews(BasicNewsRecipe):
|
class MainichiDailyITNews(BasicNewsRecipe):
|
||||||
title = u'\u6bce\u65e5\u65b0\u805e(IT&\u5bb6\u96fb)'
|
title = u'\u6bce\u65e5\u65b0\u805e(IT&\u5bb6\u96fb)'
|
||||||
@ -14,6 +15,7 @@ class MainichiDailyITNews(BasicNewsRecipe):
|
|||||||
|
|
||||||
remove_tags_before = {'class':"NewsTitle"}
|
remove_tags_before = {'class':"NewsTitle"}
|
||||||
remove_tags = [{'class':"RelatedArticle"}]
|
remove_tags = [{'class':"RelatedArticle"}]
|
||||||
|
remove_tags_after = {'class':"Credit"}
|
||||||
|
|
||||||
def parse_feeds(self):
|
def parse_feeds(self):
|
||||||
|
|
||||||
@ -29,4 +31,4 @@ class MainichiDailyITNews(BasicNewsRecipe):
|
|||||||
index = curfeed.articles.index(d)
|
index = curfeed.articles.index(d)
|
||||||
curfeed.articles[index:index+1] = []
|
curfeed.articles[index:index+1] = []
|
||||||
|
|
||||||
return feeds remove_tags_after = {'class':"Credit"}
|
return feeds
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Eddie Lau'
|
__copyright__ = '2010, Eddie Lau'
|
||||||
'''
|
'''
|
||||||
modified from Singtao Toronto calibre recipe by rty
|
|
||||||
Change Log:
|
Change Log:
|
||||||
|
2010/12/07: add entertainment section, use newspaper front page as ebook cover, suppress date display in section list
|
||||||
|
(to avoid wrong date display in case the user generates the ebook in a time zone different from HKT)
|
||||||
2010/11/22: add English section, remove eco-news section which is not updated daily, correct
|
2010/11/22: add English section, remove eco-news section which is not updated daily, correct
|
||||||
ordering of articles
|
ordering of articles
|
||||||
2010/11/12: add news image and eco-news section
|
2010/11/12: add news image and eco-news section
|
||||||
@ -17,14 +18,15 @@ from calibre.web.feeds.recipes import BasicNewsRecipe
|
|||||||
from contextlib import nested
|
from contextlib import nested
|
||||||
|
|
||||||
|
|
||||||
from calibre import __appname__, strftime
|
from calibre import __appname__
|
||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
from calibre.ebooks.metadata.toc import TOC
|
from calibre.ebooks.metadata.toc import TOC
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.utils.date import now as nowf
|
|
||||||
|
|
||||||
class MPHKRecipe(BasicNewsRecipe):
|
class MPHKRecipe(BasicNewsRecipe):
|
||||||
|
IsKindleUsed = True # to avoid generating periodical in which CJK characters can't be displayed in section/article view
|
||||||
|
|
||||||
title = 'Ming Pao - Hong Kong'
|
title = 'Ming Pao - Hong Kong'
|
||||||
oldest_article = 1
|
oldest_article = 1
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
@ -39,13 +41,13 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
encoding = 'Big5-HKSCS'
|
encoding = 'Big5-HKSCS'
|
||||||
recursions = 0
|
recursions = 0
|
||||||
conversion_options = {'linearize_tables':True}
|
conversion_options = {'linearize_tables':True}
|
||||||
extra_css = 'img {display: block; margin-left: auto; margin-right: auto; margin-top: 10px; margin-bottom: 10px;}'
|
timefmt = ''
|
||||||
#extra_css = 'img {float:right; margin:4px;}'
|
extra_css = 'img {display: block; margin-left: auto; margin-right: auto; margin-top: 10px; margin-bottom: 10px;} font>b {font-size:200%; font-weight:bold;}'
|
||||||
masthead_url = 'http://news.mingpao.com/image/portals_top_logo_news.gif'
|
masthead_url = 'http://news.mingpao.com/image/portals_top_logo_news.gif'
|
||||||
keep_only_tags = [dict(name='h1'),
|
keep_only_tags = [dict(name='h1'),
|
||||||
#dict(name='font', attrs={'style':['font-size:14pt; line-height:160%;']}), # for entertainment page
|
dict(name='font', attrs={'style':['font-size:14pt; line-height:160%;']}), # for entertainment page title
|
||||||
dict(attrs={'class':['photo']}),
|
dict(attrs={'class':['photo']}),
|
||||||
dict(attrs={'id':['newscontent']}),
|
dict(attrs={'id':['newscontent']}), # entertainment page content
|
||||||
dict(attrs={'id':['newscontent01','newscontent02']})]
|
dict(attrs={'id':['newscontent01','newscontent02']})]
|
||||||
remove_tags = [dict(name='style'),
|
remove_tags = [dict(name='style'),
|
||||||
dict(attrs={'id':['newscontent135']})] # for the finance page
|
dict(attrs={'id':['newscontent135']})] # for the finance page
|
||||||
@ -55,51 +57,68 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
lambda match: '<h1>'),
|
lambda match: '<h1>'),
|
||||||
(re.compile(r'</h5>', re.DOTALL|re.IGNORECASE),
|
(re.compile(r'</h5>', re.DOTALL|re.IGNORECASE),
|
||||||
lambda match: '</h1>'),
|
lambda match: '</h1>'),
|
||||||
|
(re.compile(r'<p><a href=.+?</a></p>', re.DOTALL|re.IGNORECASE), # for entertainment page
|
||||||
|
lambda match: '')
|
||||||
]
|
]
|
||||||
|
|
||||||
def image_url_processor(cls, baseurl, url):
|
def image_url_processor(cls, baseurl, url):
|
||||||
# trick: break the url at the first occurance of digit, add an additional
|
# trick: break the url at the first occurance of digit, add an additional
|
||||||
# '_' at the front
|
# '_' at the front
|
||||||
# not working, may need to move this to preprocess_html() method
|
# not working, may need to move this to preprocess_html() method
|
||||||
#minIdx = 10000
|
# minIdx = 10000
|
||||||
#i0 = url.find('0')
|
# i0 = url.find('0')
|
||||||
#if i0 >= 0 and i0 < minIdx:
|
# if i0 >= 0 and i0 < minIdx:
|
||||||
# minIdx = i0
|
# minIdx = i0
|
||||||
#i1 = url.find('1')
|
# i1 = url.find('1')
|
||||||
#if i1 >= 0 and i1 < minIdx:
|
# if i1 >= 0 and i1 < minIdx:
|
||||||
# minIdx = i1
|
# minIdx = i1
|
||||||
#i2 = url.find('2')
|
# i2 = url.find('2')
|
||||||
#if i2 >= 0 and i2 < minIdx:
|
# if i2 >= 0 and i2 < minIdx:
|
||||||
# minIdx = i2
|
# minIdx = i2
|
||||||
#i3 = url.find('3')
|
# i3 = url.find('3')
|
||||||
#if i3 >= 0 and i0 < minIdx:
|
# if i3 >= 0 and i0 < minIdx:
|
||||||
# minIdx = i3
|
# minIdx = i3
|
||||||
#i4 = url.find('4')
|
# i4 = url.find('4')
|
||||||
#if i4 >= 0 and i4 < minIdx:
|
# if i4 >= 0 and i4 < minIdx:
|
||||||
# minIdx = i4
|
# minIdx = i4
|
||||||
#i5 = url.find('5')
|
# i5 = url.find('5')
|
||||||
#if i5 >= 0 and i5 < minIdx:
|
# if i5 >= 0 and i5 < minIdx:
|
||||||
# minIdx = i5
|
# minIdx = i5
|
||||||
#i6 = url.find('6')
|
# i6 = url.find('6')
|
||||||
#if i6 >= 0 and i6 < minIdx:
|
# if i6 >= 0 and i6 < minIdx:
|
||||||
# minIdx = i6
|
# minIdx = i6
|
||||||
#i7 = url.find('7')
|
# i7 = url.find('7')
|
||||||
#if i7 >= 0 and i7 < minIdx:
|
# if i7 >= 0 and i7 < minIdx:
|
||||||
# minIdx = i7
|
# minIdx = i7
|
||||||
#i8 = url.find('8')
|
# i8 = url.find('8')
|
||||||
#if i8 >= 0 and i8 < minIdx:
|
# if i8 >= 0 and i8 < minIdx:
|
||||||
# minIdx = i8
|
# minIdx = i8
|
||||||
#i9 = url.find('9')
|
# i9 = url.find('9')
|
||||||
#if i9 >= 0 and i9 < minIdx:
|
# if i9 >= 0 and i9 < minIdx:
|
||||||
# minIdx = i9
|
# minIdx = i9
|
||||||
#return url[0:minIdx] + '_' + url[minIdx+1:]
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def get_fetchdate(self):
|
def get_dtlocal(self):
|
||||||
dt_utc = datetime.datetime.utcnow()
|
dt_utc = datetime.datetime.utcnow()
|
||||||
# convert UTC to local hk time - at around HKT 6.00am, all news are available
|
# convert UTC to local hk time - at around HKT 6.00am, all news are available
|
||||||
dt_local = dt_utc - datetime.timedelta(-2.0/24)
|
dt_local = dt_utc - datetime.timedelta(-2.0/24)
|
||||||
return dt_local.strftime("%Y%m%d")
|
return dt_local
|
||||||
|
|
||||||
|
def get_fetchdate(self):
|
||||||
|
return self.get_dtlocal().strftime("%Y%m%d")
|
||||||
|
|
||||||
|
def get_fetchday(self):
|
||||||
|
# convert UTC to local hk time - at around HKT 6.00am, all news are available
|
||||||
|
return self.get_dtlocal().strftime("%d")
|
||||||
|
|
||||||
|
def get_cover_url(self):
|
||||||
|
cover = 'http://news.mingpao.com/' + self.get_fetchdate() + '/' + self.get_fetchdate() + '_' + self.get_fetchday() + 'gacov.jpg'
|
||||||
|
br = BasicNewsRecipe.get_browser()
|
||||||
|
try:
|
||||||
|
br.open(cover)
|
||||||
|
except:
|
||||||
|
cover = None
|
||||||
|
return cover
|
||||||
|
|
||||||
def parse_index(self):
|
def parse_index(self):
|
||||||
feeds = []
|
feeds = []
|
||||||
@ -127,9 +146,9 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
# if eco_articles:
|
# if eco_articles:
|
||||||
# feeds.append((u'\u74b0\u4fdd Eco News', eco_articles))
|
# feeds.append((u'\u74b0\u4fdd Eco News', eco_articles))
|
||||||
# special - entertainment
|
# special - entertainment
|
||||||
#ent_articles = self.parse_ent_section('http://ol.mingpao.com/cfm/star1.cfm')
|
ent_articles = self.parse_ent_section('http://ol.mingpao.com/cfm/star1.cfm')
|
||||||
#if ent_articles:
|
if ent_articles:
|
||||||
# feeds.append(('Entertainment', ent_articles))
|
feeds.append((u'\u5f71\u8996 Entertainment', ent_articles))
|
||||||
return feeds
|
return feeds
|
||||||
|
|
||||||
def parse_section(self, url):
|
def parse_section(self, url):
|
||||||
@ -164,6 +183,7 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
return current_articles
|
return current_articles
|
||||||
|
|
||||||
def parse_eco_section(self, url):
|
def parse_eco_section(self, url):
|
||||||
|
dateStr = self.get_fetchdate()
|
||||||
soup = self.index_to_soup(url)
|
soup = self.index_to_soup(url)
|
||||||
divs = soup.findAll(attrs={'class': ['bullet']})
|
divs = soup.findAll(attrs={'class': ['bullet']})
|
||||||
current_articles = []
|
current_articles = []
|
||||||
@ -173,23 +193,25 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
title = self.tag_to_string(a)
|
title = self.tag_to_string(a)
|
||||||
url = a.get('href', False)
|
url = a.get('href', False)
|
||||||
url = 'http://tssl.mingpao.com/htm/marketing/eco/cfm/' +url
|
url = 'http://tssl.mingpao.com/htm/marketing/eco/cfm/' +url
|
||||||
if url not in included_urls and url.rfind('Redirect') == -1:
|
if url not in included_urls and url.rfind('Redirect') == -1 and not url.rfind('.txt') == -1 and not url.rfind(dateStr) == -1:
|
||||||
current_articles.append({'title': title, 'url': url, 'description':''})
|
current_articles.append({'title': title, 'url': url, 'description':''})
|
||||||
included_urls.append(url)
|
included_urls.append(url)
|
||||||
return current_articles
|
return current_articles
|
||||||
|
|
||||||
#def parse_ent_section(self, url):
|
def parse_ent_section(self, url):
|
||||||
# dateStr = self.get_fetchdate()
|
soup = self.index_to_soup(url)
|
||||||
# soup = self.index_to_soup(url)
|
a = soup.findAll('a', href=True)
|
||||||
# a = soup.findAll('a', href=True)
|
a.reverse()
|
||||||
# current_articles = []
|
current_articles = []
|
||||||
# included_urls = []
|
included_urls = []
|
||||||
# for i in a:
|
for i in a:
|
||||||
# title = self.tag_to_string(i)
|
title = self.tag_to_string(i)
|
||||||
# url = 'http://ol.mingpao.com/cfm/' + i.get('href', False)
|
url = 'http://ol.mingpao.com/cfm/' + i.get('href', False)
|
||||||
# if url not in included_urls and not url.rfind('.txt') == -1 and not url.rfind(dateStr) == -1 and not title == '':
|
if (url not in included_urls) and (not url.rfind('.txt') == -1) and (not url.rfind('star') == -1):
|
||||||
# current_articles.append({'title': title, 'url': url, 'description': ''})
|
current_articles.append({'title': title, 'url': url, 'description': ''})
|
||||||
# return current_articles
|
included_urls.append(url)
|
||||||
|
current_articles.reverse()
|
||||||
|
return current_articles
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
for item in soup.findAll(style=True):
|
for item in soup.findAll(style=True):
|
||||||
@ -201,21 +223,26 @@ class MPHKRecipe(BasicNewsRecipe):
|
|||||||
return soup
|
return soup
|
||||||
|
|
||||||
def create_opf(self, feeds, dir=None):
|
def create_opf(self, feeds, dir=None):
|
||||||
#super(MPHKRecipe,self).create_opf(feeds, dir)
|
if self.IsKindleUsed == False:
|
||||||
|
super(MPHKRecipe,self).create_opf(feeds, dir)
|
||||||
|
return
|
||||||
if dir is None:
|
if dir is None:
|
||||||
dir = self.output_dir
|
dir = self.output_dir
|
||||||
title = self.short_title()
|
title = self.short_title()
|
||||||
if self.output_profile.periodical_date_in_title:
|
title += ' ' + self.get_fetchdate()
|
||||||
title += strftime(self.timefmt)
|
#if self.output_profile.periodical_date_in_title:
|
||||||
|
# title += strftime(self.timefmt)
|
||||||
mi = MetaInformation(title, [__appname__])
|
mi = MetaInformation(title, [__appname__])
|
||||||
mi.publisher = __appname__
|
mi.publisher = __appname__
|
||||||
mi.author_sort = __appname__
|
mi.author_sort = __appname__
|
||||||
mi.publication_type = self.publication_type+':'+self.short_title()
|
mi.publication_type = self.publication_type+':'+self.short_title()
|
||||||
mi.timestamp = nowf()
|
#mi.timestamp = nowf()
|
||||||
|
mi.timestamp = self.get_dtlocal()
|
||||||
mi.comments = self.description
|
mi.comments = self.description
|
||||||
if not isinstance(mi.comments, unicode):
|
if not isinstance(mi.comments, unicode):
|
||||||
mi.comments = mi.comments.decode('utf-8', 'replace')
|
mi.comments = mi.comments.decode('utf-8', 'replace')
|
||||||
mi.pubdate = nowf()
|
#mi.pubdate = nowf()
|
||||||
|
mi.pubdate = self.get_dtlocal()
|
||||||
opf_path = os.path.join(dir, 'index.opf')
|
opf_path = os.path.join(dir, 'index.opf')
|
||||||
ncx_path = os.path.join(dir, 'index.ncx')
|
ncx_path = os.path.join(dir, 'index.ncx')
|
||||||
opf = OPFCreator(dir, mi)
|
opf = OPFCreator(dir, mi)
|
||||||
|
@ -14,7 +14,7 @@ class TheHeiseOnline(BasicNewsRecipe):
|
|||||||
oldest_article = 3
|
oldest_article = 3
|
||||||
description = 'In association with Heise Online'
|
description = 'In association with Heise Online'
|
||||||
publisher = 'Heise Media UK Ltd.'
|
publisher = 'Heise Media UK Ltd.'
|
||||||
category = 'news, technology, security'
|
category = 'news, technology, security, OSS, internet'
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
language = 'en'
|
language = 'en'
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
@ -27,6 +27,12 @@ class TheHeiseOnline(BasicNewsRecipe):
|
|||||||
feeds = [
|
feeds = [
|
||||||
(u'The H News Feed', u'http://www.h-online.com/news/atom.xml')
|
(u'The H News Feed', u'http://www.h-online.com/news/atom.xml')
|
||||||
]
|
]
|
||||||
|
cover_url = 'http://www.h-online.com/icons/logo_theH.gif'
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(id="logo"),
|
||||||
|
dict(id="footer")
|
||||||
|
]
|
||||||
|
|
||||||
def print_version(self, url):
|
def print_version(self, url):
|
||||||
return url + '?view=print'
|
return url + '?view=print'
|
||||||
|
68
resources/recipes/toyokeizai.recipe
Normal file
68
resources/recipes/toyokeizai.recipe
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||||
|
'''
|
||||||
|
www.toyokeizai.net
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
import re
|
||||||
|
|
||||||
|
class Toyokeizai(BasicNewsRecipe):
|
||||||
|
title = u'ToyoKeizai News'
|
||||||
|
__author__ = 'Hiroshi Miura'
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 50
|
||||||
|
description = 'Japanese traditional economy and business magazine, only for advanced subscribers supported'
|
||||||
|
publisher = 'Toyokeizai Shinbun Sha'
|
||||||
|
category = 'economy, magazine, japan'
|
||||||
|
language = 'ja'
|
||||||
|
encoding = 'euc-jp'
|
||||||
|
index = 'http://member.toyokeizai.net/news/'
|
||||||
|
remove_javascript = True
|
||||||
|
no_stylesheets = True
|
||||||
|
masthead_title = u'TOYOKEIZAI'
|
||||||
|
needs_subscription = True
|
||||||
|
timefmt = '[%y/%m/%d]'
|
||||||
|
recursions = 5
|
||||||
|
match_regexps =[ r'page/\d+']
|
||||||
|
|
||||||
|
keep_only_tags = [
|
||||||
|
dict(name='div', attrs={'class':['news']}),
|
||||||
|
dict(name='div', attrs={'class':["news_cont"]}),
|
||||||
|
dict(name='div', attrs={'class':["news_con"]}),
|
||||||
|
# dict(name='div', attrs={'class':["norightsMessage"]})
|
||||||
|
]
|
||||||
|
remove_tags = [{'class':"mt35 mgz"},
|
||||||
|
{'class':"mt20 newzia"},
|
||||||
|
{'class':"mt20 fontS"},
|
||||||
|
{'class':"bk_btn_m"},
|
||||||
|
dict(id='newzia_connect_member')
|
||||||
|
]
|
||||||
|
|
||||||
|
def parse_index(self):
|
||||||
|
feeds = []
|
||||||
|
soup = self.index_to_soup(self.index)
|
||||||
|
topstories = soup.find('ul',attrs={'class':'list6'})
|
||||||
|
if topstories:
|
||||||
|
newsarticles = []
|
||||||
|
for itt in topstories.findAll('li'):
|
||||||
|
itema = itt.find('a',href=True)
|
||||||
|
itemd = itt.find('span')
|
||||||
|
newsarticles.append({
|
||||||
|
'title' :itema.string
|
||||||
|
,'date' :re.compile(r"\- ").sub("",itemd.string)
|
||||||
|
,'url' :'http://member.toyokeizai.net' + itema['href']
|
||||||
|
,'description':itema['title']
|
||||||
|
})
|
||||||
|
feeds.append(('news', newsarticles))
|
||||||
|
return feeds
|
||||||
|
|
||||||
|
def get_browser(self):
|
||||||
|
br = BasicNewsRecipe.get_browser()
|
||||||
|
if self.username is not None and self.password is not None:
|
||||||
|
br.open('http://member.toyokeizai.net/norights/form/')
|
||||||
|
br.select_form(nr=0)
|
||||||
|
br['kaiin_id'] = self.username
|
||||||
|
br['password'] = self.password
|
||||||
|
res = br.submit()
|
||||||
|
return br
|
@ -129,6 +129,7 @@ class CoverCache(Thread): # {{{
|
|||||||
self.keep_running = True
|
self.keep_running = True
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
|
self.allowed_ids = frozenset([])
|
||||||
self.null_image = QImage()
|
self.null_image = QImage()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@ -175,6 +176,11 @@ class CoverCache(Thread): # {{{
|
|||||||
break
|
break
|
||||||
for id_ in ids:
|
for id_ in ids:
|
||||||
time.sleep(0.050) # Limit 20/second to not overwhelm the GUI
|
time.sleep(0.050) # Limit 20/second to not overwhelm the GUI
|
||||||
|
if not self.keep_running:
|
||||||
|
return
|
||||||
|
with self.lock:
|
||||||
|
if id_ not in self.allowed_ids:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
img = self._image_for_id(id_)
|
img = self._image_for_id(id_)
|
||||||
except:
|
except:
|
||||||
@ -193,6 +199,7 @@ class CoverCache(Thread): # {{{
|
|||||||
|
|
||||||
def set_cache(self, ids):
|
def set_cache(self, ids):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
self.allowed_ids = frozenset(ids)
|
||||||
already_loaded = set([])
|
already_loaded = set([])
|
||||||
for id in self.cache.keys():
|
for id in self.cache.keys():
|
||||||
if id in ids:
|
if id in ids:
|
||||||
@ -213,7 +220,8 @@ class CoverCache(Thread): # {{{
|
|||||||
def refresh(self, ids):
|
def refresh(self, ids):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
for id_ in ids:
|
for id_ in ids:
|
||||||
self.cache.pop(id_, None)
|
cover = self.cache.pop(id_, None)
|
||||||
|
if cover is not None:
|
||||||
self.load_queue.put(id_)
|
self.load_queue.put(id_)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -54,12 +54,15 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
|
|||||||
changed = True
|
changed = True
|
||||||
if not changed:
|
if not changed:
|
||||||
changed = fmt != orig_fmt
|
changed = fmt != orig_fmt
|
||||||
|
|
||||||
|
ret = None
|
||||||
if return_data:
|
if return_data:
|
||||||
|
ret = data
|
||||||
if changed:
|
if changed:
|
||||||
if hasattr(img, 'set_compression_quality') and fmt == 'jpg':
|
if hasattr(img, 'set_compression_quality') and fmt == 'jpg':
|
||||||
img.set_compression_quality(compression_quality)
|
img.set_compression_quality(compression_quality)
|
||||||
return img.export(fmt)
|
ret = img.export(fmt)
|
||||||
return data
|
else:
|
||||||
if changed:
|
if changed:
|
||||||
if hasattr(img, 'set_compression_quality') and fmt == 'jpg':
|
if hasattr(img, 'set_compression_quality') and fmt == 'jpg':
|
||||||
img.set_compression_quality(compression_quality)
|
img.set_compression_quality(compression_quality)
|
||||||
@ -67,6 +70,7 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
|
|||||||
else:
|
else:
|
||||||
with lopen(path, 'wb') as f:
|
with lopen(path, 'wb') as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
return ret
|
||||||
|
|
||||||
def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg'):
|
def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg'):
|
||||||
img = Image()
|
img = Image()
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include "magick_constants.h"
|
#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; }
|
||||||
|
|
||||||
// magick_set_exception {{{
|
// magick_set_exception {{{
|
||||||
PyObject* magick_set_exception(MagickWand *wand) {
|
PyObject* magick_set_exception(MagickWand *wand) {
|
||||||
ExceptionType ext;
|
ExceptionType ext;
|
||||||
@ -54,6 +57,7 @@ magick_PixelWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
magick_PixelWand_color_getter(magick_PixelWand *self, void *closure) {
|
magick_PixelWand_color_getter(magick_PixelWand *self, void *closure) {
|
||||||
const char *fp;
|
const char *fp;
|
||||||
|
NULL_CHECK(NULL);
|
||||||
fp = PixelGetColorAsNormalizedString(self->wand);
|
fp = PixelGetColorAsNormalizedString(self->wand);
|
||||||
return Py_BuildValue("s", fp);
|
return Py_BuildValue("s", fp);
|
||||||
}
|
}
|
||||||
@ -62,6 +66,8 @@ static int
|
|||||||
magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closure) {
|
magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closure) {
|
||||||
char *fmt;
|
char *fmt;
|
||||||
|
|
||||||
|
NULL_CHECK(-1);
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete PixelWand color");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete PixelWand color");
|
||||||
return -1;
|
return -1;
|
||||||
@ -80,8 +86,21 @@ magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closu
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// PixelWand.destroy {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_PixelWand_destroy(magick_PixelWand *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
self->wand = DestroyPixelWand(self->wand);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// PixelWand attr list {{{
|
// PixelWand attr list {{{
|
||||||
static PyMethodDef magick_PixelWand_methods[] = {
|
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 */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -175,10 +194,21 @@ magick_DrawingWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrawingWand.destroy {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_DrawingWand_destroy(magick_DrawingWand *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
self->wand = DestroyDrawingWand(self->wand);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// DrawingWand.font {{{
|
// DrawingWand.font {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) {
|
magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) {
|
||||||
const char *fp;
|
const char *fp;
|
||||||
|
NULL_CHECK(NULL);
|
||||||
fp = DrawGetFont(self->wand);
|
fp = DrawGetFont(self->wand);
|
||||||
return Py_BuildValue("s", fp);
|
return Py_BuildValue("s", fp);
|
||||||
}
|
}
|
||||||
@ -186,6 +216,7 @@ magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) {
|
|||||||
static int
|
static int
|
||||||
magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
char *fmt;
|
char *fmt;
|
||||||
|
NULL_CHECK(-1);
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand font");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand font");
|
||||||
@ -208,11 +239,13 @@ magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *cl
|
|||||||
// DrawingWand.font_size {{{
|
// DrawingWand.font_size {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_DrawingWand_fontsize_getter(magick_DrawingWand *self, void *closure) {
|
magick_DrawingWand_fontsize_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
return Py_BuildValue("d", DrawGetFontSize(self->wand));
|
return Py_BuildValue("d", DrawGetFontSize(self->wand));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
NULL_CHECK(-1)
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fontsize");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fontsize");
|
||||||
return -1;
|
return -1;
|
||||||
@ -233,12 +266,14 @@ magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void
|
|||||||
// DrawingWand.text_antialias {{{
|
// DrawingWand.text_antialias {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_DrawingWand_textantialias_getter(magick_DrawingWand *self, void *closure) {
|
magick_DrawingWand_textantialias_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
NULL_CHECK(NULL);
|
||||||
if (DrawGetTextAntialias(self->wand)) Py_RETURN_TRUE;
|
if (DrawGetTextAntialias(self->wand)) Py_RETURN_TRUE;
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
|
NULL_CHECK(-1);
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand textantialias");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand textantialias");
|
||||||
return -1;
|
return -1;
|
||||||
@ -253,6 +288,7 @@ magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val,
|
|||||||
// DrawingWand.gravity {{{
|
// DrawingWand.gravity {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_DrawingWand_gravity_getter(magick_DrawingWand *self, void *closure) {
|
magick_DrawingWand_gravity_getter(magick_DrawingWand *self, void *closure) {
|
||||||
|
NULL_CHECK(NULL);
|
||||||
return Py_BuildValue("n", DrawGetGravity(self->wand));
|
return Py_BuildValue("n", DrawGetGravity(self->wand));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +296,8 @@ static int
|
|||||||
magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void *closure) {
|
||||||
int grav;
|
int grav;
|
||||||
|
|
||||||
|
NULL_CHECK(-1);
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand gravity");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand gravity");
|
||||||
return -1;
|
return -1;
|
||||||
@ -281,6 +319,9 @@ magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void
|
|||||||
|
|
||||||
// DrawingWand attr list {{{
|
// DrawingWand attr list {{{
|
||||||
static PyMethodDef magick_DrawingWand_methods[] = {
|
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 */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -402,6 +443,7 @@ magick_Image_load(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
Py_ssize_t dlen;
|
Py_ssize_t dlen;
|
||||||
MagickBooleanType res;
|
MagickBooleanType res;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL;
|
if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL;
|
||||||
|
|
||||||
res = MagickReadImageBlob(self->wand, data, dlen);
|
res = MagickReadImageBlob(self->wand, data, dlen);
|
||||||
@ -420,6 +462,7 @@ magick_Image_read(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
const char *data;
|
const char *data;
|
||||||
MagickBooleanType res;
|
MagickBooleanType res;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
if (!PyArg_ParseTuple(args, "s", &data)) return NULL;
|
if (!PyArg_ParseTuple(args, "s", &data)) return NULL;
|
||||||
|
|
||||||
res = MagickReadImage(self->wand, data);
|
res = MagickReadImage(self->wand, data);
|
||||||
@ -441,6 +484,8 @@ magick_Image_create_canvas(magick_Image *self, PyObject *args, PyObject *kwargs)
|
|||||||
PixelWand *pw;
|
PixelWand *pw;
|
||||||
MagickBooleanType res = MagickFalse;
|
MagickBooleanType res = MagickFalse;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "nns", &width, &height, &bgcolor)) return NULL;
|
if (!PyArg_ParseTuple(args, "nns", &width, &height, &bgcolor)) return NULL;
|
||||||
|
|
||||||
pw = NewPixelWand();
|
pw = NewPixelWand();
|
||||||
@ -464,6 +509,8 @@ magick_Image_font_metrics(magick_Image *self, PyObject *args, PyObject *kwargs)
|
|||||||
DrawingWand *dw;
|
DrawingWand *dw;
|
||||||
double *metrics;
|
double *metrics;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!s", &magick_DrawingWandType, &dw_, &text)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!s", &magick_DrawingWandType, &dw_, &text)) return NULL;
|
||||||
dw = ((magick_DrawingWand*)dw_)->wand;
|
dw = ((magick_DrawingWand*)dw_)->wand;
|
||||||
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
||||||
@ -491,6 +538,8 @@ magick_Image_annotate(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
DrawingWand *dw;
|
DrawingWand *dw;
|
||||||
double x, y, angle;
|
double x, y, angle;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!ddds", &magick_DrawingWandType, &dw_, &x, &y, &angle, &text)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!ddds", &magick_DrawingWandType, &dw_, &x, &y, &angle, &text)) return NULL;
|
||||||
dw = ((magick_DrawingWand*)dw_)->wand;
|
dw = ((magick_DrawingWand*)dw_)->wand;
|
||||||
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; }
|
||||||
@ -510,6 +559,8 @@ magick_Image_export(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
PyObject *ans;
|
PyObject *ans;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &fmt)) return NULL;
|
if (!PyArg_ParseTuple(args, "s", &fmt)) return NULL;
|
||||||
|
|
||||||
if (!MagickSetFormat(self->wand, fmt)) {
|
if (!MagickSetFormat(self->wand, fmt)) {
|
||||||
@ -533,6 +584,8 @@ magick_Image_export(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
magick_Image_size_getter(magick_Image *self, void *closure) {
|
magick_Image_size_getter(magick_Image *self, void *closure) {
|
||||||
size_t width, height;
|
size_t width, height;
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
width = MagickGetImageWidth(self->wand);
|
width = MagickGetImageWidth(self->wand);
|
||||||
height = MagickGetImageHeight(self->wand);
|
height = MagickGetImageHeight(self->wand);
|
||||||
return Py_BuildValue("nn", width, height);
|
return Py_BuildValue("nn", width, height);
|
||||||
@ -545,6 +598,9 @@ magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
double blur;
|
double blur;
|
||||||
MagickBooleanType res;
|
MagickBooleanType res;
|
||||||
|
|
||||||
|
NULL_CHECK(-1)
|
||||||
|
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete image size");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete image size");
|
||||||
return -1;
|
return -1;
|
||||||
@ -592,6 +648,8 @@ magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
magick_Image_format_getter(magick_Image *self, void *closure) {
|
magick_Image_format_getter(magick_Image *self, void *closure) {
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
fmt = MagickGetImageFormat(self->wand);
|
fmt = MagickGetImageFormat(self->wand);
|
||||||
return Py_BuildValue("s", fmt);
|
return Py_BuildValue("s", fmt);
|
||||||
}
|
}
|
||||||
@ -599,6 +657,8 @@ magick_Image_format_getter(magick_Image *self, void *closure) {
|
|||||||
static int
|
static int
|
||||||
magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) {
|
magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) {
|
||||||
char *fmt;
|
char *fmt;
|
||||||
|
NULL_CHECK(-1)
|
||||||
|
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete image format");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete image format");
|
||||||
@ -628,6 +688,8 @@ magick_Image_distort(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
MagickBooleanType res;
|
MagickBooleanType res;
|
||||||
double *arguments = NULL;
|
double *arguments = NULL;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "iOO", &method, &argv, &bestfit)) return 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; }
|
if (!PySequence_Check(argv)) { PyErr_SetString(PyExc_TypeError, "arguments must be a sequence"); return NULL; }
|
||||||
@ -658,6 +720,8 @@ static PyObject *
|
|||||||
magick_Image_trim(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_trim(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
double fuzz;
|
double fuzz;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL;
|
if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL;
|
||||||
|
|
||||||
if (!MagickTrimImage(self->wand, fuzz)) return magick_set_exception(self->wand);
|
if (!MagickTrimImage(self->wand, fuzz)) return magick_set_exception(self->wand);
|
||||||
@ -672,6 +736,8 @@ static PyObject *
|
|||||||
magick_Image_thumbnail(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_thumbnail(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
Py_ssize_t width, height;
|
Py_ssize_t width, height;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "nn", &width, &height)) return NULL;
|
if (!PyArg_ParseTuple(args, "nn", &width, &height)) return NULL;
|
||||||
|
|
||||||
if (!MagickThumbnailImage(self->wand, width, height)) return magick_set_exception(self->wand);
|
if (!MagickThumbnailImage(self->wand, width, height)) return magick_set_exception(self->wand);
|
||||||
@ -686,6 +752,8 @@ static PyObject *
|
|||||||
magick_Image_crop(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_crop(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
Py_ssize_t width, height, x, y;
|
Py_ssize_t width, height, x, y;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return 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);
|
if (!MagickCropImage(self->wand, width, height, x, y)) return magick_set_exception(self->wand);
|
||||||
@ -701,6 +769,8 @@ magick_Image_set_border_color(magick_Image *self, PyObject *args, PyObject *kwar
|
|||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
magick_PixelWand *pw;
|
magick_PixelWand *pw;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!", &magick_PixelWandType, &obj)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!", &magick_PixelWandType, &obj)) return NULL;
|
||||||
pw = (magick_PixelWand*)obj;
|
pw = (magick_PixelWand*)obj;
|
||||||
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
||||||
@ -719,6 +789,8 @@ magick_Image_rotate(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
magick_PixelWand *pw;
|
magick_PixelWand *pw;
|
||||||
double degrees;
|
double degrees;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!d", &magick_PixelWandType, &obj, °rees)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!d", &magick_PixelWandType, &obj, °rees)) return NULL;
|
||||||
pw = (magick_PixelWand*)obj;
|
pw = (magick_PixelWand*)obj;
|
||||||
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
||||||
@ -735,6 +807,8 @@ static PyObject *
|
|||||||
magick_Image_set_page(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_set_page(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
Py_ssize_t width, height, x, y;
|
Py_ssize_t width, height, x, y;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return 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);
|
if (!MagickSetImagePage(self->wand, width, height, x, y)) return magick_set_exception(self->wand);
|
||||||
@ -749,6 +823,8 @@ static PyObject *
|
|||||||
magick_Image_set_compression_quality(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_set_compression_quality(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
Py_ssize_t quality;
|
Py_ssize_t quality;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "n", &quality)) return NULL;
|
if (!PyArg_ParseTuple(args, "n", &quality)) return NULL;
|
||||||
|
|
||||||
if (!MagickSetImageCompressionQuality(self->wand, quality)) return magick_set_exception(self->wand);
|
if (!MagickSetImageCompressionQuality(self->wand, quality)) return magick_set_exception(self->wand);
|
||||||
@ -767,6 +843,8 @@ magick_Image_has_transparent_pixels(magick_Image *self, PyObject *args, PyObject
|
|||||||
size_t r, c, width, height;
|
size_t r, c, width, height;
|
||||||
double alpha;
|
double alpha;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
height = MagickGetImageHeight(self->wand);
|
height = MagickGetImageHeight(self->wand);
|
||||||
pi = NewPixelIterator(self->wand);
|
pi = NewPixelIterator(self->wand);
|
||||||
|
|
||||||
@ -790,6 +868,8 @@ magick_Image_has_transparent_pixels(magick_Image *self, PyObject *args, PyObject
|
|||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_Image_normalize(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_normalize(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!MagickNormalizeImage(self->wand)) return magick_set_exception(self->wand);
|
if (!MagickNormalizeImage(self->wand)) return magick_set_exception(self->wand);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
@ -804,6 +884,8 @@ magick_Image_add_border(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
magick_PixelWand *pw;
|
magick_PixelWand *pw;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!nn", &magick_PixelWandType, &obj, &dx, &dy)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!nn", &magick_PixelWandType, &obj, &dx, &dy)) return NULL;
|
||||||
pw = (magick_PixelWand*)obj;
|
pw = (magick_PixelWand*)obj;
|
||||||
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; }
|
||||||
@ -820,6 +902,8 @@ static PyObject *
|
|||||||
magick_Image_sharpen(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_sharpen(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
double radius, sigma;
|
double radius, sigma;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "dd", &radius, &sigma)) return NULL;
|
if (!PyArg_ParseTuple(args, "dd", &radius, &sigma)) return NULL;
|
||||||
|
|
||||||
if (!MagickSharpenImage(self->wand, radius, sigma)) return magick_set_exception(self->wand);
|
if (!MagickSharpenImage(self->wand, radius, sigma)) return magick_set_exception(self->wand);
|
||||||
@ -836,6 +920,9 @@ magick_Image_quantize(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
int colorspace;
|
int colorspace;
|
||||||
PyObject *dither, *measure_error;
|
PyObject *dither, *measure_error;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ninOO", &number_colors, &colorspace, &treedepth, &dither, &measure_error)) return 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);
|
if (!MagickQuantizeImage(self->wand, number_colors, colorspace, treedepth, PyObject_IsTrue(dither), PyObject_IsTrue(measure_error))) return magick_set_exception(self->wand);
|
||||||
@ -848,6 +935,8 @@ magick_Image_quantize(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_Image_despeckle(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
magick_Image_despeckle(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!MagickDespeckleImage(self->wand)) return magick_set_exception(self->wand);
|
if (!MagickDespeckleImage(self->wand)) return magick_set_exception(self->wand);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
@ -857,6 +946,8 @@ magick_Image_despeckle(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
|||||||
// Image.type {{{
|
// Image.type {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
magick_Image_type_getter(magick_Image *self, void *closure) {
|
magick_Image_type_getter(magick_Image *self, void *closure) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
return Py_BuildValue("n", MagickGetImageType(self->wand));
|
return Py_BuildValue("n", MagickGetImageType(self->wand));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,6 +955,8 @@ static int
|
|||||||
magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) {
|
magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) {
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
NULL_CHECK(-1)
|
||||||
|
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Cannot delete image type");
|
PyErr_SetString(PyExc_TypeError, "Cannot delete image type");
|
||||||
return -1;
|
return -1;
|
||||||
@ -885,8 +978,21 @@ magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) {
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Image.destroy {{{
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
magick_Image_destroy(magick_Image *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
self->wand = DestroyMagickWand(self->wand);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Image attr list {{{
|
// Image attr list {{{
|
||||||
static PyMethodDef magick_Image_methods[] = {
|
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."},
|
||||||
|
|
||||||
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
|
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
|
||||||
"Load an image from a byte buffer (string)"
|
"Load an image from a byte buffer (string)"
|
||||||
},
|
},
|
||||||
@ -1001,6 +1107,7 @@ static PyGetSetDef magick_Image_getsetters[] = {
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject magick_ImageType = { // {{{
|
static PyTypeObject magick_ImageType = { // {{{
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyObject_HEAD_INIT(NULL)
|
||||||
0, /*ob_size*/
|
0, /*ob_size*/
|
||||||
@ -1053,6 +1160,9 @@ magick_Image_compose(magick_Image *self, PyObject *args, PyObject *kwargs)
|
|||||||
magick_Image *src;
|
magick_Image *src;
|
||||||
MagickBooleanType res = MagickFalse;
|
MagickBooleanType res = MagickFalse;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!nnO", &magick_ImageType, &img, &left, &top, &op_)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!nnO", &magick_ImageType, &img, &left, &top, &op_)) return NULL;
|
||||||
src = (magick_Image*)img;
|
src = (magick_Image*)img;
|
||||||
if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;}
|
if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;}
|
||||||
@ -1078,6 +1188,8 @@ magick_Image_copy(magick_Image *self, PyObject *args, PyObject *kwargs)
|
|||||||
PyObject *img;
|
PyObject *img;
|
||||||
magick_Image *src;
|
magick_Image *src;
|
||||||
|
|
||||||
|
NULL_CHECK(NULL)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!", &magick_ImageType, &img)) return NULL;
|
if (!PyArg_ParseTuple(args, "O!", &magick_ImageType, &img)) return NULL;
|
||||||
src = (magick_Image*)img;
|
src = (magick_Image*)img;
|
||||||
if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;}
|
if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;}
|
||||||
@ -1153,3 +1265,4 @@ initmagick(void)
|
|||||||
MagickWandGenesis();
|
MagickWandGenesis();
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user