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 import bbox
, canvasitem
, 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(self
.content
)
77 class mesh(canvasitem
.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 "".join(["\000%s%s%s" % (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
.to8bitstring())
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
116 fd
, fname
= tempfile
.mkstemp()
117 f
= os
.fdopen(fd
, "wb")
119 c
.pipeGS(fname
, device
="pngalpha", resolution
=writer
.mesh_as_bitmap_resolution
)
120 i
= Image
.open(fname
)
122 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
, self
.bbox().lly_pt
, i
)
123 # we slightly shift the bitmap to re-center it, as the bitmap might contain some additional border
124 # unfortunately we need to construct another bitmap instance for that ...
125 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
+ 0.5*(self
.bbox().width_pt()-b
.bbox().width_pt()),
126 self
.bbox().lly_pt
+ 0.5*(self
.bbox().height_pt()-b
.bbox().height_pt()), i
)
127 b
.processPS(file, writer
, context
, registry
, bbox
)
129 thisbbox
= self
.bbox()
131 file.write("""<< /ShadingType 4
133 /BitsPerCoordinate 24
136 /Decode [%f %f %f %f %s]
137 /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter
138 >> shfill\n""" % (self
.elements
[0].nodes
[0].value
.colorspacestring(),
139 thisbbox
.llx_pt
, thisbbox
.urx_pt
, thisbbox
.lly_pt
, thisbbox
.ury_pt
,
140 " ".join(["0 1" for value
in self
.elements
[0].nodes
[0].value
.to8bitstring()])))
141 file.write(binascii
.b2a_hex(zlib
.compress(self
.data(thisbbox
))))
144 def processPDF(self
, file, writer
, context
, registry
, bbox
):
145 if writer
.mesh_as_bitmap
:
146 from pyx
import bitmap
, canvas
150 fd
, fname
= tempfile
.mkstemp()
151 f
= os
.fdopen(fd
, "wb")
153 c
.pipeGS(fname
, device
="pngalpha", resolution
=writer
.mesh_as_bitmap_resolution
)
154 i
= Image
.open(fname
)
156 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
, self
.bbox().lly_pt
, i
)
157 # we slightly shift the bitmap to re-center it, as the bitmap might contain some additional border
158 # unfortunately we need to construct another bitmap instance for that ...
159 b
= bitmap
.bitmap_pt(self
.bbox().llx_pt
+ 0.5*(self
.bbox().width_pt()-b
.bbox().width_pt()),
160 self
.bbox().lly_pt
+ 0.5*(self
.bbox().height_pt()-b
.bbox().height_pt()), i
)
161 b
.processPDF(file, writer
, context
, registry
, bbox
)
163 thisbbox
= self
.bbox()
165 d
= self
.data(thisbbox
)
167 filter = "/Filter /FlateDecode\n"
171 name
= "shading-%s" % id(self
)
172 shading
= PDFGenericResource("shading", name
, """<<
175 /BitsPerCoordinate 24
178 /Decode [%f %f %f %f %s]
183 endstream\n""" % (self
.elements
[0].nodes
[0].value
.colorspacestring(),
184 thisbbox
.llx_pt
, thisbbox
.urx_pt
, thisbbox
.lly_pt
, thisbbox
.ury_pt
,
185 " ".join(["0 1" for value
in self
.elements
[0].nodes
[0].value
.to8bitstring()]),
187 registry
.add(shading
)
188 registry
.addresource("Shading", name
, shading
)
189 file.write("/%s sh\n" % name
)