mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
RTF Input: Substitute a dummy image for WMF images in the RTF document
This commit is contained in:
parent
3cd9ffcec6
commit
0bab82e9b1
@ -159,11 +159,31 @@ class RTFInput(InputFormatPlugin):
|
|||||||
return imap
|
return imap
|
||||||
|
|
||||||
def convert_image(self, name):
|
def convert_image(self, name):
|
||||||
from calibre.utils.magick import Image
|
try:
|
||||||
img = Image()
|
return self.rasterize_wmf(name)
|
||||||
img.open(name)
|
except:
|
||||||
|
self.log.exception('Failed to convert WMF image %r'%name)
|
||||||
|
return self.replace_wmf(name)
|
||||||
|
|
||||||
|
def replace_wmf(self, name):
|
||||||
|
from calibre.ebooks import calibre_cover
|
||||||
|
data = calibre_cover('Conversion of WMF images is not supported',
|
||||||
|
'Use Microsoft Word or OpenOffice to save this RTF file'
|
||||||
|
' as HTML and convert that in calibre.', title_size=36,
|
||||||
|
author_size=20)
|
||||||
name = name.replace('.wmf', '.jpg')
|
name = name.replace('.wmf', '.jpg')
|
||||||
img.save(name)
|
with open(name, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def rasterize_wmf(self, name):
|
||||||
|
from calibre.utils.wmf import extract_raster_image
|
||||||
|
with open(name, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
data = extract_raster_image(data)
|
||||||
|
name = name.replace('.wmf', '.jpg')
|
||||||
|
with open(name, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,5 +5,52 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import glob
|
||||||
|
|
||||||
|
from calibre.constants import plugins, iswindows, filesystem_encoding
|
||||||
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
|
from calibre import CurrentDir
|
||||||
|
from calibre.utils.magick import Image, PixelWand
|
||||||
|
|
||||||
|
class Unavailable(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class NoRaster(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def extract_raster_image(wmf_data):
|
||||||
|
try:
|
||||||
|
wmf, wmf_err = plugins['wmf']
|
||||||
|
except KeyError:
|
||||||
|
raise Unavailable('libwmf not available on this platform')
|
||||||
|
if wmf_err:
|
||||||
|
raise Unavailable(wmf_err)
|
||||||
|
|
||||||
|
if iswindows:
|
||||||
|
import sys, os
|
||||||
|
appdir = sys.app_dir
|
||||||
|
if isinstance(appdir, unicode):
|
||||||
|
appdir = appdir.encode(filesystem_encoding)
|
||||||
|
fdir = os.path.join(appdir, 'wmffonts')
|
||||||
|
wmf.set_font_dir(fdir)
|
||||||
|
|
||||||
|
data = ''
|
||||||
|
|
||||||
|
with TemporaryDirectory('wmf2png') as tdir:
|
||||||
|
with CurrentDir(tdir):
|
||||||
|
wmf.render(wmf_data)
|
||||||
|
|
||||||
|
images = list(sorted(glob.glob('*.png')))
|
||||||
|
if not images:
|
||||||
|
raise NoRaster('No raster images in WMF')
|
||||||
|
data = open(images[0], 'rb').read()
|
||||||
|
|
||||||
|
im = Image()
|
||||||
|
im.load(data)
|
||||||
|
pw = PixelWand()
|
||||||
|
pw.color = '#ffffff'
|
||||||
|
im.rotate(pw, 180)
|
||||||
|
|
||||||
|
return im.export('png')
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <libwmf/api.h>
|
#include <libwmf/api.h>
|
||||||
#include <libwmf/svg.h>
|
#include <libwmf/svg.h>
|
||||||
|
//#include <libwmf/gd.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *data;
|
char *data;
|
||||||
@ -13,7 +14,7 @@ typedef struct {
|
|||||||
|
|
||||||
//This code is taken mostly from the Abiword wmf plugin
|
//This code is taken mostly from the Abiword wmf plugin
|
||||||
|
|
||||||
|
// Buffer read {{{
|
||||||
// returns unsigned char cast to int, or EOF
|
// returns unsigned char cast to int, or EOF
|
||||||
static int wmf_WMF_read(void * context) {
|
static int wmf_WMF_read(void * context) {
|
||||||
char c;
|
char c;
|
||||||
@ -22,11 +23,11 @@ static int wmf_WMF_read(void * context) {
|
|||||||
if (info->pos == info->len)
|
if (info->pos == info->len)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
c = info->data[pos];
|
c = info->data[info->pos];
|
||||||
|
|
||||||
info->pos++;
|
info->pos++;
|
||||||
|
|
||||||
return (int)c;
|
return (int)((unsigned char)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns (-1) on error, else 0
|
// returns (-1) on error, else 0
|
||||||
@ -44,8 +45,17 @@ static long wmf_WMF_tell(void * context) {
|
|||||||
|
|
||||||
return (long) info->pos;
|
return (long) info->pos;
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
|
||||||
|
char _png_name_buf[100];
|
||||||
|
char *wmf_png_name(void *ctxt) {
|
||||||
|
int *num = (int*)ctxt;
|
||||||
|
*num = *num + 1;
|
||||||
|
snprintf(_png_name_buf, 90, "%04d.png", *num);
|
||||||
|
return _png_name_buf;
|
||||||
|
}
|
||||||
|
|
||||||
#define CLEANUP if(API) { if (stream) wmf_free(API, stream); wmf_api_destroy(API); };
|
#define CLEANUP if(API) { if (stream) wmf_free(API, stream); wmf_api_destroy(API); };
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
@ -66,9 +76,9 @@ wmf_render(PyObject *self, PyObject *args) {
|
|||||||
|
|
||||||
unsigned int max_width = 1600;
|
unsigned int max_width = 1600;
|
||||||
unsigned int max_height = 1200;
|
unsigned int max_height = 1200;
|
||||||
unsigned long max_flags = 0;
|
|
||||||
|
|
||||||
static const char* Default_Description = "wmf2svg";
|
static const char* Default_Description = "wmf2svg";
|
||||||
|
int fname_counter = 0;
|
||||||
|
|
||||||
wmf_error_t err;
|
wmf_error_t err;
|
||||||
|
|
||||||
@ -125,6 +135,8 @@ wmf_render(PyObject *self, PyObject *args) {
|
|||||||
ddata->Description = (char *)Default_Description;
|
ddata->Description = (char *)Default_Description;
|
||||||
|
|
||||||
ddata->bbox = bbox;
|
ddata->bbox = bbox;
|
||||||
|
ddata->image.context = (void *)&fname_counter;
|
||||||
|
ddata->image.name = wmf_png_name;
|
||||||
|
|
||||||
wmf_display_size(API, &disp_width, &disp_height, 96, 96);
|
wmf_display_size(API, &disp_width, &disp_height, 96, 96);
|
||||||
|
|
||||||
@ -156,9 +168,9 @@ wmf_render(PyObject *self, PyObject *args) {
|
|||||||
ddata->height = (unsigned int) ceil ((double) wmf_height);
|
ddata->height = (unsigned int) ceil ((double) wmf_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
ddata->flags |= WMF_SVG_INLINE_IMAGES;
|
// Needs GD
|
||||||
|
//ddata->flags |= WMF_SVG_INLINE_IMAGES;
|
||||||
ddata->flags |= WMF_GD_OUTPUT_MEMORY | WMF_GD_OWN_BUFFER;
|
//ddata->flags |= WMF_GD_OUTPUT_MEMORY | WMF_GD_OWN_BUFFER;
|
||||||
|
|
||||||
err = wmf_play(API, 0, &(bbox));
|
err = wmf_play(API, 0, &(bbox));
|
||||||
|
|
||||||
@ -178,11 +190,32 @@ wmf_render(PyObject *self, PyObject *args) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void set_libwmf_fontdir(const char *);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
wmf_setfontdir(PyObject *self, PyObject *args) {
|
||||||
|
char *path;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &path))
|
||||||
|
return NULL;
|
||||||
|
set_libwmf_fontdir(path);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef wmf_methods[] = {
|
static PyMethodDef wmf_methods[] = {
|
||||||
{"render", wmf_render, METH_VARARGS,
|
{"render", wmf_render, METH_VARARGS,
|
||||||
"render(path) -> Render wmf as svg."
|
"render(data) -> Render wmf as svg."
|
||||||
},
|
},
|
||||||
|
#ifdef _WIN32
|
||||||
|
{"set_font_dir", wmf_setfontdir, METH_VARARGS,
|
||||||
|
"set_font_dir(path) -> Set the path to the fonts dir on windows, must be called at least once before using render()"
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user