1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2006-2011 André Wobst <wobsta@users.sourceforge.net>
6 # This file is part of PyX (http://pyx.sourceforge.net/).
8 # PyX is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # PyX is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with PyX; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 # Just a quick'n'dirty ascii art (I'll do a nice PyX plot later on):
31 # neighbor3 |element * node3
39 import struct
, binascii
, zlib
, os
, tempfile
40 from . import bbox
, baseclasses
, color
, pdfwriter
, unit
45 def __init__(self
, coords_pt
, value
):
46 self
.coords_pt
= coords_pt
52 def __init__(self
, coords
, value
):
53 node_pt
.__init
__(self
, [unit
.topt(coord
) for coord
in coords
], value
)
58 def __init__(self
, nodes
, neighbors
=None):
60 self
.neighbors
= neighbors
63 def coords24bit_pt(coords_pt
, min_pt
, max_pt
):
64 return struct
.pack(">I", int((coords_pt
-min_pt
)*16777215.0/(max_pt
-min_pt
)))[1:]
67 class PDFGenericResource(pdfwriter
.PDFobject
):
69 def __init__(self
, type, name
, content
):
70 pdfwriter
.PDFobject
.__init
__(self
, type, name
)
71 self
.content
= content
73 def write(self
, file, writer
, registry
):
74 file.write_bytes(self
.content
)
77 class mesh(baseclasses
.canvasitem
):
79 def __init__(self
, elements
, check
=1):
80 self
.elements
= elements
83 for element
in elements
:
84 if len(element
.nodes
) != 3:
85 raise ValueError("triangular mesh expected")
87 for node
in element
.nodes
:
88 if not colorspacestring
:
89 colorspacestring
= node
.value
.colorspacestring()
90 elif node
.value
.colorspacestring() != colorspacestring
:
91 raise ValueError("color space mismatch")
92 except AttributeError:
93 raise ValueError("gray, rgb or cmyk color values expected")
94 for node
in element
.nodes
:
95 if len(node
.coords_pt
) != 2:
96 raise ValueError("two dimensional coordinates expected")
99 return bbox
.bbox_pt(min([node
.coords_pt
[0] for element
in self
.elements
for node
in element
.nodes
]),
100 min([node
.coords_pt
[1] for element
in self
.elements
for node
in element
.nodes
]),
101 max([node
.coords_pt
[0] for element
in self
.elements
for node
in element
.nodes
]),
102 max([node
.coords_pt
[1] for element
in self
.elements
for node
in element
.nodes
]))
104 def data(self
, bbox
):
105 return b
"".join([b
"\000" + coords24bit_pt(node
.coords_pt
[0], bbox
.llx_pt
, bbox
.urx_pt
) +
106 coords24bit_pt(node
.coords_pt
[1], bbox
.lly_pt
, bbox
.ury_pt
) +
107 node
.value
.to8bitbytes()
108 for element
in self
.elements
for node
in element
.nodes
])
110 def processPS(self
, file, writer
, context
, registry
, bbox
):
111 if writer
.mesh_as_bitmap
:
112 from pyx
import bitmap
, canvas
113 from PIL
import Image
116 i
= Image
.open(c
.pipeGS("pngalpha", resolution
=writer
.mesh_as_bitmap_resolution
))
118 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
, self
.bbox().lly_pt
, i
)
119 # we slightly shift the bitmap to re-center it, as the bitmap might contain some additional border
120 # unfortunately we need to construct another bitmap instance for that ...
121 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
+ 0.5*(self
.bbox().width_pt()-b
.bbox().width_pt()),
122 self
.bbox().lly_pt
+ 0.5*(self
.bbox().height_pt()-b
.bbox().height_pt()), i
)
123 b
.processPS(file, writer
, context
, registry
, bbox
)
125 thisbbox
= self
.bbox()
127 file.write("""<< /ShadingType 4
129 /BitsPerCoordinate 24
132 /Decode [%f %f %f %f %s]
133 /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter
134 >> shfill\n""" % (self
.elements
[0].nodes
[0].value
.colorspacestring(),
135 thisbbox
.llx_pt
, thisbbox
.urx_pt
, thisbbox
.lly_pt
, thisbbox
.ury_pt
,
136 " ".join(["0 1" for value
in self
.elements
[0].nodes
[0].value
.to8bitbytes()])))
137 file.write_bytes(binascii
.b2a_hex(zlib
.compress(self
.data(thisbbox
))))
140 def processPDF(self
, file, writer
, context
, registry
, bbox
):
141 if writer
.mesh_as_bitmap
:
142 from pyx
import bitmap
, canvas
143 from PIL
import Image
146 i
= Image
.open(c
.pipeGS("pngalpha", resolution
=writer
.mesh_as_bitmap_resolution
))
148 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
, self
.bbox().lly_pt
, i
)
149 # we slightly shift the bitmap to re-center it, as the bitmap might contain some additional border
150 # unfortunately we need to construct another bitmap instance for that ...
151 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
+ 0.5*(self
.bbox().width_pt()-b
.bbox().width_pt()),
152 self
.bbox().lly_pt
+ 0.5*(self
.bbox().height_pt()-b
.bbox().height_pt()), i
)
153 b
.processPDF(file, writer
, context
, registry
, bbox
)
155 thisbbox
= self
.bbox()
157 d
= self
.data(thisbbox
)
159 filter = "/Filter /FlateDecode\n"
163 name
= "shading-%s" % id(self
)
164 shading
= PDFGenericResource("shading", name
, ("""<<
167 /BitsPerCoordinate 24
170 /Decode [%f %f %f %f %s]
174 """ % (self
.elements
[0].nodes
[0].value
.colorspacestring(),
175 thisbbox
.llx_pt
, thisbbox
.urx_pt
, thisbbox
.lly_pt
, thisbbox
.ury_pt
,
176 " ".join(["0 1" for value
in self
.elements
[0].nodes
[0].value
.to8bitbytes()]),
177 len(d
), filter)).encode('ascii') + d
+ b
"\nendstream\n")
178 registry
.add(shading
)
179 registry
.addresource("Shading", name
, shading
)
180 file.write("/%s sh\n" % name
)