├── Makefile ├── scripts └── tests │ ├── bezier-test.bash │ └── test2.svg ├── bezierenvelope.inx ├── README.pod ├── bezierenvelope.py └── LICENSE /Makefile: -------------------------------------------------------------------------------- 1 | EXTENSIONS_DIR = $(HOME)/.config/inkscape/extensions 2 | 3 | MKDIR_P = mkdir -p 4 | COPY_CMD = cp -f 5 | 6 | all: 7 | 8 | install: 9 | $(MKDIR_P) "$(EXTENSIONS_DIR)" 10 | $(COPY_CMD) bezierenvelope.inx bezierenvelope.py "$(EXTENSIONS_DIR)/" 11 | -------------------------------------------------------------------------------- /scripts/tests/bezier-test.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e -x 3 | src_path="`pwd`" 4 | test -e bezierenvelope.py 5 | test -e .git 6 | test -e scripts/tests/test2.svg 7 | if test -f "out.svg" 8 | then 9 | rm -f "out.svg" 10 | fi 11 | PYTHONPATH=/usr/share/inkscape/extensions python3 "${src_path}/bezierenvelope.py" --id=path839 --id=path837 --output "${src_path}/out.svg" "${src_path}"/scripts/tests/test2.svg 12 | inkscape "${src_path}/out.svg" 13 | -------------------------------------------------------------------------------- /bezierenvelope.inx: -------------------------------------------------------------------------------- 1 | 2 | 3 | <_name>Bezier Envelope 4 | de.gerrit_karius.envelope 5 | 6 | path 7 | 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /README.pod: -------------------------------------------------------------------------------- 1 | =encoding utf8 2 | 3 | =head1 ABOUT 4 | 5 | This is the update of the Bezier Envelope extension for Inkscape ( 6 | L - an open-source vector graphics editor) version 7 | 0.48. 8 | 9 | It is from the original author, GERRIT KARIUS. 10 | 11 | — Thanks, Gerrit. 12 | 13 | =head1 INSTRUCTIONS 14 | 15 | Clone the repository and copy the C and C 16 | files to the “Inkscape→ share→ extensions” folder. This can also be achieved by 17 | running C on UNIX flavored systems. 18 | 19 | The extension can be accessed using the “Extensions → Modify Path → Bezier Envelope” menu item. 20 | (Not to be confused with the plain “Envelope” menu item) 21 | 22 | =cut 23 | -------------------------------------------------------------------------------- /scripts/tests/test2.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 33 | 35 | 36 | 38 | image/svg+xml 39 | 41 | 42 | 43 | 44 | 45 | 49 | 53 | 57 | 61 | 65 | 69 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /bezierenvelope.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Bezier Envelope extension for Inkscape 4 | Copyright (C) 2009 Gerrit Karius 5 | 6 | This program is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU General Public License 8 | as published by the Free Software Foundation; either version 2 9 | of the License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | 20 | 21 | About the Bezier Envelope extension: 22 | 23 | This extension implements Bezier enveloping. 24 | It takes an arbitrary path (the "letter") and a 4-sided path 25 | (the "envelope") as input. 26 | The envelope must be 4 segments long. Unless the letter is to be rotated 27 | or flipped, 28 | the envelope should begin at the upper left corner and be drawn clockwise. 29 | The extension then attempts to squeeze the letter into the envelope 30 | by rearranging all anchor and handle points of the letter's path. 31 | 32 | In order to do this, the bounding box of the letter is used. 33 | All anchor and bezier handle points get new x and y coordinates 34 | between 0% and 100% 35 | according to their place inside the bounding box. 36 | The 4 sides of the envelope are then interpreted as deformed axes. 37 | Points at 0% or 100% could be placed along these axes, but because most points 38 | are somewhere inside the bounding box, some tweening of the axes must be done. 39 | 40 | The function map_points_to_morph does the tweening. 41 | Say, some point is at x=30%, y=40%. 42 | For the tweening, the function tween_cubic first calculates a straight tween 43 | of the y axis at the x percentage of 30%. 44 | This tween axis now floats somewhere between the y axis keys 45 | at the x percentage, 46 | but is not necessarily inside the envelope, because the x 47 | axes are not straight. 48 | Now, the end points on the two x axes at 30% are calculated. The function 49 | match() 50 | takes these points and calculates a "stretch" transform which maps the two 51 | anchor 52 | points of the y axis tween to the two points on the x axes by rotating the 53 | tween and 54 | stretching it along its endpoints. This transform is then applied to the handle 55 | points, 56 | to get the entire tweened y axis to its x tweened position. 57 | Last, the point at the y percentage 40% of this y axis tween is calculated. 58 | That is the final point of the enveloped letter. 59 | 60 | Finally, after all of the letter's points have been recalculated in 61 | this manner, 62 | the resulting path is taken and replaces the letter's original path. 63 | 64 | TODO: 65 | * Some points of the letter appear outside the envelope, apparently 66 | because the bounding box 67 | calculated by simpletransform.py is only a rough estimate. 68 | -> Calculate the real bbox, 69 | perhaps using other existing extensions, or py2geom. 70 | * Currently, both letter and envelope must be paths to work. 71 | -> Arbitrary other shapes like circles and rectangles should be 72 | interpreted as paths. 73 | * It should be possible to select several letters, and squeeze them into 74 | one envelope as a group. 75 | * It should be possible to insert a clone of the letter, instead of 76 | replacing it. 77 | * Bug #241565 prevented the matrix parser constructors from working. 78 | This extension can 79 | only be used with the fixed version of simpletransform.py. 80 | As a workaround, two matrix constructors 81 | were copied into this file. 82 | * This program was originally written in Java. Maybe for some code, 83 | Python shortcuts can be used. 84 | 85 | I hope the comments are not too verbose. Enjoy! 86 | 87 | ''' 88 | import math 89 | import sys 90 | 91 | import inkex 92 | from inkex import Transform 93 | from inkex import paths 94 | from inkex.paths import Path 95 | 96 | # from ffgeom import * 97 | # import ffgeom 98 | 99 | 100 | class BezierEnvelope(inkex.Effect): 101 | 102 | segmentTypes = ["move", "line", "quad", "cubic", "close"] # noqa: N815 103 | 104 | def __init__(self): 105 | inkex.Effect.__init__(self) 106 | 107 | def effect(self): 108 | if len(self.options.ids) < 2: 109 | raise Exception( 110 | "Two paths must be selected. The 1st is " + 111 | "the letter, the 2nd is the envelope and must have 4 sides.") 112 | exit() 113 | 114 | letter_elem = self.svg.selected[self.options.ids[0]] 115 | envelope_elem = self.svg.selected[self.options.ids[1]] 116 | 117 | if (letter_elem.tag != inkex.addNS('path', 'svg') or 118 | envelope_elem.tag != inkex.addNS('path', 'svg')): 119 | raise Exception("Both letter and envelope must be SVG paths.") 120 | exit() 121 | 122 | axes = extract_morph_axes(Path(envelope_elem.get('d')).to_arrays()) 123 | if axes is None: 124 | raise Exception("No axes found on envelope.") 125 | if len(axes) < 4: 126 | raise Exception("The envelope path has less than 4 segments.") 127 | for i in range(4): 128 | if axes[i] is None: 129 | raise Exception("axes[%i] is None" % i) 130 | # morph the enveloped element according to the axes 131 | morph_element(letter_elem, envelope_elem, axes) 132 | 133 | 134 | def morph_element(letter_elem, envelope_elem, axes): 135 | path = Path(letter_elem.get('d')).to_arrays() 136 | morphed_path = morph_path(path, axes) 137 | letter_elem.set("d", str(Path(morphed_path))) 138 | 139 | 140 | # Morphs a path into a new path, according to cubic curved bounding axes. 141 | def morph_path(path, axes): 142 | bounds = [ 143 | y for x in list(Path(paths.Path(path).to_superpath()).bounding_box()) 144 | for y in list(x)] 145 | new_path = [] 146 | current = [0.0, 0.0] 147 | start = [0.0, 0.0] 148 | 149 | for cmd, params in path: 150 | segment_type = cmd 151 | points = params 152 | if segment_type == "M": 153 | start[0] = points[0] 154 | start[1] = points[1] 155 | segment_type = convert_segment_to_cubic( 156 | current, segment_type, points, start) 157 | percentages = [0.0]*len(points) 158 | morphed = [0.0]*len(points) 159 | num_points = get_num_points(segment_type) 160 | normalize_points(bounds, points, percentages, num_points) 161 | map_points_to_morph(axes, percentages, morphed, num_points) 162 | add_segment(new_path, segment_type, morphed) 163 | if len(points) >= 2: 164 | current[0] = points[len(points)-2] 165 | current[1] = points[len(points)-1] 166 | return new_path 167 | 168 | 169 | def get_num_points(segment_type): 170 | if segment_type == "M": 171 | return 1 172 | if segment_type == "L": 173 | return 1 174 | if segment_type == "Q": 175 | return 2 176 | if segment_type == "C": 177 | return 3 178 | if segment_type == "Z": 179 | return 0 180 | return -1 181 | 182 | 183 | def add_segment(path, segment_type, points): 184 | path.append([segment_type, points]) 185 | 186 | 187 | # Converts visible path segments (Z, L, Q) into absolute cubic segments (C). 188 | def convert_segment_to_cubic(current, segment_type, points, start): 189 | if segment_type == "H": 190 | # print(current, points, start) 191 | assert len(points) == 1 192 | points.insert(0, current[0]) 193 | # points[0] += current[0] 194 | # print(segmentType, current, points, start) 195 | return convert_segment_to_cubic(current, "L", points, start) 196 | if segment_type == "V": 197 | # print(points) 198 | assert len(points) == 1 199 | points.append(current[1]) 200 | # points[1] += current[1] 201 | # print(segmentType, current, points, start) 202 | return convert_segment_to_cubic(current, "L", points, start) 203 | if segment_type == "M": 204 | return "M" 205 | if segment_type == "C": 206 | return "C" 207 | elif segment_type == "Z": 208 | for i in range(6): 209 | points.append(0.0) 210 | points[4] = start[0] 211 | points[5] = start[1] 212 | third_x = (points[4] - current[0]) / 3.0 213 | third_y = (points[5] - current[1]) / 3.0 214 | points[2] = points[4]-third_x 215 | points[3] = points[5]-third_y 216 | points[0] = current[0]+third_x 217 | points[1] = current[1]+third_y 218 | return "C" 219 | elif segment_type == "L": 220 | for i in range(4): 221 | points.append(0.0) 222 | points[4] = points[0] 223 | points[5] = points[1] 224 | third_x = (points[4] - current[0]) / 3.0 225 | third_y = (points[5] - current[1]) / 3.0 226 | points[2] = points[4]-third_x 227 | points[3] = points[5]-third_y 228 | points[0] = current[0]+third_x 229 | points[1] = current[1]+third_y 230 | return "C" 231 | elif segment_type == "Q": 232 | for i in range(2): 233 | points.append(0.0) 234 | first_third_x = (points[0] - current[0]) * 2.0 / 3.0 235 | first_third_y = (points[1] - current[1]) * 2.0 / 3.0 236 | second_third_x = (points[2] - points[0]) * 2.0 / 3.0 237 | second_third_y = (points[3] - points[1]) * 2.0 / 3.0 238 | points[4] = points[2] 239 | points[5] = points[3] 240 | points[0] = current[0] + first_third_x 241 | points[1] = current[1] + first_third_y 242 | points[2] = points[2] - second_third_x 243 | points[3] = points[3] - second_third_y 244 | return "C" 245 | else: 246 | sys.stderr.write("unsupported segment type: %s\n" % (segment_type)) 247 | return segment_type 248 | 249 | 250 | # Normalizes the points of a path segment, so that they are expressed as 251 | # percentage coordinates 252 | # relative to the bounding box axes of the total shape. 253 | # @param bounds The bounding box of the shape. 254 | # @param points The points of the segment. 255 | # @param percentages The returned points in normalized percentage form. 256 | # @param num_points 257 | def normalize_points(bounds, points, percentages, num_points): 258 | # bounds has structure xmin, xmax, ymin, yMax 259 | xmin, xmax, ymin, ymax = bounds 260 | for i in range(num_points): 261 | x = i*2 262 | y = i*2+1 263 | percentages[x] = (points[x] - xmin) / (xmax-xmin) 264 | percentages[y] = (points[y] - ymin) / (ymax-ymin) 265 | 266 | 267 | # Extracts 4 axes from a path. It is assumed that the path 268 | # starts with a move, followed by 4 cubic paths. 269 | # The extraction reverses the last 2 axes, 270 | # so that they run in parallel with the first 2. 271 | # @param path The path that is formed by the axes. 272 | # @return The definition points of the 4 cubic path axes as 273 | # float arrays, bundled in another array. 274 | def extract_morph_axes(path): 275 | points = [] 276 | current = [0.0, 0.0] 277 | start = [0.0, 0.0] 278 | # the curved axis definitions go in here 279 | axes = [None]*4 280 | i = 0 281 | 282 | for cmd, params in path: 283 | points = params 284 | cmd = convert_segment_to_cubic(current, cmd, points, start) 285 | 286 | if cmd == "M": 287 | current[0] = points[0] 288 | current[1] = points[1] 289 | start[0] = points[0] 290 | start[1] = points[1] 291 | 292 | elif cmd == "C": 293 | 294 | # 1st cubic becomes x axis 0 295 | # 2nd cubic becomes y axis 1 296 | # 3rd cubic becomes x axis 2 and is reversed 297 | # 4th cubic becomes y axis 3 and is reversed 298 | if i % 2 == 0: 299 | index = i 300 | else: 301 | index = 4-i 302 | if(i < 2): 303 | # axes 1 and 2 304 | axes[index] = current[0:2] + points[0:6] 305 | elif(i < 4): 306 | # axes 3 and 4 307 | axes[index] = [ 308 | points[4], points[5], points[2], points[3], 309 | points[0], points[1], current[0], current[1] 310 | ] 311 | else: 312 | # more than 4 axes - hopefully it was an unnecessary trailing Z 313 | {} 314 | current[0] = points[4] 315 | current[1] = points[5] 316 | i = i + 1 317 | elif cmd == "Z": 318 | # do nothing 319 | pass 320 | else: 321 | raise Exception("Unsupported segment type: %s" % cmd) 322 | return None 323 | 324 | return axes 325 | 326 | 327 | # Projects points in percentage coordinates into a morphed coordinate 328 | # system that is framed 329 | # by 2 x cubic curves (along the x axis) and 2 y cubic curves 330 | # (along the y axis). 331 | # @param axes The x and y axes of the envelope. 332 | # @param percentage The current segment of the letter in 333 | # normalized percentage form. 334 | # @param morphed The array to hold the returned morphed path. 335 | # @param num_points The number of points to be transformed. 336 | def map_points_to_morph(axes, percentage, morphed, num_points): 337 | # rename the axes for legibility 338 | y_cubic_0 = axes[1] 339 | y_cubic_1 = axes[3] 340 | x_cubic_0 = axes[0] 341 | x_cubic_1 = axes[2] 342 | # morph each point 343 | for i in range(0, num_points): 344 | x = i*2 345 | y = i*2+1 346 | # tween between the morphed y axes according to the x percentage 347 | tweened_y = tween_cubic(y_cubic_0, y_cubic_1, percentage[x]) 348 | # get 2 points on the morphed x axes 349 | x_spot_0 = calc_point_on_cubic(x_cubic_0, percentage[x]) 350 | x_spot_1 = calc_point_on_cubic(x_cubic_1, percentage[x]) 351 | # create a transform that stretches the 352 | # y axis tween between these 2 points 353 | y_anchor_0 = [tweened_y[0], tweened_y[1]] 354 | y_anchor_1 = [tweened_y[6], tweened_y[7]] 355 | x_transform = match(y_anchor_0, y_anchor_1, x_spot_0, x_spot_1) 356 | # map the y axis tween to the 2 points by 357 | # applying the stretch transform 358 | for j in range(4): 359 | x2 = j*2 360 | y2 = j*2+1 361 | point_on_y = [tweened_y[x2], tweened_y[y2]] 362 | Transform(x_transform).apply_to_point(point_on_y) 363 | tweened_y[x2] = point_on_y[0] 364 | tweened_y[y2] = point_on_y[1] 365 | # get the point on the tweened and transformed y axis 366 | # according to the y percentage 367 | morphed_point = calc_point_on_cubic(tweened_y, percentage[y]) 368 | morphed[x] = morphed_point[0] 369 | morphed[y] = morphed_point[1] 370 | 371 | 372 | # Calculates the point on a cubic bezier curve at the given percentage. 373 | def calc_point_on_cubic(c, t): 374 | point = [0.0, 0.0] 375 | _t_2 = t*t 376 | _t_3 = _t_2*t 377 | _1_t = 1-t 378 | _1_t_2 = _1_t*_1_t 379 | _1_t_3 = _1_t_2*_1_t 380 | 381 | for i in range(0, 2): 382 | point[i] = c[i]*_1_t_3 + 3*c[2+i]*_1_t_2*t + \ 383 | 3*c[4+i]*_1_t*_t_2 + c[6+i]*_t_3 384 | return point 385 | 386 | 387 | # Tweens 2 bezier curves in a straightforward way, 388 | # i.e. each of the points on the curve is tweened along a straight line 389 | # between the respective point on key1 and key2. 390 | def tween_cubic(key1, key2, percentage): 391 | tween = [] 392 | for i in range(len(key1)): 393 | tween.append(key1[i] + percentage * (key2[i] - key1[i])) 394 | return tween 395 | 396 | 397 | # Calculates a transform that matches 2 points to 2 anchors 398 | # by rotating and scaling (up or down) along the axis that is formed by 399 | # a line between the two points. 400 | def match(p1, p2, a1, a2): 401 | x = 0 402 | y = 1 403 | # distances 404 | dp = [p2[x]-p1[x], p2[y]-p1[y]] 405 | da = [a2[x]-a1[x], a2[y]-a1[y]] 406 | # angles 407 | angle_p = math.atan2(dp[x], dp[y]) 408 | angle_a = math.atan2(da[x], da[y]) 409 | # radians 410 | # rp = math.sqrt(dp[x]*dp[x] + dp[y]*dp[y]) 411 | # ra = math.sqrt(da[x]*da[x] + da[y]*da[y]) 412 | rp = math.hypot(dp[x], dp[y]) 413 | ra = math.hypot(da[x], da[y]) 414 | # scale 415 | scale = ra / rp 416 | # transforms in the order they are applied 417 | t1 = Transform("translate(%f,%f)" % (-p1[x], -p1[y])).matrix 418 | # t2 = simpletransform.parseTransform("rotate(%f)"%(-angle_p)) 419 | # t3 = simpletransform.parseTransform("scale(%f,%f)"%(scale, scale)) 420 | # t4 = simpletransform.parseTransform("rotate(%f)"%angle_a) 421 | t2 = rotate_transform(-angle_p) 422 | t3 = scale_transform(scale, scale) 423 | t4 = rotate_transform(angle_a) 424 | t5 = Transform("translate(%f,%f)" % (a1[x], a1[y])).matrix 425 | # transforms in the order they are multiplied 426 | t = t5 427 | t = Transform(t) * Transform(t4) 428 | t = Transform(t) * Transform(t3) 429 | t = Transform(t) * Transform(t2) 430 | t = Transform(t) * Transform(t1) 431 | # return the combined transform 432 | return t 433 | 434 | 435 | def rotate_transform(a): 436 | c = math.cos(a) 437 | s = math.sin(a) 438 | return [[c, -s, 0], [s, c, 0]] 439 | 440 | 441 | def scale_transform(sx, sy): 442 | return [[sx, 0, 0], [0, sy, 0]] 443 | 444 | 445 | e = BezierEnvelope() 446 | e.run() 447 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------