You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
|
|
|
|
|
1
|
2
(1) |
3
(4) |
4
(9) |
5
(14) |
6
(8) |
7
(14) |
8
(1) |
9
(2) |
10
(9) |
11
(5) |
12
(11) |
13
(4) |
14
(4) |
15
(1) |
16
|
17
(1) |
18
(2) |
19
(4) |
20
(10) |
21
(3) |
22
(3) |
23
(2) |
24
(8) |
25
(6) |
26
(5) |
27
|
28
(3) |
29
|
30
(3) |
|
|
|
|
|
|
Revision: 3778 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3778&view=rev Author: mdboom Date: 2007年09月04日 12:52:23 -0700 (2007年9月04日) Log Message: ----------- Simplify and fix a memory leak. Modified Paths: -------------- trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007年09月04日 19:29:45 UTC (rev 3777) +++ trunk/matplotlib/src/ft2font.cpp 2007年09月04日 19:52:23 UTC (rev 3778) @@ -42,14 +42,14 @@ FT_Library _ft2Library; -FT2Image::FT2Image() : - _isDirty(true), - _buffer(NULL), - _width(0), _height(0), - _rgbCopy(NULL), - _rgbaCopy(NULL) { - _VERBOSE("FT2Image::FT2Image"); -} +// FT2Image::FT2Image() : +// _isDirty(true), +// _buffer(NULL), +// _width(0), _height(0), +// _rgbCopy(NULL), +// _rgbaCopy(NULL) { +// _VERBOSE("FT2Image::FT2Image"); +// } FT2Image::FT2Image(unsigned long width, unsigned long height) : _isDirty(true), @@ -65,75 +65,28 @@ _VERBOSE("FT2Image::~FT2Image"); delete [] _buffer; _buffer=NULL; + delete _rgbCopy; + delete _rgbaCopy; } void FT2Image::resize(unsigned long width, unsigned long height) { size_t numBytes = width*height; - if (_width != width || _height != height) { + if (width != _width || height != _height) { + if (numBytes > _width*_height) { + delete [] _buffer; + _buffer = new unsigned char [numBytes]; + } + _width = width; _height = height; - - delete [] _buffer; - _buffer = new unsigned char [numBytes]; } - for (size_t n=0; n<numBytes; n++) - _buffer[n] = 0; + memset(_buffer, 0, numBytes); _isDirty = true; } -char FT2Image::resize__doc__[] = -"resize(width, height)\n" -"\n" -"Resize the dimensions of the image (it is cleared in the process).\n" -; -Py::Object -FT2Image::py_resize(const Py::Tuple & args) { - _VERBOSE("FT2Image::resize"); - - args.verify_length(2); - - long x0 = Py::Int(args[0]); - long y0 = Py::Int(args[1]); - - resize(x0, y0); - - return Py::Object(); -} - -void FT2Image::clear() { - _VERBOSE("FT2Image::clear"); - - _width = 0; - _height = 0; - _isDirty = true; - delete [] _buffer; - _buffer = NULL; - if (_rgbCopy) { - delete _rgbCopy; - _rgbCopy = NULL; - } - if (_rgbaCopy) { - delete _rgbaCopy; - _rgbaCopy = NULL; - } -} -char FT2Image::clear__doc__[] = -"clear()\n" -"\n" -"Clear the contents of the image.\n" -; -Py::Object -FT2Image::py_clear(const Py::Tuple & args) { - args.verify_length(0); - - clear(); - - return Py::Object(); -} - void FT2Image::draw_bitmap( FT_Bitmap* bitmap, FT_Int x, @@ -345,9 +298,7 @@ unsigned char *dst = _rgbaCopy->_buffer; while (src != src_end) { - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; + dst += 3; *dst++ = *src++; } } @@ -824,8 +775,7 @@ _VERBOSE("FT2Font::clear"); args.verify_length(0); - if (image) - image->clear(); + delete image; angle = 0.0; @@ -1194,11 +1144,9 @@ size_t width = (string_bbox.xMax-string_bbox.xMin) / 64 + 2; size_t height = (string_bbox.yMax-string_bbox.yMin) / 64 + 2; - if (!image) { - image = new FT2Image(width, height); - } else { - image->resize(width, height); - } + Py_XDECREF(image); + image = NULL; + image = new FT2Image(width, height); for ( size_t n = 0; n < glyphs.size(); n++ ) { @@ -1764,10 +1712,6 @@ behaviors().name("FT2Image"); behaviors().doc("FT2Image"); - add_varargs_method("clear", &FT2Image::py_clear, - FT2Image::clear__doc__); - add_varargs_method("resize", &FT2Image::py_resize, - FT2Image::resize__doc__); add_varargs_method("write_bitmap", &FT2Image::py_write_bitmap, FT2Image::write_bitmap__doc__); add_varargs_method("draw_rect", &FT2Image::py_draw_rect, Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007年09月04日 19:29:45 UTC (rev 3777) +++ trunk/matplotlib/src/ft2font.h 2007年09月04日 19:52:23 UTC (rev 3778) @@ -22,14 +22,12 @@ // the freetype string rendered into a width, height buffer class FT2Image : public Py::PythonExtension<FT2Image> { public: - FT2Image(); + // FT2Image(); FT2Image(unsigned long width, unsigned long height); ~FT2Image(); static void init_type(); - void resize(unsigned long width, unsigned long height); - void clear(); void draw_bitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y); void write_bitmap(const char* filename) const; void draw_rect(unsigned long x0, unsigned long y0, @@ -41,10 +39,6 @@ unsigned int get_height() const { return _height; }; const unsigned char *const get_buffer() const { return _buffer; }; - static char clear__doc__ []; - Py::Object py_clear(const Py::Tuple & args); - static char resize__doc__ []; - Py::Object py_resize(const Py::Tuple & args); static char write_bitmap__doc__ []; Py::Object py_write_bitmap(const Py::Tuple & args); static char draw_rect__doc__ []; @@ -71,6 +65,8 @@ void makeRgbCopy(); void makeRgbaCopy(); + + void resize(unsigned long width, unsigned long height); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3777 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3777&view=rev Author: mdboom Date: 2007年09月04日 12:29:45 -0700 (2007年9月04日) Log Message: ----------- Better error messages. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007年09月04日 19:00:18 UTC (rev 3776) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007年09月04日 19:29:45 UTC (rev 3777) @@ -138,7 +138,7 @@ Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \ StringStart, StringEnd, ParseFatalException, FollowedBy, Regex, \ operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf, \ - ParseException, MatchFirst, NoMatch + ParseException, MatchFirst, NoMatch, Empty from matplotlib.afm import AFM from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \ @@ -1787,6 +1787,14 @@ ############################################################################## # PARSER +def Error(msg): + def raise_error(s, loc, toks): + raise ParseFatalException(msg) + + empty = Empty() + empty.setParseAction(raise_error) + return empty + class Parser(object): _binary_operators = Set(r''' + * @@ -1887,9 +1895,10 @@ ).setParseAction(self.space).setName('space') customspace =(Literal(r'\hspace') - + lbrace - + float - + rbrace + + (( lbrace + + float + + rbrace + ) | Error(r"Expected \hspace{n}")) ).setParseAction(self.customspace).setName('customspace') symbol =(Regex(r"([a-zA-Z0-9 +\-*/<>=:,.;!'@()])|(\\[%${}\[\]])") @@ -1926,8 +1935,8 @@ bslash + Literal("frac") ) - + group - + group + + ((group + group) + | Error(r"Expected \frac{num}{den}")) ).setParseAction(self.frac).setName("frac") sqrt = Group( @@ -1946,7 +1955,7 @@ + Suppress(Literal("]")), default = None ) - + group + + (group | Error("Expected \sqrt{value}")) ).setParseAction(self.sqrt).setName("sqrt") placeable <<(accent @@ -1955,7 +1964,7 @@ ^ group ^ frac ^ sqrt - ) + ) | Error("Expected symbol or group") simple <<(space | customspace @@ -1983,12 +1992,12 @@ leftDelim = oneOf(r"( [ { \lfloor \langle \lceil") rightDelim = oneOf(r") ] } \rfloor \rangle \rceil") autoDelim <<(Suppress(Literal(r"\left")) - + (leftDelim | ambiDelim) + + ((leftDelim | ambiDelim) | Error("Expected a delimiter")) + Group( autoDelim ^ OneOrMore(simple)) + Suppress(Literal(r"\right")) - + (rightDelim | ambiDelim) + + ((rightDelim | ambiDelim) | Error("Expected a delimiter")) ) math = OneOrMore( @@ -2007,7 +2016,8 @@ + ZeroOrMore( Suppress(math_delim) + math - + Suppress(math_delim) + + (Suppress(math_delim) + | Error("Expected end of math '$'")) + non_math ) ) + StringEnd() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3776 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3776&view=rev Author: mdboom Date: 2007年09月04日 12:00:18 -0700 (2007年9月04日) Log Message: ----------- Add support for arbitrary angles of rotation on mathtext in Agg backend. Uses agg to rotate the raster of the text. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/src/_backend_agg.cpp trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007年09月04日 19:00:18 UTC (rev 3776) @@ -174,17 +174,10 @@ 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi.get(), prop) - - if angle == 90: - width, height = height, width - ox, oy = oy, ox - x = int(x) - width + ox - y = int(y) - height + oy - font_image.rotate() - else: - x = int(x) + ox - y = int(y) - height + oy - self._renderer.draw_text_image(font_image, x, y + 1, gc) + + x = int(x) + ox + y = int(y) - oy + self._renderer.draw_text_image(font_image, x, y + 1, angle, gc) if 0: self._renderer.draw_rectangle(gc, None, int(x), @@ -205,12 +198,14 @@ if len(s) == 1 and ord(s) > 127: font.load_char(ord(s), flags=LOAD_DEFAULT) else: - font.set_text(s, angle, flags=LOAD_DEFAULT) + font.set_text(s, 0, flags=LOAD_DEFAULT) font.draw_glyphs_to_bitmap() #print x, y, int(x), int(y) - self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, gc) + # We pass '0' for angle here, since is has already been rotated + # (in vector space) in the above call to font.set_text. + self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc) def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): @@ -229,7 +224,7 @@ Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb) m,n,tmp = Z.shape # TODO: descent of TeX text (I am imitating backend_ps here -JKS) - return n, m, m + return n, m, 0 if ismath: ox, oy, width, height, descent, fonts, used_characters = \ Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2007年09月04日 19:00:18 UTC (rev 3776) @@ -275,10 +275,9 @@ l,b,r,t = texmanager.get_ps_bbox(s, fontsize) w = (r-l) h = (t-b) - #print s, w, h # TODO: We need a way to get a good baseline from # text.usetex - return w, h, h + return w, h, 0 if ismath: width, height, descent, pswriter, used_characters = \ Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007年09月04日 19:00:18 UTC (rev 3776) @@ -541,7 +541,7 @@ self.font = font self.charmap = font.get_charmap() self.glyphmap = dict( - [(glyphind, ccode) for ccode, glyphind in self.charmap.items()]) + [(glyphind, ccode) for ccode, glyphind in self.charmap.iteritems()]) def __repr__(self): return repr(self.font) @@ -671,7 +671,7 @@ def __init__(self, *args, **kwargs): TruetypeFonts.__init__(self, *args, **kwargs) if not len(self.fontmap): - for key, val in self._fontmap.items(): + for key, val in self._fontmap.iteritems(): fullpath = os.path.join(self.basepath, val + ".ttf") self.fontmap[key] = fullpath self.fontmap[val] = fullpath Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/_backend_agg.cpp 2007年09月04日 19:00:18 UTC (rev 3776) @@ -16,6 +16,9 @@ #include "agg_scanline_storage_aa.h" #include "agg_scanline_storage_bin.h" #include "agg_renderer_primitives.h" +#include "agg_span_image_filter_gray.h" +#include "agg_span_interpolator_linear.h" +#include "agg_span_allocator.h" #include "util/agg_color_conv_rgb8.h" #include "ft2font.h" @@ -2103,13 +2106,74 @@ } +/** + * This is a custom span generator that converts spans in the + * 8-bit inverted greyscale font buffer to rgba that agg can use. + */ +template< + class ColorT, + class ChildGenerator> +class font_to_rgba : + public agg::span_generator<ColorT, + agg::span_allocator<ColorT> > +{ +public: + typedef ChildGenerator child_type; + typedef ColorT color_type; + typedef agg::span_allocator<color_type> allocator_type; + typedef agg::span_generator< + ColorT, + agg::span_allocator<ColorT> > base_type; +private: + child_type* _gen; + allocator_type _alloc; + color_type _color; + +public: + font_to_rgba(child_type* gen, color_type color) : + base_type(_alloc), + _gen(gen), + _color(color) { + } + color_type* generate(int x, int y, unsigned len) + { + color_type* dst = base_type::allocator().span(); + + typename child_type::color_type* src = _gen->generate(x, y, len); + + do { + *dst = _color; + dst->a = src->v; + ++src; + ++dst; + } while (--len); + + return base_type::allocator().span(); + } + + void prepare(unsigned max_span_len) + { + _alloc.allocate(max_span_len); + _gen->prepare(max_span_len); + } + +}; + Py::Object RendererAgg::draw_text_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_text"); + + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_image_filter_gray<agg::gray8, interpolator_type> + image_span_gen_type; + typedef font_to_rgba<pixfmt::color_type, image_span_gen_type> + span_gen_type; + typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> + renderer_type; - args.verify_length(4); + args.verify_length(5); FT2Image *image = static_cast<FT2Image*>(args[0].ptr()); if (!image->get_buffer()) @@ -2125,70 +2189,48 @@ return Py::Object(); } - GCAgg gc = GCAgg(args[3], dpi); + double angle = Py::Float( args[3] ); + + GCAgg gc = GCAgg(args[4], dpi); - set_clipbox_rasterizer( gc.cliprect); - - - pixfmt::color_type p; - p.r = int(255*gc.color.r); - p.b = int(255*gc.color.b); - p.g = int(255*gc.color.g); - p.a = int(255*gc.color.a); - - //y = y-font->image.height; - unsigned thisx, thisy; - - double l = 0; - double b = 0; - double r = width; - double t = height; - if (gc.cliprect!=NULL) { - l = gc.cliprect[0] ; - b = gc.cliprect[1] ; - double w = gc.cliprect[2]; - double h = gc.cliprect[3]; - r = l+w; - t = b+h; - } - + set_clipbox_rasterizer(gc.cliprect); + const unsigned char* const buffer = image->get_buffer(); + agg::rendering_buffer srcbuf + ((agg::int8u*)buffer, image->get_width(), + image->get_height(), image->get_width()); + agg::pixfmt_gray8 pixf_img(srcbuf); - for (size_t i=0; i< image->get_width(); i++) { - for (size_t j=0; j< image->get_height(); j++) { - thisx = i+x+image->offsetx; - thisy = j+y+image->offsety; - if (thisx<l || thisx>=r) continue; - if (thisy<height-t || thisy>=height-b) continue; - pixFmt->blend_pixel - (thisx, thisy, p, buffer[i + j*image->get_width()]); - } - } + agg::trans_affine mtx; + mtx *= agg::trans_affine_translation(0, -(int)image->get_height()); + mtx *= agg::trans_affine_rotation(-angle * agg::pi / 180.0); + mtx *= agg::trans_affine_translation(x, y); + + agg::path_storage rect; + rect.move_to(0, 0); + rect.line_to(image->get_width(), 0); + rect.line_to(image->get_width(), image->get_height()); + rect.line_to(0, image->get_height()); + rect.line_to(0, 0); + agg::conv_transform<agg::path_storage> rect2(rect, mtx); + + agg::trans_affine inv_mtx(mtx); + inv_mtx.invert(); + + agg::image_filter_lut filter; + filter.calculate(agg::image_filter_spline36()); + interpolator_type interpolator(inv_mtx); + agg::span_allocator<agg::gray8> gray_span_allocator; + image_span_gen_type image_span_generator(gray_span_allocator, + srcbuf, 0, interpolator, filter); + span_gen_type output_span_generator(&image_span_generator, gc.color); + renderer_type ri(*rendererBase, output_span_generator); + agg::rasterizer_scanline_aa<> rasterizer; + agg::scanline_p8 scanline; + rasterizer.add_path(rect2); + agg::render_scanlines(rasterizer, scanline, ri); - /* bbox the text for debug purposes - - agg::path_storage path; - - path.move_to(x, y); - path.line_to(x, y+font->image.height); - path.line_to(x+font->image.width, y+font->image.height); - path.line_to(x+font->image.width, y); - path.close_polygon(); - - agg::rgba edgecolor(1,0,0,1); - - //now fill the edge - agg::conv_stroke<agg::path_storage> stroke(path); - stroke.width(1.0); - rendererAA->color(edgecolor); - //self->theRasterizer->gamma(agg::gamma_power(gamma)); - theRasterizer->add_path(stroke); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - - */ - return Py::Object(); - } Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/ft2font.cpp 2007年09月04日 19:00:18 UTC (rev 3776) @@ -43,8 +43,6 @@ FT_Library _ft2Library; FT2Image::FT2Image() : - offsetx(0), offsety(0), - _bRotated(false), _isDirty(true), _buffer(NULL), _width(0), _height(0), @@ -54,8 +52,6 @@ } FT2Image::FT2Image(unsigned long width, unsigned long height) : - offsetx(0), offsety(0), - _bRotated(false), _isDirty(true), _buffer(NULL), _width(0), _height(0), @@ -85,7 +81,6 @@ for (size_t n=0; n<numBytes; n++) _buffer[n] = 0; - _bRotated = false; _isDirty = true; } @@ -113,10 +108,7 @@ _width = 0; _height = 0; - offsetx = 0; - offsety = 0; _isDirty = true; - _bRotated = false; delete [] _buffer; _buffer = NULL; if (_rgbCopy) { @@ -142,58 +134,6 @@ return Py::Object(); } -void FT2Image::rotate() { - // If we have already rotated, just return. - if (_bRotated) - return; - - unsigned long width = _width; - unsigned long height = _height; - - unsigned long newWidth = _height; - unsigned long newHeight = _width; - - unsigned long numBytes = _width * _height; - - unsigned char * buffer = new unsigned char [numBytes]; - - unsigned long i, j, k, offset, nhMinusOne; - - nhMinusOne = newHeight - 1; - - unsigned char * read_it = _buffer; - - for (i=0; i<height; i++) { - offset = i*width; - for (j=0; j<width; j++) { - k = nhMinusOne - j; - buffer[i + k*newWidth] = *(read_it++); - } - } - - delete [] _buffer; - _buffer = buffer; - _width = newWidth; - _height = newHeight; - _bRotated = true; - _isDirty = true; -} -char FT2Image::rotate__doc__[] = -"rotate()\n" -"\n" -"Rotates the image 90 degrees.\n" -; -Py::Object -FT2Image::py_rotate(const Py::Tuple & args) { - _VERBOSE("FT2Image::rotate"); - - args.verify_length(0); - - rotate(); - - return Py::Object(); -} - void FT2Image::draw_bitmap( FT_Bitmap* bitmap, FT_Int x, @@ -404,17 +344,11 @@ unsigned char *src_end = src + (_width * _height); unsigned char *dst = _rgbaCopy->_buffer; - // This pre-multiplies the alpha, which apparently shouldn't - // be necessary for wxGTK, but it sure as heck seems to be. - unsigned int c; - unsigned int tmp; while (src != src_end) { - c = *src++; - tmp = ((255 - c) * c) >> 8; - *dst++ = tmp; - *dst++ = tmp; - *dst++ = tmp; - *dst++ = c; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = *src++; } } @@ -1266,12 +1200,6 @@ image->resize(width, height); } - image->offsetx = (int)(string_bbox.xMin / 64.0); - if (angle==0) - image->offsety = -image->get_height(); - else - image->offsety = (int)(-string_bbox.yMax/64.0); - for ( size_t n = 0; n < glyphs.size(); n++ ) { FT_BBox bbox; @@ -1840,8 +1768,6 @@ FT2Image::clear__doc__); add_varargs_method("resize", &FT2Image::py_resize, FT2Image::resize__doc__); - add_varargs_method("rotate", &FT2Image::py_rotate, - FT2Image::rotate__doc__); add_varargs_method("write_bitmap", &FT2Image::py_write_bitmap, FT2Image::write_bitmap__doc__); add_varargs_method("draw_rect", &FT2Image::py_draw_rect, Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007年09月04日 18:19:16 UTC (rev 3775) +++ trunk/matplotlib/src/ft2font.h 2007年09月04日 19:00:18 UTC (rev 3776) @@ -30,7 +30,6 @@ void resize(unsigned long width, unsigned long height); void clear(); - void rotate(); void draw_bitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y); void write_bitmap(const char* filename) const; void draw_rect(unsigned long x0, unsigned long y0, @@ -46,8 +45,6 @@ Py::Object py_clear(const Py::Tuple & args); static char resize__doc__ []; Py::Object py_resize(const Py::Tuple & args); - static char rotate__doc__ []; - Py::Object py_rotate(const Py::Tuple & args); static char write_bitmap__doc__ []; Py::Object py_write_bitmap(const Py::Tuple & args); static char draw_rect__doc__ []; @@ -64,11 +61,7 @@ Py::Object py_get_width(const Py::Tuple & args); Py::Object py_get_height(const Py::Tuple & args); - unsigned long offsetx; - unsigned long offsety; - private: - bool _bRotated; bool _isDirty; unsigned char *_buffer; unsigned long _width; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3775 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3775&view=rev Author: jouni Date: 2007年09月04日 11:19:16 -0700 (2007年9月04日) Log Message: ----------- More work on supporting Type 1 fonts in PDF, still doesn't produce usable files. Modified Paths: -------------- trunk/matplotlib/API_CHANGES trunk/matplotlib/lib/matplotlib/afm.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py Modified: trunk/matplotlib/API_CHANGES =================================================================== --- trunk/matplotlib/API_CHANGES 2007年09月04日 14:52:03 UTC (rev 3774) +++ trunk/matplotlib/API_CHANGES 2007年09月04日 18:19:16 UTC (rev 3775) @@ -15,7 +15,8 @@ to read an afm file in addition to a pfa/pfb file, to get metrics and kerning information for a Type 1 font. - The AFM class now supports querying CapHeight and stem widths. + The AFM class now supports querying CapHeight and stem widths. The + get_name_char method now has an isord kwarg like get_width_char. Changed pcolor default to shading='flat'; but as noted now in the docstring, it is preferable to simply use the edgecolor kwarg. Modified: trunk/matplotlib/lib/matplotlib/afm.py =================================================================== --- trunk/matplotlib/lib/matplotlib/afm.py 2007年09月04日 14:52:03 UTC (rev 3774) +++ trunk/matplotlib/lib/matplotlib/afm.py 2007年09月04日 18:19:16 UTC (rev 3775) @@ -378,11 +378,12 @@ """ return self.get_str_bbox_and_descent(s)[:4] - def get_name_char(self, c): + def get_name_char(self, c, isord=False): """ Get the name of the character, ie, ';' is 'semicolon' """ - wx, name, bbox = self._metrics[ord(c)] + if not isord: c=ord(c) + wx, name, bbox = self._metrics[c] return name def get_width_char(self, c, isord=False): Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月04日 14:52:03 UTC (rev 3774) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月04日 18:19:16 UTC (rev 3775) @@ -18,6 +18,7 @@ from math import ceil, cos, floor, pi, sin from sets import Set +import matplotlib from matplotlib import __version__, rcParams, agg, get_data_path from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ @@ -493,12 +494,16 @@ def embedType1(self, filename, fontinfo): fh = open(filename, 'rb') + matplotlib.verbose.report( + 'Embedding Type 1 font ' + filename, 'debug') try: fontdata = fh.read() finally: fh.close() fh = open(fontinfo.afmfile, 'rb') + matplotlib.verbose.report( + 'Reading metrics from ' + fontinfo.afmfile, 'debug') try: afmdata = AFM(fh) finally: @@ -519,9 +524,26 @@ differencesArray = [ Name(ch) for ch in dviread.Encoding(fontinfo.encodingfile) ] differencesArray = [ 0 ] + differencesArray + firstchar = 0 lastchar = len(differencesArray) - 2 + widths = [ 100 for x in range(firstchar,lastchar+1) ] # XXX TODO else: - lastchar = 255 # ? + widths = [ None for i in range(256) ] + for ch in range(256): + try: + widths[ch] = afmdata.get_width_char(ch, isord=True) + except KeyError: + pass + not_None = (ch for ch in range(256) + if widths[ch] is not None) + firstchar = not_None.next() + lastchar = max(not_None) + widths = widths[firstchar:lastchar+1] + + differencesArray = [ firstchar ] + for ch in range(firstchar, lastchar+1): + differencesArray.append(Name( + afmdata.get_name_char(ch, isord=True))) fontdict = { 'Type': Name('Font'), @@ -533,16 +555,15 @@ 'FontDescriptor': fontdescObject, } - if fontinfo.encodingfile is not None: - fontdict.update({ - 'Encoding': { 'Type': Name('Encoding'), - 'Differences': differencesArray }, - }) + fontdict.update({ + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + }) flags = 0 if fixed_pitch: flags |= 1 << 0 # fixed width if 0: flags |= 1 << 1 # TODO: serif - if 0: flags |= 1 << 2 # TODO: symbolic + if 1: flags |= 1 << 2 # TODO: symbolic else: flags |= 1 << 5 # non-symbolic if italic_angle: flags |= 1 << 6 # italic if 0: flags |= 1 << 16 # TODO: all caps @@ -557,12 +578,16 @@ 'ItalicAngle': italic_angle, 'Ascent': font.ascender, 'Descent': font.descender, - 'CapHeight': afmdata.get_capheight(), + 'CapHeight': 1000, # default guess if missing from AFM file 'XHeight': afmdata.get_xheight(), 'FontFile': fontfileObject, 'FontFamily': Name(familyname), #'FontWeight': a number where 400 = Regular, 700 = Bold } + try: + descriptor['CapHeight'] = afmdata.get_capheight() + except KeyError: + pass # StemV is obligatory in PDF font descriptors but optional in # AFM files. The collection of AFM files in my TeX Live 2007 @@ -579,7 +604,7 @@ descriptor['StemH'] = StemH self.writeObject(fontdictObject, fontdict) - self.writeObject(widthsObject, [ 100 for i in range(256)]) # XXX TODO + self.writeObject(widthsObject, widths) self.writeObject(fontdescObject, descriptor) fontdata = type1font.Type1Font(filename) @@ -591,6 +616,8 @@ self.currentstream.write(fontdata.data) self.endStream() + return fontdictObject + def _get_xobject_symbol_name(self, filename, symbol_name): return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007年09月04日 14:52:03 UTC (rev 3774) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007年09月04日 18:19:16 UTC (rev 3775) @@ -35,6 +35,7 @@ opens the file; actually reading the file happens when iterating through the pages of the file. """ + matplotlib.verbose.report('Dvi: ' + filename, 'debug') self.file = open(filename, 'rb') self.dpi = dpi self.fonts = {} @@ -57,7 +58,7 @@ while True: have_page = self._read() if have_page: - yield self.text, self.boxes + yield self._output() else: break This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3774 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3774&view=rev Author: jdh2358 Date: 2007年09月04日 07:52:03 -0700 (2007年9月04日) Log Message: ----------- added manuels star poly patch Modified Paths: -------------- trunk/matplotlib/examples/scatter_star_poly.py trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/collections.py trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc trunk/matplotlib/lib/matplotlib/pylab.py trunk/matplotlib/mpl1/mpl1.py Modified: trunk/matplotlib/examples/scatter_star_poly.py =================================================================== --- trunk/matplotlib/examples/scatter_star_poly.py 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/examples/scatter_star_poly.py 2007年09月04日 14:52:03 UTC (rev 3774) @@ -3,19 +3,25 @@ x = pylab.nx.mlab.rand(10) y = pylab.nx.mlab.rand(10) -pylab.subplot(221) +pylab.subplot(321) pylab.scatter(x,y,s=80,marker=">") -pylab.subplot(222) +pylab.subplot(322) pylab.scatter(x,y,s=80,marker=(5,0)) verts = zip([-1.,1.,1.],[-1.,-1.,1.]) -pylab.subplot(223) +pylab.subplot(323) pylab.scatter(x,y,s=80,marker=(verts,0)) # equivalent: #pylab.scatter(x,y,s=80,marker=None, verts=verts) -pylab.subplot(224) +pylab.subplot(324) pylab.scatter(x,y,s=80,marker=(5,1)) +pylab.subplot(325) +pylab.scatter(x,y,s=80,marker='+') + +pylab.subplot(326) +pylab.scatter(x,y,s=80,marker=(5,2), edgecolor='g') + pylab.show() Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/lib/matplotlib/axes.py 2007年09月04日 14:52:03 UTC (rev 3774) @@ -3976,16 +3976,18 @@ if not self._hold: self.cla() syms = { # a dict from symbol to (numsides, angle) - 's' : (4, math.pi/4.0), # square - 'o' : (20, 0), # circle - '^' : (3,0), # triangle up - '>' : (3,math.pi/2.0), # triangle right - 'v' : (3,math.pi), # triangle down - '<' : (3,3*math.pi/2.0), # triangle left - 'd' : (4,0), # diamond - 'p' : (5,0), # pentagram - 'h' : (6,0), # hexagon - '8' : (8,0), # octagon + 's' : (4,math.pi/4.0,0), # square + 'o' : (20,0,0), # circle + '^' : (3,0,0), # triangle up + '>' : (3,math.pi/2.0,0), # triangle right + 'v' : (3,math.pi,0), # triangle down + '<' : (3,3*math.pi/2.0,0), # triangle left + 'd' : (4,0,0), # diamond + 'p' : (5,0,0), # pentagram + 'h' : (6,0,0), # hexagon + '8' : (8,0,0), # octagon + '+' : (4,0,2), # plus + 'x' : (4,math.pi/4.0,2) # cross } self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) @@ -4013,7 +4015,7 @@ else: edgecolors = 'None' sym = None - starlike = False + symstyle = 0 # to be API compatible if marker is None and not (verts is None): @@ -4025,7 +4027,7 @@ sym = syms.get(marker) if sym is None and verts is None: raise ValueError('Unknown marker symbol to scatter') - numsides, rotation = syms[marker] + numsides, rotation, symstyle = syms[marker] elif iterable(marker): # accept marker to be: @@ -4040,21 +4042,19 @@ # (numsides, style, [angle]) if len(marker)==2: - numsides, rotation = marker[0], math.pi/4. + numsides, rotation = marker[0], 0. elif len(marker)==3: numsides, rotation = marker[0], marker[2] sym = True - if marker[1]==1: - # starlike symbol, everthing else is interpreted - # as solid symbol - starlike = True + if marker[1] in (1,2): + symstyle = marker[1] else: verts = npy.asarray(marker[0]) if sym is not None: - if not starlike: + if symstyle==0: collection = mcoll.RegularPolyCollection( self.figure.dpi, @@ -4065,7 +4065,7 @@ offsets = zip(x,y), transOffset = self.transData, ) - else: + elif symstyle==1: collection = mcoll.StarPolygonCollection( self.figure.dpi, numsides, rotation, scales, @@ -4075,6 +4075,16 @@ offsets = zip(x,y), transOffset = self.transData, ) + elif symstyle==2: + collection = mcoll.AsteriskPolygonCollection( + self.figure.dpi, + numsides, rotation, scales, + facecolors = colors, + edgecolors = edgecolors, + linewidths = linewidths, + offsets = zip(x,y), + transOffset = self.transData, + ) else: # rescale verts rescale = npy.sqrt(max(verts[:,0]**2+verts[:,1]**2)) Modified: trunk/matplotlib/lib/matplotlib/collections.py =================================================================== --- trunk/matplotlib/lib/matplotlib/collections.py 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/lib/matplotlib/collections.py 2007年09月04日 14:52:03 UTC (rev 3774) @@ -568,9 +568,42 @@ ns2 = self.numsides*2 r = scale*npy.ones(ns2) r[1::2] *= 0.5 - theta = (2.*math.pi/(ns2))*npy.arange(ns2) + self.rotation + theta = (math.pi/self.numsides)*npy.arange(ns2) + self.rotation self._verts = zip( r*npy.sin(theta), r*npy.cos(theta) ) +class AsteriskPolygonCollection(RegularPolyCollection): + def __init__(self, + dpi, + numsides, + rotation = 0 , + sizes = (1,), + **kwargs): + """ + Draw a regular asterisk Polygone with numsides spikes. + + * dpi is the figure dpi instance, and is required to do the + area scaling. + + * numsides: the number of spikes of the polygon + + * sizes gives the area of the circle circumscribing the + regular polygon in points^2 + + * rotation is the rotation of the polygon in radians + + %(PatchCollection)s + """ + + RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) + __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + + def _update_verts(self): + scale = 1.0/math.sqrt(math.pi) + r = scale*npy.ones(self.numsides*2) + r[1::2] = 0 + theta = (math.pi/self.numsides)*npy.arange(2*self.numsides) + self.rotation + self._verts = zip( r*npy.sin(theta), r*npy.cos(theta) ) + class LineCollection(Collection, cm.ScalarMappable): """ All parameters must be sequences or scalars; if scalars, they will Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc =================================================================== --- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlibrc 2007年09月04日 14:52:03 UTC (rev 3774) @@ -26,7 +26,7 @@ #### CONFIGURATION BEGINS HERE # the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg # Agg Cairo GD GDK Paint PS PDF SVG Template -backend : WXAgg +backend : TkAgg numerix : numpy # numpy, Numeric or numarray #maskedarray : False # True to use external maskedarray module # instead of numpy.ma; this is a temporary Modified: trunk/matplotlib/lib/matplotlib/pylab.py =================================================================== --- trunk/matplotlib/lib/matplotlib/pylab.py 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/lib/matplotlib/pylab.py 2007年09月04日 14:52:03 UTC (rev 3774) @@ -1464,8 +1464,8 @@ is either an int or a string. if it is an int, it indicates the column number. If it is a string, it indicates the column header. mpl will make column headers lower case, replace spaces with - strings, and remove all illegal characters; so 'Adj Close*' will - have name 'adj_close' + underscores, and remove all illegal characters; so 'Adj Close*' + will have name 'adj_close' if len(cols)==1, only that column will be plotted on the y axis. if len(cols)>1, the first element will be an identifier for data @@ -1480,7 +1480,8 @@ names in both. comments, skiprows, checkrows, and delimiter are all passed on to - matplotlib.mlab.csv2rec to load the data into a record array + matplotlib.mlab.csv2rec to load the data into a record array. See + the help there fore more information. kwargs are passed on to plotting functions Modified: trunk/matplotlib/mpl1/mpl1.py =================================================================== --- trunk/matplotlib/mpl1/mpl1.py 2007年09月04日 05:58:48 UTC (rev 3773) +++ trunk/matplotlib/mpl1/mpl1.py 2007年09月04日 14:52:03 UTC (rev 3774) @@ -12,7 +12,7 @@ sudo rm -rf /usr/local/lib/python2.5/site-packages/enthought* sudo easy_install \ -f http://code.enthought.com/enstaller/eggs/source/unstable \ - "enthought.resource <3.0a" "enthought.traits < 3.0a" + "enthought.traits < 3.0a" """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3773 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3773&view=rev Author: efiring Date: 2007年09月03日 22:58:48 -0700 (2007年9月03日) Log Message: ----------- Update CHANGELOG and API_CHANGES for Manuel Metz's errorbar patch. Modified Paths: -------------- trunk/matplotlib/API_CHANGES trunk/matplotlib/CHANGELOG Modified: trunk/matplotlib/API_CHANGES =================================================================== --- trunk/matplotlib/API_CHANGES 2007年09月04日 05:53:56 UTC (rev 3772) +++ trunk/matplotlib/API_CHANGES 2007年09月04日 05:58:48 UTC (rev 3773) @@ -1,3 +1,7 @@ + The errorbar method and function now accept additional kwargs + so that upper and lower limits can be indicated by capping the + bar with a caret instead of a straight line segment. + The dviread.py file now has a parser for files like psfonts.map and pdftex.map, to map TeX font names to external files. Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007年09月04日 05:53:56 UTC (rev 3772) +++ trunk/matplotlib/CHANGELOG 2007年09月04日 05:58:48 UTC (rev 3773) @@ -1,3 +1,6 @@ +2007年09月03日 Added ability of errorbar show limits via caret or + arrowhead ends on the bars; patch by Manual Metz. - EF + 2007年09月03日 Created type1font.py, added features to AFM and FT2Font (see API_CHANGES), started work on embedding Type 1 fonts in pdf files. - JKS @@ -7,7 +10,7 @@ 2007年08月16日 Added a set_extent method to AxesImage, allow data extent to be modified after initial call to imshow - DSD -2007年08月14日 Fixed a bug in pyqt4 subplots-adjust. Thanks to +2007年08月14日 Fixed a bug in pyqt4 subplots-adjust. Thanks to Xavier Gnata for the report and suggested fix - DSD 2007年08月13日 Use pickle to cache entire fontManager; change to using This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3772 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3772&view=rev Author: efiring Date: 2007年09月03日 22:53:56 -0700 (2007年9月03日) Log Message: ----------- Errorbar limit symbols patch by Manuel Metz Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/lines.py Added Paths: ----------- trunk/matplotlib/examples/errorbar_limits.py Added: trunk/matplotlib/examples/errorbar_limits.py =================================================================== --- trunk/matplotlib/examples/errorbar_limits.py (rev 0) +++ trunk/matplotlib/examples/errorbar_limits.py 2007年09月04日 05:53:56 UTC (rev 3772) @@ -0,0 +1,40 @@ +''' +Illustration of upper and lower limit symbols on errorbars +''' + +from math import pi +from numpy import array, arange, sin +import pylab as P + +fig = P.figure() +x = arange(10.0) +y = sin(arange(10.0)/20.0*pi) + +P.errorbar(x,y,yerr=0.1,capsize=3) + +y = sin(arange(10.0)/20.0*pi) + 1 +P.errorbar(x,y,yerr=0.1, uplims=True) + +y = sin(arange(10.0)/20.0*pi) + 2 +upperlimits = array([1,0]*5) +lowerlimits = array([0,1]*5) +P.errorbar(x, y, yerr=0.1, uplims=upperlimits, lolims=lowerlimits) + +P.xlim(-1,10) + +fig = P.figure() +x = arange(10.0)/10.0 +y = (x+0.1)**2 + +P.errorbar(x, y, xerr=0.1, xlolims=True) +y = (x+0.1)**3 + +P.errorbar(x+0.6, y, xerr=0.1, xuplims=upperlimits, xlolims=lowerlimits) + +y = (x+0.1)**4 +P.errorbar(x+1.2, y, xerr=0.1, xuplims=True) + +P.xlim(-0.2,2.4) +P.ylim(-0.1,1.3) + +P.show() Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2007年09月03日 22:16:19 UTC (rev 3771) +++ trunk/matplotlib/lib/matplotlib/axes.py 2007年09月04日 05:53:56 UTC (rev 3772) @@ -3522,10 +3522,13 @@ def errorbar(self, x, y, yerr=None, xerr=None, fmt='-', ecolor=None, capsize=3, - barsabove=False, **kwargs): + barsabove=False, lolims=False, uplims=False, + xlolims=False, xuplims=False, **kwargs): """ ERRORBAR(x, y, yerr=None, xerr=None, - fmt='b-', ecolor=None, capsize=3, barsabove=False) + fmt='b-', ecolor=None, capsize=3, barsabove=False, + lolims=False, uplims=False, + xlolims=False, xuplims=False) Plot x versus y with error deltas in yerr and xerr. Vertical errorbars are plotted if yerr is not None @@ -3554,6 +3557,11 @@ barsabove, if True, will plot the errorbars above the plot symbols - default is below + lolims, uplims, xlolims, xuplims: These arguments can be used + to indicate that a value gives only upper/lower limits. In + that case a caret symbol is used to indicate this. lims-arguments + may be of the same type as xerr and yerr. + kwargs are passed on to the plot command for the markers. So you can add additional key=value pairs to control the errorbar markers. For example, this code makes big red @@ -3579,18 +3587,18 @@ if not self._hold: self.cla() # make sure all the args are iterable arrays - if not iterable(x): x = npy.asarray([x]) + if not iterable(x): x = npy.array([x]) else: x = npy.asarray(x) - if not iterable(y): y = npy.asarray([y]) + if not iterable(y): y = npy.array([y]) else: y = npy.asarray(y) if xerr is not None: - if not iterable(xerr): xerr = npy.asarray([xerr]) + if not iterable(xerr): xerr = npy.array([xerr]) else: xerr = npy.asarray(xerr) if yerr is not None: - if not iterable(yerr): yerr = npy.asarray([yerr]) + if not iterable(yerr): yerr = npy.array([yerr]) else: yerr = npy.asarray(yerr) l0 = None @@ -3607,6 +3615,18 @@ if 'lw' in kwargs: lines_kw['lw']=kwargs['lw'] + if not iterable(lolims): lolims = npy.array([lolims]*len(x), bool) + else: lolims = npy.asarray(lolims, bool) + + if not iterable(uplims): uplims = npy.array([uplims]*len(x), bool) + else: uplims = npy.asarray(uplims, bool) + + if not iterable(xlolims): xlolims = npy.array([xlolims]*len(x), bool) + else: xlolims = npy.asarray(xlolims, bool) + + if not iterable(xuplims): xuplims = npy.array([xuplims]*len(x), bool) + else: xuplims = npy.asarray(xuplims, bool) + if capsize > 0: plot_kw = { 'ms':2*capsize, @@ -3626,9 +3646,20 @@ barcols.append( self.hlines(y, left, right, **lines_kw ) ) if capsize > 0: - caplines.extend( self.plot(left, y, 'k|', **plot_kw) ) - caplines.extend( self.plot(right, y, 'k|', **plot_kw) ) + if xlolims.any(): + caplines.extend( self.plot(left[xlolims], y[xlolims], ls='None', marker=mlines.CARETLEFT, **plot_kw) ) + xlolims = ~xlolims + caplines.extend( self.plot(left[xlolims], y[xlolims], 'k|', **plot_kw) ) + else: + caplines.extend( self.plot(left, y, 'k|', **plot_kw) ) + if xuplims.any(): + caplines.extend( self.plot(right[xuplims], y[xuplims], ls='None', marker=mlines.CARETRIGHT, **plot_kw) ) + xuplims = ~xuplims + caplines.extend( self.plot(right[xuplims], y[xuplims], 'k|', **plot_kw) ) + else: + caplines.extend( self.plot(right, y, 'k|', **plot_kw) ) + if yerr is not None: if len(yerr.shape) == 1: lower = y-yerr @@ -3639,9 +3670,21 @@ barcols.append( self.vlines(x, lower, upper, **lines_kw) ) if capsize > 0: - caplines.extend( self.plot(x, lower, 'k_', **plot_kw) ) - caplines.extend( self.plot(x, upper, 'k_', **plot_kw) ) + if lolims.any(): + caplines.extend( self.plot(x[lolims], lower[lolims], ls='None', marker=mlines.CARETDOWN, **plot_kw) ) + lolims = ~lolims + caplines.extend( self.plot(x[lolims], lower[lolims], 'k_', **plot_kw) ) + else: + caplines.extend( self.plot(x, lower, 'k_', **plot_kw) ) + + if uplims.any(): + caplines.extend( self.plot(x[uplims], upper[uplims], ls='None', marker=mlines.CARETUP, **plot_kw) ) + uplims = ~uplims + caplines.extend( self.plot(x[uplims], upper[uplims], 'k_', **plot_kw) ) + else: + caplines.extend( self.plot(x, upper, 'k_', **plot_kw) ) + if not barsabove and fmt is not None: l0, = self.plot(x,y,fmt,**kwargs) Modified: trunk/matplotlib/lib/matplotlib/lines.py =================================================================== --- trunk/matplotlib/lib/matplotlib/lines.py 2007年09月03日 22:16:19 UTC (rev 3771) +++ trunk/matplotlib/lib/matplotlib/lines.py 2007年09月04日 05:53:56 UTC (rev 3772) @@ -21,7 +21,9 @@ from transforms import lbwh_to_bbox, LOG10 from matplotlib import rcParams -TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN = range(4) +# special-purpose marker identifiers: +(TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, + CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) def unmasked_index_ranges(mask, compressed = True): ''' @@ -97,7 +99,7 @@ point_hits = (cx - x)**2 + (cy - y)**2 <= radius**2 #if any(point_hits): print "points",xr[candidates] candidates = candidates & ~point_hits[:-1] & ~point_hits[1:] - + # For those candidates which remain, determine how far they lie away # from the line. px,py = xr+u*dx,yr+u*dy @@ -147,6 +149,10 @@ TICKRIGHT : '_draw_tickright', TICKUP : '_draw_tickup', TICKDOWN : '_draw_tickdown', + CARETLEFT : '_draw_caretleft', + CARETRIGHT : '_draw_caretright', + CARETUP : '_draw_caretup', + CARETDOWN : '_draw_caretdown', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', @@ -1201,6 +1207,62 @@ renderer.draw_line(gc, x, y, x-offset2, y+offset1) renderer.draw_line(gc, x, y, x-offset2, y-offset1) + def _draw_caretdown(self, renderer, gc, xt, yt): + offset = 0.5*renderer.points_to_pixels(self._markersize) + offset1 = 1.5*offset + if self._newstyle: + path = agg.path_storage() + path.move_to(-offset, offset1) + path.line_to(0, 0) + path.line_to(+offset, offset1) + renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) + else: + for (x,y) in zip(xt, yt): + renderer.draw_line(gc, x-offset, y+offset1, x, y) + renderer.draw_line(gc, x, y, x+offset, y+offset1) + + def _draw_caretup(self, renderer, gc, xt, yt): + offset = 0.5*renderer.points_to_pixels(self._markersize) + offset1 = 1.5*offset + if self._newstyle: + path = agg.path_storage() + path.move_to(-offset, -offset1) + path.line_to(0, 0) + path.line_to(+offset, -offset1) + renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) + else: + for (x,y) in zip(xt, yt): + renderer.draw_line(gc, x-offset, y-offset1, x, y) + renderer.draw_line(gc, x, y, x+offset, y-offset1) + + def _draw_caretleft(self, renderer, gc, xt, yt): + offset = 0.5*renderer.points_to_pixels(self._markersize) + offset1 = 1.5*offset + if self._newstyle: + path = agg.path_storage() + path.move_to(offset1, -offset) + path.line_to(0, 0) + path.line_to(offset1, offset) + renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) + else: + for (x,y) in zip(xt, yt): + renderer.draw_line(gc, x+offset1, y-offset, x, y) + renderer.draw_line(gc, x, y, x+offset1, y+offset) + + def _draw_caretright(self, renderer, gc, xt, yt): + offset = 0.5*renderer.points_to_pixels(self._markersize) + offset1 = 1.5*offset + if self._newstyle: + path = agg.path_storage() + path.move_to(-offset1, -offset) + path.line_to(0, 0) + path.line_to(-offset1, offset) + renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) + else: + for (x,y) in zip(xt, yt): + renderer.draw_line(gc, x-offset1, y-offset, x, y) + renderer.draw_line(gc, x, y, x-offset1, y+offset) + def _draw_x(self, renderer, gc, xt, yt): offset = 0.5*renderer.points_to_pixels(self._markersize) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3771 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3771&view=rev Author: jouni Date: 2007年09月03日 15:16:19 -0700 (2007年9月03日) Log Message: ----------- Fix some obvious bugs in Type 1 font support; now it at least produces a pdf file, at least with Computer Modern Roman, but viewer applications complain that the fonts are broken. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月03日 21:36:17 UTC (rev 3770) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月03日 22:16:19 UTC (rev 3771) @@ -515,21 +515,30 @@ _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ ul_position, ul_thickness = font.get_ps_font_info() - differencesArray = [ 0 ] + [ Name(ch) for ch in - dviread.Encoding(fontinfo.encoding) ] + if fontinfo.encodingfile is not None: + differencesArray = [ Name(ch) for ch in + dviread.Encoding(fontinfo.encodingfile) ] + differencesArray = [ 0 ] + differencesArray + lastchar = len(differencesArray) - 2 + else: + lastchar = 255 # ? fontdict = { 'Type': Name('Font'), 'Subtype': Name('Type1'), 'BaseFont': Name(font.postscript_name), 'FirstChar': 0, - 'LastChar': len(differencesArray) - 2, + 'LastChar': lastchar, 'Widths': widthsObject, 'FontDescriptor': fontdescObject, - 'Encoding': { 'Type': Name('Encoding'), - 'Differences': differencesArray }, } + if fontinfo.encodingfile is not None: + fontdict.update({ + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + }) + flags = 0 if fixed_pitch: flags |= 1 << 0 # fixed width if 0: flags |= 1 << 1 # TODO: serif @@ -570,11 +579,11 @@ descriptor['StemH'] = StemH self.writeObject(fontdictObject, fontdict) - self.writeObject(widthsObject, widths) + self.writeObject(widthsObject, [ 100 for i in range(256)]) # XXX TODO self.writeObject(fontdescObject, descriptor) fontdata = type1font.Type1Font(filename) - len1, len2, len3 = fontdata.lenghts() + len1, len2, len3 = fontdata.lengths() self.beginStream(fontfileObject.id, None, { 'Length1': len1, 'Length2': len2, @@ -1386,14 +1395,8 @@ self.file.output(Op.grestore) def _draw_tex(self, gc, x, y, s, prop, angle): - # Rename to draw_tex to enable, but note the following: - # TODO: - # - font sizes other than 10pt - # - fonts other than the three ttf files included with matplotlib - # (will need to support Type-1 fonts and find them with kpsewhich) - # - encoding issues (e.g. \alpha doesn't work now) - # - overall robustness - # - ... + # Rename to draw_tex to enable, but it doesn't work at the moment + texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3770 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3770&view=rev Author: jouni Date: 2007年09月03日 14:36:17 -0700 (2007年9月03日) Log Message: ----------- Created new file type1font.py for supporting Type 1 fonts; quite preliminary for now. Started adding Type 1 support to PDF backend for purposes of usetex. Modified Paths: -------------- trunk/matplotlib/API_CHANGES trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/afm.py trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py trunk/matplotlib/src/ft2font.cpp trunk/matplotlib/src/ft2font.h Added Paths: ----------- trunk/matplotlib/lib/matplotlib/type1font.py Modified: trunk/matplotlib/API_CHANGES =================================================================== --- trunk/matplotlib/API_CHANGES 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/API_CHANGES 2007年09月03日 21:36:17 UTC (rev 3770) @@ -1,3 +1,18 @@ + The dviread.py file now has a parser for files like psfonts.map + and pdftex.map, to map TeX font names to external files. + + The file type1font.py contains a new class for Type 1 fonts. + Currently it simply reads pfa and pfb format files and stores the + data in pfa format, which is the format for embedding Type 1 fonts + in postscript and pdf files. In the future the class might + actually parse the font to allow e.g. subsetting. + + FT2Font now supports FT_Attach_File. In practice this can be used + to read an afm file in addition to a pfa/pfb file, to get metrics + and kerning information for a Type 1 font. + + The AFM class now supports querying CapHeight and stem widths. + Changed pcolor default to shading='flat'; but as noted now in the docstring, it is preferable to simply use the edgecolor kwarg. Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/CHANGELOG 2007年09月03日 21:36:17 UTC (rev 3770) @@ -1,3 +1,9 @@ +2007年09月03日 Created type1font.py, added features to AFM and FT2Font + (see API_CHANGES), started work on embedding Type 1 fonts + in pdf files. - JKS + +2007年09月02日 Continued work on dviread.py. - JKS + 2007年08月16日 Added a set_extent method to AxesImage, allow data extent to be modified after initial call to imshow - DSD Modified: trunk/matplotlib/lib/matplotlib/afm.py =================================================================== --- trunk/matplotlib/lib/matplotlib/afm.py 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/afm.py 2007年09月03日 21:36:17 UTC (rev 3770) @@ -103,7 +103,8 @@ 'Version': _to_str, 'Notice': _to_str, 'EncodingScheme': _to_str, - 'CapHeight': _to_float, + 'CapHeight': _to_float, # Is the second version a mistake, or + 'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS 'XHeight': _to_float, 'Ascender': _to_float, 'Descender': _to_float, @@ -112,7 +113,6 @@ 'StartCharMetrics': _to_int, 'CharacterSet': _to_str, 'Characters': _to_int, - 'Capheight': _to_int, } d = {} @@ -446,6 +446,10 @@ "Return the fontangle as float" return self._header['ItalicAngle'] + def get_capheight(self): + "Return the cap height as float" + return self._header['CapHeight'] + def get_xheight(self): "Return the xheight as float" return self._header['XHeight'] @@ -453,6 +457,20 @@ def get_underline_thickness(self): "Return the underline thickness as float" return self._header['UnderlineThickness'] + + def get_horizontal_stem_width(self): + """ + Return the standard horizontal stem width as float, or None if + not specified in AFM file. + """ + return self._header.get('StdHW', None) + + def get_vertical_stem_width(self): + """ + Return the standard vertical stem width as float, or None if + not specified in AFM file. + """ + return self._header.get('StdVW', None) if __name__=='__main__': Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月03日 21:36:17 UTC (rev 3770) @@ -26,7 +26,8 @@ from matplotlib.figure import Figure from matplotlib.font_manager import findfont from matplotlib.afm import AFM -from matplotlib.dviread import Dvi +import matplotlib.type1font as type1font +import matplotlib.dviread as dviread from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \ LOAD_NO_HINTING, KERNING_UNFITTED from matplotlib.mathtext import MathTextParser @@ -367,6 +368,7 @@ # self.fontNames maps filenames to internal font names self.fontNames = {} self.nextFont = 1 # next free internal font name + self.fontInfo = {} # information on fonts: metrics, encoding self.alphaStates = {} # maps alpha values to graphics state objects self.nextAlphaState = 1 @@ -438,6 +440,12 @@ self.currentstream = None def fontName(self, fontprop): + """ + Select a font based on fontprop and return a name suitable for + Op.selectfont. If fontprop is a string, it will be interpreted + as the filename of the font. + """ + if is_string_like(fontprop): filename = fontprop elif rcParams['pdf.use14corefonts']: @@ -458,6 +466,9 @@ for filename, Fx in self.fontNames.items(): if filename.endswith('.afm'): fontdictObject = self._write_afm_font(filename) + elif filename.endswith('.pfb') or filename.endswith('.pfa'): + # a Type 1 font; limited support for now + fontdictObject = self.embedType1(filename, self.fontInfo[Fx]) else: realpath, stat_key = get_realpath_and_stat(filename) chars = self.used_characters.get(stat_key) @@ -480,6 +491,97 @@ self.writeObject(fontdictObject, fontdict) return fontdictObject + def embedType1(self, filename, fontinfo): + fh = open(filename, 'rb') + try: + fontdata = fh.read() + finally: + fh.close() + + fh = open(fontinfo.afmfile, 'rb') + try: + afmdata = AFM(fh) + finally: + fh.close() + + font = FT2Font(filename) + font.attach_file(fontinfo.afmfile) + + widthsObject, fontdescObject, fontdictObject, fontfileObject = \ + [ self.reserveObject(n) for n in + ('font widths', 'font descriptor', + 'font dictionary', 'font file') ] + + _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ + ul_position, ul_thickness = font.get_ps_font_info() + + differencesArray = [ 0 ] + [ Name(ch) for ch in + dviread.Encoding(fontinfo.encoding) ] + + fontdict = { + 'Type': Name('Font'), + 'Subtype': Name('Type1'), + 'BaseFont': Name(font.postscript_name), + 'FirstChar': 0, + 'LastChar': len(differencesArray) - 2, + 'Widths': widthsObject, + 'FontDescriptor': fontdescObject, + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + } + + flags = 0 + if fixed_pitch: flags |= 1 << 0 # fixed width + if 0: flags |= 1 << 1 # TODO: serif + if 0: flags |= 1 << 2 # TODO: symbolic + else: flags |= 1 << 5 # non-symbolic + if italic_angle: flags |= 1 << 6 # italic + if 0: flags |= 1 << 16 # TODO: all caps + if 0: flags |= 1 << 17 # TODO: small caps + if 0: flags |= 1 << 18 # TODO: force bold + + descriptor = { + 'Type': Name('FontDescriptor'), + 'FontName': Name(font.postscript_name), + 'Flags': flags, + 'FontBBox': font.bbox, + 'ItalicAngle': italic_angle, + 'Ascent': font.ascender, + 'Descent': font.descender, + 'CapHeight': afmdata.get_capheight(), + 'XHeight': afmdata.get_xheight(), + 'FontFile': fontfileObject, + 'FontFamily': Name(familyname), + #'FontWeight': a number where 400 = Regular, 700 = Bold + } + + # StemV is obligatory in PDF font descriptors but optional in + # AFM files. The collection of AFM files in my TeX Live 2007 + # collection has values ranging from 22 to 219, with both + # median and mode 50, so if the AFM file is silent, I'm + # guessing 50. -JKS + StemV = afmdata.get_vertical_stem_width() + if StemV is None: StemV = 50 + descriptor['StemV'] = StemV + + # StemH is entirely optional: + StemH = afmdata.get_horizontal_stem_width() + if StemH is not None: + descriptor['StemH'] = StemH + + self.writeObject(fontdictObject, fontdict) + self.writeObject(widthsObject, widths) + self.writeObject(fontdescObject, descriptor) + + fontdata = type1font.Type1Font(filename) + len1, len2, len3 = fontdata.lenghts() + self.beginStream(fontfileObject.id, None, + { 'Length1': len1, + 'Length2': len2, + 'Length3': len3 }) + self.currentstream.write(fontdata.data) + self.endStream() + def _get_xobject_symbol_name(self, filename, symbol_name): return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], @@ -1034,6 +1136,7 @@ self.encode_string = self.encode_string_type42 self.mathtext_parser = MathTextParser("Pdf") self.image_magnification = dpi/72.0 + self.tex_font_map = None def finalize(self): self.gc.finalize() @@ -1050,6 +1153,12 @@ # Restore gc to avoid unwanted side effects gc._fillcolor = orig_fill + def tex_font_mapping(self, texfont): + if self.tex_font_map is None: + self.tex_font_map = \ + dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + return self.tex_font_map[texfont] + def track_characters(self, font, s): """Keeps track of which characters are required from each font.""" @@ -1288,9 +1397,8 @@ texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) - dvi = Dvi(dvifile, 72) + dvi = dviread.Dvi(dvifile, 72) text, boxes = iter(dvi).next() - fontdir = os.path.join(get_data_path(), 'fonts', 'ttf') if angle == 0: # avoid rounding errors in common case def mytrans(x1, y1): @@ -1303,14 +1411,17 @@ self.check_gc(gc, gc._rgb) self.file.output(Op.begin_text) - oldfont, oldx, oldy = None, 0, 0 - for x1, y1, font, glyph in text: - if font != oldfont: - fontname, fontsize = dvi.fontinfo(font) - fontfile = os.path.join(fontdir, fontname+'.ttf') - self.file.output(self.file.fontName(fontfile), - fontsize, Op.selectfont) - oldfont = font + oldfontnum, oldx, oldy = None, 0, 0 + for x1, y1, fontnum, glyph in text: + if fontnum != oldfontnum: + texname, fontsize = dvi.fontinfo(fontnum) + fontinfo = self.tex_font_mapping(texname) + pdfname = self.file.fontName(fontinfo.filename) + self.file.fontInfo[pdfname] = Bunch( + encodingfile=fontinfo.encoding, + afmfile=fontinfo.afm) + self.file.output(pdfname, fontsize, Op.selectfont) + oldfontnum = fontnum x1, y1 = mytrans(x1, y1) self._setup_textpos(x1, y1, angle, oldx, oldy) self.file.output(chr(glyph), Op.show) Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007年09月03日 21:36:17 UTC (rev 3770) @@ -410,11 +410,11 @@ def __getitem__(self, texname): result = self._font[texname] - if result.filename is not None \ - and not result.filename.startswith('/'): - result.filename = find_tex_file(result.filename) - if result.encoding is not None \ - and not result.encoding.startswith('/'): + fn, enc = result.filename, result.encoding + if fn is not None and not fn.startswith('/'): + result.filename = find_tex_file(fn) + result.afm = find_tex_file(fn[:-4] + '.afm') + if enc is not None and not enc.startswith('/'): result.encoding = find_tex_file(result.encoding) return result @@ -473,6 +473,51 @@ texname=texname, psname=psname, effects=effects, encoding=encoding, filename=filename) +class Encoding(object): + + def __init__(self, filename): + file = open(filename, 'rt') + try: + self.encoding = self._parse(file) + finally: + file.close() + + def __iter__(self): + for name in self.encoding: + yield name + + def _parse(self, file): + result = [] + + state = 0 + for line in file: + comment_start = line.find('%') + if comment_start > -1: + line = line[:comment_start] + line = line.strip() + + if state == 0: + # Expecting something like /FooEncoding [ + if '[' in line: + state = 1 + line = line[line.index('[')+1].strip() + + if state == 1: + words = line.split() + for w in words: + if w.startswith('/'): + # Allow for /abc/def/ghi + subwords = w.split('/') + result.extend(subwords[1:]) + else: + raise ValueError, "Broken name in encoding file: " + w + + # Expecting ] def + if ']' in line: + break + + return result + def find_tex_file(filename, format=None): """ Call kpsewhich to find a file in the texmf tree. Added: trunk/matplotlib/lib/matplotlib/type1font.py =================================================================== --- trunk/matplotlib/lib/matplotlib/type1font.py (rev 0) +++ trunk/matplotlib/lib/matplotlib/type1font.py 2007年09月03日 21:36:17 UTC (rev 3770) @@ -0,0 +1,95 @@ +""" +A class representing a Type 1 font. + +This version merely allows reading in pfa and pfb files, and stores +the data in pfa format (which can be embedded in PostScript or PDF +files). A more complete class might support subsetting. + +Usage: font = Type1Font(filename) + somefile.write(font.data) # writes out font in pfa format + len1, len2, len3 = font.lengths() # needed for pdf embedding + +Source: Adobe Technical Note #5040, Supporting Downloadable PostScript +Language Fonts. + +If extending this class, see also: Adobe Type 1 Font Format, Adobe +Systems Incorporated, third printing, v1.1, 1993. ISBN 0-201-57044-0. +""" + +import struct + +class Type1Font(object): + + def __init__(self, filename): + file = open(filename, 'rb') + try: + self._read(file) + finally: + file.close() + + def _read(self, file): + rawdata = file.read() + if not rawdata.startswith(chr(128)): + self.data = rawdata + return + + self.data = '' + while len(rawdata) > 0: + if not rawdata.startswith(chr(128)): + raise RuntimeError, \ + 'Broken pfb file (expected byte 128, got %d)' % \ + ord(rawdata[0]) + type = ord(rawdata[1]) + if type in (1,2): + length, = struct.unpack('<i', rawdata[2:6]) + segment = rawdata[6:6+length] + rawdata = rawdata[6+length:] + + if type == 1: # ASCII text: include verbatim + self.data += segment + elif type == 2: # binary data: encode in hexadecimal + self.data += ''.join(['%02x' % ord(char) + for char in segment]) + elif type == 3: # end of file + break + else: + raise RuntimeError, \ + 'Unknown segment type %d in pfb file' % type + + def lengths(self): + """ + Compute the lengths of the three parts of a Type 1 font. + + The three parts are: (1) the cleartext part, which ends in a + eexec operator; (2) the encrypted part; (3) the fixed part, + which contains 512 ASCII zeros possibly divided on various + lines, a cleartomark operator, and possibly something else. + """ + + # Cleartext part: just find the eexec and skip the eol char(s) + idx = self.data.index('eexec') + idx += len('eexec') + while self.data[idx] in ('\n', '\r'): + idx += 1 + len1 = idx + + # Encrypted part: find the cleartomark operator and count + # zeros backward + idx = self.data.rindex('cleartomark') - 1 + zeros = 512 + while zeros and self.data[idx] in ('0', '\n', '\r'): + if self.data[idx] == '0': + zeros -= 1 + idx -= 1 + if zeros: + raise RuntimeError, 'Insufficiently many zeros in Type 1 font' + + len2 = idx - len1 + len3 = len(self.data) - idx + + return len1, len2, len3 + +if __name__ == '__main__': + import sys + font = Type1Font(sys.argv[1]) + sys.stdout.write(font.data) Modified: trunk/matplotlib/src/ft2font.cpp =================================================================== --- trunk/matplotlib/src/ft2font.cpp 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/src/ft2font.cpp 2007年09月03日 21:36:17 UTC (rev 3770) @@ -1552,11 +1552,11 @@ } Py::Tuple info(9); - info[0] = Py::String(fontinfo.version); - info[1] = Py::String(fontinfo.notice); - info[2] = Py::String(fontinfo.full_name); - info[3] = Py::String(fontinfo.family_name); - info[4] = Py::String(fontinfo.weight); + info[0] = Py::String(fontinfo.version ? fontinfo.version : ""); + info[1] = Py::String(fontinfo.notice ? fontinfo.notice : ""); + info[2] = Py::String(fontinfo.full_name ? fontinfo.full_name : ""); + info[3] = Py::String(fontinfo.family_name ? fontinfo.family_name : ""); + info[4] = Py::String(fontinfo.weight ? fontinfo.weight : ""); info[5] = Py::Long(fontinfo.italic_angle); info[6] = Py::Int(fontinfo.is_fixed_pitch); info[7] = Py::Int(fontinfo.underline_position); @@ -1788,7 +1788,30 @@ return Py::asObject(image); } +char FT2Font::attach_file__doc__ [] = + "attach_file(filename)\n" + "\n" + "Attach a file with extra information on the font\n" + "(in practice, an AFM file with the metrics of a Type 1 font).\n" + "Throws an exception if unsuccessful.\n"; Py::Object +FT2Font::attach_file (const Py::Tuple &args) { + args.verify_length(1); + + std::string filename = Py::String(args[0]); + FT_Error error = + FT_Attach_File(face, filename.c_str()); + + if (error) { + std::ostringstream s; + s << "Could not attach file " << filename + << " (freetype error code " << error << ")" << std::endl; + throw Py::RuntimeError(s.str()); + } + return Py::Object(); +} + +Py::Object ft2font_module::new_ft2image (const Py::Tuple &args) { args.verify_length(2); @@ -1894,6 +1917,8 @@ FT2Font::get_sfnt_table__doc__); add_varargs_method("get_image", &FT2Font::get_image, FT2Font::get_image__doc__); + add_varargs_method("attach_file", &FT2Font::attach_file, + FT2Font::attach_file__doc__); behaviors().supportGetattr(); behaviors().supportSetattr(); @@ -1949,6 +1974,7 @@ " max_advance_height same for vertical layout\n" " underline_position vertical position of the underline bar\n" " underline_thickness vertical thickness of the underline\n" +" postscript_name PostScript name of the font\n" ; #if defined(_MSC_VER) Modified: trunk/matplotlib/src/ft2font.h =================================================================== --- trunk/matplotlib/src/ft2font.h 2007年09月03日 18:27:22 UTC (rev 3769) +++ trunk/matplotlib/src/ft2font.h 2007年09月03日 21:36:17 UTC (rev 3770) @@ -122,6 +122,7 @@ Py::Object get_ps_font_info(const Py::Tuple & args); Py::Object get_sfnt_table(const Py::Tuple & args); Py::Object get_image(const Py::Tuple & args); + Py::Object attach_file(const Py::Tuple & args); int setattr( const char *_name, const Py::Object &value ); Py::Object getattr( const char *_name ); FT2Image* image; @@ -163,6 +164,7 @@ static char get_ps_font_info__doc__[]; static char get_sfnt_table__doc__[]; static char get_image__doc__[]; + static char attach_file__doc__[]; }; // the extension module This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3769 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3769&view=rev Author: efiring Date: 2007年09月03日 11:27:22 -0700 (2007年9月03日) Log Message: ----------- Added example of a standalone colorbar. Added Paths: ----------- trunk/matplotlib/examples/colorbar_only.py Added: trunk/matplotlib/examples/colorbar_only.py =================================================================== --- trunk/matplotlib/examples/colorbar_only.py (rev 0) +++ trunk/matplotlib/examples/colorbar_only.py 2007年09月03日 18:27:22 UTC (rev 3769) @@ -0,0 +1,28 @@ +''' +Make a colorbar as a separate figure. +''' + +import pylab +import matplotlib as mpl + +# Make a figure and axes with dimensions as desired. +fig = pylab.figure(figsize=(8,1.5)) +ax = fig.add_axes([0.05, 0.4, 0.9, 0.5]) + +# Set the colormap and norm to correspond to the data for which +# the colorbar will be used. +cmap = mpl.cm.cool +norm = mpl.colors.Normalize(vmin=5, vmax=10) + +# ColorbarBase derives from ScalarMappable and puts a colorbar +# in a specified axes, so it has everything needed for a +# standalone colorbar. There are many more kwargs, but the +# following gives a basic continuous colorbar with ticks +# and labels. +cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap, + norm=norm, + orientation='horizontal') +cb.set_label('Some Units') + +pylab.show() + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3768 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3768&view=rev Author: jouni Date: 2007年09月03日 09:29:08 -0700 (2007年9月03日) Log Message: ----------- Fix buglet in get_text_width_height_descent of backend_agg when text.usetex is in effect. The descent returned is probably not correct, but it should be similar to the one returned by backend_ps. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007年09月02日 18:49:20 UTC (rev 3767) +++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2007年09月03日 16:29:08 UTC (rev 3768) @@ -228,7 +228,8 @@ texmanager = self.get_texmanager() Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb) m,n,tmp = Z.shape - return n,m + # TODO: descent of TeX text (I am imitating backend_ps here -JKS) + return n, m, m if ismath: ox, oy, width, height, descent, fonts, used_characters = \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3767 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3767&view=rev Author: jouni Date: 2007年09月02日 11:49:20 -0700 (2007年9月02日) Log Message: ----------- Some refactoring of dviread, plus a reader for psfonts.map format files Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年08月31日 19:35:09 UTC (rev 3766) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007年09月02日 18:49:20 UTC (rev 3767) @@ -1288,9 +1288,8 @@ texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) - dvi = Dvi(dvifile) - dvi.read() - text, boxes = dvi.output(72) + dvi = Dvi(dvifile, 72) + text, boxes = iter(dvi).next() fontdir = os.path.join(get_data_path(), 'fonts', 'ttf') if angle == 0: # avoid rounding errors in common case Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007年08月31日 19:35:09 UTC (rev 3766) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007年09月02日 18:49:20 UTC (rev 3767) @@ -1,40 +1,78 @@ """ -An experimental module for reading single-page dvi files output by -TeX. Several limitations make this not (currently) useful as a -general-purpose dvi preprocessor. The idea is that the file has a -single page with only a single formula or other piece of text. +An experimental module for reading dvi files output by TeX. Several +limitations make this not (currently) useful as a general-purpose dvi +preprocessor. Interface: - dvi = Dvi(filename) - dvi.read() - text, boxes = dvi.output(72) - for x,y,font,glyph in text: - fontname, pointsize = dvi.fontinfo(font) - ... - for x,y,height,width in boxes: - ... + dvi = Dvi(filename, 72) + for text, boxes in dvi: # iterate over pages + text, boxes = dvi.output(72) + for x,y,font,glyph in text: + fontname, pointsize = dvi.fontinfo(font) + ... + for x,y,height,width in boxes: + ... """ -from matplotlib.cbook import Bunch +import matplotlib +import matplotlib.cbook as mpl_cbook import os import struct -dvistate = Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) +_dvistate = mpl_cbook.Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) class Dvi(object): + """ + A dvi ("device-independent") file, as produced by TeX. + The current implementation only reads the first page and does not + even attempt to verify the postamble. + """ - def __init__(self, filename): - self.filename = filename - self.text = [] # list of (x,y,fontnum,glyphnum) - self.boxes = [] # list of (x,y,width,height) + def __init__(self, filename, dpi): + """ + Initialize the object. This takes the filename as input and + opens the file; actually reading the file happens when + iterating through the pages of the file. + """ + self.file = open(filename, 'rb') + self.dpi = dpi self.fonts = {} + self.state = _dvistate.pre - def output(self, dpi): - """Return lists of text and box objects transformed into a standard - Cartesian coordinate system at the given dpi value. The coordinates - are floating point numbers, but otherwise precision is not lost and - coordinate values are not clipped to integers.""" + def __iter__(self): + """ + Iterate through the pages of the file. + + Returns (text, pages) pairs, where: + text is a list of (x, y, fontnum, glyphnum) tuples + boxes is a list of (x, y, height, width) tuples + + The coordinates are transformed into a standard Cartesian + coordinate system at the dpi value given when initializing. + The coordinates are floating point numbers, but otherwise + precision is not lost and coordinate values are not clipped to + integers. + """ + while True: + have_page = self._read() + if have_page: + yield self.text, self.boxes + else: + break + + def close(self): + """ + Close the underlying file if it is open. + """ + if not self.file.closed: + self.file.close() + + def _output(self): + """ + Output the text and boxes belonging to the most recent page. + text, boxes = dvi._output() + """ t0 = self.text[0] minx, miny, maxx, maxy = t0[0], t0[1], t0[0], t0[1] for x,y,_,_ in self.text + self.boxes: @@ -42,31 +80,43 @@ if y < miny: miny = y if x > maxx: maxx = x if y > maxy: maxy = y - d = dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units + d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units text = [ ((x-minx)*d, (maxy-y)*d, f, g) for (x,y,f,g) in self.text ] boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ] return text, boxes def fontinfo(self, f): - """Name and size in (Adobe) points.""" + """ + texname, pointsize = dvi.fontinfo(fontnum) + + Name and size in points (Adobe points, not TeX points). + """ return self.fonts[f].name, self.fonts[f].scale * (72.0 / (72.27 * 2**16)) - def read(self, debug=False): - self.file = open(self.filename, 'rb') - try: - self.state = dvistate.pre - while True: - byte = ord(self.file.read(1)) - if byte == '': - break # eof - self.dispatch(byte) - if debug and self.state == dvistate.inpage: - print self.h, self.v - if byte == 140: break # end of page; we only read a single page for now - finally: - self.file.close() + def _read(self): + """ + Read one page from the file. Return True if successful, + False if there were no more pages. + """ + while True: + byte = ord(self.file.read(1)) + self._dispatch(byte) + if self.state == _dvistate.inpage: + matplotlib.verbose.report( + 'Dvi._read: after %d at %f,%f' % + (byte, self.h, self.v), + 'debug-annoying') + if byte == 140: # end of page + return True + if self.state == _dvistate.post_post: # end of file + self.close() + return False - def arg(self, nbytes, signed=False): + def _arg(self, nbytes, signed=False): + """ + Read and return an integer argument "nbytes" long. + Signedness is determined by the "signed" keyword. + """ str = self.file.read(nbytes) value = ord(str[0]) if signed and value >= 0x80: @@ -75,76 +125,81 @@ value = 0x100*value + ord(str[i]) return value - def dispatch(self, byte): - if 0 <= byte <= 127: self.set_char(byte) - elif byte == 128: self.set_char(self.arg(1)) - elif byte == 129: self.set_char(self.arg(2)) - elif byte == 130: self.set_char(self.arg(3)) - elif byte == 131: self.set_char(self.arg(4, True)) - elif byte == 132: self.set_rule(self.arg(4, True), self.arg(4, True)) - elif byte == 133: self.put_char(self.arg(1)) - elif byte == 134: self.put_char(self.arg(2)) - elif byte == 135: self.put_char(self.arg(3)) - elif byte == 136: self.put_char(self.arg(4, True)) - elif byte == 137: self.put_rule(self.arg(4, True), self.arg(4, True)) - elif byte == 138: self.nop() - elif byte == 139: self.bop(*[self.arg(4, True) for i in range(11)]) - elif byte == 140: self.eop() - elif byte == 141: self.push() - elif byte == 142: self.pop() - elif byte == 143: self.right(self.arg(1, True)) - elif byte == 144: self.right(self.arg(2, True)) - elif byte == 145: self.right(self.arg(3, True)) - elif byte == 146: self.right(self.arg(4, True)) - elif byte == 147: self.right_w(None) - elif byte == 148: self.right_w(self.arg(1, True)) - elif byte == 149: self.right_w(self.arg(2, True)) - elif byte == 150: self.right_w(self.arg(3, True)) - elif byte == 151: self.right_w(self.arg(4, True)) - elif byte == 152: self.right_x(None) - elif byte == 153: self.right_x(self.arg(1, True)) - elif byte == 154: self.right_x(self.arg(2, True)) - elif byte == 155: self.right_x(self.arg(3, True)) - elif byte == 156: self.right_x(self.arg(4, True)) - elif byte == 157: self.down(self.arg(1, True)) - elif byte == 158: self.down(self.arg(2, True)) - elif byte == 159: self.down(self.arg(3, True)) - elif byte == 160: self.down(self.arg(4, True)) - elif byte == 161: self.down_y(None) - elif byte == 162: self.down_y(self.arg(1, True)) - elif byte == 163: self.down_y(self.arg(2, True)) - elif byte == 164: self.down_y(self.arg(3, True)) - elif byte == 165: self.down_y(self.arg(4, True)) - elif byte == 166: self.down_z(None) - elif byte == 167: self.down_z(self.arg(1, True)) - elif byte == 168: self.down_z(self.arg(2, True)) - elif byte == 169: self.down_z(self.arg(3, True)) - elif byte == 170: self.down_z(self.arg(4, True)) - elif 171 <= byte <= 234: self.fnt_num(byte-171) - elif byte == 235: self.fnt_num(self.arg(1)) - elif byte == 236: self.fnt_num(self.arg(2)) - elif byte == 237: self.fnt_num(self.arg(3)) - elif byte == 238: self.fnt_num(self.arg(4, True)) + def _dispatch(self, byte): + """ + Based on the opcode "byte", read the correct kinds of + arguments from the dvi file and call the method implementing + that opcode with those arguments. + """ + if 0 <= byte <= 127: self._set_char(byte) + elif byte == 128: self._set_char(self._arg(1)) + elif byte == 129: self._set_char(self._arg(2)) + elif byte == 130: self._set_char(self._arg(3)) + elif byte == 131: self._set_char(self._arg(4, True)) + elif byte == 132: self._set_rule(self._arg(4, True), self._arg(4, True)) + elif byte == 133: self._put_char(self._arg(1)) + elif byte == 134: self._put_char(self._arg(2)) + elif byte == 135: self._put_char(self._arg(3)) + elif byte == 136: self._put_char(self._arg(4, True)) + elif byte == 137: self._put_rule(self._arg(4, True), self._arg(4, True)) + elif byte == 138: self._nop() + elif byte == 139: self._bop(*[self._arg(4, True) for i in range(11)]) + elif byte == 140: self._eop() + elif byte == 141: self._push() + elif byte == 142: self._pop() + elif byte == 143: self._right(self._arg(1, True)) + elif byte == 144: self._right(self._arg(2, True)) + elif byte == 145: self._right(self._arg(3, True)) + elif byte == 146: self._right(self._arg(4, True)) + elif byte == 147: self._right_w(None) + elif byte == 148: self._right_w(self._arg(1, True)) + elif byte == 149: self._right_w(self._arg(2, True)) + elif byte == 150: self._right_w(self._arg(3, True)) + elif byte == 151: self._right_w(self._arg(4, True)) + elif byte == 152: self._right_x(None) + elif byte == 153: self._right_x(self._arg(1, True)) + elif byte == 154: self._right_x(self._arg(2, True)) + elif byte == 155: self._right_x(self._arg(3, True)) + elif byte == 156: self._right_x(self._arg(4, True)) + elif byte == 157: self._down(self._arg(1, True)) + elif byte == 158: self._down(self._arg(2, True)) + elif byte == 159: self._down(self._arg(3, True)) + elif byte == 160: self._down(self._arg(4, True)) + elif byte == 161: self._down_y(None) + elif byte == 162: self._down_y(self._arg(1, True)) + elif byte == 163: self._down_y(self._arg(2, True)) + elif byte == 164: self._down_y(self._arg(3, True)) + elif byte == 165: self._down_y(self._arg(4, True)) + elif byte == 166: self._down_z(None) + elif byte == 167: self._down_z(self._arg(1, True)) + elif byte == 168: self._down_z(self._arg(2, True)) + elif byte == 169: self._down_z(self._arg(3, True)) + elif byte == 170: self._down_z(self._arg(4, True)) + elif 171 <= byte <= 234: self._fnt_num(byte-171) + elif byte == 235: self._fnt_num(self._arg(1)) + elif byte == 236: self._fnt_num(self._arg(2)) + elif byte == 237: self._fnt_num(self._arg(3)) + elif byte == 238: self._fnt_num(self._arg(4, True)) elif 239 <= byte <= 242: - len = self.arg(byte-238) + len = self._arg(byte-238) special = self.file.read(len) - self.xxx(special) + self._xxx(special) elif 243 <= byte <= 246: - k = self.arg(byte-242, byte==246) - c, s, d, a, l = [ self.arg(x) for x in (4, 4, 4, 1, 1) ] + k = self._arg(byte-242, byte==246) + c, s, d, a, l = [ self._arg(x) for x in (4, 4, 4, 1, 1) ] n = self.file.read(a+l) - self.fnt_def(k, c, s, d, a, l, n) + self._fnt_def(k, c, s, d, a, l, n) elif byte == 247: - i, num, den, mag, k = [ self.arg(x) for x in (1, 4, 4, 4, 1) ] + i, num, den, mag, k = [ self._arg(x) for x in (1, 4, 4, 4, 1) ] x = self.file.read(k) - self.pre(i, num, den, mag, x) - elif byte == 248: self.post() - elif byte == 249: self.post_post() + self._pre(i, num, den, mag, x) + elif byte == 248: self._post() + elif byte == 249: self._post_post() else: raise ValueError, "unknown command: byte %d"%byte - def pre(self, i, num, den, mag, comment): - if self.state != dvistate.pre: + def _pre(self, i, num, den, mag, comment): + if self.state != _dvistate.pre: raise ValueError, "pre command in middle of dvi file" if i != 2: raise ValueError, "Unknown dvi format %d"%i @@ -159,111 +214,116 @@ raise ValueError, "nonstandard magnification in dvi file" # meaning: LaTeX seems to frown on setting \mag, so # I think we can assume this is constant - self.state = dvistate.outer + self.state = _dvistate.outer - def set_char(self, char): - if self.state != dvistate.inpage: + def _set_char(self, char): + if self.state != _dvistate.inpage: raise ValueError, "misplaced set_char in dvi file" - self.put_char(char) + self._put_char(char) font = self.fonts[self.f] width = font.tfm.width[char] width = (width * font.scale) >> 20 self.h += width - def set_rule(self, a, b): - if self.state != dvistate.inpage: + def _set_rule(self, a, b): + if self.state != _dvistate.inpage: raise ValueError, "misplaced set_rule in dvi file" - self.put_rule(a, b) + self._put_rule(a, b) self.h += b - def put_char(self, char): - if self.state != dvistate.inpage: + def _put_char(self, char): + if self.state != _dvistate.inpage: raise ValueError, "misplaced put_char in dvi file" self.text.append((self.h, self.v, self.f, char)) - def put_rule(self, a, b): - if self.state != dvistate.inpage: + def _put_rule(self, a, b): + if self.state != _dvistate.inpage: raise ValueError, "misplaced put_rule in dvi file" if a > 0 and b > 0: self.boxes.append((self.h, self.v, a, b)) - def nop(self): + def _nop(self): pass - def bop(self, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, p): - if self.state != dvistate.outer: + def _bop(self, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, p): + if self.state != _dvistate.outer: + print '+++', self.state raise ValueError, "misplaced bop in dvi file" - self.state = dvistate.inpage + self.state = _dvistate.inpage self.h, self.v, self.w, self.x, self.y, self.z = 0, 0, 0, 0, 0, 0 self.stack = [] + self.text = [] # list of (x,y,fontnum,glyphnum) + self.boxes = [] # list of (x,y,width,height) - def eop(self): - if self.state != dvistate.inpage: + def _eop(self): + if self.state != _dvistate.inpage: raise ValueError, "misplaced eop in dvi file" - self.state = dvistate.outer + self.state = _dvistate.outer del self.h, self.v, self.w, self.x, self.y, self.z, self.stack - def push(self): - if self.state != dvistate.inpage: + def _push(self): + if self.state != _dvistate.inpage: raise ValueError, "misplaced push in dvi file" self.stack.append((self.h, self.v, self.w, self.x, self.y, self.z)) - def pop(self): - if self.state != dvistate.inpage: + def _pop(self): + if self.state != _dvistate.inpage: raise ValueError, "misplaced pop in dvi file" self.h, self.v, self.w, self.x, self.y, self.z = self.stack.pop() - def right(self, b): - if self.state != dvistate.inpage: + def _right(self, b): + if self.state != _dvistate.inpage: raise ValueError, "misplaced right in dvi file" self.h += b - def right_w(self, new_w): - if self.state != dvistate.inpage: + def _right_w(self, new_w): + if self.state != _dvistate.inpage: raise ValueError, "misplaced w in dvi file" if new_w is not None: self.w = new_w self.h += self.w - def right_x(self, new_x): - if self.state != dvistate.inpage: + def _right_x(self, new_x): + if self.state != _dvistate.inpage: raise ValueError, "misplaced x in dvi file" if new_x is not None: self.x = new_x self.h += self.x - def down(self, a): - if self.state != dvistate.inpage: + def _down(self, a): + if self.state != _dvistate.inpage: raise ValueError, "misplaced down in dvi file" self.v += a - def down_y(self, new_y): - if self.state != dvistate.inpage: + def _down_y(self, new_y): + if self.state != _dvistate.inpage: raise ValueError, "misplaced y in dvi file" if new_y is not None: self.y = new_y self.v += self.y - def down_z(self, new_z): - if self.state != dvistate.inpage: + def _down_z(self, new_z): + if self.state != _dvistate.inpage: raise ValueError, "misplaced z in dvi file" if new_z is not None: self.z = new_z self.v += self.z - def fnt_num(self, k): - if self.state != dvistate.inpage: + def _fnt_num(self, k): + if self.state != _dvistate.inpage: raise ValueError, "misplaced fnt_num in dvi file" self.f = k - def xxx(self, special): - pass + def _xxx(self, special): + matplotlib.verbose.report( + 'Dvi._xxx: encountered special: %s' + % ''.join((32 <= ord(ch) < 127) and ch + or '<%02x>' % ord(ch) + for ch in special), + 'debug') - def fnt_def(self, k, c, s, d, a, l, n): - filename = n[-l:] + '.tfm' - pipe = os.popen('kpsewhich ' + filename, 'r') - filename = pipe.readline().rstrip() - pipe.close() + def _fnt_def(self, k, c, s, d, a, l, n): + filename = find_tex_file(n[-l:] + '.tfm') tfm = Tfm(filename) if c != 0 and tfm.checksum != 0 and c != tfm.checksum: raise ValueError, 'tfm checksum mismatch: %s'%n @@ -271,41 +331,186 @@ #if d != tfm.design_size: # raise ValueError, 'tfm design size mismatch: %d in dvi, %d in %s'%\ # (d, tfm.design_size, n) - self.fonts[k] = Bunch(scale=s, tfm=tfm, name=n) + self.fonts[k] = mpl_cbook.Bunch(scale=s, tfm=tfm, name=n) - def post(self): - raise NotImplementedError + def _post(self): + if self.state != _dvistate.outer: + raise ValueError, "misplaced post in dvi file" + self.state = _dvistate.post_post + # TODO: actually read the postamble and finale? + # currently post_post just triggers closing the file - def post_post(self): + def _post_post(self): raise NotImplementedError class Tfm(object): + """ + A TeX Font Metric file. This implementation covers only the bare + minimum needed by the Dvi class. + Attributes: + checksum: for verifying against dvi file + design_size: design size of the font (in what units?) + width[i]: width of character #i, needs to be scaled + by the factor specified in the dvi file + (this is a dict because indexing may not start from 0) + """ + def __init__(self, filename): file = open(filename, 'rb') - header1 = file.read(24) - lh, bc, ec, nw = \ - struct.unpack('!4H', header1[2:10]) - header2 = file.read(4*lh) - self.checksum, self.design_size = \ - struct.unpack('!2I', header2[:8]) - # plus encoding information etc. + try: + header1 = file.read(24) + lh, bc, ec, nw = \ + struct.unpack('!4H', header1[2:10]) + header2 = file.read(4*lh) + self.checksum, self.design_size = \ + struct.unpack('!2I', header2[:8]) + # there is also encoding information etc. + char_info = file.read(4*(ec-bc+1)) + widths = file.read(4*nw) + finally: + file.close() - char_info = file.read(4*(ec-bc+1)) - widths = file.read(4*nw) - - file.close() - widths = struct.unpack('!%dI' % nw, widths) self.width = {} for i in range(ec-bc): self.width[bc+i] = widths[ord(char_info[4*i])] +class PsfontsMap(object): + """ + A psfonts.map formatted file, mapping TeX fonts to PS fonts. + Usage: map = PsfontsMap('.../psfonts.map'); map['cmr10'] + + For historical reasons, TeX knows many Type-1 fonts by different + names than the outside world. (For one thing, the names have to + fit in eight characters.) Also, TeX's native fonts are not Type-1 + but Metafont, which is nontrivial to convert to PostScript except + as a bitmap. While high-quality conversions to Type-1 format exist + and are shipped with modern TeX distributions, we need to know + which Type-1 fonts are the counterparts of which native fonts. For + these reasons a mapping is needed from internal font names to font + file names. + + A texmf tree typically includes mapping files called e.g. + psfonts.map, pdftex.map, dvipdfm.map. psfonts.map is used by + dvips, pdftex.map by pdfTeX, and dvipdfm.map by dvipdfm. + psfonts.map might avoid embedding the 35 PostScript fonts, while + the pdf-related files perhaps only avoid the "Base 14" pdf fonts. + But the user may have configured these files differently. + """ + + def __init__(self, filename): + self._font = {} + file = open(filename, 'rt') + try: + self._parse(file) + finally: + file.close() + + def __getitem__(self, texname): + result = self._font[texname] + if result.filename is not None \ + and not result.filename.startswith('/'): + result.filename = find_tex_file(result.filename) + if result.encoding is not None \ + and not result.encoding.startswith('/'): + result.encoding = find_tex_file(result.encoding) + return result + + def _parse(self, file): + """Parse each line into words.""" + for line in file: + line = line.strip() + if line == '' or line.startswith('%'): + continue + words, pos = [], 0 + while pos < len(line): + if line[pos] == '"': # double quoted word + pos += 1 + end = line.index('"', pos) + words.append(line[pos:end]) + pos = end + 1 + else: # ordinary word + end = line.find(' ', pos+1) + if end == -1: end = len(line) + words.append(line[pos:end]) + pos = end + while pos < len(line) and line[pos] == ' ': + pos += 1 + self._register(words) + + def _register(self, words): + """Register a font described by "words". + + The format is, AFAIK: texname fontname [effects and filenames] + Effects are PostScript snippets like ".177 SlantFont", + filenames begin with one or two less-than signs. A filename + ending in enc is an encoding file, other filenames are font + files. This can be overridden with a left bracket: <[foobar + indicates an encoding file named foobar. + + There is some difference between <foo.pfb and <<bar.pfb in + subsetting, but I have no example of << in my TeX installation. + """ + texname, psname = words[:2] + effects, encoding, filename = [], None, None + for word in words[2:]: + if not word.startswith('<'): + effects.append(word) + else: + word = word.lstrip('<') + if word.startswith('['): + assert encoding is None + encoding = word[1:] + elif word.endswith('.enc'): + assert encoding is None + encoding = word + else: + assert filename is None + filename = word + self._font[texname] = mpl_cbook.Bunch( + texname=texname, psname=psname, effects=effects, + encoding=encoding, filename=filename) + +def find_tex_file(filename, format=None): + """ + Call kpsewhich to find a file in the texmf tree. + If format is not None, it is used as the value for the --format option. + See the kpathsea documentation for more information. + + Apparently most existing TeX distributions on Unix-like systems + use kpathsea. I hear MikTeX (a popular distribution on Windows) + doesn't use kpathsea, so what do we do? (TODO) + """ + + cmd = 'kpsewhich ' + if format is not None: + assert "'" not in format + cmd += "--format='" + format + "' " + assert "'" not in filename + cmd += "'" + filename + "'" + + pipe = os.popen(cmd, 'r') + result = pipe.readline().rstrip() + pipe.close() + + return result + if __name__ == '__main__': - dvi = Dvi('foo.dvi') - dvi.read(debug=True) - for x,y,f,c in dvi.text: - print x,y,c,chr(c),dvi.fonts[f].__dict__ - print dvi.output(72) + matplotlib.verbose.set_level('debug') + dvi = Dvi('foo.dvi', 72) + fontmap = PsfontsMap(find_tex_file('pdftex.map')) + for text,boxes in dvi: + print '=== new page ===' + fPrev = None + for x,y,f,c in text: + texname = dvi.fonts[f].name + print x,y,c,chr(c),texname + if f != fPrev: + print 'font', texname, '=', fontmap[texname].__dict__ + fPrev = f + for x,y,w,h in boxes: + print x,y,'BOX',w,h + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.