├── snippets ├── __init__.py ├── 1_shapes │ ├── __init__.py │ ├── bezier_curve.py │ ├── dashed_lines.py │ ├── basic_shapes.py │ └── line_join_line_cap.py ├── 2_transforms │ ├── __init__.py │ ├── invert_y_coordinates.py │ ├── rotate.py │ ├── matrix.py │ └── translate_and_scale.py ├── 4_patterns │ ├── __init__.py │ ├── brick.png │ ├── repeating_pattern.png │ ├── patterns.py │ └── repeating_pattern.py ├── 5_gradients │ ├── __init__.py │ ├── x.png │ ├── linear_gradient.py │ └── radial_gradients.py ├── 9_formats │ ├── __init__.py │ ├── pdf.py │ ├── png.py │ ├── ps.py │ ├── svg.py │ ├── eps.py │ └── multipage_pdf.py ├── 3_clip_and_mask │ ├── __init__.py │ ├── mask.png │ ├── church.png │ ├── example.png │ ├── masked_church.png │ ├── clip.py │ └── mask.py ├── 6_text_and_fonts │ ├── __init__.py │ └── text.py ├── 7_antialiasing │ ├── __init__.py │ └── antialiasing.py └── 8_animated_gifs │ ├── __init__.py │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── sq.gif │ ├── movie.gif │ ├── gif.py │ └── sq_logo_animated.py ├── img ├── 9_formats │ ├── pdf.pdf │ ├── png.png │ ├── multipage_pdf.pdf │ ├── svg.svg │ ├── eps.eps │ └── ps.ps ├── 2_transforms │ ├── matrix.png │ ├── rotate.png │ ├── invert_y_coordinates.png │ └── translate_and_scale.png ├── 3_clip_and_mask │ ├── clip.png │ └── mask.png ├── 4_patterns │ ├── patterns.png │ └── repeating_pattern.png ├── 8_animated_gifs │ ├── gif.gif │ └── sq_logo_animated.gif ├── 1_shapes │ ├── basic_shapes.png │ ├── bezier_curve.png │ ├── dashed_lines.png │ └── line_join_line_cap.png ├── 6_text_and_fonts │ └── text.png ├── 5_gradients │ ├── linear_gradient.png │ └── radial_gradients.png └── 7_antialiasing │ └── antialiasing.png ├── requirements.txt ├── css ├── pycairo.css └── pygments.css ├── README.md ├── template.html ├── LICENSE ├── .gitignore ├── make.py └── index.html /snippets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/1_shapes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/2_transforms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/4_patterns/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/5_gradients/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/9_formats/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/6_text_and_fonts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/7_antialiasing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/8_animated_gifs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/9_formats/pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/9_formats/pdf.pdf -------------------------------------------------------------------------------- /img/9_formats/png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/9_formats/png.png -------------------------------------------------------------------------------- /snippets/5_gradients/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/5_gradients/x.png -------------------------------------------------------------------------------- /img/2_transforms/matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/2_transforms/matrix.png -------------------------------------------------------------------------------- /img/2_transforms/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/2_transforms/rotate.png -------------------------------------------------------------------------------- /img/3_clip_and_mask/clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/3_clip_and_mask/clip.png -------------------------------------------------------------------------------- /img/3_clip_and_mask/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/3_clip_and_mask/mask.png -------------------------------------------------------------------------------- /img/4_patterns/patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/4_patterns/patterns.png -------------------------------------------------------------------------------- /img/8_animated_gifs/gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/8_animated_gifs/gif.gif -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Pygments==2.3.1 2 | numpy==1.15.4 3 | pycairo==1.16.3 4 | imageio==2.4.1 5 | Pillow==5.4.1 6 | -------------------------------------------------------------------------------- /img/1_shapes/basic_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/1_shapes/basic_shapes.png -------------------------------------------------------------------------------- /img/1_shapes/bezier_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/1_shapes/bezier_curve.png -------------------------------------------------------------------------------- /img/1_shapes/dashed_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/1_shapes/dashed_lines.png -------------------------------------------------------------------------------- /img/6_text_and_fonts/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/6_text_and_fonts/text.png -------------------------------------------------------------------------------- /img/9_formats/multipage_pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/9_formats/multipage_pdf.pdf -------------------------------------------------------------------------------- /snippets/4_patterns/brick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/4_patterns/brick.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/1.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/2.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/3.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/4.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/5.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/sq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/sq.gif -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/3_clip_and_mask/mask.png -------------------------------------------------------------------------------- /img/1_shapes/line_join_line_cap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/1_shapes/line_join_line_cap.png -------------------------------------------------------------------------------- /img/4_patterns/repeating_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/4_patterns/repeating_pattern.png -------------------------------------------------------------------------------- /img/5_gradients/linear_gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/5_gradients/linear_gradient.png -------------------------------------------------------------------------------- /img/5_gradients/radial_gradients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/5_gradients/radial_gradients.png -------------------------------------------------------------------------------- /img/7_antialiasing/antialiasing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/7_antialiasing/antialiasing.png -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/church.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/3_clip_and_mask/church.png -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/3_clip_and_mask/example.png -------------------------------------------------------------------------------- /snippets/8_animated_gifs/movie.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/8_animated_gifs/movie.gif -------------------------------------------------------------------------------- /img/2_transforms/invert_y_coordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/2_transforms/invert_y_coordinates.png -------------------------------------------------------------------------------- /img/2_transforms/translate_and_scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/2_transforms/translate_and_scale.png -------------------------------------------------------------------------------- /img/8_animated_gifs/sq_logo_animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/img/8_animated_gifs/sq_logo_animated.gif -------------------------------------------------------------------------------- /snippets/4_patterns/repeating_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/4_patterns/repeating_pattern.png -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/masked_church.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nst/PyCairoVisualDoc/HEAD/snippets/3_clip_and_mask/masked_church.png -------------------------------------------------------------------------------- /css/pycairo.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | } 4 | 5 | table, td, th { 6 | border: 1px solid black; 7 | vertical-align: top; 8 | padding: 1em; 9 | } 10 | 11 | img { 12 | border:1px solid black; 13 | } 14 | 15 | body { 16 | background-color: AliceBlue; 17 | } 18 | -------------------------------------------------------------------------------- /snippets/9_formats/pdf.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | from cairo import PDFSurface 3 | import math 4 | 5 | def draw_pdf(filename): 6 | 7 | surface = PDFSurface(filename, 320, 240) 8 | c = cairo.Context(surface) 9 | 10 | c.set_source_rgb(1, 1, 1) 11 | c.paint() 12 | 13 | c.arc(100, 80, 50, 0, 2*math.pi) 14 | c.set_source_rgba(1,0,0,1) 15 | c.fill() 16 | 17 | surface.show_page() 18 | -------------------------------------------------------------------------------- /snippets/9_formats/png.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_png(filename): 5 | 6 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 320, 240) 7 | c = cairo.Context(surface) 8 | 9 | c.set_source_rgb(1, 1, 1) 10 | c.paint() 11 | 12 | c.arc(100, 80, 50, 0, 2*math.pi) 13 | c.set_source_rgba(1,0,0,1) 14 | c.fill() 15 | 16 | surface.write_to_png(filename) 17 | -------------------------------------------------------------------------------- /snippets/9_formats/ps.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | from cairo import PSSurface 3 | import math 4 | 5 | def draw_ps(filename): 6 | 7 | surface = PSSurface(filename, 320, 240) 8 | c = cairo.Context(surface) 9 | 10 | c.set_source_rgb(1, 1, 1) 11 | c.paint() 12 | 13 | c.arc(100, 80, 50, 0, 2*math.pi) 14 | c.set_source_rgba(1,0,0,1) 15 | c.fill() 16 | 17 | surface.show_page() 18 | -------------------------------------------------------------------------------- /snippets/9_formats/svg.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | from cairo import SVGSurface 3 | import math 4 | 5 | def draw_svg_asd(filename): 6 | 7 | surface = SVGSurface(filename, 320, 240) 8 | c = cairo.Context(surface) 9 | 10 | c.set_source_rgb(1, 1, 1) 11 | c.paint() 12 | 13 | c.arc(100, 80, 50, 0, 2*math.pi) 14 | c.set_source_rgba(1,0,0,1) 15 | c.fill() 16 | 17 | surface.finish() 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyCairoVisualDoc 2 | Turns PyCairo snippets into HTML 3 | 4 | Snippets are organized in the `snippets/` module. 5 | 6 | Install the requirements with `pip install -r requirements.txt` 7 | 8 | Run the program with: `python make.py` 9 | 10 | The program generates `index.html` and `img/`. 11 | 12 | These files can be published along with `css/`. 13 | 14 | Typical output: [http://seriot.ch/pycairo/](http://seriot.ch/pycairo/) 15 | -------------------------------------------------------------------------------- /snippets/9_formats/eps.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | from cairo import PSSurface 3 | import math 4 | 5 | def draw_eps(filename): 6 | 7 | surface = PSSurface(filename, 320, 240) 8 | surface.set_eps(True) 9 | c = cairo.Context(surface) 10 | 11 | c.set_source_rgb(1, 1, 1) 12 | c.paint() 13 | 14 | c.arc(100, 80, 50, 0, 2*math.pi) 15 | c.set_source_rgba(1,0,0,1) 16 | c.fill() 17 | 18 | surface.show_page() 19 | -------------------------------------------------------------------------------- /img/9_formats/svg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets/9_formats/multipage_pdf.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | from cairo import PDFSurface 3 | import math 4 | 5 | def draw_pdf(filename): 6 | 7 | surface = PDFSurface(filename, 320, 240) 8 | c = cairo.Context(surface) 9 | 10 | c.set_source_rgb(1, 1, 1) 11 | c.paint() 12 | 13 | c.arc(150, 150, 50, 0, 2*math.pi) 14 | c.set_source_rgba(1,0,0,1) 15 | c.fill() 16 | 17 | surface.show_page() 18 | 19 | c.set_source_rgb(1, 1, 1) 20 | c.paint() 21 | 22 | c.arc(100, 100, 50, 0, 2*math.pi) 23 | c.set_source_rgba(1,0,1,1) 24 | c.fill() 25 | 26 | surface.show_page() 27 | -------------------------------------------------------------------------------- /snippets/1_shapes/bezier_curve.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_png(filename): 5 | 6 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 7 | c = cairo.Context(surface) 8 | 9 | x0, y0 = 50, 50 10 | x1, y1 = 180, 220 11 | x2, y2 = 350, 180 12 | x3, y3 = 400, 50 13 | 14 | c.move_to(x0, y0) 15 | c.curve_to(x1, y1, x2, y2, x3, y3) 16 | c.stroke() 17 | 18 | for x,y in [(x0, y0), (x1, y1), (x2, y2), (x3, y3)]: 19 | c.arc(x-2, y-2, 4, 0, 2*math.pi) 20 | c.stroke() 21 | 22 | surface.write_to_png(filename) 23 | -------------------------------------------------------------------------------- /snippets/2_transforms/invert_y_coordinates.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | 3 | def draw_line(c): 4 | c.move_to(10, 10) 5 | c.line_to(100, 100) 6 | c.stroke() 7 | 8 | def draw_png(filename): 9 | 10 | s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 11 | c = cairo.Context(s) 12 | 13 | c.set_source_rgb(1,0,0) 14 | draw_line(c) 15 | 16 | # invert y coordinates 17 | m = cairo.Matrix(yy=-1, y0=s.get_height()) 18 | c.transform(m) 19 | 20 | c.set_source_rgb(0,0,1) 21 | draw_line(c) 22 | 23 | s.write_to_png(filename) 24 | 25 | if __name__ == "__main__": 26 | 27 | draw() 28 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PyCairo Visual Documentation 6 | 7 | 8 | 9 | 10 |

PyCairo Visual Documentation

11 | 12 |
Author: Nicolas Seriot
13 | Date: {date}
14 | PyCairo Version: {pycairo_version}
15 | GitHub: https://github.com/nst/PyCairoVisualDoc
16 | 17 | {content} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /snippets/2_transforms/rotate.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_png_rotate(filename): 5 | 6 | surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, 512, 300) 7 | c = cairo.Context(surface) 8 | 9 | c.set_source_rgb(1,1,1) 10 | c.paint() 11 | 12 | c.set_source_rgb(0,0,0) 13 | 14 | c.save() 15 | c.translate(50, 50) 16 | c.rectangle(0, 0, 250, 150) 17 | c.stroke() 18 | c.restore() 19 | 20 | c.save() 21 | c.translate(250, 150) 22 | c.rotate(math.pi / 4.0) 23 | c.rectangle(0, 0, 250, 150) 24 | c.stroke() 25 | c.restore() 26 | 27 | surface.write_to_png(filename) 28 | -------------------------------------------------------------------------------- /snippets/1_shapes/dashed_lines.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | 3 | def draw_png(filename): 4 | 5 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 300) 6 | c = cairo.Context(surface) 7 | 8 | c.set_line_width(5) 9 | 10 | c.set_source_rgb(0,0,0) 11 | 12 | # 15 drawn, 10 not drawn, etc 13 | c.set_dash([15, 10]) 14 | 15 | c.move_to(50, 50) 16 | c.line_to(400, 50) 17 | c.stroke() 18 | 19 | # 10 drawn, 30 not drawn, 5 drawn, then 20 | # 10 *not* drawn, 30 drawn, 5 not drawn, etc 21 | c.set_dash([10, 30, 5]) 22 | 23 | c.move_to(50, 100) 24 | c.line_to(400, 100) 25 | c.stroke() 26 | 27 | surface.write_to_png(filename) 28 | -------------------------------------------------------------------------------- /snippets/5_gradients/linear_gradient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | 6 | def draw_png(filename): 7 | 8 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 9 | c = cairo.Context(surface) 10 | 11 | x0, y0 = 20, 20 12 | x1, y1 = 20, 220 13 | lg = cairo.LinearGradient(x0, y0, x1, y1) 14 | lg.add_color_stop_rgba(0.0, 1, 0, 0, 1) 15 | lg.add_color_stop_rgba(0.5, 0, 1, 0, 1) 16 | lg.add_color_stop_rgba(1.0, 0, 0, 1, 1) 17 | 18 | c.rectangle(20, 20, 200, 200) 19 | c.set_source(lg) 20 | c.fill() 21 | 22 | surface.write_to_png(filename) 23 | 24 | if __name__ == "__main__": 25 | 26 | draw_png("x.gif") 27 | -------------------------------------------------------------------------------- /snippets/2_transforms/matrix.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_rect(c): 5 | c.set_source_rgb(1,0,0) 6 | c.rectangle(20, 20, 150, 100) 7 | c.fill() 8 | 9 | def draw_png_asd(filename): 10 | 11 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 12 | c = cairo.Context(surface) 13 | 14 | draw_rect(c) 15 | 16 | # x_new = xx * x + xy * y + x0 17 | # y_new = yx * x + yy * y + y0 18 | 19 | # cairo.Matrix(xx, yx, 20 | # xy, yy, 21 | # x0, y0) 22 | 23 | m = cairo.Matrix(1.0, 0.5, 24 | 0, 1.0, 25 | 256, 0.0) 26 | 27 | c.transform(m) 28 | 29 | draw_rect(c) 30 | 31 | surface.write_to_png(filename) 32 | -------------------------------------------------------------------------------- /snippets/8_animated_gifs/gif.py: -------------------------------------------------------------------------------- 1 | import os 2 | import imageio 3 | 4 | def images_paths(): 5 | # ensure we can read images when working from another dir 6 | cwd = os.getcwd() 7 | dir_path = os.path.dirname(os.path.realpath(__file__)) 8 | os.chdir(dir_path) 9 | files = [os.path.sep.join([dir_path, s]) 10 | for s in os.listdir(dir_path) 11 | if s.endswith('.png')] 12 | files.sort() 13 | os.chdir(cwd) 14 | return files 15 | 16 | def draw_gif(filename): 17 | 18 | images = [] 19 | 20 | for s in images_paths(): 21 | images.append(imageio.imread(s)) 22 | 23 | imageio.mimsave(filename, images, format='GIF', duration=0.5) 24 | 25 | if __name__ == "__main__": 26 | 27 | draw_gif("movie.gif") 28 | -------------------------------------------------------------------------------- /snippets/2_transforms/translate_and_scale.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_picture(c, x, y, scale): 5 | 6 | c.save() 7 | 8 | c.translate(x, y) 9 | c.scale(scale, scale) 10 | 11 | c.set_source_rgb(1, 0, 0) 12 | c.arc(120, 120, 120, 0, 2*math.pi) 13 | c.fill() 14 | 15 | c.set_source_rgb(1, 1, 1) 16 | c.arc(160, 90, 40, 0, 2*math.pi) 17 | c.fill() 18 | 19 | c.restore() 20 | 21 | def draw_png_asd(filename): 22 | 23 | surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, 512, 300) 24 | #surface.set_device_scale(2,2) 25 | c = cairo.Context(surface) 26 | #c.set_antialias(cairo.ANTIALIAS_NONE) 27 | 28 | c.set_source_rgb(1, 1, 1) 29 | c.paint() 30 | 31 | draw_picture(c, x=30, y=30, scale=1) 32 | draw_picture(c, x=350, y=50, scale=0.5) 33 | draw_picture(c, x=290, y=170, scale=0.25) 34 | 35 | surface.write_to_png(filename) 36 | -------------------------------------------------------------------------------- /snippets/1_shapes/basic_shapes.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | 4 | def draw_png(filename): 5 | 6 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 7 | c = cairo.Context(surface) 8 | 9 | # background 10 | c.set_source_rgb(1,1,1) 11 | c.paint() 12 | 13 | # lines 14 | c.set_source_rgb(0,0,0) 15 | c.move_to(50, 100) 16 | c.line_to(100, 150) 17 | c.rel_line_to(150, -100) 18 | c.rel_move_to(-10, -10) 19 | c.rel_line_to(20, 20) 20 | c.set_line_width(2) 21 | c.stroke() 22 | 23 | # rectangles 24 | c.set_line_width(6) 25 | c.rectangle(300, 50, 100, 50) 26 | c.stroke() 27 | 28 | # arcs 29 | c.set_source_rgb(1,0,1) 30 | # x, y, radius, start_angle, stop_angle 31 | c.arc(200, 180, 40, 0, 2*math.pi) 32 | c.fill_preserve() 33 | c.set_line_width(2) 34 | c.set_source_rgb(0,0,0) 35 | c.stroke() 36 | 37 | surface.write_to_png(filename) 38 | -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/clip.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | import os 4 | 5 | def create_from_png(image_name): 6 | # ensure we can read image when working from another dir 7 | cwd = os.getcwd() 8 | dir_path = os.path.dirname(os.path.realpath(__file__)) 9 | os.chdir(dir_path) 10 | ims = cairo.ImageSurface.create_from_png(image_name) 11 | os.chdir(cwd) 12 | return ims 13 | 14 | def draw_png(filename): 15 | 16 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 17 | c = cairo.Context(surface) 18 | 19 | ims = create_from_png("church.png") 20 | 21 | # BEGIN 22 | c.arc(100, 100, 75, 0, 2*math.pi) 23 | 24 | c.save() 25 | c.clip() 26 | c.set_source_surface(ims, 0, 0) 27 | c.paint() 28 | c.restore() 29 | 30 | c.set_source_surface(ims, 256, 0) 31 | c.paint() 32 | # END 33 | 34 | surface.write_to_png(filename) 35 | 36 | if __name__ == "__main__": 37 | 38 | draw_png("clip.png") 39 | -------------------------------------------------------------------------------- /snippets/4_patterns/patterns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | import os 6 | 7 | def create_from_png(image_name): 8 | # ensure we can read image when working from another dir 9 | cwd = os.getcwd() 10 | dir_path = os.path.dirname(os.path.realpath(__file__)) 11 | os.chdir(dir_path) 12 | ims = cairo.ImageSurface.create_from_png(image_name) 13 | os.chdir(cwd) 14 | return ims 15 | 16 | def draw_png(filename): 17 | 18 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 19 | c = cairo.Context(surface) 20 | 21 | pat_surface = create_from_png("brick.png") 22 | pat = cairo.SurfacePattern(pat_surface) 23 | pat.set_extend(cairo.EXTEND_REPEAT) 24 | 25 | c.set_source(pat) 26 | c.arc(100, 100, 50, 0, 2*math.pi) 27 | c.fill() 28 | 29 | c.set_source_surface(pat_surface, 256, 50) 30 | c.paint() 31 | 32 | surface.write_to_png(filename) 33 | 34 | if __name__ == "__main__": 35 | 36 | draw_gif_sqlogo("brick.png") 37 | -------------------------------------------------------------------------------- /snippets/5_gradients/radial_gradients.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | 6 | def draw_png(filename): 7 | 8 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 9 | c = cairo.Context(surface) 10 | 11 | # cx0 - x coordinate for the center of the start circle 12 | # cy0 - y coordinate for the center of the start circle 13 | # radius0 - radius of the start circle 14 | # cx1 - x coordinate for the center of the end circle 15 | # cy1 - y coordinate for the center of the end circle 16 | # radius1 - radius of the end circle 17 | 18 | pat = cairo.RadialGradient(135, 130, 15, 19 | 140, 140, 40) 20 | pat.add_color_stop_rgba(0, 1, 1, 1, 1) 21 | pat.add_color_stop_rgba(0.3, 0.5, 0.5, 1, 1) 22 | pat.add_color_stop_rgba(1, 0, 0, 1, 1) 23 | c.set_source(pat) 24 | c.arc(150, 150, 50, 0, 2*math.pi) 25 | c.fill() 26 | 27 | surface.write_to_png(filename) 28 | 29 | if __name__ == "__main__": 30 | 31 | draw_png("radial_gradient.png") 32 | -------------------------------------------------------------------------------- /snippets/6_text_and_fonts/text.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | 5 | def draw_png(filename): 6 | 7 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 8 | c = cairo.Context(surface) 9 | 10 | # choose font 11 | 12 | c.select_font_face("Courier New") 13 | c.set_font_size(14) 14 | 15 | # basic example 16 | 17 | c.move_to(50, 50) 18 | c.show_text("Hello World") 19 | 20 | # right align 21 | 22 | for y, adj in [(100, "naughty"), (120, "cool"), (140, "bad")]: 23 | s = "%s cats" % adj 24 | _, _, txt_width, _, _, _ = c.text_extents(s) 25 | c.move_to(150 - txt_width, y) 26 | c.show_text(s) 27 | 28 | # pick another font 29 | 30 | c.select_font_face("Times", 31 | cairo.FONT_SLANT_ITALIC, 32 | cairo.FONT_WEIGHT_BOLD) 33 | c.set_font_size(56) 34 | 35 | c.move_to(200, 100) 36 | c.show_text("Hi there") 37 | 38 | surface.write_to_png(filename) 39 | 40 | if __name__ == "__main__": 41 | 42 | draw_gif_sqlogo("x.gif") 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nicolas Seriot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /snippets/7_antialiasing/antialiasing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | 6 | def draw_png(filename): 7 | 8 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 9 | c = cairo.Context(surface) 10 | 11 | c.select_font_face("Courier New") 12 | c.set_font_size(28) 13 | 14 | fo = cairo.FontOptions() 15 | fo.set_antialias(cairo.ANTIALIAS_DEFAULT) 16 | c.set_font_options(fo) 17 | 18 | c.move_to(50, 50) 19 | c.show_text("Antialias Default") 20 | 21 | fo = cairo.FontOptions() 22 | fo.set_antialias(cairo.ANTIALIAS_NONE) 23 | c.set_font_options(fo) 24 | 25 | c.move_to(50, 100) 26 | c.show_text("Antialias None") 27 | 28 | # 29 | 30 | c.set_antialias(cairo.ANTIALIAS_DEFAULT) 31 | 32 | c.arc(170, 170, 50, 0, 2*math.pi) 33 | c.set_source_rgba(1,0,0,1) 34 | c.fill() 35 | 36 | c.set_antialias(cairo.ANTIALIAS_NONE) 37 | 38 | c.arc(370, 170, 50, 0, 2*math.pi) 39 | c.set_source_rgba(1,0,0,1) 40 | c.fill() 41 | 42 | surface.write_to_png(filename) 43 | 44 | if __name__ == "__main__": 45 | 46 | draw_png("x.gif") 47 | -------------------------------------------------------------------------------- /snippets/3_clip_and_mask/mask.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | import math 3 | import os 4 | 5 | def create_from_png(image_name): 6 | # ensure we can read image when working from another dir 7 | cwd = os.getcwd() 8 | dir_path = os.path.dirname(os.path.realpath(__file__)) 9 | os.chdir(dir_path) 10 | ims = cairo.ImageSurface.create_from_png(image_name) 11 | os.chdir(cwd) 12 | return ims 13 | 14 | def draw_png(filename): 15 | 16 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 17 | c = cairo.Context(surface) 18 | 19 | # draw mask alone 20 | mask_img = create_from_png('mask.png') 21 | c.set_source_surface(mask_img, 0, 0) 22 | c.paint() 23 | 24 | church_img = create_from_png('church.png') 25 | c.set_source_surface(church_img, 256, 0) 26 | c.paint() 27 | 28 | # clip masking area 29 | c.rectangle(256, 0, church_img.get_width(), church_img.get_height()) 30 | c.clip() 31 | 32 | # apply mask 33 | c.set_operator(cairo.OPERATOR_DEST_IN) 34 | c.set_source_surface(mask_img, 256, 0) 35 | c.paint() 36 | 37 | surface.write_to_png(filename) 38 | 39 | if __name__ == "__main__": 40 | 41 | draw_png("masked_church.png") 42 | -------------------------------------------------------------------------------- /snippets/1_shapes/line_join_line_cap.py: -------------------------------------------------------------------------------- 1 | import cairo 2 | 3 | def draw_png(filename): 4 | 5 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 300) 6 | c = cairo.Context(surface) 7 | 8 | c.set_line_width(20) 9 | 10 | c.move_to(50, 100) 11 | c.rel_line_to(50, -50) 12 | c.rel_line_to(50, 50) 13 | c.set_line_join(cairo.LINE_JOIN_MITER) # default 14 | c.stroke() 15 | 16 | c.move_to(50, 150) 17 | c.rel_line_to(50, -50) 18 | c.rel_line_to(50, 50) 19 | c.set_line_join(cairo.LINE_JOIN_BEVEL) 20 | c.stroke() 21 | 22 | c.move_to(50, 200) 23 | c.rel_line_to(50, -50) 24 | c.rel_line_to(50, 50) 25 | c.set_line_join(cairo.LINE_JOIN_ROUND) 26 | c.stroke() 27 | 28 | c.move_to(200, 50) 29 | c.rel_line_to(0, 150) 30 | c.set_line_cap(cairo.LINE_CAP_BUTT) 31 | c.stroke() 32 | 33 | c.move_to(240, 50) 34 | c.rel_line_to(0, 150) 35 | c.set_line_cap(cairo.LINE_CAP_ROUND) 36 | c.stroke() 37 | 38 | c.move_to(280, 50) 39 | c.rel_line_to(0, 150) 40 | c.set_line_cap(cairo.LINE_CAP_SQUARE) 41 | c.stroke() 42 | 43 | c.rectangle(350, 50, 100, 100) 44 | c.set_line_join(cairo.LINE_JOIN_ROUND) 45 | c.stroke() 46 | 47 | surface.write_to_png(filename) 48 | -------------------------------------------------------------------------------- /snippets/4_patterns/repeating_pattern.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | import os 6 | 7 | def create_from_png(image_name): 8 | # ensure we can read image when working from another dir 9 | cwd = os.getcwd() 10 | dir_path = os.path.dirname(os.path.realpath(__file__)) 11 | os.chdir(dir_path) 12 | ims = cairo.ImageSurface.create_from_png(image_name) 13 | os.chdir(cwd) 14 | return ims 15 | 16 | def draw_png(filename): 17 | 18 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256) 19 | c = cairo.Context(surface) 20 | 21 | # pattern surface 22 | ps = cairo.ImageSurface(cairo.FORMAT_ARGB32, 50, 50) 23 | pc = cairo.Context(ps) 24 | 25 | # draw blue circles on the pattern surface context 26 | pc.set_source_rgb(1, 1, 1) 27 | pc.paint() 28 | pc.set_source_rgb(0, 0, 1) 29 | pc.arc(25, 25, 10, 0, 2 * 3.14159) 30 | pc.fill() 31 | 32 | # create the pattern 33 | p = cairo.SurfacePattern(ps) 34 | p.set_extend(cairo.EXTEND_REPEAT) 35 | 36 | # Use the pattern to fill the main surface 37 | c.set_source(p) 38 | c.rectangle(100, 50, 300, 200) 39 | c.fill() 40 | 41 | surface.write_to_png(filename) 42 | 43 | if __name__ == "__main__": 44 | 45 | draw_png("repeating_pattern.png") 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /snippets/8_animated_gifs/sq_logo_animated.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import cairo 4 | import math 5 | import imageio 6 | import numpy 7 | 8 | from PIL import Image 9 | 10 | COLOR_ORANGE_SQ = (250/255., 92/255., 53/255.) 11 | COLOR_WHITE = (1, 1, 1) 12 | 13 | def as_numpy_array(surface): 14 | 15 | w = surface.get_width() 16 | h = surface.get_height() 17 | 18 | data = surface.get_data() 19 | 20 | a = numpy.ndarray(shape=(h,w), dtype=numpy.uint32, buffer=data) 21 | 22 | i = Image.frombytes("RGBA", (w,h), a, "raw", "BGRA", 0, 1) 23 | 24 | return numpy.asarray(i) 25 | 26 | def add_image(writer, surface): 27 | 28 | a = as_numpy_array(surface) 29 | writer.append_data(a) 30 | 31 | def draw_gif_sqlogo(filename): 32 | 33 | gif_writer = imageio.get_writer(filename, mode='I', duration=0.5) 34 | 35 | w, h = 280, 280 36 | 37 | surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) 38 | c = cairo.Context(surface) 39 | 40 | # white background 41 | 42 | c.set_source_rgb(1, 1, 1) 43 | c.paint() 44 | c.fill() 45 | #add_image(gif_writer, surface) 46 | 47 | c.translate(20, 20) 48 | 49 | # main circle 50 | 51 | c.set_source_rgb (*COLOR_ORANGE_SQ) 52 | c.arc(120, 120, 120, 0, 2*math.pi) 53 | c.fill() 54 | add_image(gif_writer, surface) 55 | 56 | # white rects 57 | 58 | c.set_source_rgb (*COLOR_WHITE) 59 | c.rectangle(60, 70, 120, 20) 60 | c.fill() 61 | add_image(gif_writer, surface) 62 | 63 | c.rectangle(60, 110, 120, 60) 64 | c.fill() 65 | add_image(gif_writer, surface) 66 | 67 | # orange part of the bridge 68 | 69 | c.set_source_rgb (*COLOR_ORANGE_SQ) 70 | c.rectangle(80, 145, 30, 25) 71 | c.fill() 72 | add_image(gif_writer, surface) 73 | 74 | c.rectangle(130, 145, 30, 25) 75 | c.fill() 76 | add_image(gif_writer, surface) 77 | 78 | c.arc(95, 145, 15, 0, 2*math.pi) 79 | c.fill() 80 | add_image(gif_writer, surface) 81 | 82 | c.arc(145, 145, 15, 0, 2*math.pi) 83 | c.fill() 84 | add_image(gif_writer, surface) 85 | 86 | if __name__ == "__main__": 87 | 88 | draw_gif_sqlogo("sq.gif") 89 | -------------------------------------------------------------------------------- /img/9_formats/eps.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%Creator: cairo 1.18.0 (https://cairographics.org) 3 | %%CreationDate: Mon Aug 12 17:37:28 2024 4 | %%Pages: 1 5 | %%DocumentData: Clean7Bit 6 | %%LanguageLevel: 2 7 | %%BoundingBox: 0 0 320 240 8 | %%EndComments 9 | %%BeginProlog 10 | 50 dict begin 11 | /q { gsave } bind def 12 | /Q { grestore } bind def 13 | /cm { 6 array astore concat } bind def 14 | /w { setlinewidth } bind def 15 | /J { setlinecap } bind def 16 | /j { setlinejoin } bind def 17 | /M { setmiterlimit } bind def 18 | /d { setdash } bind def 19 | /m { moveto } bind def 20 | /l { lineto } bind def 21 | /c { curveto } bind def 22 | /h { closepath } bind def 23 | /re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto 24 | 0 exch rlineto 0 rlineto closepath } bind def 25 | /S { stroke } bind def 26 | /f { fill } bind def 27 | /f* { eofill } bind def 28 | /n { newpath } bind def 29 | /W { clip } bind def 30 | /W* { eoclip } bind def 31 | /BT { } bind def 32 | /ET { } bind def 33 | /BDC { mark 3 1 roll /BDC pdfmark } bind def 34 | /EMC { mark /EMC pdfmark } bind def 35 | /cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def 36 | /Tj { show currentpoint cairo_store_point } bind def 37 | /TJ { 38 | { 39 | dup 40 | type /stringtype eq 41 | { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse 42 | } forall 43 | currentpoint cairo_store_point 44 | } bind def 45 | /cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore 46 | cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def 47 | /Tf { pop /cairo_font exch def /cairo_font_matrix where 48 | { pop cairo_selectfont } if } bind def 49 | /Td { matrix translate cairo_font_matrix matrix concatmatrix dup 50 | /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point 51 | /cairo_font where { pop cairo_selectfont } if } bind def 52 | /Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def 53 | cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def 54 | /g { setgray } bind def 55 | /rg { setrgbcolor } bind def 56 | /d1 { setcachedevice } bind def 57 | /cairo_data_source { 58 | CairoDataIndex CairoData length lt 59 | { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } 60 | { () } ifelse 61 | } def 62 | /cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def 63 | /cairo_image { image cairo_flush_ascii85_file } def 64 | /cairo_imagemask { imagemask cairo_flush_ascii85_file } def 65 | %%EndProlog 66 | %%BeginSetup 67 | %%EndSetup 68 | %%Page: 1 1 69 | %%BeginPageSetup 70 | %%PageBoundingBox: 0 0 320 240 71 | %%EndPageSetup 72 | q 0 0 320 240 rectclip 73 | 1 0 0 -1 0 240 cm q 74 | 1 g 75 | 0 0 320 240 rectfill 76 | 1 0 0 rg 77 | 150 80 m 150 107.613 127.613 130 100 130 c 72.387 130 50 107.613 50 80 78 | c 50 52.387 72.387 30 100 30 c 127.613 30 150 52.387 150 80 c f 79 | Q Q 80 | showpage 81 | %%Trailer 82 | end 83 | %%EOF 84 | -------------------------------------------------------------------------------- /img/9_formats/ps.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 2 | %%Creator: cairo 1.18.0 (https://cairographics.org) 3 | %%CreationDate: Mon Aug 12 17:37:28 2024 4 | %%Pages: 1 5 | %%DocumentData: Clean7Bit 6 | %%LanguageLevel: 2 7 | %%DocumentMedia: 113x85mm 320 240 0 () () 8 | %%BoundingBox: 0 0 320 240 9 | %%EndComments 10 | %%BeginProlog 11 | /languagelevel where 12 | { pop languagelevel } { 1 } ifelse 13 | 2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto 14 | (This print job requires a PostScript Language Level 2 printer.) show 15 | showpage quit } if 16 | /q { gsave } bind def 17 | /Q { grestore } bind def 18 | /cm { 6 array astore concat } bind def 19 | /w { setlinewidth } bind def 20 | /J { setlinecap } bind def 21 | /j { setlinejoin } bind def 22 | /M { setmiterlimit } bind def 23 | /d { setdash } bind def 24 | /m { moveto } bind def 25 | /l { lineto } bind def 26 | /c { curveto } bind def 27 | /h { closepath } bind def 28 | /re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto 29 | 0 exch rlineto 0 rlineto closepath } bind def 30 | /S { stroke } bind def 31 | /f { fill } bind def 32 | /f* { eofill } bind def 33 | /n { newpath } bind def 34 | /W { clip } bind def 35 | /W* { eoclip } bind def 36 | /BT { } bind def 37 | /ET { } bind def 38 | /BDC { mark 3 1 roll /BDC pdfmark } bind def 39 | /EMC { mark /EMC pdfmark } bind def 40 | /cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def 41 | /Tj { show currentpoint cairo_store_point } bind def 42 | /TJ { 43 | { 44 | dup 45 | type /stringtype eq 46 | { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse 47 | } forall 48 | currentpoint cairo_store_point 49 | } bind def 50 | /cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore 51 | cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def 52 | /Tf { pop /cairo_font exch def /cairo_font_matrix where 53 | { pop cairo_selectfont } if } bind def 54 | /Td { matrix translate cairo_font_matrix matrix concatmatrix dup 55 | /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point 56 | /cairo_font where { pop cairo_selectfont } if } bind def 57 | /Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def 58 | cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def 59 | /g { setgray } bind def 60 | /rg { setrgbcolor } bind def 61 | /d1 { setcachedevice } bind def 62 | /cairo_data_source { 63 | CairoDataIndex CairoData length lt 64 | { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } 65 | { () } ifelse 66 | } def 67 | /cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def 68 | /cairo_image { image cairo_flush_ascii85_file } def 69 | /cairo_imagemask { imagemask cairo_flush_ascii85_file } def 70 | /cairo_set_page_size { 71 | % Change paper size, but only if different from previous paper size otherwise 72 | % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size 73 | % so we use the same when checking if the size changes. 74 | /setpagedevice where { 75 | pop currentpagedevice 76 | /PageSize known { 77 | 2 copy 78 | currentpagedevice /PageSize get aload pop 79 | exch 4 1 roll 80 | sub abs 5 gt 81 | 3 1 roll 82 | sub abs 5 gt 83 | or 84 | } { 85 | true 86 | } ifelse 87 | { 88 | 2 array astore 89 | 2 dict begin 90 | /PageSize exch def 91 | /ImagingBBox null def 92 | currentdict end 93 | setpagedevice 94 | } { 95 | pop pop 96 | } ifelse 97 | } { 98 | pop 99 | } ifelse 100 | } def 101 | %%EndProlog 102 | %%BeginSetup 103 | %%EndSetup 104 | %%Page: 1 1 105 | %%BeginPageSetup 106 | %%PageMedia: 113x85mm 107 | %%PageBoundingBox: 0 0 320 240 108 | 320 240 cairo_set_page_size 109 | %%EndPageSetup 110 | q 0 0 320 240 rectclip 111 | 1 0 0 -1 0 240 cm q 112 | 1 g 113 | 0 0 320 240 rectfill 114 | 1 0 0 rg 115 | 150 80 m 150 107.613 127.613 130 100 130 c 72.387 130 50 107.613 50 80 116 | c 50 52.387 72.387 30 100 30 c 127.613 30 150 52.387 150 80 c f 117 | Q Q 118 | showpage 119 | %%Trailer 120 | %%EOF 121 | -------------------------------------------------------------------------------- /css/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 9 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 14 | .highlight .ge { font-style: italic } /* Generic.Emph */ 15 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 18 | .highlight .go { color: #333333 } /* Generic.Output */ 19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 28 | .highlight .kt { color: #902000 } /* Keyword.Type */ 29 | .highlight .m { color: #208050 } /* Literal.Number */ 30 | .highlight .s { color: #4070a0 } /* Literal.String */ 31 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 32 | .highlight .nb { color: #007020 } /* Name.Builtin */ 33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 34 | .highlight .no { color: #60add5 } /* Name.Constant */ 35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 37 | .highlight .ne { color: #007020 } /* Name.Exception */ 38 | .highlight .nf { color: #06287e } /* Name.Function */ 39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /make.py: -------------------------------------------------------------------------------- 1 | import pkgutil 2 | import inspect 3 | import cairo 4 | import math 5 | import os 6 | import re 7 | 8 | from operator import attrgetter 9 | from time import strftime 10 | 11 | from pygments import highlight 12 | from pygments.lexers import PythonLexer 13 | from pygments.formatters import HtmlFormatter 14 | 15 | from cairo import SVGSurface, PDFSurface 16 | 17 | def get_submodules(mod): 18 | 19 | l = [] 20 | for loader, module_name, is_pkg in pkgutil.walk_packages(mod.__path__, mod.__name__+'.'): 21 | if not is_pkg: 22 | l.append(__import__(module_name, fromlist='xxx')) 23 | return sorted(l, key=attrgetter('__name__')) 24 | 25 | def call_drawing_function(f): 26 | 27 | m = re.match("draw_(png|svg|pdf|gif|ps|eps).*", f.__name__) 28 | 29 | if not m: 30 | print("xx", f.__name__) 31 | return None 32 | 33 | print("-- %s()" % f.__name__) 34 | 35 | mod_comps = mod.__name__.split(".") 36 | dir_comps = ["img"] + mod_comps[1:-1] 37 | directory = os.path.sep.join(dir_comps) 38 | 39 | if not os.path.exists(directory): 40 | os.makedirs(directory) 41 | 42 | ext = m.groups()[0] 43 | 44 | image_name = "%s.%s" % (os.path.sep.join([directory, mod_comps[2]]), ext) 45 | 46 | f(image_name) 47 | 48 | return image_name 49 | 50 | def path_items(mod): 51 | 52 | comps = mod.__name__.split(".") 53 | 54 | d = {} 55 | d["id"] = ".".join(comps[1:]) 56 | d["title"] = ".".join(comps[1].split("_")[1:]).capitalize() 57 | d["filename"] = comps[-1] + ".py" 58 | d["filepath"] = os.path.sep.join(comps) + ".py" 59 | d["filename_with_parent_dir"] = os.path.sep.join(comps[-2:]) + ".py" 60 | 61 | return d 62 | 63 | if __name__ == "__main__": 64 | 65 | """ 66 | Create an HTML file with snippets source code + images. 67 | 68 | Images are generated for all modules according to functions names. 69 | 70 | Optional code delimiters: "# BEGIN" and "# END". 71 | """ 72 | 73 | s = "" 74 | 75 | modules = get_submodules(__import__('snippets')) 76 | 77 | sections = {} 78 | 79 | for mod in modules: 80 | name = mod.__name__.split(".")[1] 81 | sections.setdefault(name, []).append(mod) 82 | 83 | s += "

Content

\n" 84 | 85 | s += "
    \n" 86 | for name, mods in sorted(iter(sections.items())): 87 | s += '
  1. %s\n' % " ".join(name.split("_")[1:]).capitalize() 88 | s += "\n
  2. \n" 93 | s += "
\n" 94 | 95 | s += '\n' 96 | 97 | for mod in modules: 98 | 99 | d = path_items(mod) 100 | 101 | s += '\n' % d["id"] 102 | s += '\n" 120 | 121 | # add source code to HTML 122 | 123 | with open(d["filepath"]) as f: 124 | code = f.read() 125 | 126 | if "# BEGIN" in code and "# END" in code: 127 | # TODO: use regex, allow several chunks 128 | code = code.split("# BEGIN")[1].lstrip("\n").split("# END")[0].rstrip() 129 | 130 | s += '\n" 139 | s += "\n" 140 | 141 | s += "
\n' 103 | 104 | functions = [o for n,o in inspect.getmembers(mod) if inspect.isfunction(o)] 105 | 106 | module_and_functions = [] 107 | 108 | for f in functions: 109 | 110 | image_name = call_drawing_function(f) 111 | 112 | if image_name != None: 113 | _, ext = os.path.splitext(image_name) 114 | if ext in [".pdf", ".ps", ".eps"]: 115 | s += '%s\n' % (image_name, os.path.basename(image_name)) 116 | else: 117 | s += '%s\n' % (image_name, d["id"]) 118 | 119 | s += "\n' 131 | 132 | s += "/%s\n" % d["filename_with_parent_dir"] 133 | 134 | hightlighted_code = highlight(code, PythonLexer(), HtmlFormatter()) 135 | 136 | s += "%s\n" % hightlighted_code 137 | 138 | s += "
\n" 142 | 143 | with open("template.html", "r") as f: 144 | template = f.read() 145 | 146 | d = {"pycairo_version": cairo.cairo_version_string(), "content": s, "date": strftime("%Y-%m-%d %H:%M:%S")} 147 | 148 | html = template.format(**d) 149 | 150 | with open("index.html", "w") as f: 151 | f.write(html) 152 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PyCairo Visual Documentation 6 | 7 | 8 | 9 | 10 |

PyCairo Visual Documentation

11 | 12 |
Author: Nicolas Seriot
  13 | Date: 2024-08-12 17:37:28
  14 | PyCairo Version: 1.18.0
  15 | GitHub: https://github.com/nst/PyCairoVisualDoc
16 | 17 |

Content

18 |
    19 |
  1. Shapes 20 | 26 |
  2. 27 |
  3. Transforms 28 | 34 |
  4. 35 |
  5. Clip and mask 36 | 40 |
  6. 41 |
  7. Patterns 42 | 46 |
  8. 47 |
  9. Gradients 48 | 52 |
  10. 53 |
  11. Text and fonts 54 | 57 |
  12. 58 |
  13. Antialiasing 59 | 62 |
  14. 63 |
  15. Animated gifs 64 | 68 |
  16. 69 |
  17. Formats 70 | 78 |
  18. 79 |
80 | 81 | 82 | 85 | 127 | 128 | 129 | 132 | 159 | 160 | 161 | 164 | 196 | 197 | 198 | 201 | 253 | 254 | 255 | 258 | 290 | 291 | 292 | 295 | 331 | 332 | 333 | 336 | 368 | 369 | 370 | 373 | 413 | 414 | 415 | 418 | 433 | 434 | 435 | 438 | 484 | 485 | 486 | 489 | 530 | 531 | 532 | 535 | 585 | 586 | 587 | 590 | 621 | 622 | 623 | 626 | 662 | 663 | 664 | 667 | 714 | 715 | 716 | 719 | 770 | 771 | 772 | 775 | 807 | 808 | 809 | 812 | 905 | 906 | 907 | 910 | 933 | 934 | 935 | 938 | 969 | 970 | 971 | 974 | 996 | 997 | 998 | 1001 | 1022 | 1023 | 1024 | 1027 | 1049 | 1050 | 1051 | 1054 | 1076 | 1077 |
83 | 1_shapes.basic_shapes 84 | 86 | /1_shapes/basic_shapes.py 87 |
import cairo
  88 | import math
  89 | 
  90 | def draw_png(filename):
  91 | 
  92 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
  93 |     c = cairo.Context(surface)
  94 |     
  95 |     # background
  96 |     c.set_source_rgb(1,1,1)
  97 |     c.paint()
  98 | 
  99 |     # lines
 100 |     c.set_source_rgb(0,0,0)
 101 |     c.move_to(50, 100)
 102 |     c.line_to(100, 150)
 103 |     c.rel_line_to(150, -100)
 104 |     c.rel_move_to(-10, -10)
 105 |     c.rel_line_to(20, 20)
 106 |     c.set_line_width(2)
 107 |     c.stroke()
 108 |     
 109 |     # rectangles
 110 |     c.set_line_width(6)
 111 |     c.rectangle(300, 50, 100, 50)
 112 |     c.stroke()
 113 |     
 114 |     # arcs
 115 |     c.set_source_rgb(1,0,1)
 116 |     # x, y, radius, start_angle, stop_angle
 117 |     c.arc(200, 180, 40, 0, 2*math.pi)
 118 |     c.fill_preserve()
 119 |     c.set_line_width(2)
 120 |     c.set_source_rgb(0,0,0)
 121 |     c.stroke()
 122 |     
 123 |     surface.write_to_png(filename)
 124 | 
125 | 126 |
130 | 1_shapes.bezier_curve 131 | 133 | /1_shapes/bezier_curve.py 134 |
import cairo
 135 | import math
 136 | 
 137 | def draw_png(filename):
 138 | 
 139 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 140 |     c = cairo.Context(surface)
 141 |     
 142 |     x0, y0 = 50, 50
 143 |     x1, y1 = 180, 220    
 144 |     x2, y2 = 350, 180
 145 |     x3, y3 = 400, 50
 146 |         
 147 |     c.move_to(x0, y0)
 148 |     c.curve_to(x1, y1, x2, y2, x3, y3)        
 149 |     c.stroke()
 150 |     
 151 |     for x,y in [(x0, y0), (x1, y1), (x2, y2), (x3, y3)]:
 152 |         c.arc(x-2, y-2, 4, 0, 2*math.pi)
 153 |         c.stroke()
 154 |     
 155 |     surface.write_to_png(filename)
 156 | 
157 | 158 |
162 | 1_shapes.dashed_lines 163 | 165 | /1_shapes/dashed_lines.py 166 |
import cairo
 167 | 
 168 | def draw_png(filename):
 169 | 
 170 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 300)
 171 |     c = cairo.Context(surface)
 172 | 
 173 |     c.set_line_width(5)
 174 |     
 175 |     c.set_source_rgb(0,0,0)
 176 |     
 177 |     # 15 drawn, 10 not drawn, etc
 178 |     c.set_dash([15, 10])
 179 | 
 180 |     c.move_to(50, 50)  
 181 |     c.line_to(400, 50)
 182 |     c.stroke()
 183 | 
 184 |     # 10 drawn, 30 not drawn, 5 drawn, then
 185 |     # 10 *not* drawn, 30 drawn, 5 not drawn, etc
 186 |     c.set_dash([10, 30, 5])
 187 | 
 188 |     c.move_to(50, 100)
 189 |     c.line_to(400, 100)
 190 |     c.stroke()
 191 | 
 192 |     surface.write_to_png(filename)
 193 | 
194 | 195 |
199 | 1_shapes.line_join_line_cap 200 | 202 | /1_shapes/line_join_line_cap.py 203 |
import cairo
 204 | 
 205 | def draw_png(filename):
 206 | 
 207 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 300)
 208 |     c = cairo.Context(surface)
 209 |     
 210 |     c.set_line_width(20)
 211 |     
 212 |     c.move_to(50, 100)
 213 |     c.rel_line_to(50, -50)
 214 |     c.rel_line_to(50, 50)
 215 |     c.set_line_join(cairo.LINE_JOIN_MITER) # default
 216 |     c.stroke()
 217 |     
 218 |     c.move_to(50, 150)
 219 |     c.rel_line_to(50, -50)
 220 |     c.rel_line_to(50, 50)
 221 |     c.set_line_join(cairo.LINE_JOIN_BEVEL)
 222 |     c.stroke()
 223 | 
 224 |     c.move_to(50, 200)
 225 |     c.rel_line_to(50, -50)
 226 |     c.rel_line_to(50, 50)
 227 |     c.set_line_join(cairo.LINE_JOIN_ROUND)
 228 |     c.stroke()
 229 | 
 230 |     c.move_to(200, 50)
 231 |     c.rel_line_to(0, 150)
 232 |     c.set_line_cap(cairo.LINE_CAP_BUTT)
 233 |     c.stroke()
 234 | 
 235 |     c.move_to(240, 50)
 236 |     c.rel_line_to(0, 150)
 237 |     c.set_line_cap(cairo.LINE_CAP_ROUND)
 238 |     c.stroke()
 239 | 
 240 |     c.move_to(280, 50)
 241 |     c.rel_line_to(0, 150)
 242 |     c.set_line_cap(cairo.LINE_CAP_SQUARE)
 243 |     c.stroke()
 244 | 
 245 |     c.rectangle(350, 50, 100, 100)        
 246 |     c.set_line_join(cairo.LINE_JOIN_ROUND)
 247 |     c.stroke()
 248 |     
 249 |     surface.write_to_png(filename)
 250 | 
251 | 252 |
256 | 2_transforms.invert_y_coordinates 257 | 259 | /2_transforms/invert_y_coordinates.py 260 |
import cairo
 261 | 
 262 | def draw_line(c):
 263 |     c.move_to(10, 10)
 264 |     c.line_to(100, 100)
 265 |     c.stroke()
 266 | 
 267 | def draw_png(filename):
 268 | 
 269 |     s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 270 |     c = cairo.Context(s)
 271 |     
 272 |     c.set_source_rgb(1,0,0)
 273 |     draw_line(c)
 274 |     
 275 |     # invert y coordinates
 276 |     m = cairo.Matrix(yy=-1, y0=s.get_height())
 277 |     c.transform(m)
 278 |     
 279 |     c.set_source_rgb(0,0,1)
 280 |     draw_line(c)
 281 |     
 282 |     s.write_to_png(filename)
 283 | 
 284 | if __name__ == "__main__":
 285 | 
 286 |     draw()
 287 | 
288 | 289 |
293 | 2_transforms.matrix 294 | 296 | /2_transforms/matrix.py 297 |
import cairo
 298 | import math
 299 | 
 300 | def draw_rect(c):
 301 |     c.set_source_rgb(1,0,0)
 302 |     c.rectangle(20, 20, 150, 100)
 303 |     c.fill()
 304 | 
 305 | def draw_png_asd(filename):
 306 | 
 307 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 308 |     c = cairo.Context(surface)
 309 |     
 310 |     draw_rect(c)
 311 |     
 312 |     # x_new = xx * x + xy * y + x0
 313 |     # y_new = yx * x + yy * y + y0
 314 | 
 315 |     # cairo.Matrix(xx, yx,
 316 |     #              xy, yy,
 317 |     #              x0, y0)
 318 |     
 319 |     m = cairo.Matrix(1.0, 0.5,
 320 |                      0,   1.0,
 321 |                      256, 0.0)
 322 |     
 323 |     c.transform(m)
 324 |     
 325 |     draw_rect(c)
 326 |     
 327 |     surface.write_to_png(filename)
 328 | 
329 | 330 |
334 | 2_transforms.rotate 335 | 337 | /2_transforms/rotate.py 338 |
import cairo
 339 | import math
 340 | 
 341 | def draw_png_rotate(filename):
 342 | 
 343 |     surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, 512, 300)
 344 |     c = cairo.Context(surface)
 345 |     
 346 |     c.set_source_rgb(1,1,1)
 347 |     c.paint()
 348 |     
 349 |     c.set_source_rgb(0,0,0)
 350 |     
 351 |     c.save()
 352 |     c.translate(50, 50)
 353 |     c.rectangle(0, 0, 250, 150)
 354 |     c.stroke()
 355 |     c.restore()
 356 |     
 357 |     c.save()
 358 |     c.translate(250, 150)
 359 |     c.rotate(math.pi / 4.0)
 360 |     c.rectangle(0, 0, 250, 150)
 361 |     c.stroke()
 362 |     c.restore()
 363 |     
 364 |     surface.write_to_png(filename)
 365 | 
366 | 367 |
371 | 2_transforms.translate_and_scale 372 | 374 | /2_transforms/translate_and_scale.py 375 |
import cairo
 376 | import math
 377 | 
 378 | def draw_picture(c, x, y, scale):
 379 | 
 380 |     c.save()
 381 |     
 382 |     c.translate(x, y)
 383 |     c.scale(scale, scale)
 384 | 
 385 |     c.set_source_rgb(1, 0, 0)
 386 |     c.arc(120, 120, 120, 0, 2*math.pi)
 387 |     c.fill()
 388 | 
 389 |     c.set_source_rgb(1, 1, 1)
 390 |     c.arc(160, 90, 40, 0, 2*math.pi)
 391 |     c.fill()
 392 |         
 393 |     c.restore()
 394 | 
 395 | def draw_png_asd(filename):
 396 | 
 397 |     surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, 512, 300)
 398 |     #surface.set_device_scale(2,2)
 399 |     c = cairo.Context(surface)
 400 |     #c.set_antialias(cairo.ANTIALIAS_NONE)
 401 |     
 402 |     c.set_source_rgb(1, 1, 1)
 403 |     c.paint()
 404 |     
 405 |     draw_picture(c, x=30, y=30, scale=1)
 406 |     draw_picture(c, x=350, y=50, scale=0.5)
 407 |     draw_picture(c, x=290, y=170, scale=0.25)
 408 |     
 409 |     surface.write_to_png(filename)
 410 | 
411 | 412 |
416 | 3_clip_and_mask.clip 417 | 419 | /3_clip_and_mask/clip.py 420 |
    c.arc(100, 100, 75, 0, 2*math.pi)
 421 |     
 422 |     c.save()
 423 |     c.clip()
 424 |     c.set_source_surface(ims, 0, 0)    
 425 |     c.paint()
 426 |     c.restore()
 427 | 
 428 |     c.set_source_surface(ims, 256, 0)    
 429 |     c.paint()
 430 | 
431 | 432 |
436 | 3_clip_and_mask.mask 437 | 439 | /3_clip_and_mask/mask.py 440 |
import cairo
 441 | import math
 442 | import os
 443 | 
 444 | def create_from_png(image_name):
 445 |     # ensure we can read image when working from another dir
 446 |     cwd = os.getcwd()
 447 |     dir_path = os.path.dirname(os.path.realpath(__file__))
 448 |     os.chdir(dir_path)
 449 |     ims = cairo.ImageSurface.create_from_png(image_name)
 450 |     os.chdir(cwd)
 451 |     return ims
 452 | 
 453 | def draw_png(filename):
 454 | 
 455 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 456 |     c = cairo.Context(surface)
 457 | 
 458 |     # draw mask alone
 459 |     mask_img = create_from_png('mask.png')  
 460 |     c.set_source_surface(mask_img, 0, 0)
 461 |     c.paint()
 462 |     
 463 |     church_img = create_from_png('church.png')  
 464 |     c.set_source_surface(church_img, 256, 0)
 465 |     c.paint()
 466 |     
 467 |     # clip masking area
 468 |     c.rectangle(256, 0, church_img.get_width(), church_img.get_height())
 469 |     c.clip()
 470 |     
 471 |     # apply mask
 472 |     c.set_operator(cairo.OPERATOR_DEST_IN)
 473 |     c.set_source_surface(mask_img, 256, 0)
 474 |     c.paint()
 475 |     
 476 |     surface.write_to_png(filename)
 477 | 
 478 | if __name__ == "__main__":
 479 | 
 480 |     draw_png("masked_church.png")
 481 | 
482 | 483 |
487 | 4_patterns.patterns 488 | 490 | /4_patterns/patterns.py 491 |
#!/usr/bin/env python
 492 | 
 493 | import cairo
 494 | import math
 495 | import os
 496 | 
 497 | def create_from_png(image_name):
 498 |     # ensure we can read image when working from another dir
 499 |     cwd = os.getcwd()
 500 |     dir_path = os.path.dirname(os.path.realpath(__file__))
 501 |     os.chdir(dir_path)
 502 |     ims = cairo.ImageSurface.create_from_png(image_name)
 503 |     os.chdir(cwd)
 504 |     return ims
 505 | 
 506 | def draw_png(filename):
 507 | 
 508 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 509 |     c = cairo.Context(surface)
 510 |     
 511 |     pat_surface = create_from_png("brick.png")
 512 |     pat = cairo.SurfacePattern(pat_surface)
 513 |     pat.set_extend(cairo.EXTEND_REPEAT)
 514 |     
 515 |     c.set_source(pat)
 516 |     c.arc(100, 100, 50, 0, 2*math.pi)
 517 |     c.fill()
 518 |     
 519 |     c.set_source_surface(pat_surface, 256, 50)    
 520 |     c.paint()
 521 | 
 522 |     surface.write_to_png(filename)
 523 | 
 524 | if __name__ == "__main__":
 525 | 
 526 |     draw_gif_sqlogo("brick.png")
 527 | 
528 | 529 |
533 | 4_patterns.repeating_pattern 534 | 536 | /4_patterns/repeating_pattern.py 537 |
#!/usr/bin/env python
 538 | 
 539 | import cairo
 540 | import math
 541 | import os
 542 | 
 543 | def create_from_png(image_name):
 544 |     # ensure we can read image when working from another dir
 545 |     cwd = os.getcwd()
 546 |     dir_path = os.path.dirname(os.path.realpath(__file__))
 547 |     os.chdir(dir_path)
 548 |     ims = cairo.ImageSurface.create_from_png(image_name)
 549 |     os.chdir(cwd)
 550 |     return ims
 551 | 
 552 | def draw_png(filename):
 553 | 
 554 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 555 |     c = cairo.Context(surface)
 556 |     
 557 |     # pattern surface
 558 |     ps = cairo.ImageSurface(cairo.FORMAT_ARGB32, 50, 50)
 559 |     pc = cairo.Context(ps)
 560 |     
 561 |     # draw blue circles on the pattern surface context
 562 |     pc.set_source_rgb(1, 1, 1)
 563 |     pc.paint()
 564 |     pc.set_source_rgb(0, 0, 1)
 565 |     pc.arc(25, 25, 10, 0, 2 * 3.14159)
 566 |     pc.fill()
 567 | 
 568 |     # create the pattern
 569 |     p = cairo.SurfacePattern(ps)
 570 |     p.set_extend(cairo.EXTEND_REPEAT)
 571 | 
 572 |     # Use the pattern to fill the main surface
 573 |     c.set_source(p)
 574 |     c.rectangle(100, 50, 300, 200)
 575 |     c.fill()
 576 |     
 577 |     surface.write_to_png(filename)
 578 | 
 579 | if __name__ == "__main__":
 580 | 
 581 |     draw_png("repeating_pattern.png")
 582 | 
583 | 584 |
588 | 5_gradients.linear_gradient 589 | 591 | /5_gradients/linear_gradient.py 592 |
#!/usr/bin/env python
 593 | 
 594 | import cairo
 595 | import math
 596 | 
 597 | def draw_png(filename):
 598 | 
 599 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 600 |     c = cairo.Context(surface)
 601 |     
 602 |     x0, y0 = 20, 20
 603 |     x1, y1 = 20, 220
 604 |     lg = cairo.LinearGradient(x0, y0, x1, y1)
 605 |     lg.add_color_stop_rgba(0.0, 1, 0, 0, 1) 
 606 |     lg.add_color_stop_rgba(0.5, 0, 1, 0, 1) 
 607 |     lg.add_color_stop_rgba(1.0, 0, 0, 1, 1) 
 608 | 
 609 |     c.rectangle(20, 20, 200, 200)
 610 |     c.set_source(lg)
 611 |     c.fill()
 612 |     
 613 |     surface.write_to_png(filename)
 614 | 
 615 | if __name__ == "__main__":
 616 | 
 617 |     draw_png("x.gif")
 618 | 
619 | 620 |
624 | 5_gradients.radial_gradients 625 | 627 | /5_gradients/radial_gradients.py 628 |
#!/usr/bin/env python
 629 | 
 630 | import cairo
 631 | import math
 632 | 
 633 | def draw_png(filename):
 634 | 
 635 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 636 |     c = cairo.Context(surface)
 637 |     
 638 |     # cx0 - x coordinate for the center of the start circle
 639 |     # cy0 - y coordinate for the center of the start circle
 640 |     # radius0 - radius of the start circle
 641 |     # cx1 - x coordinate for the center of the end circle
 642 |     # cy1 - y coordinate for the center of the end circle
 643 |     # radius1 - radius of the end circle
 644 | 
 645 |     pat = cairo.RadialGradient(135, 130, 15,
 646 |                                140, 140, 40)
 647 |     pat.add_color_stop_rgba(0, 1, 1, 1, 1)
 648 |     pat.add_color_stop_rgba(0.3, 0.5, 0.5, 1, 1)
 649 |     pat.add_color_stop_rgba(1, 0, 0, 1, 1)
 650 |     c.set_source(pat)
 651 |     c.arc(150, 150, 50, 0, 2*math.pi)
 652 |     c.fill()
 653 |     
 654 |     surface.write_to_png(filename)
 655 | 
 656 | if __name__ == "__main__":
 657 | 
 658 |     draw_png("radial_gradient.png")
 659 | 
660 | 661 |
665 | 6_text_and_fonts.text 666 | 668 | /6_text_and_fonts/text.py 669 |
#!/usr/bin/env python
 670 | 
 671 | import cairo
 672 | 
 673 | def draw_png(filename):
 674 | 
 675 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 676 |     c = cairo.Context(surface)
 677 | 
 678 |     # choose font
 679 |         
 680 |     c.select_font_face("Courier New")
 681 |     c.set_font_size(14)
 682 | 
 683 |     # basic example
 684 | 
 685 |     c.move_to(50, 50)
 686 |     c.show_text("Hello World")
 687 | 
 688 |     # right align
 689 | 
 690 |     for y, adj in [(100, "naughty"), (120, "cool"), (140, "bad")]:
 691 |         s = "%s cats" % adj
 692 |         _, _, txt_width, _, _, _ = c.text_extents(s)        
 693 |         c.move_to(150 - txt_width, y)
 694 |         c.show_text(s)
 695 |     
 696 |     # pick another font
 697 |        
 698 |     c.select_font_face("Times",
 699 |                        cairo.FONT_SLANT_ITALIC,
 700 |                        cairo.FONT_WEIGHT_BOLD)
 701 |     c.set_font_size(56)
 702 | 
 703 |     c.move_to(200, 100)
 704 |     c.show_text("Hi there")
 705 | 
 706 |     surface.write_to_png(filename)
 707 | 
 708 | if __name__ == "__main__":
 709 | 
 710 |     draw_gif_sqlogo("x.gif")
 711 | 
712 | 713 |
717 | 7_antialiasing.antialiasing 718 | 720 | /7_antialiasing/antialiasing.py 721 |
#!/usr/bin/env python
 722 | 
 723 | import cairo
 724 | import math
 725 | 
 726 | def draw_png(filename):
 727 | 
 728 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 512, 256)
 729 |     c = cairo.Context(surface)
 730 |     
 731 |     c.select_font_face("Courier New")
 732 |     c.set_font_size(28)
 733 | 
 734 |     fo = cairo.FontOptions()
 735 |     fo.set_antialias(cairo.ANTIALIAS_DEFAULT)
 736 |     c.set_font_options(fo)
 737 | 
 738 |     c.move_to(50, 50)
 739 |     c.show_text("Antialias Default")    
 740 | 
 741 |     fo = cairo.FontOptions()
 742 |     fo.set_antialias(cairo.ANTIALIAS_NONE)
 743 |     c.set_font_options(fo)
 744 | 
 745 |     c.move_to(50, 100)
 746 |     c.show_text("Antialias None")    
 747 | 
 748 |     #
 749 |     
 750 |     c.set_antialias(cairo.ANTIALIAS_DEFAULT)
 751 | 
 752 |     c.arc(170, 170, 50, 0, 2*math.pi)
 753 |     c.set_source_rgba(1,0,0,1)
 754 |     c.fill()
 755 | 
 756 |     c.set_antialias(cairo.ANTIALIAS_NONE)
 757 | 
 758 |     c.arc(370, 170, 50, 0, 2*math.pi)
 759 |     c.set_source_rgba(1,0,0,1)
 760 |     c.fill()
 761 |     
 762 |     surface.write_to_png(filename)
 763 | 
 764 | if __name__ == "__main__":
 765 | 
 766 |     draw_png("x.gif")
 767 | 
768 | 769 |
773 | 8_animated_gifs.gif 774 | 776 | /8_animated_gifs/gif.py 777 |
import os
 778 | import imageio
 779 | 
 780 | def images_paths():
 781 |     # ensure we can read images when working from another dir
 782 |     cwd = os.getcwd()
 783 |     dir_path = os.path.dirname(os.path.realpath(__file__))
 784 |     os.chdir(dir_path)
 785 |     files = [os.path.sep.join([dir_path, s])
 786 |              for s in os.listdir(dir_path)
 787 |              if s.endswith('.png')]
 788 |     files.sort()
 789 |     os.chdir(cwd)
 790 |     return files
 791 | 
 792 | def draw_gif(filename):
 793 | 
 794 |     images = []
 795 |     
 796 |     for s in images_paths():
 797 |         images.append(imageio.imread(s))
 798 |     
 799 |     imageio.mimsave(filename, images, format='GIF', duration=0.5)
 800 | 
 801 | if __name__ == "__main__":
 802 | 
 803 |     draw_gif("movie.gif")
 804 | 
805 | 806 |
810 | 8_animated_gifs.sq_logo_animated 811 | 813 | /8_animated_gifs/sq_logo_animated.py 814 |
#!/usr/bin/env python
 815 | 
 816 | import cairo
 817 | import math
 818 | import imageio
 819 | import numpy
 820 | 
 821 | from PIL import Image
 822 | 
 823 | COLOR_ORANGE_SQ = (250/255., 92/255., 53/255.)
 824 | COLOR_WHITE = (1, 1, 1)
 825 | 
 826 | def as_numpy_array(surface):
 827 | 
 828 |     w = surface.get_width()
 829 |     h = surface.get_height()
 830 |     
 831 |     data = surface.get_data()
 832 |     
 833 |     a = numpy.ndarray(shape=(h,w), dtype=numpy.uint32, buffer=data)
 834 |     
 835 |     i = Image.frombytes("RGBA", (w,h), a, "raw", "BGRA", 0, 1)
 836 |     
 837 |     return numpy.asarray(i)
 838 | 
 839 | def add_image(writer, surface):
 840 |     
 841 |     a = as_numpy_array(surface)
 842 |     writer.append_data(a)
 843 |     
 844 | def draw_gif_sqlogo(filename):
 845 | 
 846 |     gif_writer = imageio.get_writer(filename, mode='I', duration=0.5)
 847 |         
 848 |     w, h = 280, 280
 849 |     
 850 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
 851 |     c = cairo.Context(surface)
 852 |     
 853 |     # white background
 854 |     
 855 |     c.set_source_rgb(1, 1, 1)
 856 |     c.paint()
 857 |     c.fill()
 858 |     #add_image(gif_writer, surface)
 859 |     
 860 |     c.translate(20, 20)
 861 | 
 862 |     # main circle
 863 |     
 864 |     c.set_source_rgb (*COLOR_ORANGE_SQ)
 865 |     c.arc(120, 120, 120, 0, 2*math.pi)
 866 |     c.fill()
 867 |     add_image(gif_writer, surface)
 868 |     
 869 |     # white rects
 870 |     
 871 |     c.set_source_rgb (*COLOR_WHITE)
 872 |     c.rectangle(60, 70, 120, 20)
 873 |     c.fill()
 874 |     add_image(gif_writer, surface)
 875 | 
 876 |     c.rectangle(60, 110, 120, 60)
 877 |     c.fill()
 878 |     add_image(gif_writer, surface)
 879 |     
 880 |     # orange part of the bridge
 881 |     
 882 |     c.set_source_rgb (*COLOR_ORANGE_SQ)
 883 |     c.rectangle(80, 145, 30, 25)
 884 |     c.fill()
 885 |     add_image(gif_writer, surface)
 886 |     
 887 |     c.rectangle(130, 145, 30, 25)
 888 |     c.fill()
 889 |     add_image(gif_writer, surface)
 890 | 
 891 |     c.arc(95, 145,  15, 0, 2*math.pi)
 892 |     c.fill()
 893 |     add_image(gif_writer, surface)
 894 | 
 895 |     c.arc(145, 145, 15, 0, 2*math.pi)
 896 |     c.fill()
 897 |     add_image(gif_writer, surface)
 898 | 
 899 | if __name__ == "__main__":
 900 | 
 901 |     draw_gif_sqlogo("sq.gif")
 902 | 
903 | 904 |
908 | eps.eps 909 | 911 | /9_formats/eps.py 912 |
import cairo
 913 | from cairo import PSSurface
 914 | import math
 915 | 
 916 | def draw_eps(filename):
 917 |     
 918 |     surface = PSSurface(filename, 320, 240)
 919 |     surface.set_eps(True)
 920 |     c = cairo.Context(surface)
 921 | 
 922 |     c.set_source_rgb(1, 1, 1)
 923 |     c.paint()
 924 | 
 925 |     c.arc(100, 80, 50, 0, 2*math.pi)
 926 |     c.set_source_rgba(1,0,0,1)
 927 |     c.fill()
 928 |     
 929 |     surface.show_page()
 930 | 
931 | 932 |
936 | multipage_pdf.pdf 937 | 939 | /9_formats/multipage_pdf.py 940 |
import cairo
 941 | from cairo import PDFSurface
 942 | import math
 943 | 
 944 | def draw_pdf(filename):
 945 |     
 946 |     surface = PDFSurface(filename, 320, 240)
 947 |     c = cairo.Context(surface)
 948 | 
 949 |     c.set_source_rgb(1, 1, 1)
 950 |     c.paint()
 951 | 
 952 |     c.arc(150, 150, 50, 0, 2*math.pi)
 953 |     c.set_source_rgba(1,0,0,1)
 954 |     c.fill()
 955 | 
 956 |     surface.show_page()
 957 | 
 958 |     c.set_source_rgb(1, 1, 1)
 959 |     c.paint()
 960 | 
 961 |     c.arc(100, 100, 50, 0, 2*math.pi)
 962 |     c.set_source_rgba(1,0,1,1)
 963 |     c.fill()
 964 | 
 965 |     surface.show_page()
 966 | 
967 | 968 |
972 | pdf.pdf 973 | 975 | /9_formats/pdf.py 976 |
import cairo
 977 | from cairo import PDFSurface
 978 | import math
 979 | 
 980 | def draw_pdf(filename):
 981 |     
 982 |     surface = PDFSurface(filename, 320, 240)
 983 |     c = cairo.Context(surface)
 984 | 
 985 |     c.set_source_rgb(1, 1, 1)
 986 |     c.paint()
 987 | 
 988 |     c.arc(100, 80, 50, 0, 2*math.pi)
 989 |     c.set_source_rgba(1,0,0,1)
 990 |     c.fill()
 991 | 
 992 |     surface.show_page()
 993 | 
994 | 995 |
999 | 9_formats.png 1000 | 1002 | /9_formats/png.py 1003 |
import cairo
1004 | import math
1005 | 
1006 | def draw_png(filename):
1007 | 
1008 |     surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 320, 240)
1009 |     c = cairo.Context(surface)
1010 | 
1011 |     c.set_source_rgb(1, 1, 1)
1012 |     c.paint()
1013 | 
1014 |     c.arc(100, 80, 50, 0, 2*math.pi)
1015 |     c.set_source_rgba(1,0,0,1)
1016 |     c.fill()
1017 |     
1018 |     surface.write_to_png(filename)
1019 | 
1020 | 1021 |
1025 | ps.ps 1026 | 1028 | /9_formats/ps.py 1029 |
import cairo
1030 | from cairo import PSSurface
1031 | import math
1032 | 
1033 | def draw_ps(filename):
1034 |     
1035 |     surface = PSSurface(filename, 320, 240)
1036 |     c = cairo.Context(surface)
1037 | 
1038 |     c.set_source_rgb(1, 1, 1)
1039 |     c.paint()
1040 | 
1041 |     c.arc(100, 80, 50, 0, 2*math.pi)
1042 |     c.set_source_rgba(1,0,0,1)
1043 |     c.fill()
1044 | 
1045 |     surface.show_page()
1046 | 
1047 | 1048 |
1052 | 9_formats.svg 1053 | 1055 | /9_formats/svg.py 1056 |
import cairo
1057 | from cairo import SVGSurface
1058 | import math
1059 | 
1060 | def draw_svg_asd(filename):
1061 |     
1062 |     surface = SVGSurface(filename, 320, 240)
1063 |     c = cairo.Context(surface)
1064 | 
1065 |     c.set_source_rgb(1, 1, 1)
1066 |     c.paint()
1067 | 
1068 |     c.arc(100, 80, 50, 0, 2*math.pi)
1069 |     c.set_source_rgba(1,0,0,1)
1070 |     c.fill()
1071 | 
1072 |     surface.finish()
1073 | 
1074 | 1075 |
1078 | 1079 | 1080 | 1081 | 1082 | --------------------------------------------------------------------------------