├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── workflows │ ├── crystal.yml │ └── deploy-docs.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples ├── sample_window │ ├── .gitignore │ ├── Makefile │ ├── shard.yml │ ├── spec │ │ ├── sample_window_spec.cr │ │ └── spec_helper.cr │ └── src │ │ ├── sample_window.cr │ │ └── sample_window │ │ └── version.cr ├── sample_window_hl │ ├── .gitignore │ ├── Makefile │ ├── shard.yml │ ├── spec │ │ ├── sample_window_hl_spec.cr │ │ └── spec_helper.cr │ └── src │ │ ├── sample_window_hl.cr │ │ └── sample_window_hl │ │ └── version.cr ├── screenshot │ └── sample_window.png └── svg_sample │ ├── .gitignore │ ├── Makefile │ ├── shard.yml │ └── src │ └── svg_sample.cr ├── shard.yml ├── spec ├── cairo-cr_spec.cr └── spec_helper.cr └── src ├── cairo.cr └── cairo ├── antialias.cr ├── c ├── features.cr ├── lib_cairo.cr ├── pdf.cr ├── ps.cr ├── script.cr ├── script_interpreter.cr ├── svg.cr ├── tee.cr └── xlib.cr ├── color_stop.cr ├── content.cr ├── context.cr ├── device.cr ├── device_type.cr ├── extend.cr ├── extents.cr ├── fill_rule.cr ├── filter.cr ├── font_extents.cr ├── font_face.cr ├── font_options.cr ├── font_slant.cr ├── font_type.cr ├── font_weight.cr ├── format.cr ├── glyph.cr ├── glyph_array.cr ├── hint_metrics.cr ├── hint_style.cr ├── line_cap.cr ├── line_join.cr ├── matrix.cr ├── operator.cr ├── path.cr ├── path_data.cr ├── path_data_header.cr ├── path_data_type.cr ├── pattern.cr ├── pattern_type.cr ├── pdf_metadata.cr ├── pdf_outline_flags.cr ├── pdf_surface.cr ├── pdf_version.cr ├── point.cr ├── ps_level.cr ├── ps_surface.cr ├── rectangle.cr ├── rectangle_int.cr ├── rectangle_list.cr ├── region.cr ├── region_overlap.cr ├── rgba.cr ├── scaled_font.cr ├── script.cr ├── script_interpreter.cr ├── script_mode.cr ├── status.cr ├── status_exception.cr ├── subpixel_order.cr ├── surface.cr ├── surface_observer_mode.cr ├── surface_type.cr ├── svg_surface.cr ├── svg_unit.cr ├── svg_version.cr ├── tee_surface.cr ├── text_cluster.cr ├── text_cluster_array.cr ├── text_cluster_flags.cr ├── text_extents.cr ├── user_data_key.cr ├── version.cr └── xlib_surface.cr /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cr] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at szektam2@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 1. Fork it ( https://github.com/TamasSzekeres/cairo-cr/fork ) 4 | 2. Create your feature branch (git checkout -b my-new-feature) 5 | 3. Commit your changes (git commit -am 'Add some feature') 6 | 4. Push to the branch (git push origin my-new-feature) 7 | 5. Create a new Pull Request 8 | 9 | # Contributors 10 | 11 | - [TamasSzekeres](https://github.com/TamasSzekeres) Tamás Szekeres - creator, maintainer 12 | -------------------------------------------------------------------------------- /.github/workflows/crystal.yml: -------------------------------------------------------------------------------- 1 | name: Crystal CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Download source 14 | uses: actions/checkout@v2 15 | - name: Install X11 (ubuntu-latest) 16 | run: sudo apt-get install libx11-dev 17 | - name: Install Cairo (ubuntu-latest) 18 | run: sudo apt-get install libcairo2 libcairo2-dev 19 | - name: Install Crystal 20 | uses: oprypin/install-crystal@v1 21 | - name: Install shards 22 | run: shards update --ignore-crystal-version 23 | - name: Run tests 24 | run: crystal spec -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy docs 2 | on: 3 | push: 4 | pull_request: 5 | schedule: 6 | - cron: '0 6 * * 6' 7 | jobs: 8 | build: 9 | name: Deploy docs 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Download source 13 | uses: actions/checkout@v2 14 | - name: Install Crystal 15 | uses: oprypin/install-crystal@v1 16 | - name: Install shards 17 | run: shards update --ignore-crystal-version 18 | - name: Generate docs 19 | run: crystal doc 20 | - name: Deploy to gh-pages 21 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 22 | uses: oprypin/push-to-gh-pages@v3 23 | with: 24 | publish_dir: docs 25 | commit_message: 'Generate docs: ' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /doc/ 3 | /docs/ 4 | /libs/ 5 | /lib/ 6 | /.crystal/ 7 | /.shards/ 8 | 9 | /examples/sample_window/sample_window 10 | /examples/sample_window_hl/sample_window_hl 11 | 12 | # Libraries don't need dependency lock 13 | # Dependencies will be locked in application that uses them 14 | /shard.lock 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [1.0.3] - 2022-06-12 8 | ### Fixed 9 | - change return type of `LibCairo::pop_group_to_source` to `Void` 10 | - invalid function call in `Context::pop_group_to_source` (thanks, @aravindavk) 11 | 12 | ## [1.0.2] - 2022-05-02 13 | ### Fixed 14 | - missing argument in `Context::set_source_surface` (thanks, @aravindavk) 15 | 16 | ## [1.0.1] - 2022-01-22 17 | ### Fixed 18 | - wrong code in documentation (thanks, @aravindavk) 19 | 20 | ## [1.0.0] - 2021-04-13 21 | - Updated to Crystal 1.0.0 22 | ### Added 23 | - Documentation 24 | - Pdf types: 25 | - `PdfOutlineFlags` 26 | - `PdfMetadata` 27 | - Pdf functions: 28 | - `PdfSurface#set_metadata` 29 | - `PdfSurface#set_page_label` 30 | - `PdfSurface#set_thumbnail_size` 31 | - Svg type: 32 | - `SvgUnit` 33 | - Svg functions: 34 | - `SvgSurface#document_unit` 35 | - `SvgSurface#document_unit=` 36 | 37 | ## [0.3.1] - 2020-09-23 38 | - Updated to Crystal 0.35.1 39 | 40 | ## [0.3.0] - 2019-10-13 41 | - Updated to Crystal 0.31.1 42 | ### Fixed 43 | - Must rename `unsafe_at` to `unsafe_fetch` in `Cairo::RectangleList` (#8, thanks @DmitryBochkarev) 44 | 45 | ## [0.2.2] - 2018-06-17 46 | ### Fixed 47 | - namespace missing in `Context::initializer` (#7, thanks @hodefoting) 48 | 49 | ## [0.2.1] - 2018-03-21 50 | ### Fixed 51 | - `Context::font_face` function (#6, thanks @bird1079s) 52 | 53 | ## [0.2.0] - 2018-01-20 54 | ### Added 55 | - High level classes and structs. 56 | ### Changed 57 | - **(breaking change)** Low level binding moved to **C** namespace 58 | - **(breaking change)** `Cairo` binding class renamed to `LibCairo` 59 | 60 | ## [0.1.0] - 2017-05-18 61 | - First release 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2021 Tamás Szekeres 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cairo-cr 2 | 3 | [Cairo](https://cairographics.org/) bindings for Crystal language. 4 | 5 | ![Crystal CI](https://github.com/TamasSzekeres/cairo-cr/actions/workflows/crystal.yml/badge.svg) 6 | [![GitHub release](https://img.shields.io/github/release/TamasSzekeres/cairo-cr.svg)](https://github.com/TamasSzekeres/cairo-cr/releases) 7 | [![Docs](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://tamasszekeres.github.io/cairo-cr/) 8 | 9 | ## Installation 10 | 11 | First install cairo: 12 | ```bash 13 | sudo apt-get install libcairo2 libcairo2-dev 14 | ``` 15 | 16 | Add this to your application's `shard.yml`: 17 | 18 | ```yaml 19 | dependencies: 20 | cairo: 21 | github: TamasSzekeres/cairo-cr 22 | ``` 23 | Then run in terminal: 24 | ```bash 25 | shards install 26 | ``` 27 | 28 | See also: [x11-cr](https://github.com/TamasSzekeres/x11-cr) 29 | 30 | ## Usage 31 | 32 | ```crystal 33 | require "x11" 34 | require "cairo" 35 | 36 | module YourModule 37 | include X11::C # for low-level usage 38 | include Cairo::C # for low-level usage 39 | include X11 # for high-level usage 40 | include Cairo # for high-level usage 41 | end 42 | ``` 43 | 44 | For more details see the sample in [/examples](/examples) folder. 45 | 46 | ## Sample 47 | 48 | Build and run the low-level sample: 49 | ```shell 50 | cd examples/sample_window 51 | shards build 52 | ./bin/sample_window 53 | ``` 54 | ![Sample Window](https://raw.githubusercontent.com/TamasSzekeres/cairo-cr/master/examples/screenshot/sample_window.png) 55 | 56 | Build and run the high-level sample: 57 | ```shell 58 | cd examples/sample_window_hl 59 | shards build 60 | ./bin/sample_window 61 | ``` 62 | 63 | ## Documentation 64 | 65 | You can generate documentation for yourself: 66 | ```shell 67 | crystal doc 68 | ``` 69 | Then you can open `/docs/index.html` in your browser. 70 | 71 | Or you can view last commited documentation online at: [https://tamasszekeres.github.io/cairo-cr/](https://tamasszekeres.github.io/cairo-cr/). 72 | 73 | ## Contributing 74 | 75 | 1. Fork it () 76 | 2. Create your feature branch (git checkout -b my-new-feature) 77 | 3. Commit your changes (git commit -am 'Add some feature') 78 | 4. Push to the branch (git push origin my-new-feature) 79 | 5. Create a new Pull Request 80 | 81 | ## Contributors 82 | 83 | - [Tamás Szekeres](https://github.com/TamasSzekeres) - creator, maintainer 84 | -------------------------------------------------------------------------------- /examples/sample_window/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | 6 | /sample_window 7 | 8 | # Libraries don't need dependency lock 9 | # Dependencies will be locked in application that uses them 10 | /shard.lock 11 | -------------------------------------------------------------------------------- /examples/sample_window/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | crystal build src/sample_window.cr --link-flags -L/usr/X11R6/lib/ 3 | 4 | clean: 5 | rm sample_window 6 | -------------------------------------------------------------------------------- /examples/sample_window/shard.yml: -------------------------------------------------------------------------------- 1 | name: sample_window 2 | version: 0.1.0 3 | 4 | authors: 5 | - Tamás Szekeres 6 | 7 | targets: 8 | sample_window: 9 | main: src/sample_window.cr 10 | 11 | dependencies: 12 | x11: 13 | github: TamasSzekeres/x11-cr 14 | branch: master 15 | 16 | cairo: 17 | github: TamasSzekeres/cairo-cr 18 | branch: master 19 | 20 | crystal: 0.35.1 21 | 22 | license: MIT 23 | -------------------------------------------------------------------------------- /examples/sample_window/spec/sample_window_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe SampleWindow do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /examples/sample_window/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/sample_window" 3 | -------------------------------------------------------------------------------- /examples/sample_window/src/sample_window.cr: -------------------------------------------------------------------------------- 1 | require "x11" 2 | require "cairo" 3 | 4 | module X11Sample 5 | include X11::C 6 | include Cairo::C 7 | 8 | WM_DELETE_WINDOW_STR = "WM_DELETE_WINDOW" 9 | 10 | def self.main 11 | d = uninitialized X::PDisplay 12 | d = X.open_display(nil) 13 | wm_delete_window = X.intern_atom(d, WM_DELETE_WINDOW_STR, 0) 14 | 15 | if d.is_a?(Nil) 16 | return 1 17 | end 18 | 19 | s = X11::C.default_screen d 20 | root_win = X11::C.root_window d, s 21 | black_pix = X11::C.black_pixel d, s 22 | white_pix = X11::C.white_pixel d, s 23 | win = X.create_simple_window d, root_win, 10, 10, 400, 300, 1, black_pix, white_pix 24 | X.select_input d, win, 25 | ButtonPressMask | ButtonReleaseMask | 26 | ButtonMotionMask | ExposureMask | EnterWindowMask | 27 | LeaveWindowMask | KeyPressMask | KeyReleaseMask 28 | X.map_window d, win 29 | X.set_wm_protocols d, win, pointerof(wm_delete_window), 1 30 | 31 | # Set Window Title. 32 | X.store_name d, win, "Simple Window" 33 | 34 | sfc = LibCairo.xlib_surface_create d, win, X.default_visual(d, s), 400, 300 35 | ctx = LibCairo.create sfc 36 | 37 | e = uninitialized X::Event 38 | while true 39 | if X.pending d 40 | X.next_event(d, pointerof(e)) 41 | case e.type 42 | when Expose 43 | LibCairo.set_source_rgba ctx, 1, 1, 1, 1 44 | LibCairo.rectangle ctx, 0, 0, 400, 300 45 | LibCairo.fill ctx 46 | 47 | LibCairo.set_source_rgb ctx, 0, 0, 0 48 | LibCairo.move_to ctx, 0, 0 49 | LibCairo.line_to ctx, 400, 300 50 | LibCairo.move_to ctx, 400, 0 51 | LibCairo.line_to ctx, 0, 300 52 | LibCairo.set_line_width ctx, 10 53 | LibCairo.stroke ctx 54 | 55 | LibCairo.rectangle ctx, 0, 0, 200, 150 56 | LibCairo.set_source_rgba ctx, 1, 0, 0, 0.80 57 | LibCairo.fill ctx 58 | 59 | LibCairo.rectangle ctx, 0, 150, 200, 150 60 | LibCairo.set_source_rgba ctx, 0, 1, 0, 0.60 61 | LibCairo.fill ctx 62 | 63 | LibCairo.rectangle ctx, 200, 0, 200, 150 64 | LibCairo.set_source_rgba ctx, 0, 0, 1, 0.40 65 | LibCairo.fill ctx 66 | when ClientMessage 67 | break if e.client.data.ul[0] == wm_delete_window 68 | when KeyPress 69 | break 70 | end 71 | end 72 | end 73 | 74 | LibCairo.destroy ctx 75 | LibCairo.surface_destroy sfc 76 | 77 | X.destroy_window d, win 78 | X.close_display d 79 | 0 80 | end 81 | 82 | main 83 | end 84 | -------------------------------------------------------------------------------- /examples/sample_window/src/sample_window/version.cr: -------------------------------------------------------------------------------- 1 | module SampleWindow 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /examples/sample_window_hl/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | 6 | /sample_window_hl 7 | 8 | # Libraries don't need dependency lock 9 | # Dependencies will be locked in application that uses them 10 | /shard.lock 11 | -------------------------------------------------------------------------------- /examples/sample_window_hl/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | crystal build src/sample_window_hl.cr --link-flags -L/usr/X11R6/lib/ 3 | 4 | clean: 5 | rm sample_window_hl 6 | -------------------------------------------------------------------------------- /examples/sample_window_hl/shard.yml: -------------------------------------------------------------------------------- 1 | name: sample_window_hl 2 | version: 1.0.0 3 | crystal: ~> 1.0 4 | 5 | authors: 6 | - Tamás Szekeres 7 | 8 | license: MIT 9 | 10 | targets: 11 | sample_window: 12 | main: src/sample_window_hl.cr 13 | 14 | dependencies: 15 | x11: 16 | github: TamasSzekeres/x11-cr 17 | branch: master 18 | version: ~> 1.0 19 | 20 | cairo: 21 | github: TamasSzekeres/cairo-cr 22 | branch: master 23 | varsion: ~> 1.0 24 | -------------------------------------------------------------------------------- /examples/sample_window_hl/spec/sample_window_hl_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe SampleWindowHl do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /examples/sample_window_hl/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/sample_window_hl" 3 | -------------------------------------------------------------------------------- /examples/sample_window_hl/src/sample_window_hl.cr: -------------------------------------------------------------------------------- 1 | require "x11" 2 | require "cairo" 3 | 4 | module X11Sample 5 | include X11 6 | include Cairo 7 | 8 | WM_DELETE_WINDOW_STR = "WM_DELETE_WINDOW" 9 | 10 | def self.main 11 | d = Display.new 12 | wm_delete_window = d.intern_atom(WM_DELETE_WINDOW_STR, false) 13 | 14 | s = d.default_screen_number 15 | root_win = d.root_window s 16 | black_pix = d.black_pixel s 17 | white_pix = d.white_pixel s 18 | win = d.create_simple_window root_win, 10, 10, 400_u32, 300_u32, 1_u32, black_pix, white_pix 19 | d.select_input win, 20 | ButtonPressMask | ButtonReleaseMask | 21 | ButtonMotionMask | ExposureMask | EnterWindowMask | 22 | LeaveWindowMask | KeyPressMask | KeyReleaseMask 23 | d.map_window win 24 | d.set_wm_protocols win, [wm_delete_window] 25 | 26 | # Set Window Title. 27 | d.store_name win, "Simple Window" 28 | 29 | sfc = Cairo::XlibSurface.new d, win, d.default_visual(s), 400, 300 30 | ctx = Cairo::Context.new sfc 31 | 32 | while true 33 | if d.pending 34 | e = d.next_event 35 | case e 36 | when ExposeEvent 37 | ctx.set_source_rgba 1.0, 0.0, 1.0, 1.0 38 | ctx.rectangle 0.0, 0.0, 400.0, 300.0 39 | ctx.fill 40 | 41 | ctx.set_source_rgb 0.0, 0.0, 0.0 42 | ctx.move_to 0.0, 0.0 43 | ctx.line_to 400.0, 300.0 44 | ctx.move_to 400.0, 0.0 45 | ctx.line_to 0.0, 300.0 46 | ctx.line_width = 10.0 47 | ctx.stroke 48 | 49 | ctx.rectangle 0.0, 0.0, 200.0, 150.0 50 | ctx.set_source_rgba 1.0, 0.0, 0.0, 0.80 51 | ctx.fill 52 | 53 | ctx.rectangle 0.0, 150.0, 200.0, 150.0 54 | ctx.set_source_rgba 0.0, 1.0, 0.0, 0.60 55 | ctx.fill 56 | 57 | ctx.rectangle 200.0, 0.0, 200.0, 150.0 58 | ctx.set_source_rgba 0.0, 0.0, 1.0, 0.40 59 | ctx.fill 60 | when ClientMessageEvent 61 | break if e.long_data[0] == wm_delete_window 62 | when KeyEvent 63 | break if e.press? 64 | end 65 | end 66 | end 67 | 68 | d.destroy_window win 69 | d.close 70 | 0 71 | end 72 | 73 | main 74 | end 75 | -------------------------------------------------------------------------------- /examples/sample_window_hl/src/sample_window_hl/version.cr: -------------------------------------------------------------------------------- 1 | module SampleWindowHl 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /examples/screenshot/sample_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TamasSzekeres/cairo-cr/3db25791492069d64056e5f2f2a803d2438aeb25/examples/screenshot/sample_window.png -------------------------------------------------------------------------------- /examples/svg_sample/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | 6 | /sample_window_hl 7 | 8 | # Libraries don't need dependency lock 9 | # Dependencies will be locked in application that uses them 10 | /shard.lock 11 | -------------------------------------------------------------------------------- /examples/svg_sample/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | shards build src/svg_sample.cr 3 | -------------------------------------------------------------------------------- /examples/svg_sample/shard.yml: -------------------------------------------------------------------------------- 1 | name: svg_sample 2 | version: 0.1.0 3 | 4 | authors: 5 | - ErikWDev 6 | - Tamás Szekeres 7 | 8 | targets: 9 | svg_sample: 10 | main: src/svg_sample.cr 11 | 12 | dependencies: 13 | x11: 14 | github: TamasSzekeres/x11-cr 15 | branch: master 16 | 17 | cairo: 18 | github: TamasSzekeres/cairo-cr 19 | branch: master 20 | 21 | crystal: 0.35.1 22 | 23 | license: MIT 24 | -------------------------------------------------------------------------------- /examples/svg_sample/src/svg_sample.cr: -------------------------------------------------------------------------------- 1 | require "cairo" 2 | 3 | at_exit do 4 | GC.collect 5 | end 6 | 7 | 8 | module SvgDrawing 9 | include Cairo 10 | 11 | def self.main 12 | # Create a new SvgSurface and specify a filename and dimensions 13 | surface = Cairo::SvgSurface.new "test.svg", 400, 300 14 | 15 | # (Optional) Restrict which version of SVG that Cairo should use. 16 | surface.restrict_to_version Cairo::SvgVersion::V_1_2 17 | 18 | # Create a context based on the surface 19 | ctx = Cairo::Context.new surface 20 | 21 | 22 | # Draw some nice shapes 23 | ctx.set_source_rgba 1.0, 0.0, 1.0, 1.0 24 | ctx.rectangle 0.0, 0.0, 400.0, 300.0 25 | ctx.fill 26 | 27 | ctx.set_source_rgb 0.0, 0.0, 0.0 28 | ctx.move_to 0.0, 0.0 29 | ctx.line_to 400.0, 300.0 30 | ctx.move_to 400.0, 0.0 31 | ctx.line_to 0.0, 300.0 32 | ctx.line_width = 10.0 33 | ctx.stroke 34 | 35 | ctx.rectangle 0.0, 0.0, 200.0, 150.0 36 | ctx.set_source_rgba 1.0, 0.0, 0.0, 0.80 37 | ctx.fill 38 | 39 | ctx.rectangle 0.0, 150.0, 200.0, 150.0 40 | ctx.set_source_rgba 0.0, 1.0, 0.0, 0.60 41 | ctx.fill 42 | 43 | ctx.rectangle 200.0, 0.0, 200.0, 150.0 44 | ctx.set_source_rgba 0.0, 0.0, 1.0, 0.40 45 | ctx.fill 46 | 47 | # Finish the surface by calling surface.finish 48 | surface.finish 49 | end 50 | 51 | main 52 | end 53 | -------------------------------------------------------------------------------- /shard.yml: -------------------------------------------------------------------------------- 1 | name: cairo 2 | version: 1.0.0 3 | crystal: ">= 0.35.0" 4 | 5 | authors: 6 | - Tamás Szekeres 7 | 8 | license: MIT 9 | 10 | description: | 11 | Cairo bindings for Crystal language. 12 | 13 | documentation: https://tamasszekeres.github.io/cairo-cr/ 14 | 15 | dependencies: 16 | x11: 17 | github: TamasSzekeres/x11-cr 18 | branch: master 19 | version: ~> 1.0 20 | 21 | libraries: 22 | libcairo: ~> 1.17 -------------------------------------------------------------------------------- /spec/cairo-cr_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Cairo do 4 | it "works" do 5 | true.should eq(true) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/cairo" 3 | -------------------------------------------------------------------------------- /src/cairo.cr: -------------------------------------------------------------------------------- 1 | require "./cairo/c/*" 2 | require "./cairo/*" 3 | -------------------------------------------------------------------------------- /src/cairo/antialias.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies the type of antialiasing to do when rendering text or shapes. 3 | # 4 | # As it is not necessarily clear from the above what advantages a particular antialias method provides, 5 | # there is also a set of hints: 6 | # - `Antialias::Fast` : Allow the backend to degrade raster quality for speed 7 | # - `Antialias::Good` : A balance between speed and quality 8 | # - `Antialias::Best` : A high-fidelity, but potentially slow, raster mode 9 | # 10 | # These make no guarantee on how the backend will perform its rasterisation (if it even rasterises!), 11 | # nor that they have any differing effect other than to enable some form of antialiasing. 12 | # In the case of glyph rendering, `Antialias::Fast` and `Antialias::Good` will be mapped to `Antialias::Gray`, 13 | # with `Antialias::Best` being equivalent to `Antialias::Subpixel`. 14 | # 15 | # The interpretation of `Antialias::Default` is left entirely up to the backend, 16 | # typically this will be similar to `Antialias::Good` . 17 | enum Antialias 18 | # Use the default antialiasing for the subsystem and target device. 19 | Default 20 | 21 | # Use a bilevel alpha mask. 22 | None 23 | 24 | # Perform single-color antialiasing (using shades of gray for black text on a white background, for example). 25 | Gray 26 | 27 | # Perform antialiasing by taking advantage of the order of subpixel elements on devices such as LCD panels. 28 | Subpixel 29 | 30 | # Hint that the backend should perform some antialiasing but prefer speed over quality. 31 | Fast 32 | 33 | # The backend should balance quality against performance 34 | Good 35 | 36 | # Hint that the backend should render at the highest quality, sacrificing speed if necessary. 37 | Best 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /src/cairo/c/features.cr: -------------------------------------------------------------------------------- 1 | module Cairo::C 2 | HAS_FC_FONT = true 3 | HAS_FT_FONT = true 4 | HAS_GOBJECT_FUNCTIONS = true 5 | 6 | # Defined if the image surface backend is available. 7 | # The image surface backend is always built in. 8 | HAS_IMAGE_SURFACE = true 9 | 10 | HAS_MIME_SURFACE = true 11 | HAS_OBSERVER_SURFACE = true 12 | 13 | # Defined if the PDF surface backend is available. 14 | HAS_PDF_SURFACE = true 15 | 16 | # Defined if the PNG functions are available. 17 | HAS_PNG_FUNCTIONS = true 18 | 19 | # Defined if the PostScript surface backend is available. 20 | HAS_PS_SURFACE = true 21 | 22 | # Defined if the recording surface backend is available. 23 | HAS_RECORDING_SURFACE = true 24 | 25 | # Defined if the script surface backend is available. 26 | HAS_SCRIPT_SURFACE = true 27 | 28 | # Defined if the Microsoft Windows surface backend is available. 29 | HAS_WIN32_SURFACE = false 30 | 31 | # Defined if the SVG surface backend is available. 32 | HAS_SVG_SURFACE = true 33 | 34 | # Defined if the tee surface backend is available. 35 | HAS_TEE_SURFACE = true 36 | 37 | # Defined if the user font backend is available. 38 | HAS_USER_FONT = true 39 | 40 | # Defined if the Quartz surface backend is available. 41 | HAS_QUARTZ_SURFACE = false 42 | 43 | # Defined if the xcb surface backend is available. 44 | HAS_XCB_SURFACE = false 45 | HAS_XCB_SHM_FUNCTIONS = false 46 | 47 | # Defined if the Xlib surface backend is available. 48 | HAS_XLIB_SURFACE = true 49 | 50 | # Defined if the XLib/XRender surface functions are available. 51 | HAS_XLIB_XRENDER_SURFACE = false 52 | end # module Cairo::C 53 | -------------------------------------------------------------------------------- /src/cairo/c/pdf.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_PDF_SURFACE %} 5 | module Cairo::C 6 | @[Link("cairo")] 7 | lib LibCairo 8 | enum PdfVersionT 9 | V_1_4 10 | V_1_5 11 | end 12 | 13 | fun pdf_surface_create = cairo_pdf_surface_create( 14 | filename : UInt8*, 15 | width_in_points : Float64, 16 | height_in_points : Float64 17 | ) : PSurfaceT 18 | 19 | fun pdf_surface_create_for_stream = cairo_pdf_surface_create_for_stream( 20 | write_func : WriteFuncT, 21 | closure : Void*, 22 | width_in_points : Float64, 23 | height_in_points : Float64 24 | ) : PSurfaceT 25 | 26 | fun pdf_surface_restrict_to_version = cairo_pdf_surface_restrict_to_version( 27 | surface : PSurfaceT, 28 | version : PdfVersionT 29 | ) : Void 30 | 31 | fun pdf_get_versions = cairo_pdf_get_versions( 32 | versions : PdfVersionT**, 33 | num_versions : Int32* 34 | ) : Void 35 | 36 | fun pdf_version_to_string = cairo_pdf_version_to_string( 37 | version : PdfVersionT 38 | ) : UInt8* 39 | 40 | fun pdf_surface_set_size = cairo_pdf_surface_set_size( 41 | surface : PSurfaceT, 42 | width_in_points : Float64, 43 | height_in_points : Float64 44 | ) : Void 45 | 46 | @[Flags] 47 | enum PdfOutlineFlagsT 48 | Open = 0x1 49 | Bold = 0x2 50 | Italic = 0x4 51 | end 52 | 53 | PDF_OUTLINE_ROOT = 0 54 | 55 | fun pdf_surface_add_outline = cairo_pdf_surface_add_outline( 56 | parent_id : Int32, 57 | utf8 : UInt8*, 58 | link_attribs : UInt8*, 59 | flags : PdfOutlineFlagsT 60 | ) : Int32 61 | 62 | enum PdfMetadataT 63 | Title 64 | Author 65 | Subject 66 | Keywords 67 | Creator 68 | CreateDate 69 | ModDate 70 | end 71 | 72 | fun pdf_surface_set_metadata = cairo_pdf_surface_set_metadata( 73 | surface : PSurfaceT, 74 | metadata : PdfMetadataT, 75 | utf8 : UInt8* 76 | ) : Void 77 | 78 | fun pdf_surface_set_page_label = cairo_pdf_surface_set_page_label( 79 | surface : PSurfaceT, 80 | utf8 : UInt8* 81 | ) : Void 82 | 83 | fun pdf_surface_set_thumbnail_size = cairo_pdf_surface_set_thumbnail_size( 84 | surface : PSurfaceT, 85 | width : Int32, 86 | height : Int32 87 | ) : Void 88 | 89 | end # lib LibCairo 90 | end # module Cairo::C 91 | {% else %} # Cairo::C::HAS_PDF_SURFACE 92 | puts "Cairo was not compiled with support for the pdf backend" 93 | {% end %} # Cairo::C::HAS_PDF_SURFACE 94 | -------------------------------------------------------------------------------- /src/cairo/c/ps.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_PS_SURFACE %} 5 | module Cairo::C 6 | @[Link("cairo")] 7 | lib LibCairo 8 | # PS-surface functions 9 | 10 | enum PsLevelT 11 | Level2 12 | Level3 13 | end 14 | 15 | fun ps_surface_create = cairo_ps_surface_create( 16 | filename : UInt8*, 17 | width_in_points : Float64, 18 | height_in_points : Float64 19 | ) : PSurfaceT 20 | 21 | fun ps_surface_create_for_stream = cairo_ps_surface_create_for_stream( 22 | write_func : WriteFuncT, 23 | closure : Void*, 24 | width_in_points : Float64, 25 | height_in_points : Float64 26 | ) : PSurfaceT 27 | 28 | fun ps_surface_restrict_to_level = cairo_ps_surface_restrict_to_level( 29 | surface : PSurfaceT, 30 | level : PsLevelT 31 | ) : Void 32 | 33 | fun ps_get_levels = cairo_ps_get_levels( 34 | levels : PsLevelT**, 35 | num_levels : Int32* 36 | ) : Void 37 | 38 | fun ps_level_to_string = cairo_ps_level_to_string( 39 | level : PsLevelT 40 | ) : UInt8* 41 | 42 | fun ps_surface_set_eps = cairo_ps_surface_set_eps( 43 | surface : PSurfaceT, 44 | eps : BoolT 45 | ) : Void 46 | 47 | fun ps_surface_get_eps = cairo_ps_surface_get_eps( 48 | surface : PSurfaceT 49 | ) : BoolT 50 | 51 | fun ps_surface_set_size = cairo_ps_surface_set_size( 52 | surface : PSurfaceT, 53 | width_in_points : Float64, 54 | height_in_points : Float64 55 | ) : Void 56 | 57 | fun ps_surface_dsc_comment = cairo_ps_surface_dsc_comment( 58 | surface : PSurfaceT, 59 | comment : UInt8* 60 | ) : Void 61 | 62 | fun ps_surface_dsc_begin_setup = cairo_ps_surface_dsc_begin_setup( 63 | surface : PSurfaceT 64 | ) : Void 65 | 66 | fun ps_surface_dsc_begin_page_setup = cairo_ps_surface_dsc_begin_page_setup( 67 | surface : PSurfaceT 68 | ) : Void 69 | end # lib LibCairo 70 | end # module Cairo::C 71 | {% else %} # Cairo::C::HAS_PS_SURFACE 72 | puts "Cairo was not compiled with support for the ps backend" 73 | {% end %} # Cairo::C::HAS_PS_SURFACE 74 | -------------------------------------------------------------------------------- /src/cairo/c/script.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_SCRIPT_SURFACE %} 5 | module Cairo::C 6 | @[Link("cairo")] 7 | lib LibCairo 8 | enum ScriptModeT 9 | ModeAscii 10 | ModeBinary 11 | end 12 | 13 | fun script_create = cairo_script_create( 14 | filename : UInt8* 15 | ) : PDeviceT 16 | 17 | fun script_create_for_stream = cairo_script_create_for_stream( 18 | write_func : WriteFuncT, 19 | closure : Void* 20 | ) : PDeviceT 21 | 22 | fun script_write_comment = cairo_script_write_comment( 23 | script : PDeviceT, 24 | comment : UInt8*, 25 | len : Int32 26 | ) : Void 27 | 28 | fun script_set_mode = cairo_script_set_mode( 29 | script : PDeviceT, 30 | mode : ScriptModeT 31 | ) : Void 32 | 33 | fun script_get_mode = cairo_script_get_mode( 34 | script : PDeviceT 35 | ) : ScriptModeT 36 | 37 | fun script_surface_create = cairo_script_surface_create( 38 | script : PDeviceT, 39 | content : ContentT, 40 | width : Float64, 41 | height : Float64 42 | ) : PSurfaceT 43 | 44 | fun script_surface_create_for_target = cairo_script_surface_create_for_target( 45 | script : PDeviceT, 46 | target : PSurfaceT 47 | ) : PSurfaceT 48 | 49 | fun script_from_recording_surface = cairo_script_from_recording_surface( 50 | script : PDeviceT, 51 | recording_surface : PSurfaceT 52 | ) : StatusT 53 | end # lib LibCairo 54 | end # module Cairo::C 55 | {% else %} # Cairo::C::HAS_SCRIPT_SURFACE 56 | puts "Cairo was not compiled with support for the CairoScript backend" 57 | {% end %} # Cairo::C::HAS_SCRIPT_SURFACE 58 | -------------------------------------------------------------------------------- /src/cairo/c/script_interpreter.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | 3 | module Cairo::C 4 | @[Link("cairo")] 5 | lib LibCairo 6 | alias PScriptInterpreterT = ScriptInterpreterT* 7 | alias ScriptInterpreterT = Void* 8 | 9 | # closure, ptr -> void 10 | alias CsiDestroyFuncT = Void*, Void* -> Void 11 | 12 | # closure, content, width, height, uid -> surface 13 | alias CsiSurfaceCreateFuncT = Void*, ContentT, Float64, Float64, Int64 -> PSurfaceT 14 | 15 | # closure, surface -> cairo 16 | alias CsiContextCreateFuncT = Void*, PSurfaceT -> PCairoT 17 | 18 | # closure, cr -> void 19 | alias CsiShowPageFuncT = Void*, PCairoT -> Void 20 | 21 | # closure, cr -> void 22 | alias CsiCopyPageFuncT = Void*, PCairoT -> Void 23 | 24 | # closure, format, width, height, uid -> surface 25 | alias CsiCreateSourceImageT = Void*, FormatT, Int32, Int32, Int64 -> PSurfaceT 26 | 27 | alias PScriptInterpreterHooksT = ScriptInterpreterHooksT* 28 | struct ScriptInterpreterHooksT 29 | closure : Void* 30 | surface_create : CsiSurfaceCreateFuncT 31 | surface_destroy : CsiDestroyFuncT 32 | context_create : CsiContextCreateFuncT 33 | context_destroy : CsiDestroyFuncT 34 | show_page : CsiShowPageFuncT 35 | copy_page : CsiShowPageFuncT 36 | create_source_image : CsiCreateSourceImageT 37 | end 38 | 39 | fun script_interpreter_create = cairo_script_interpreter_create( 40 | ) : PScriptInterpreterT 41 | 42 | fun script_interpreter_install_hooks = cairo_script_interpreter_install_hooks( 43 | ctx : PScriptInterpreterT, 44 | hooks : PScriptInterpreterHooksT 45 | ) : Void 46 | 47 | fun script_interpreter_run = cairo_script_interpreter_run( 48 | ctx : PScriptInterpreterT, 49 | filename : UInt8* 50 | ) : StatusT 51 | 52 | fun script_interpreter_feed_stream = cairo_script_interpreter_feed_stream( 53 | ctx : PScriptInterpreterT, 54 | stream : Int32 55 | ) : StatusT 56 | 57 | fun script_interpreter_feed_string = cairo_script_interpreter_feed_string( 58 | ctx : PScriptInterpreterT, 59 | line : UInt8*, 60 | len : Int32 61 | ) : StatusT 62 | 63 | fun script_interpreter_get_line_number = cairo_script_interpreter_get_line_number( 64 | ctx : PScriptInterpreterT 65 | ) : UInt32 66 | 67 | fun script_interpreter_reference = cairo_script_interpreter_reference( 68 | ctx : PScriptInterpreterT 69 | ) : PScriptInterpreterT 70 | 71 | fun script_interpreter_finish = cairo_script_interpreter_finish( 72 | ctx : PScriptInterpreterT 73 | ) : StatusT 74 | 75 | fun script_interpreter_destroy = cairo_script_interpreter_destroy( 76 | ctx : PScriptInterpreterT 77 | ) : StatusT 78 | 79 | fun script_interpreter_translate_stream = cairo_script_interpreter_translate_stream( 80 | stream : Int32, 81 | write_func : WriteFuncT, 82 | closure : Void* 83 | ) : StatusT 84 | end # lib LibCairo 85 | end # module Cairo::C 86 | -------------------------------------------------------------------------------- /src/cairo/c/svg.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_SVG_SURFACE %} 5 | module Cairo::C 6 | @[Link("cairo")] 7 | lib LibCairo 8 | enum SvgVersionT 9 | V_1_1 10 | V_1_2 11 | end 12 | 13 | enum SvgUnitT 14 | User = 0 15 | Em 16 | Ex 17 | Px 18 | In 19 | Cm 20 | Mm 21 | Pt 22 | Pc 23 | Percent 24 | end 25 | 26 | fun svg_surface_create = cairo_svg_surface_create( 27 | filename : UInt8*, 28 | width_in_points : Float64, 29 | height_in_points : Float64 30 | ) : PSurfaceT 31 | 32 | fun svg_surface_create_for_stream = cairo_svg_surface_create_for_stream( 33 | write_func : WriteFuncT, 34 | closure : Void*, 35 | width_in_points : Float64, 36 | height_in_points : Float64 37 | ) : PSurfaceT 38 | 39 | fun svg_surface_restrict_to_version = cairo_svg_surface_restrict_to_version( 40 | surface : PSurfaceT, 41 | version : SvgVersionT 42 | ) : Void 43 | 44 | fun svg_get_versions = cairo_svg_get_versions( 45 | versions : SvgVersionT**, 46 | num_versions : Int32* 47 | ) : Void 48 | 49 | fun svg_version_to_string = cairo_svg_version_to_string( 50 | version : SvgVersionT 51 | ) : UInt8* 52 | 53 | fun svg_surface_set_document_unit = cairo_svg_surface_set_document_unit( 54 | surface : PSurfaceT, 55 | unit : SvgUnitT 56 | ) : Void 57 | 58 | fun svg_surface_get_document_unit = cairo_svg_surface_get_document_unit( 59 | surface : PSurfaceT 60 | ) : SvgUnitT 61 | end # lib LibCairo 62 | end # module Cairo::C 63 | {% else %} # Cairo::C::HAS_SVG_SURFACE 64 | puts "Cairo was not compiled with support for the svg backend" 65 | {% end %} # Cairo::C::HAS_SVG_SURFACE 66 | -------------------------------------------------------------------------------- /src/cairo/c/tee.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_TEE_SURFACE %} 5 | module Cairo::C 6 | @[Link("cairo")] 7 | lib LibCairo 8 | fun tee_surface_create = cairo_tee_surface_create( 9 | master : PSurfaceT 10 | ) : PSurfaceT 11 | 12 | fun tee_surface_add = cairo_tee_surface_add( 13 | surface : PSurfaceT, 14 | target : PSurfaceT 15 | ) : Void 16 | 17 | fun tee_surface_remove = cairo_tee_surface_remove( 18 | surface : PSurfaceT, 19 | target : PSurfaceT 20 | ) : Void 21 | 22 | fun tee_surface_index = cairo_tee_surface_index( 23 | surface : PSurfaceT, 24 | index : UInt32 25 | ) : PSurfaceT 26 | end # lib LibCairo 27 | end # module Cairo::C 28 | {% else %} # Cairo::C::HAS_TEE_SURFACE 29 | puts "Cairo was not compiled with support for the TEE backend" 30 | {% end %} # Cairo::C::HAS_TEE_SURFACE 31 | -------------------------------------------------------------------------------- /src/cairo/c/xlib.cr: -------------------------------------------------------------------------------- 1 | require "./lib_cairo" 2 | require "./features" 3 | 4 | {% if Cairo::C::HAS_XLIB_SURFACE %} 5 | require "x11" 6 | 7 | module Cairo::C 8 | include X11 9 | 10 | @[Link("cairo")] 11 | lib LibCairo 12 | fun xlib_surface_create = cairo_xlib_surface_create( 13 | dpy : X::PDisplay, 14 | drawable : Drawable, 15 | visual : X::PVisual, 16 | width : Int32, 17 | height : Int32 18 | ) : PSurfaceT 19 | 20 | fun xlib_surface_create_for_bitmap = cairo_xlib_surface_create_for_bitmap( 21 | dpy : X::PDisplay, 22 | bitmap : Pixmap, 23 | screen : X::PScreen, 24 | width : Int32, 25 | height : Int32 26 | ) : PSurfaceT 27 | 28 | fun xlib_surface_set_size = cairo_xlib_surface_set_size( 29 | surface : PSurfaceT, 30 | width : Int32, 31 | height : Int32 32 | ) : Void 33 | 34 | fun xlib_surface_set_drawable = cairo_xlib_surface_set_drawable( 35 | surface : PSurfaceT, 36 | drawable : Drawable, 37 | width : Int32, 38 | height : Int32 39 | ) : Void 40 | 41 | fun xlib_surface_get_display = cairo_xlib_surface_get_display( 42 | surface : PSurfaceT 43 | ) : X::PDisplay 44 | 45 | fun xlib_surface_get_drawable = cairo_xlib_surface_get_drawable( 46 | surface : PSurfaceT 47 | ) : Drawable 48 | 49 | fun xlib_surface_get_screen = cairo_xlib_surface_get_screen( 50 | surface : PSurfaceT 51 | ) : X::PScreen 52 | 53 | fun xlib_surface_get_visual = cairo_xlib_surface_get_visual( 54 | surface : PSurfaceT 55 | ) : X::PVisual 56 | 57 | fun xlib_surface_get_depth = cairo_xlib_surface_get_depth( 58 | surface : PSurfaceT 59 | ) : Int32 60 | 61 | fun xlib_surface_get_width = cairo_xlib_surface_get_width( 62 | surface : PSurfaceT 63 | ) : Int32 64 | 65 | fun xlib_surface_get_height = cairo_xlib_surface_get_height( 66 | surface : PSurfaceT 67 | ) : Int32 68 | 69 | # debug interface 70 | 71 | fun xlib_device_debug_cap_xrender_version = cairo_xlib_device_debug_cap_xrender_version( 72 | device : PDeviceT, 73 | major_version : Int32, 74 | minor_version : Int32 75 | ) : Void 76 | 77 | # precision: -1 implies automatically choose based on antialiasing mode, 78 | # any other value overrides and sets the corresponding PolyMode. 79 | fun xlib_device_debug_set_precision = cairo_xlib_device_debug_set_precision( 80 | device : PDeviceT, 81 | precision : Int32 82 | ) : Void 83 | 84 | fun xlib_device_debug_get_precision = cairo_xlib_device_debug_get_precision( 85 | device : PDeviceT, 86 | ) : Int32 87 | end # lib LibCairo 88 | end # module Cairo::C 89 | {% else %} # Cairo::C::HAS_XLIB_SURFACE 90 | puts "Cairo was not compiled with support for the xlib backend" 91 | {% end %} # Cairo::C::HAS_XLIB_SURFACE 92 | -------------------------------------------------------------------------------- /src/cairo/color_stop.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | struct ColorStop 3 | property offset : Float64 4 | property rgba : RGBA 5 | 6 | def initialize(@offset : Float64, @rgba : RGBA) 7 | end 8 | 9 | def initialize(@offset : Float64, red : Float64, green : Float64, blue : Float64, alpha : Float64) 10 | @rgba = RGBA.new(red, green, blue, alpha) 11 | end 12 | 13 | def red 14 | @rgba.red 15 | end 16 | 17 | def red=(red : Float64) 18 | @rgba.red = red 19 | end 20 | 21 | def green 22 | @rgba.green 23 | end 24 | 25 | def green=(green : Float64) 26 | @rgba.green = green 27 | end 28 | 29 | def blue 30 | @rgba.blue 31 | end 32 | 33 | def blue=(blue : Float64) 34 | @rgba.blue = blue 35 | end 36 | 37 | def alpha 38 | @rgba.alpha 39 | end 40 | 41 | def alpha=(alpha : Float64) 42 | @rgba.alpha = alpha 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /src/cairo/content.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `Content` is used to describe the content that a surface will contain, 3 | # whether color information, alpha information (translucence vs. opacity), or both. 4 | # 5 | # NOTE: The large values here are designed to keep `content` values distinct 6 | # from `Format` values so that the implementation can detect the error if users confuse the two types. 7 | enum Content 8 | # The surface will hold color content only. 9 | Color = 0x1000 10 | 11 | # The surface will hold alpha content only. 12 | Alpha = 0x2000 13 | 14 | # The surface will hold color and alpha content. 15 | ColorAlpha = 0x3000 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/cairo/device.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Devices are the abstraction Cairo employs for the rendering system used by a `Surface`. 7 | # You can get the device of a surface using `Surface#device`. 8 | # 9 | # Devices are created using custom functions specific to the rendering system you want to use. 10 | # See the documentation for the surface types for those functions. 11 | # 12 | # An important function that devices fulfill is sharing access to the rendering system between 13 | # Cairo and your application. If you want to access a device directly that you used to draw to with Cairo, 14 | # you must first call `Device#flush` to ensure that Cairo finishes all operations on the device and resets it to a clean state. 15 | # 16 | # Cairo also provides the functions `Device#acquire` and `Device#release` to synchronize access to the 17 | # rendering system in a multithreaded environment. This is done internally, but can also be used by applications. 18 | # 19 | # 20 | # A `Device` represents the driver interface for drawing operations to a `Surface`. 21 | # There are different subtypes of `Device` for different drawing backends. 22 | # 23 | # The type of a device can be queried with `Device#type`. 24 | # 25 | # Memory management of `Device` is done with `Device#reference` and `Device#finalize`. 26 | class Device 27 | def initialize(device : LibCairo::PDeviceT) 28 | raise ArgumentError.new("'device' cannot be null.") if device.null? 29 | @device = device 30 | end 31 | 32 | # Decreases the reference count on device by one. If the result is zero, 33 | # then device and all associated resources are freed. See `Device#reference`. 34 | # 35 | # This function may acquire devices if the last reference was dropped. 36 | def finalize 37 | LibCairo.device_destroy(@device) 38 | end 39 | 40 | # Increases the reference count on device by one. This prevents device from being destroyed until 41 | # a matching call to `Device#finalize` is made. 42 | # 43 | # Use `Device#reference_count` to get the number of references to a `Device`. 44 | # 45 | # ###Returns 46 | # The referenced `Device`. 47 | def reference : Device 48 | Device.new(LibCairo.device_reference(@device)) 49 | end 50 | 51 | # This function returns the type of the device. See `DeviceType` for available types. 52 | # 53 | # ###Returns 54 | # The type of device. 55 | def type : DeviceType 56 | DeviceType.new(LibCairo.device_get_type(@device).value) 57 | end 58 | 59 | # Checks whether an error has previously occurred for this device. 60 | # 61 | # ###Returns 62 | # `Status#Success` on success or an error code if the device is in an error state. 63 | def status : Status 64 | Status.new(LibCairo.device_status(@device).value) 65 | end 66 | 67 | # Acquires the device for the current thread. This function will block until no other thread has acquired the device. 68 | # 69 | # If the return value is `Status::Success`, you successfully acquired the device. 70 | # From now on your thread owns the device and no other thread will be able to acquire it until 71 | # a matching call to `Device#release`. It is allowed to recursively acquire the device multiple times from the same thread. 72 | # 73 | # You must never acquire two different devices at the same time unless this is explicitly allowed. 74 | # Otherwise the possibility of deadlocks exist. As various Cairo functions can acquire devices when called, 75 | # these functions may also cause deadlocks when you call them with an acquired device. So you must not have 76 | # a device acquired when calling them. These functions are marked in the documentation. 77 | # 78 | # ###Returns 79 | # `Status::Success` on success or an error code if the device is in an error state and could not be acquired. 80 | # After a successful call to `Device#acquire`, a matching call to `Device#release` is required. 81 | def acquire : Status 82 | Status.new(LibCairo.device_acquire(@device).value) 83 | end 84 | 85 | # Releases a device previously acquired using `Device#acquire`. See that function for details. 86 | def release 87 | LibCairo.device_release(@device) 88 | self 89 | end 90 | 91 | # Finish any pending operations for the device and also restore any temporary modifications 92 | # cairo has made to the device's state. This function must be called before switching from 93 | # using the device with Cairo to operating on it directly with native APIs. 94 | # If the device doesn't support direct access, then this function does nothing. 95 | # 96 | # This function may acquire devices. 97 | def flush 98 | LibCairo.device_flush(@device) 99 | self 100 | end 101 | 102 | # This function finishes the device and drops all references to external resources. 103 | # All surfaces, fonts and other objects created for this device will be finished, too. 104 | # Further operations on the device will not affect the device but will instead trigger a `Status::DeviceFinished` error. 105 | # 106 | # When the last call to `Device#finalize` decreases the reference count to zero, 107 | # cairo will call `Device#finish` if it hasn't been called already, before freeing the resources associated with the device. 108 | # 109 | # This function may acquire devices. 110 | def finish 111 | LibCairo.device_finish(@device) 112 | self 113 | end 114 | 115 | # Returns the current reference count of device. 116 | # 117 | # ###Returns 118 | # The current reference count of device. If the object is a `nil` object, 0 will be returned. 119 | def reference_count : UInt32 120 | LibCairo.device_get_reference_count(@device) 121 | end 122 | 123 | # Return user data previously attached to device using the specified key. 124 | # If no user data has been attached with the given key this function returns `Nil`. 125 | # 126 | # ###Parameters 127 | # - **key** the address of the UserDataKey the user data was attached to 128 | # 129 | # ###Returns 130 | # The user data previously attached or `Nil`. 131 | def user_data(key : UserDataKey) : Void* 132 | LibCairo.device_get_user_data(@device, key.to_unsafe) 133 | end 134 | 135 | # Attach user data to device. To remove user data from a surface, call this function with 136 | # the key that was used to set it and `Nil` for data. 137 | # 138 | # ###Parameters 139 | # - **key** the address of a `UserDataKey` to attach the user data to 140 | # - **user_data** 141 | # - **the** user data to attach to the `Device` 142 | # - **destroy** a `LibCairo::DestroyFuncT` which will be called when the `Context` is destroyed 143 | # or when new user data is attached using the same key. 144 | # 145 | # ###Returns 146 | # `Status::Success` or `Status::NoMemory` if a slot could not be allocated for the user data. 147 | def set_user_data(key : UserDataKey, user_data : Void*, destroy : LibCairo::DestroyFuncT) : Status 148 | Status.new(LibCairo.device_set_user_data(@device, key.to_unsafe, user_data, destroy).value) 149 | end 150 | 151 | def observer_print(write_func : LibCairo::WriteFuncT, closure : Void*) : Status 152 | Status.new(LibCairo.device_observer_print(@device, write_func, closure).value) 153 | end 154 | 155 | def observer_elapsed : Float64 156 | LibCairo.device_observer_elapsed(@device) 157 | end 158 | 159 | def observer_paint_elapsed : Float64 160 | LibCairo.device_observer_paint_elapsed(@device) 161 | end 162 | 163 | def observer_mask_elapsed : Float64 164 | LibCairo.device_observer_mask_elapsed(@device) 165 | end 166 | 167 | def observer_fill_elapsed : Float64 168 | LibCairo.device_observer_fill_elapsed(@device) 169 | end 170 | 171 | def observer_stroke_elapsed : Float64 172 | LibCairo.device_observer_stroke_elapsed(@device) 173 | end 174 | 175 | def observer_glyphs_elapsed : Float64 176 | LibCairo.device_observer_glyphs_elapsed(@device) 177 | end 178 | 179 | def to_unsafe : LibCairo::PDeviceT 180 | @device 181 | end 182 | end 183 | end 184 | -------------------------------------------------------------------------------- /src/cairo/device_type.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `DeviceType` is used to describe the type of a given device. 3 | # The devices types are also known as "backends" within cairo. 4 | # 5 | # The device type can be queried with `Device#type`. 6 | # 7 | # New entries may be added in future versions. 8 | enum DeviceType 9 | # The device is of type Direct Render Manager. 10 | DRM 11 | 12 | # The device is of type OpenGL. 13 | GL 14 | 15 | # The device is of type script. 16 | Script 17 | 18 | # The device is of type xcb. 19 | XCB 20 | 21 | # The device is of type xlib. 22 | XLib 23 | 24 | # The device is of type XML. 25 | XML 26 | 27 | # The device is of type cogl. 28 | COGL 29 | 30 | # The device is of type win32. 31 | Win32 32 | 33 | 34 | # The device is invalid. 35 | Invalid = -1 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/cairo/extend.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `Extend` is used to describe how pattern color/alpha will be determined for areas "outside" 3 | # the pattern's natural area, (for example, outside the surface bounds or outside the gradient geometry). 4 | # 5 | # Mesh patterns are not affected by the extend mode. 6 | # 7 | # The default extend mode is `Extend::None` for surface patterns and `Extend::Pad` for gradient patterns. 8 | # 9 | # New entries may be added in future versions. 10 | enum Extend 11 | # Pixels outside of the source pattern are fully. 12 | None 13 | 14 | # The pattern is tiled by repeating. 15 | Repeat 16 | 17 | # The pattern is tiled by reflecting at the edges. 18 | Reflect 19 | 20 | # Pixels outside of the pattern copy the closest pixel from the source. 21 | Pad 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/cairo/extents.cr: -------------------------------------------------------------------------------- 1 | require "./point" 2 | 3 | module Cairo 4 | struct Extents 5 | property x1 : Float64 = 0.0 6 | property y1 : Float64 = 0.0 7 | property x2 : Float64 = 0.0 8 | property y2 : Float64 = 0.0 9 | 10 | def initialize 11 | end 12 | 13 | def initialize(@x1 : Float64, @y1 : Float64, @x2 : Float64, @y2 : Float64) 14 | end 15 | 16 | def initialize(p1 : Point, p2 : Point) 17 | @x1 = p1.x 18 | @y1 = p1.y 19 | @x2 = p2.x 20 | @y2 = p2.y 21 | end 22 | 23 | def p1 : Point 24 | Point.new(@x1, @y1) 25 | end 26 | 27 | def p1=(p : Point) 28 | @x1 = p.x 29 | @y1 = p.y 30 | end 31 | 32 | def p2 : Point 33 | Point.new(@x2, @y2) 34 | end 35 | 36 | def p2=(p : Point) 37 | @x2 = p.x 38 | @y2 = p.y 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /src/cairo/fill_rule.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `FillRule` is used to select how paths are filled. For both fill rules, 3 | # whether or not a point is included in the fill is determined by taking a ray from that point to infinity 4 | # and looking at intersections with the path. The ray can be in any direction, 5 | # as long as it doesn't pass through the end point of a segment or have a tricky intersection such as intersecting tangent to the path. 6 | # (NOTE that filling is not actually implemented in this way. This is just a description of the rule that is applied.) 7 | # 8 | # The default fill rule is `FillRule::Winding`. 9 | # 10 | # New entries may be added in future versions. 11 | enum FillRule 12 | # If the path crosses the ray from left-to-right, counts +1. If the path crosses the ray from right to left, counts -1. 13 | # (Left and right are determined from the perspective of looking along the ray from the starting point.) 14 | # If the total count is non-zero, the point will be filled. 15 | Winding 16 | 17 | # Counts the total number of intersections, without regard to the orientation of the contour. 18 | # If the total number of intersections is odd, the point will be filled. 19 | EvenOdd 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/cairo/filter.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `Filter` is used to indicate what filtering should be applied when reading pixel values from patterns. 3 | # See `Pattern#filter=` for indicating the desired filter to be used with a particular pattern. 4 | enum Filter 5 | # A high-performance filter, with quality similar to `Filter::Nearest`. 6 | Fast 7 | 8 | # A reasonable-performance filter, with quality similar to `Filter::Bilinear`. 9 | Good 10 | 11 | # The highest-quality available, performance may not be suitable for interactive use. 12 | Best 13 | 14 | # Nearest-neighbor filtering. 15 | Nearest 16 | 17 | # Linear interpolation in two dimensions. 18 | Bilinear 19 | 20 | # This filter value is currently unimplemented, and should not be used in current code. 21 | Gaussian 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/cairo/font_extents.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # The `FontExtents` structure stores metric information for a font. 7 | # Values are given in the current user-space coordinate system. 8 | # 9 | # Because font metrics are in user-space coordinates, they are mostly, 10 | # but not entirely, independent of the current transformation matrix. 11 | # If you call `context.scale(2.0, 2.0)`, text will be drawn twice as big, 12 | # but the reported text extents will not be doubled. They will change slightly due 13 | # to hinting (so you can't assume that metrics are independent of the transformation matrix), 14 | # but otherwise will remain unchanged. 15 | class FontExtents 16 | def initialize 17 | @font_extents = LibCairo::FontExtentsT.new 18 | end 19 | 20 | def initialize(ascent : Float64, descent : Float64, height : Float64, 21 | max_x_advance : Float64, max_y_advance : Float64) 22 | @font_extents = LibCairo::FontExtentsT.new 23 | @font_extents.ascent = ascent 24 | @font_extents.descent = descent 25 | @font_extents.height = height 26 | @font_extents.max_x_advance = max_x_advance 27 | @font_extents.max_y_advance = max_y_advance 28 | end 29 | 30 | def initialize(@font_extents : LibCairo::FontExtentsT) 31 | end 32 | 33 | # The distance that the font extends above the baseline. 34 | # 35 | # NOTE that this is not always exactly equal to the maximum of the extents of all the glyphs in the font, 36 | # but rather is picked to express the font designer's intent as to how the font should align with elements above it. 37 | @[AlwaysInline] 38 | def ascent : Float64 39 | @font_extents.ascent 40 | end 41 | 42 | @[AlwaysInline] 43 | def ascent=(ascent : Float64) 44 | @font_extents.ascent = ascent 45 | end 46 | 47 | # The distance that the font extends below the baseline. 48 | # 49 | # This value is positive for typical fonts that include portions below the baseline. 50 | # NOTE that this is not always exactly equal to the maximum of the extents of all the glyphs in the font, 51 | # but rather is picked to express the font designer's intent as to how the font should align with elements below it. 52 | @[AlwaysInline] 53 | def descent : Float64 54 | @font_extents.descent 55 | end 56 | 57 | @[AlwaysInline] 58 | def descent=(descent : Float64) 59 | @font_extents.descent = descent 60 | end 61 | 62 | # The recommended vertical distance between baselines when setting consecutive lines of text with the font. 63 | # 64 | # This is greater than *ascent+descent* by a quantity known as the line spacing or external leading. 65 | # When space is at a premium, most fonts can be set with only a distance of *ascent+descent* between lines. 66 | @[AlwaysInline] 67 | def height : Float64 68 | @font_extents.height 69 | end 70 | 71 | @[AlwaysInline] 72 | def height=(height : Float64) 73 | @font_extents.height = height 74 | end 75 | 76 | # The maximum distance in the X direction that the origin is advanced for any glyph in the font. 77 | @[AlwaysInline] 78 | def max_x_advance : Float64 79 | @font_extents.max_x_advance 80 | end 81 | 82 | @[AlwaysInline] 83 | def max_x_advance=(max_x_advance : Float64) 84 | @font_extents.max_x_advance = max_x_advance 85 | end 86 | 87 | # The maximum distance in the Y direction that the origin is advanced for any glyph in the font. 88 | # 89 | # This will be zero for normal fonts used for horizontal writing. (The scripts of East Asia are sometimes written vertically.) 90 | @[AlwaysInline] 91 | def max_y_advance : Float64 92 | @font_extents.max_y_advance 93 | end 94 | 95 | @[AlwaysInline] 96 | def max_y_advance=(max_y_advance : Float64) 97 | @font_extents.max_y_advance = max_y_advance 98 | end 99 | 100 | def to_cairo_font_extents : LibCairo::FontExtentsT 101 | @font_extents 102 | end 103 | 104 | def to_unsafe : LibCairo::PFontExtentsT 105 | pointerof(@font_extents) 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /src/cairo/font_face.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | # `FontFace` represents a particular font at a particular weight, slant, 5 | # and other characteristic but no size, transformation, or size. 6 | # 7 | # A `FontFace` specifies all aspects of a font other than the size or font matrix 8 | # (a font matrix is used to distort a font by shearing it or scaling it unequally in the two directions). 9 | # A font face can be set on a `Context` by using `Context#font_face=`; 10 | # the size and font matrix are set with `Context#font_size=` and `Context#font_matrix=`. 11 | # 12 | # There are various types of font faces, depending on the font backend they use. 13 | # The type of a font face can be queried using `FontFace#type`. 14 | # 15 | # Memory management of `FontFace` is done with `FontFace#reference` and `FontFace#finalize`. 16 | class FontFace 17 | def initialize 18 | @font_face = LibCairo.user_font_face_create 19 | end 20 | 21 | def initialize(font_face : LibCairo::PFontFaceT) 22 | raise ArgumentError.new("'font_face' cannot be null.") if font_face.null? 23 | @font_face = font_face 24 | end 25 | 26 | # Decreases the reference count on `FontFace` by one. 27 | # If the result is zero, then `FontFace` and all associated resources are freed. 28 | # See `FontFace#reference`. 29 | def finalize 30 | LibCairo.font_face_destroy(@font_face) 31 | end 32 | 33 | # Increases the reference count on `FontFace` by one. 34 | # This prevents `FontFace` from being destroyed until a matching call 35 | # to `Context#finalize` is made. 36 | # 37 | # Use `Context#reference_count` to get the number of references to a `FontFace`. 38 | # 39 | # ###Returns 40 | # The referenced `FontFace`. 41 | def reference : FontFace 42 | FontFace.new(LibCairo.font_face_reference(@font_face)) 43 | end 44 | 45 | # Returns the current reference count of `FontFace` . 46 | # 47 | # ###Returns 48 | # Tthe current reference count of `FontFace`. If the object is a nil object, 0 will be returned. 49 | def reference_count : UInt32 50 | LibCairo.font_face_get_reference_count(@font_face) 51 | end 52 | 53 | # Checks whether an error has previously occurred for this font face. 54 | # 55 | # ###Returns 56 | # `Status::Success` or another error such as `Status::NoMemory`. 57 | def status : Status 58 | Status.new(LibCairo.font_face_status(@font_face).value) 59 | end 60 | 61 | # This function returns the type of the backend used to create a font face. 62 | # See `FontType` for available types. 63 | # 64 | # ###Returns 65 | # The type of `FontFace`. 66 | def type : FontType 67 | FontType.new(LibCairo.font_face_get_type(@font_face).value) 68 | end 69 | 70 | # Return user data previously attached to `FontFace` using the specified key. 71 | # If no user data has been attached with the given key this function returns `Nil`. 72 | # 73 | # ###Parameters 74 | # - **key** the address of the `UserDataKey` the user data was attached to 75 | # 76 | # ###Returns 77 | # The user data previously attached or `Nil`. 78 | def user_data(key : UserDataKey) : Void* 79 | LibCairo.font_face_get_user_data(@font_face, key.to_unsafe) 80 | end 81 | 82 | # Attach user data to `FontFace`. To remove user data from a font face, 83 | # call this function with the key that was used to set it and `Nil` for data. 84 | # 85 | # ###Parameters 86 | # - **key** the address of a `UserDataKey` to attach the user data to 87 | # - **user_data** the user data to attach to the font face 88 | # - **destroy** a `LibCairo::DestroyFuncT` which will be called when the font 89 | # face is destroyed or when new user data is attached using the same key 90 | # 91 | # ###Returns 92 | # `Status::Success` or `Status::NoMemory` if a slot could not be allocated for the user data. 93 | def set_user_data(key : UserDataKey, user_data : Void*, destroy : LibCairo::DestroyFuncT) : Status 94 | Status.new(LibCairo.font_face_set_user_data(@font_face, key.to_unsafe, user_data, destroy).value) 95 | end 96 | 97 | def create_scaled_font(font_matrix : Matrix, ctm : Matrix, options : FontOptions) : ScaledFont 98 | ScaledFont.new(LibCairo.scaled_font_create(@font_face, font_matrix.to_unsafe, ctm.to_unsafe, options.to_unsafe)) 99 | end 100 | 101 | # Creates a font face from a triplet of *family*, *slant*, and *weight*. 102 | # These font faces are used in implementation of the the `Context` "toy" font API. 103 | # 104 | # If family is the zero-length string "", the platform-specific default family is assumed. 105 | # The default family then can be queried using `FontFace#family`. 106 | # 107 | # The `Context#select_font_face` function uses this to create font faces. 108 | # See that function for limitations and other details of toy font faces. 109 | # 110 | # ###Parameters 111 | # - **family** a font family name, encoded in UTF-8 112 | # - **slant** the slant for the font 113 | # - **weight** the weight for the font 114 | # 115 | # ###Returns 116 | # A newly created `FontFace`. Free with `FontFace#finalize` when you are done using it. 117 | def initialize(family : String, slant : FontSlant, weight : FontWeight) 118 | @font_face = LibCairo.toy_font_face_create(family.to_unsafe, 119 | LibCairo::FontSlantT.new(slant.value), 120 | LibCairo::FontWeightT.new(weight.value)) 121 | end 122 | 123 | # Gets the familly name of a toy font. 124 | # 125 | # ###Returns 126 | # The family name. This string is owned by the font face and remains valid as long as the font face is alive (referenced). 127 | def family : String 128 | String.new(LibCairo.toy_font_face_get_family(@font_face)) 129 | end 130 | 131 | # Gets the slant a toy font. 132 | # 133 | # ###Returns 134 | # The slant value. 135 | def slant : FontSlant 136 | FontSlant.new(LibCairo.toy_font_face_get_slant(@font_face).value) 137 | end 138 | 139 | # Gets the weight a toy font. 140 | # 141 | # ###Returns 142 | # The weight value. 143 | def weight : FontWeight 144 | FontWeight.new(LibCairo.toy_font_face_get_weight(@font_face).value) 145 | end 146 | 147 | # Gets the scaled-font initialization function of a user-font. 148 | # 149 | # ###Returns 150 | # The init callback of `FontFace` or `nil` 151 | # if none set or an error has occurred. 152 | def init_func : LibCairo::UserScaledFontInitFuncT 153 | LibCairo.user_font_face_get_init_func(@font_face) 154 | end 155 | 156 | # Sets the scaled-font initialization function of a user-font. 157 | # See `LibCairo::UserScaledFontInitFuncT` for details of how the callback works. 158 | # 159 | # The font-face should not be immutable or a `Status#UserFontImmutable` error 160 | # will occur. A user font-face is immutable as soon as a scaled-font is created from it. 161 | # 162 | # ###Parameters 163 | # - **init_func** The init callback, or `nil` 164 | def init_func=(init_func : LibCairo::UserScaledFontInitFuncT) 165 | LibCairo.user_font_face_set_init_func(@font_face, init_func) 166 | self 167 | end 168 | 169 | # Gets the glyph rendering function of a user-font. 170 | # 171 | # ###Returns 172 | # The *render_glyph* callback of `FontFace` or `nil` 173 | # if none set or an error has occurred. 174 | def render_glyph_func : LibCairo::UserScaledFontRenderGlyphFuncT 175 | LibCairo.user_font_face_get_render_glyph_func(@font_face) 176 | end 177 | 178 | # Sets the glyph rendering function of a user-font. 179 | # See `LibCairo::UserScaledFontRenderGlyphFuncT for 180 | # details of how the callback works. 181 | # 182 | # The font-face should not be immutable or a `Status#UserFontImmutable` 183 | # error will occur. A user font-face is immutable as soon as 184 | # a scaled-font is created from it. 185 | # 186 | # The *render_glyph* callback is the only mandatory callback of a user-font. 187 | # If the callback is `nil` and a glyph is tried to be rendered using 188 | # `FontFace`, a `Status#UserFontError` will occur. 189 | # 190 | # ###Parameters 191 | # - **render_glyph_func** The *render_glyph* callback, or `nil` 192 | def render_glyph_func=(render_glyph_func : LibCairo::UserScaledFontRenderGlyphFuncT) 193 | LibCairo.user_font_face_set_render_glyph_func(@font_face, render_glyph_func) 194 | self 195 | end 196 | 197 | # Gets the text-to-glyphs conversion function of a user-font. 198 | # 199 | # ###Returns 200 | # The *text_to_glyphs* callback of `FontFace` or `nil` if none set or an error occurred. 201 | def text_to_glyphs_func : LibCairo::UserScaledFontTextToGlyphFuncT 202 | LibCairo.user_font_face_get_text_to_glyphs_func(@font_face) 203 | end 204 | 205 | # Sets th text-to-glyphs conversion function of a user-font. 206 | # See `LibCairo::UserScaledFontTextToGlyphsFuncT` 207 | # for details of how the callback works. 208 | # 209 | # The font-face should not be immutable or a `Status#UserFontImmutable` 210 | # error will occur. A user font-face is immutable as soon as a 211 | # scaled-font is created from it. 212 | # 213 | # ###Parameters 214 | # - **text_to_glyphs_func** The *text_to_glyphs* callback, or `nil` 215 | def text_to_glyphs_func=(text_to_glyphs_func : LibCairo::UserScaledFontTextToGlyphFuncT) 216 | LibCairo.user_font_face_set_text_to_glyphs_func(@font_face, text_to_glyphs_func) 217 | self 218 | end 219 | 220 | # Gets the unicode-to-glyph conversion function of a user-font. 221 | # 222 | # ###Returns 223 | # The *unicode_to_glyph* callback of `FontFace` or `nil` 224 | # if none set or an error occurred. 225 | def user_font_face_get_unicode_to_glyph_func : LibCairo::UserScaledFontUnicodeToGlyphFuncT 226 | LibCairo.user_font_face_get_unicode_to_glyph_func(@font_face) 227 | end 228 | 229 | # Sets the unicode-to-glyph conversion function of a user-font. 230 | # See `LibCairo::UserScaledFontUnicodeToGlyphFuncT` 231 | # for details of how the callback works. 232 | # 233 | # The font-face should not be immutable or a `Status::UserFontImmutable` 234 | # error will occur. A user font-face is immutable as soon as a 235 | # scaled-font is created from it. 236 | # 237 | # ###Parameters 238 | # - **unicode_to_glyph_func** The *unicode_to_glyph* callback, or `nil` 239 | def unicode_to_glyph_func=(unicode_to_glyph_func : LibCairo::UserScaledFontUnicodeToGlyphFuncT) 240 | LibCairo.user_font_face_set_unicode_to_glyph_func(@font_face, unicode_to_glyph_func) 241 | self 242 | end 243 | 244 | def to_unsafe : LibCairo::PFontFaceT 245 | @font_face 246 | end 247 | end 248 | end 249 | -------------------------------------------------------------------------------- /src/cairo/font_options.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # The font options specify how fonts should be rendered. 7 | # Most of the time the font options implied by a surface are just right and do not need any changes, 8 | # but for pixel-based targets tweaking font options may result in superior output on a particular display. 9 | class FontOptions 10 | # Allocates a new font options object with all options initialized to default values. 11 | # 12 | # ###Returns 13 | # A newly allocated `FontOptions`. Free with `FontOptions#finalize`. 14 | # This function always returns a valid pointer; if memory cannot be allocated, 15 | # then a special error object is returned where all operations on the object do nothing. 16 | # You can check for this with `FontOptions#status`. 17 | def initialize 18 | @font_options = LibCairo.font_options_create 19 | end 20 | 21 | def initialize(@font_options : LibCairo::PFontOptionsT) 22 | end 23 | 24 | # Destroys a `FontOptions` object created with `FontOptions#initialize` or `FontOptions#dup`. 25 | def finalize 26 | LibCairo.font_options_destroy(@font_options) 27 | end 28 | 29 | # Allocates a new font options object copying the option values from original. 30 | # 31 | # ###Returns 32 | # A newly allocated `FontOptions`. Free with `FontOptions#finalize`. 33 | # This function always returns a valid pointer; if memory cannot be allocated, 34 | # then a special error object is returned where all operations on the object do nothing. 35 | # You can check for this with `FontOptions#status`. 36 | def dup : FontOptions 37 | FontOptions.new(LibCairo.font_options_copy(@font_options)) 38 | end 39 | 40 | # Checks whether an error has previously occurred for this font options object. 41 | # 42 | # ###Returns 43 | # `Status::Success` or `Status::NoMemory`. 44 | def status : Status 45 | Status.new(LibCairo.font_options_status(@font_options)) 46 | end 47 | 48 | # Merges non-default options from other into options, replacing existing values. 49 | # This operation can be thought of as somewhat similar to compositing other onto options with the operation of `Operator::Over`. 50 | # 51 | # ###Parameters 52 | # - **other** another `FontOptions` 53 | def merge(other : FontOptions) 54 | LibCairo.font_options_merge(@font_options, other.to_unsafe) 55 | self 56 | end 57 | 58 | # Compares two font options objects for equality. 59 | # 60 | # ###Parameters 61 | # - **other** another `FontOptinos` 62 | # 63 | # ###Returns 64 | # `true` if all fields of the two font options objects match. Note that this function will return `false` if either object is in error. 65 | def equals(other : FontOptions) : Bool 66 | LibCairo.font_options_equal(@font_options, other.to_unsafe) == 1 67 | end 68 | 69 | # Compute a hash for the font options object; 70 | # this value will be useful when storing an object containing a `FontOptions` in a hash table. 71 | # 72 | # ###Returns 73 | # The hash value for the font options object. The return value can be cast to a 32-bit type if a 32-bit hash value is needed. 74 | def hash : UInt64 75 | LibCairo.font_options_hash(@font_options) 76 | end 77 | 78 | # Gets the antialiasing mode for the font options object. 79 | # 80 | # ###Returns 81 | # The antialiasing mode. 82 | def antialias : Antialias 83 | Antialias.new(LibCairo.font_options_get_antialias(@font_options).value) 84 | end 85 | 86 | # Sets the antialiasing mode for the font options object. 87 | # This specifies the type of antialiasing to do when rendering text. 88 | # 89 | # ###Parameters 90 | # - **antialias** the new antialiasing mode 91 | def antialias=(antialias : Antialias) 92 | LibCairo.font_options_set_antialias(@font_options, LibCairo::AntialiasT.new(antialias.value)) 93 | self 94 | end 95 | 96 | # Gets the subpixel order for the font options object. 97 | # See the documentation for `SubpixelOrder` for full details. 98 | # 99 | # ###Returns 100 | # The subpixel order for the font options object. 101 | def subpixel_order : SubpixelOrder 102 | SubpixelOrder.new(LibCairo.font_options_get_subpixel_order(@font_options).value) 103 | end 104 | 105 | # Sets the subpixel order for the font options object. 106 | # The subpixel order specifies the order of color elements within each pixel on the display device 107 | # when rendering with an antialiasing mode of `Antialias::Subpixel`. 108 | # See the documentation for `SubpixelOrder` for full details. 109 | # 110 | # ###Parameters 111 | # - **subpixel_order** the new subpixel order 112 | def subpixel_order=(subpixel_order : SubpixelOrder) 113 | LibCairo.font_options_set_subpixel_order(@font_options, LibCairo::SubpixelOrderT.new(subpixel_order.value)) 114 | self 115 | end 116 | 117 | # Gets the hint style for font outlines for the font options object. 118 | # See the documentation for `HintStyle` for full details. 119 | # 120 | # ###Returns 121 | # The hint style for the font options object. 122 | def hint_style : HintStyle 123 | HintStyle.new(LibCairo.font_options_get_hint_style(@font_options).value) 124 | end 125 | 126 | # Sets the hint style for font outlines for the font options object. 127 | # This controls whether to fit font outlines to the pixel grid, and if so, 128 | # whether to optimize for fidelity or contrast. 129 | # See the documentation for `HintStyle` for full details. 130 | # 131 | # ###Parameters 132 | # - **hint_style** the new hint style 133 | def hint_style=(hint_style : HintStyle) 134 | LibCairo.font_options_set_hint_style(@font_options, LibCairo::HintStyleT.new(hint_style.value)) 135 | self 136 | end 137 | 138 | # Gets the metrics hinting mode for the font options object. 139 | # See the documentation for `HintMetrics` for full details. 140 | # 141 | # ###Returns 142 | # The metrics hinting mode for the font options object. 143 | def hint_metrics : HintMetrics 144 | HintMetrics.new(LibCairo.font_options_get_hint_metrics(@font_options).value) 145 | end 146 | 147 | # Sets the metrics hinting mode for the font options object. 148 | # This controls whether metrics are quantized to integer values in device units. 149 | # See the documentation for `HintMetrics` for full details. 150 | # 151 | # ###Parameters 152 | # - **hint_metrics** the new metrics hinting mode 153 | def hint_metrics=(hint_metrics : HintMetrics) 154 | LibCairo.font_options_set_hint_metrics(@font_options, LibCairo::HintMetricsT.new(hint_metrics.value)) 155 | self 156 | end 157 | 158 | # Gets the OpenType font variations for the font options object. 159 | # See `FontOptions#variations`= for details about the string format. 160 | # 161 | # ###Returns 162 | # The font variations for the font options object. 163 | # The returned string belongs to the options and must not be modified. 164 | # It is valid until either the font options object is destroyed or the font variations in this object 165 | # is modified with `FontOptions#variations=`. 166 | def variations : String 167 | String.new(LibCairo.font_options_get_variations(@font_options)) 168 | end 169 | 170 | # Sets the OpenType font variations for the font options object. 171 | # Font variations are specified as a string with a format that is similar to the CSS font-variation-settings. 172 | # The string contains a comma-separated list of axis assignments, 173 | # which each assignment consists of a 4-character axis name and a value, separated by whitespace and optional equals sign. 174 | # 175 | # ###Parameters 176 | # - **variations** the new font variations 177 | def variations=(variation : String) 178 | LibCairo.font_options_set_variations(@font_options, variations.to_unsafe) 179 | self 180 | end 181 | 182 | def to_unsafe : LibCairo::PFontOptionsT 183 | @font_options 184 | end 185 | end 186 | end 187 | -------------------------------------------------------------------------------- /src/cairo/font_slant.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies variants of a font face based on their slant. 3 | enum FontSlant 4 | # Upright font style. 5 | Normal 6 | 7 | # Italic font style. 8 | Italic 9 | 10 | # Oblique font style. 11 | Oblique 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/cairo/font_type.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `FontType is used to describe the type of a given font face or scaled font. 3 | # The font types are also known as "font backends" within cairo. 4 | # 5 | # The type of a font face is determined by the function used to create it, 6 | # which will generally be of the form `FontFace#initialize`. 7 | # The font face type can be queried with `FontFace#type`. 8 | # 9 | # The various `FontFace` functions can be used with a font face of any type. 10 | # 11 | # The type of a scaled font is determined by the type of the font face passed to 12 | # `FontFace#create_scaled_font`. The scaled font type can be queried with `scaledFont#type`. 13 | # 14 | # The various `ScaledFont` functions can be used with scaled fonts of any type, 15 | # but some font backends also provide type-specific functions that must only be 16 | # called with a scaled font of the appropriate type. 17 | # 18 | # The behavior of calling a type-specific function with a scaled font of the wrong type is undefined. 19 | # 20 | # New entries may be added in future versions. 21 | enum FontType 22 | # The font was created using cairo's toy font api. 23 | Toy 24 | 25 | # The font is of type FreeType. 26 | Ft 27 | 28 | # The font is of type Win32. 29 | Win32 30 | 31 | # The font is of type Quartz 32 | Quartz 33 | 34 | # The font was create using cairo's user font api. 35 | User 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/cairo/font_weight.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies variants of a font face based on their weight. 3 | enum FontWeight 4 | # Normal font weight. 5 | Normal 6 | 7 | # Bold font weight. 8 | Bold 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /src/cairo/format.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # `Format` is used to identify the memory format of image data. 7 | enum Format 8 | # No such format exists or is supported. 9 | Invalid = -1 10 | 11 | # Each pixel is a 32-bit quantity, with alpha in the upper 8 bits, 12 | # then red, then green, then blue. The 32-bit quantities are stored native-endian. 13 | # Pre-multiplied alpha is used. (That is, 50% transparent red is 0x80800000, not 0x80ff0000.) 14 | ARGB32 = 0 15 | 16 | # Each pixel is a 32-bit quantity, with the upper 8 bits unused. 17 | # Red, Green, and Blue are stored in the remaining 24 bits in that order. 18 | RGB24 = 1 19 | 20 | # Each pixel is a 8-bit quantity holding an alpha value. 21 | A8 = 2 22 | 23 | # Each pixel is a 1-bit quantity holding an alpha value. 24 | # Pixels are packed together into 32-bit quantities. 25 | # The ordering of the bits matches the endianness of the platform. 26 | # On a big-endian machine, the first pixel is in the uppermost bit, 27 | # on a little-endian machine the first pixel is in the least-significant bit. 28 | A1 = 3 29 | 30 | # Each pixel is a 16-bit quantity with red in the upper 5 bits, 31 | # then green in the middle 6 bits, and blue in the lower 5 bits. 32 | RGB16_565 = 4 33 | 34 | # Like `Format::RGB24` but with 10bpc. 35 | RGB30 = 5 36 | 37 | # This function provides a stride value that will respect all alignment requirements of the accelerated 38 | # image-rendering code within cairo. 39 | # 40 | # ###Parameters 41 | # - **width** The desired width of an image surface to be created. 42 | # 43 | # ###Returns 44 | # The appropriate stride to use given the desired format and width, 45 | # or -1 if either the format is invalid or the width too large. 46 | def stride_for_width(width : Int32) : Int32 47 | LibCairo.format_stride_for_width(LibCairo::FormatT.new(self.value), width) 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /src/cairo/glyph.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # The `Glyph` structure holds information about a single glyph when drawing 7 | # or measuring text. A font is (in simple terms) a collection of shapes used 8 | # to draw text. A glyph is one of these shapes. There can be multiple glyphs 9 | # for a single character (alternates to be used in different contexts, for 10 | # example), or a glyph can be a *ligature* of multiple characters. Cairo 11 | # doesn't expose any way of converting input text into glyphs, so in order 12 | # to use the Cairo interfaces that take arrays of glyphs, you must directly 13 | # access the appropriate underlying font system. 14 | # 15 | # NOTE: that the offsets given by *x* and *y* are not cumulative. 16 | # When drawing or measuring text, 17 | # each glyph is individually positioned with respect to the overall origin. 18 | struct Glyph 19 | def initialize 20 | @glyph = uninitialized LibCairo::GlyphT 21 | @glyph.index = 0_u64 22 | @glyph.x = 0.0 23 | @glyph.y = 0.0 24 | end 25 | 26 | def initialize(index : UInt64, x : Float64, y : Float64) 27 | @glyph = uninitialized LibCairo::GlyphT 28 | @glyph.index = index 29 | @glyph.x = x 30 | @glyph.y = y 31 | end 32 | 33 | def initialize(@glyph : LibCairo::GlyphT) 34 | end 35 | 36 | def initialize(glyph : LibCairo::PGlyphT) 37 | raise ArgumentError.new("'glyph' cannot be null.") if glyph.null? 38 | @glyph = glyph.value 39 | end 40 | 41 | # Glyph index in the font. The exact interpretation of the glyph index depends on the font technology being used. 42 | def index : UInt64 43 | @glyph.index 44 | end 45 | 46 | def index=(index : UInt64) 47 | @glyph.index = index 48 | end 49 | 50 | # The offset in the X direction between the origin used for drawing or measuring the string and the origin of this glyph. 51 | def x : Float64 52 | @glyph.x 53 | end 54 | 55 | def x=(x : Float64) 56 | @glyph.x = x 57 | end 58 | 59 | # The offset in the Y direction between the origin used for drawing or measuring the string and the origin of this glyph. 60 | def y : Float64 61 | @glyph.y 62 | end 63 | 64 | def y=(y : Float64) 65 | @glyph.y = y 66 | end 67 | 68 | def to_cairo_glyph : LibCairo::GlyphT 69 | @glyph 70 | end 71 | 72 | def to_unsafe : LibCairo::PGlyphT 73 | pointerof(@glyph) 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /src/cairo/glyph_array.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./glyph" 3 | 4 | module Cairo 5 | include Cairo::C 6 | 7 | class GlyphArray 8 | include Indexable(Glyph) 9 | 10 | # Allocates an array of `Glyph`'s. 11 | # 12 | # ###Parameters 13 | # - ***num_glyphs** number of glyphs to allocate 14 | # 15 | # ###Returns 16 | # The newly allocated array of glyphs that should be freed using `GlyphArray#finalize` 17 | def initialize(num_glyphs : Int32) 18 | @glyphs = LibCairo.glyph_allocate(num_glyphs) 19 | raise "Can't allocate glyphs." if @glyphs.null? 20 | @num_glyphs = num_glyphs 21 | end 22 | 23 | def initialize(glyphs : LibCairo::PGlyphT, num_glyphs : Int32) 24 | raise ArgumentError.new("'glyphs' cannot be null.") if glyphs.null? 25 | raise ArgumentError.new("'num_glyphs' must be positive.") unless num_glyphs > 0 26 | 27 | @glyphs = glyphs 28 | @num_glyphs = num_glyphs 29 | end 30 | 31 | def finalize 32 | LibCairo.glyph_free(@glyphs) 33 | @num_glyphs = 0 34 | end 35 | 36 | # :inherit: 37 | def size 38 | @num_glyphs 39 | end 40 | 41 | # :inherit: 42 | def unsafe_fetch(index : Int) 43 | (@glyphs + index).value 44 | end 45 | 46 | def []=(index : Int, glyph : Glyph) 47 | check_index_out_of_bounds index 48 | (@glyphs + index).value = glyph.to_unsafe.value 49 | end 50 | 51 | def to_unsafe : LibCairo::PGlyphT 52 | @glyphs 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /src/cairo/hint_metrics.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies whether to hint font metrics; hinting font metrics means quantizing 3 | # them so that they are integer values in device space. Doing this improves the 4 | # consistency of letter and line spacing, 5 | # however it also means that text will be laid out differently at different zoom factors. 6 | enum HintMetrics 7 | # Hint metrics in the default manner for the font backend and target device. 8 | Default 9 | 10 | # Do not hint font metrics. 11 | Off 12 | 13 | # Hint font metrics. 14 | On 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/cairo/hint_style.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies the type of hinting to do on font outlines. 3 | # Hinting is the process of fitting outlines to the pixel grid in order to improve the appearance of the result. 4 | # Since hinting outlines involves distorting them, it also reduces the faithfulness to the original outline shapes. 5 | # Not all of the outline hinting styles are supported by all font backends. 6 | # 7 | # New entries may be added in future versions. 8 | enum HintStyle 9 | # Use the default hint style for font backend and target device. 10 | Default 11 | 12 | # Do not hint outlines. 13 | None 14 | 15 | # Hint outlines slightly to improve contrast while retaining good fidelity to the original shapes. 16 | Slight 17 | 18 | # Hint outlines with medium strength giving a compromise between fidelity to the original shapes and contrast. 19 | Medium 20 | 21 | # Hint outlines to maximize contrast. 22 | Full 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /src/cairo/line_cap.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies how to render the endpoints of the path when stroking. 3 | # 4 | # The default line cap style is `LineCap::Butt`. 5 | enum LineCap 6 | # Start(stop) the line exactly at the start(end) point. 7 | Butt 8 | 9 | # Use a round ending, the center of the circle is the end. 10 | Round 11 | 12 | # Use squared ending, the center of the square is the end. 13 | Square 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/cairo/line_join.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies how to render the junction of two lines when stroking. 3 | # 4 | # The default line join style is `LineJoin::Miter`. 5 | enum LineJoin 6 | # Use a sharp (angled) corner, see `Context#miter_limit=(limit)`. 7 | Miter 8 | 9 | # Use a rounded join, the center of the circle is the joint point. 10 | Round 11 | 12 | # Use a cut-off join, the join is cut off at half the line width from the joint point. 13 | Bevel 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/cairo/matrix.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Wrapper for LibCairo::MatrixT 7 | # 8 | # `Matrix` is used throughout cairo to convert between different coordinate spaces. 9 | # A `Matrix` holds an affine transformation, such as a scale, rotation, shear, or a combination of these. 10 | struct Matrix 11 | def initialize 12 | @m = LibCairo::MatrixT.new 13 | end 14 | 15 | def initialize(@m : LibCairo::MatrixT) 16 | end 17 | 18 | def initialize(xx : Float64, yx : Float64, 19 | xy : Float64, yy : Float64, 20 | x0 : Float64, y0 : Float64) 21 | @m = LibCairo::MatrixT.new 22 | @m.xx = xx 23 | @m.yx = yx 24 | @m.xy = xy 25 | @m.yy = yy 26 | @m.x0 = x0 27 | @m.y0 = y0 28 | end 29 | 30 | def xx : Float64 31 | @m.xx 32 | end 33 | 34 | def xx=(xx : Float64) 35 | @m.xx = xx 36 | end 37 | 38 | def yx : Float64 39 | @m.yx 40 | end 41 | 42 | def yx=(yx : Float64) 43 | @m.yx = yx 44 | end 45 | 46 | def xy : Float64 47 | @m.xy 48 | end 49 | 50 | def xy=(xy : Float64) 51 | @m.xy = xy 52 | end 53 | 54 | def yy : Float64 55 | @m.yy 56 | end 57 | 58 | def yy=(yy : Float64) 59 | @m.yy = yy 60 | end 61 | 62 | def x0 : Float64 63 | @m.x0 64 | end 65 | 66 | def x0=(x0 : Float64) 67 | @m.x0 = x0 68 | end 69 | 70 | def y0 : Float64 71 | @m.y0 72 | end 73 | 74 | def y0=(y0 : Float64) 75 | @m.y0 = y0 76 | end 77 | 78 | # Sets matrix to be the affine transformation given by *xx*, *yx*, *xy*, *yy*, *x0*, *y0*. The transformation is given by: 79 | # ``` 80 | # x_new = xx * x + xy * y + x0 81 | # y_new = yx * x + yy * y + y0 82 | # ``` 83 | # 84 | # ###Parameters 85 | # - **xx** xx component of the affine transformation 86 | # - **yx** yx component of the affine transformation 87 | # - **xy** xy component of the affine transformation 88 | # - **yy** yy component of the affine transformation 89 | # - **x0** X translation component of the affine transformation 90 | # - **y0** Y translation component of the affine transformation 91 | def init(xx : Float64, yx : Float64, xy : Float64, yy : Float64, x0 : Float64, y0 : Float64) 92 | LibCairo.matrix_init(to_unsafe, xx, yx, xy, yy, x0, y0) 93 | self 94 | end 95 | 96 | # Modifies matrix to be an identity transformation. 97 | def init_identity 98 | LibCairo.matrix_init_identity(to_unsafe) 99 | self 100 | end 101 | 102 | # Initializes matrix to a transformation that translates by *tx* and *ty* in the *X* and *Y* dimensions, respectively. 103 | # 104 | # ###Parameters 105 | # - **tx** amount to translate in the X direction 106 | # - **ty** amount to translate in the Y direction 107 | def init_translate(tx : Float64, ty : Float64) 108 | LibCairo.matrix_init_translate(to_unsafe, tx, ty) 109 | self 110 | end 111 | 112 | # Initializes matrix to a transformation that scales by *sx* and *sy* in the *X* and *Y* dimensions, respectively. 113 | # 114 | # ###Parameters 115 | # - **sx** scale factor in the X direction 116 | # - **sy** scale factor in the Y direction 117 | def init_scale(sx : Float64, sy : Float64) 118 | LibCairo.matrix_init_scale(to_unsafe, sx, sy) 119 | self 120 | end 121 | 122 | # Initialized matrix to a transformation that rotates by radians. 123 | # 124 | # ###Parameters 125 | # - **radians** angle of rotation, in radians. 126 | # The direction of rotation is defined such that positive angles rotate in the direction 127 | # from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, 128 | # positive angles rotate in a clockwise direction. 129 | def init_rotate(radians : Float64) 130 | LibCairo.matrix_init_rotate(to_unsafe, radians) 131 | self 132 | end 133 | 134 | # Applies a translation by *tx*, *ty* to the transformation in matrix. 135 | # The effect of the new transformation is to first translate the coordinates by *tx* and *ty*, 136 | # then apply the original transformation to the coordinates. 137 | # 138 | # ###Parameters 139 | # - **tx** amount to translate in the X direction 140 | # - **ty** amount to translate in the Y direction 141 | def translate(tx : Float64, ty : Float64) 142 | LibCairo.matrix_translate(to_unsafe, tx, ty) 143 | self 144 | end 145 | 146 | # Applies scaling by *sx*, *sy* to the transformation in matrix. 147 | # The effect of the new transformation is to first scale the coordinates by *sx* and *sy*, 148 | # then apply the original transformation to the coordinates. 149 | # 150 | # ###Parameters 151 | # - **sx** scale factor in the X direction 152 | # - **sy** scale factor in the Y direction 153 | def scale(sx : Float64, sy : Float64) 154 | LibCairo.matrix_scale(to_unsafe, sx, sy) 155 | self 156 | end 157 | 158 | # Applies rotation by radians to the transformation in matrix. 159 | # The effect of the new transformation is to first rotate the coordinates by radians, 160 | # then apply the original transformation to the coordinates. 161 | # 162 | # ###Parameters 163 | # - **radians** angle of rotation, in radians. 164 | # The direction of rotation is defined such that positive angles rotate in the direction 165 | # from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, 166 | # positive angles rotate in a clockwise direction. 167 | def rotate(radians : Float64) 168 | LibCairo.matrix_rotate(to_unsafe, radians) 169 | self 170 | end 171 | 172 | # Changes matrix to be the inverse of its original value. Not all transformation matrices have inverses; 173 | # if the matrix collapses points together (it is degenerate), then it has no inverse and this function will fail. 174 | # 175 | ###Returns 176 | # If matrix has an inverse, modifies matrix to be the inverse matrix and returns 177 | # `Status::Success`. Otherwise, returns `Status::InvalidMatrix`. 178 | def invert : Status 179 | Status.new(LibCairo.matrix_invert(to_unsafe).value) 180 | end 181 | 182 | # Multiplies the affine transformations in *a* and *b* together and returns the result. 183 | # The effect of the resulting transformation is to first apply the transformation in *a* to the coordinates 184 | # and then apply the transformation in *b* to the coordinates. 185 | # 186 | # It is allowable for result to be identical to either *a* or *b*. 187 | # 188 | # ###Parameters 189 | # - **a** a `Matrix` 190 | # - **b** a `Matrix` 191 | def multiply(a : Matrix, b : Matrix) 192 | LibCairo.matrix_multiply(to_unsafe, a.to_unsafe, b.to_unsafe) 193 | self 194 | end 195 | 196 | # Transforms the distance vector *(dx, dy)* by matrix. 197 | # This is similar to `Matrix#transform_point` except that the translation components 198 | # of the transformation are ignored. The calculation of the returned vector is as follows: 199 | # ``` 200 | # dx2 = dx1 * a + dy1 * c 201 | # dy2 = dx1 * b + dy1 * d 202 | # ``` 203 | # 204 | # Affine transformations are position invariant, so the same vector always transforms to the same vector. 205 | # If *(x1, y1)* transforms to *(x2, y2)* then *(x1 + dx1, y1 + dy1)* will transform 206 | # to *(x1 + dx2, y1 + dy2)* for all values of *x1* and *x2*. 207 | # 208 | # ###Parameters 209 | # - **dx** X component of a distance vector. 210 | # - **dy** Y component of a distance vector. 211 | # 212 | # ###Returns 213 | # Transformed vector. 214 | def transform_distance(d : Point) : Point 215 | dx = d.x 216 | dy = d.y 217 | LibCairo.matrix_transform_distance(to_unsafe, 218 | pointerof(dx), pointerof(dy)) 219 | Point.new(dx, dy) 220 | end 221 | 222 | # Transforms the point *(x, y)* by matrix. 223 | # 224 | # ###Parameters 225 | # - **x** X position. 226 | # - **y** Y position. 227 | # 228 | # ###Returns 229 | # Transformed vector. 230 | def transform_point(p : Point) : Point 231 | x = p.x 232 | y = p.y 233 | LibCairo.matrix_transform_point(to_unsafe, 234 | pointerof(x), pointerof(y)) 235 | Point.new(x, y) 236 | end 237 | 238 | # Returns the underlieing structure. 239 | def to_cairo_matrix : LibCairo::MatrixT 240 | @m 241 | end 242 | 243 | # Returns the pointer of the underlieing structure. 244 | def to_unsafe : LibCairo::PMatrixT 245 | pointerof(@m) 246 | end 247 | end 248 | end 249 | -------------------------------------------------------------------------------- /src/cairo/operator.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `Operator` is used to set the compositing operator for all cairo drawing operations. 3 | # 4 | # The default operator is `Operator::Over`. 5 | # 6 | # The operators marked as unbounded modify their destination even outside of the mask layer 7 | # (that is, their effect is not bound by the mask layer). However, their effect can still be limited by way of clipping. 8 | # 9 | # To keep things simple, the operator descriptions here document the behavior for when both source and destination are either fully transparent 10 | # or fully opaque. The actual implementation works for translucent layers too. 11 | # For a more detailed explanation of the effects of each operator, including the mathematical definitions, 12 | # see [https://cairographics.org/operators/](https://cairographics.org/operators/). 13 | enum Operator 14 | # Clear destination layer (bounded). 15 | Clear 16 | 17 | # Replace destination layer (bounded). 18 | Source 19 | 20 | # Draw source layer on top of destination layer. 21 | Over 22 | 23 | # Draw source where there was destination content (unbounded). 24 | In 25 | 26 | # Draw source where there was no destination content (unbounded). 27 | Out 28 | 29 | # Draw source on top of destination content and only there. 30 | Atop 31 | 32 | # Ignore the source. 33 | Dest 34 | 35 | # Draw destination on top of source. 36 | DestOver 37 | 38 | # Leave destination only where there was source content (unbounded). 39 | DestIn 40 | 41 | # Leave destination only where there was no source content. 42 | DestOut 43 | 44 | # Leave destination on top of source content and only there (unbounded). 45 | DestAtop 46 | 47 | # Source and destination are shown where there is only one of them. 48 | Xor 49 | 50 | # Source and destination layers are accumulated. 51 | Add 52 | 53 | # Like over, but assuming source and dest are disjoint geometries. 54 | Saturate 55 | 56 | # Source and destination layers are multiplied. This causes the result to be at least as dark as the darker inputs. 57 | Multiply 58 | 59 | # Source and destination are complemented and multiplied. This causes the result to be at least as light as the lighter inputs. 60 | Screen 61 | 62 | # Multiplies or screens, depending on the lightness of the destination color. 63 | Overlay 64 | 65 | # Replaces the destination with the source if it is darker, otherwise keeps the source. 66 | Darken 67 | 68 | # Replaces the destination with the source if it is lighter, otherwise keeps the source. 69 | Lighten 70 | 71 | # Brightens the destination color to reflect the source color. 72 | ColorDodge 73 | 74 | # Darkens the destination color to reflect the source color. 75 | ColorBurn 76 | 77 | # Multiplies or screens, dependent on source color. 78 | HardLight 79 | 80 | # Darkens or lightens, dependent on source color. 81 | SoftLight 82 | 83 | # Takes the difference of the source and destination color. 84 | Difference 85 | 86 | # Produces an effect similar to difference, but with lower contrast. 87 | Exclusion 88 | 89 | # Creates a color with the hue of the source and the saturation and luminosity of the target. 90 | HslHue 91 | 92 | # Creates a color with the saturation of the source and the hue and luminosity of the target. 93 | # Painting with this mode onto a gray area produces no change. 94 | HslSaturation 95 | 96 | # Creates a color with the hue and saturation of the source and the luminosity of the target. 97 | # This preserves the gray levels of the target and is useful for coloring monochrome images or tinting color images. 98 | HslColor 99 | 100 | # Creates a color with the luminosity of the source and the hue and saturation of the target. 101 | # This produces an inverse effect to `Operator::HslColor`. 102 | HslLuminosity 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /src/cairo/path.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | # Paths are the most basic drawing tools and are primarily used to implicitly generate simple masks. 5 | # 6 | # Path is a data structure for holding a path. This data structure serves as the return value for 7 | # `Context#copy_path˙ and `Context#copy_path_flat` as well the input value for `Context#append`. 8 | # 9 | # See `PathDataType` for hints on how to iterate over the actual data within the path. 10 | # 11 | # The num_data function gives the number of elements in the data array. 12 | # This number is larger than the number of independent path portions (defined in `PathDataType`), 13 | # since the data includes both headers and coordinates for each portion. 14 | class Path 15 | def initialize(path : LibCairo::PPathT) 16 | raise ArgumentError.new("'path' cannot be null.") if path.null? 17 | @path = path 18 | end 19 | 20 | # Immediately releases all memory associated with path. 21 | # After a call to `Path#finalize` the path pointer is no longer valid and should not be used further. 22 | # 23 | # NOTE: should only be called `Path` returned by a `Context` function. 24 | # Any path that is created manually (ie. outside of `Context`) should be destroyed manually as well. 25 | def finalize 26 | LibCairo.path_destroy(@path) 27 | end 28 | 29 | # Returns the current error status. 30 | def status : Status 31 | Status.new(@path.value.status.value) 32 | end 33 | 34 | def status=(status : Status) 35 | @path.value.status = LibCairo::StatusT.new(status.value) 36 | end 37 | 38 | def [](index : Int) : PathData 39 | PathData.new(@path.value.data[index]) 40 | end 41 | 42 | # Returns the number of elements in the path. 43 | def num_data : Int32 44 | @path.value.num_data 45 | end 46 | 47 | def to_cairo_path : LibCairo::PathT 48 | @path.value 49 | end 50 | 51 | def to_unsafe : LibCairo::PPathT 52 | @path 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /src/cairo/path_data.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Wrapper for LibCairo::PathDataT 7 | # 8 | # `PathData` is used to represent the path data inside a `Path`. 9 | # 10 | # The data structure is designed to try to balance the demands of efficiency and ease-of-use. 11 | # A path is represented as an array of `PathData`, which is a union of headers and points. 12 | # 13 | # Each portion of the path is represented by one or more elements in the array, (one header followed by 0 or more points). 14 | # The length value of the header is the number of array elements for the current portion including the header, 15 | # (ie. length == 1 + # of points), and where the number of points for each element type is as follows: 16 | # - `PathDataType::MoveTo`: 1 point 17 | # - `PathDataType::LineTo`: 1 point 18 | # - `PathDataType::CurveTo`: 3 points 19 | # - `PathDataType::ClosePath`: 0 points 20 | # 21 | # The semantics and ordering of the coordinate values are consistent with `Context#move_to`, 22 | # `Context#line_to`, `Context#curve_to`, and `Context#close_path`. 23 | # 24 | # Here is sample code for iterating through a `Path`: 25 | # ``` 26 | # i = 0 27 | # path = ctx.copy_path 28 | # while i < path.num_data 29 | # data = path[i] 30 | # case data.header.type 31 | # when PathDataType::MoveTo 32 | # data1 = path[i + 1] 33 | # printf("MoveTo(%5.2f, %5.2f)\n", data1.point.x, data1.point.y) 34 | # when PathDataType::LineTo 35 | # data1 = path[i + 1] 36 | # printf("LineTo(%5.2f, %5.2f)\n", data1.point.x, data1.point.y) 37 | # when PathDataType::CurveTo 38 | # data1 = path[i + 1] 39 | # data2 = path[i + 2] 40 | # data3 = path[i + 3] 41 | # printf("CurveTo(%5.2f, %5.2f)\n", data1.point.x, data1.point.y) 42 | # printf(" (%5.2f, %5.2f)\n", data2.point.x, data2.point.y) 43 | # printf(" (%5.2f, %5.2f)\n", data3.point.x, data3.point.y) 44 | # when PathDataType::ClosePath 45 | # puts "ClosePath" 46 | # end 47 | # i += data.header.length 48 | # end 49 | # ``` 50 | struct PathData 51 | def initialize(header : PathDataHeader) 52 | @data = LibCairo::PathDataT.new 53 | @data.header = header.to_cairo_path_data_header 54 | end 55 | 56 | def initialize(point : Point) 57 | @data = LibCairo::PathDataT.new 58 | @data.point = point.to_path_data_point 59 | end 60 | 61 | def initialize(@data : LibCairo::PathDataT) 62 | end 63 | 64 | def header : PathDataHeader 65 | PathDataHeader.new(@data.header) 66 | end 67 | 68 | def header=(header : PathDataHeader) 69 | @data.header = header.to_cairo_path_data_header 70 | end 71 | 72 | def point : Point 73 | Point.new(@data.point) 74 | end 75 | 76 | def point=(point : Point) 77 | @data.point = point.to_path_data_point 78 | end 79 | 80 | def to_cairo_path_data : LibCairo::PathDataT 81 | @data 82 | end 83 | 84 | def to_unsafe : LibCairo::PPathDataT 85 | pointerof(@data) 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /src/cairo/path_data_header.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Wrapper for LibCairo::PathDataHeaderT 7 | struct PathDataHeader 8 | def initialize 9 | @header = PathDataHeaderT.new 10 | end 11 | 12 | def initialize(type : PathDataType, length : Int32) 13 | @header = PathDataHeaderT.new 14 | @header.type = PathDataHeaderT.new(type.value) 15 | @header.length = length 16 | end 17 | 18 | def initialize(@header : LibCairo::PathDataHeaderT) 19 | end 20 | 21 | def type : PathDataType 22 | PathDataType.new(@header.type.value) 23 | end 24 | 25 | def type=(type : PathDataType) 26 | @header.type = LibCairo::PathDataType.new(type.value) 27 | end 28 | 29 | def length : Int32 30 | @header.length 31 | end 32 | 33 | def length=(length : Int32) 34 | @header.length = length 35 | end 36 | 37 | def to_cairo_path_data_header : LibCairo::PathDataHeaderT 38 | @header 39 | end 40 | 41 | def to_unsafe : LibCairo::PPathDataHeaderT 42 | pointerof(@header) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /src/cairo/path_data_type.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Used to describe the type of one portion of a path when represented as a `Path`. 3 | # See `PathData` for details. 4 | enum PathDataType 5 | # A move-to operation. 6 | MoveTo 7 | 8 | # A line-to operation. 9 | LineTo 10 | 11 | # A curve-to operation. 12 | CurveTo 13 | 14 | # A close-path operation. 15 | ClosePath 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/cairo/pattern_type.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `PatternType` is used to describe the type of a given pattern. 3 | # 4 | # The type of a pattern is determined by the function used to create it. 5 | # The `Pattern#create_rgb` and `Pattern#create_rgba` functions create `PatternType::Solid` patterns. 6 | # 7 | # The pattern type can be queried with `Pattern#type`. 8 | # 9 | # Most `Pattern` functions can be called with a pattern of any type, 10 | # (though trying to change the extend or filter for a solid pattern will have no effect). 11 | # A notable exception is `Pattern#add_color_stop` which must only be called with gradient patterns 12 | # (either `PatternType::Linear` or `PatternType::Radial`). Otherwise the pattern will be shutdown and put into an error state. 13 | # 14 | # New entries may be added in future versions. 15 | enum PatternType 16 | # The pattern is a solid (uniform) color. It may be opaque or translucent. 17 | Solid 18 | 19 | # The pattern is a based on a surface (an image). 20 | Surface 21 | 22 | # The pattern is a linear gradient. 23 | Linear 24 | 25 | # The pattern is a radial gradient. 26 | Radial 27 | 28 | # The pattern is a mesh. 29 | Mesh 30 | 31 | # The pattern is a user pattern providing raster data. 32 | RasterSource 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /src/cairo/pdf_metadata.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Used by the `PdfSurface#set_metadata` function specify the metadata to set. 3 | enum PdfMetadata 4 | # The document title. 5 | Title 6 | 7 | # The document author. 8 | Author 9 | 10 | # The document subject. 11 | Subject 12 | 13 | # The document keywords. 14 | Keywords 15 | 16 | # The document creator. 17 | Creator 18 | 19 | # The document creation date. 20 | CreateDate 21 | 22 | # The document modification date. 23 | ModDate 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /src/cairo/pdf_outline_flags.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Used by the `PdfSurface#add_outline` function specify the attributes of an 3 | # outline item. These flags may be bitwise-or'd to produce any combination 4 | # of flags. 5 | @[Flags] 6 | enum PdfOutlineFlags 7 | # The outline item defaults to open in the PDF viewer. 8 | Open = 0x1 9 | 10 | # The outline item is displayed by the viewer in bold text. 11 | Bold = 0x2 12 | 13 | # The outline item is displayed by the viewer in italic text. 14 | Italic = 0x4 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/cairo/pdf_surface.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | require "./c/pdf" 4 | require "./surface" 5 | 6 | {% if Cairo::C::HAS_PDF_SURFACE %} 7 | 8 | module Cairo 9 | include Cairo::C 10 | 11 | # The PDF surface is used to render cairo graphics to Adobe PDF files and is 12 | # a multi-page vector surface backend. 13 | # 14 | # The following mime types are supported: 15 | # - `Cairo::C::LibCairo::MIME_TYPE_JPEG`, 16 | # - `Cairo::C::LibCairo::MIME_TYPE_JP2`, 17 | # - `Cairo::C::LibCairo::MIME_TYPE_UNIQUE_ID`, 18 | # - `Cairo::C::LibCairo::MIME_TYPE_JBIG2`, 19 | # - `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL`, 20 | # - `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL_ID`, 21 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX`, 22 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS`. 23 | # 24 | # ###JBIG2 Images 25 | # JBIG2 data in PDF must be in the embedded format as described 26 | # in ISO/IEC 11544. Image specific JBIG2 data must be in 27 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2`. Any global segments in the JBIG2 data 28 | # (segments with page association field set to 0) must be in 29 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL`. The global data may be shared 30 | # by multiple images. All images sharing the same global data must set 31 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL_ID` to a unique identifier. 32 | # At least one of the images must provide the global data using 33 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL`. The global data will only be 34 | # embedded once and shared by all JBIG2 images with the same 35 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL_ID`. 36 | # 37 | # ###CCITT Fax Images 38 | # The `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX` mime data requires a number of 39 | # decoding parameters These parameters are specified 40 | # using `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS`. 41 | # 42 | # `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS` mime data must contain 43 | # a string of the form `"param1=value1 param2=value2 ..."`. 44 | # 45 | # *Columns*: [required] An integer specifying the width of the image in pixels. 46 | # 47 | # *Rows*: [required] An integer specifying the height of the image in scan lines. 48 | # 49 | # *K* : [optional] An integer identifying the encoding scheme used. 50 | # < 0 is 2 dimensional Group 4, = 0 is Group3 1 dimensional, > 0 51 | # is mixed 1 and 2 dimensional encoding. Default is 0. 52 | # 53 | # *EndOfLine* : [optional] If true end-of-line bit patterns are present. 54 | # Default is false. 55 | # 56 | # *EncodedByteAlign* : [optional] If true the end of line is padded with 0 57 | # bits so the next line begins on a byte boundary. Default is false. 58 | # 59 | # *EndOfBlock* : [optional] If true the data contains an end-of-block 60 | # pattern. Default is true. 61 | # 62 | # *BlackIs1* : [optional] If true 1 bits are black pixels. Default is false. 63 | # 64 | # *DamagedRowsBeforeError* : [optional] An integer specifying the number of 65 | # damages rows tolerated before an error occurs. Default is 0. 66 | # 67 | # Boolean values may be "true" or "false", or 1 or 0. 68 | # 69 | # These parameters are the same as the CCITTFaxDecode parameters in the 70 | # [PostScript Language Reference](https://www.adobe.com/products/postscript/pdfs/PLRM.pdf) 71 | # and [Portable Document Format (PDF)](https://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf). 72 | # Refer to these documents for further details. 73 | # 74 | # An example `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS` string is: 75 | # `"Columns=10230 Rows=40000 K=1 EndOfLine=true EncodedByteAlign=1 BlackIs1=false"` 76 | class PdfSurface < Surface 77 | # Creates a PDF surface of the specified size in points to be written to 78 | # filename. 79 | # 80 | # ###Parameters 81 | # - **filename** a filename for the PDF output (must be writable), `nil` 82 | # may be used to specify no output. This will generate a PDF surface that 83 | # may be queried and used as a source, without generating a temporary file. 84 | # - **width_in_points** width of the surface, 85 | # in points (1 point == 1/72.0 inch) 86 | # - **height_in_points** height of the surface, 87 | # in points (1 point == 1/72.0 inch) 88 | # 89 | # ###Returns 90 | # A pointer to the newly created `Surface`. The caller owns the surface and 91 | # should call `Surface#finalize` when done with it. 92 | # 93 | # This function always returns a valid pointer, but it will return a 94 | # pointer to a "nil" surface if an error such as out of memory occurs. 95 | # You can use `Surface#status` to check for this. 96 | def initialize(filename : String, width_in_points : Float64, height_in_points : Float64) 97 | super(LibCairo.pdf_surface_create(filename.to_unsafe, width_in_points, height_in_points)) 98 | end 99 | 100 | # Creates a PDF surface of the specified size in points to be written 101 | # incrementally to the stream represented by write_func and closure . 102 | # 103 | # ###Parameters 104 | # - **write_func** a `Cairo::C::LibCairo::WriteFuncT` to accept the output 105 | # data, may be `nil` to indicate a no-op *write_func*. 106 | # With a no-op *write_func*, the surface may be queried or used as a source 107 | # without generating any temporary files. 108 | # - **closure** the closure argument for *write_func* 109 | # - **width_in_points** width of the surface, 110 | # in points (1 point == 1/72.0 inch) 111 | # - **height_in_points** height of the surface, 112 | # in points (1 point == 1/72.0 inch) 113 | # 114 | # ###Returns 115 | # A pointer to the newly created `Surface`. 116 | # The caller owns the surface and should call `Surface#finalize` when done 117 | # with it. 118 | # 119 | # This function always returns a valid pointer, but it will return a 120 | # pointer to a "nil" surface if an error such as out of memory occurs. 121 | # You can use `Surface#status` to check for this. 122 | def initialize(write_func : LibCairo::WriteFuncT, closure : Void*, width_in_points : Float64, height_in_points : Float64) 123 | super(LibCairo.pdf_surface_create_for_stream(write_func, closure, width_in_points, height_in_points)) 124 | end 125 | 126 | # Restricts the generated PDF file to version. 127 | # See `PdfSurface#versions` for a list of available version values 128 | # that can be used here. 129 | # 130 | # This function should only be called before any drawing operations have 131 | # been performed on the given surface. The simplest way to do this is to 132 | # call this function immediately after creating the surface. 133 | # 134 | # ###Parameters 135 | # - **version** PDF version 136 | def restrict_to_version(version : PdfVersion) 137 | LibCairo.pdf_surface_restrict_to_version(to_unsafe, LibCairo::PdfVersionT.new(version.value)) 138 | self 139 | end 140 | 141 | # Used to retrieve the list of supported versions. 142 | # See `PdfSurface#restrict_to_version`. 143 | # 144 | # ###Returns 145 | # Supported version list. 146 | def self.versions : Array(PdfVersion) 147 | LibCairo.pdf_get_versions(out version, out num_versions) 148 | return [] of PdfVersion if num_versions == 0 149 | Array(PdfVersion).new(num_versions) do |i| 150 | PdfVersion.new(version[i].value) 151 | end 152 | end 153 | 154 | # Changes the size of a PDF surface for the current (and subsequent) pages. 155 | # 156 | # This function should only be called before any drawing operations have 157 | # been performed on the current page. The simplest way to do this is to 158 | # call this function immediately after creating the surface or immediately 159 | # after completing a page with either `Context#show_page` 160 | # or `Context#copy_page`. 161 | # 162 | # ###Parameters 163 | # - **width_in_points** new surface width, in points 164 | # (1 point == 1/72.0 inch) 165 | # - **height_in_points** new surface height, 166 | # in points (1 point == 1/72.0 inch) 167 | def set_size(width_in_points : Float64, height_in_points : Float64) 168 | LibCairo.pdf_surface_set_size(to_unsafe, width_in_points, height_in_points) 169 | self 170 | end 171 | 172 | # Add an item to the document outline hierarchy with the name that links 173 | # to the location specified by *link_attribs*. Link attributes have the 174 | # same keys and values as the *Link Tag*, excluding the "rect" attribute. 175 | # The item will be a child of the item with id *parent_id*. 176 | # Use `Cairo::C::LibCaio::PDF_OUTLINE_ROOT` as the parent id of top level items. 177 | # 178 | # ###Parameters 179 | # - **parent_id** the id of the parent item or 180 | # `Cairo::C::LibCairo::PDF_OUTLINE_ROOT` if this is a top level item. 181 | # - **name** the name of the outline 182 | # - **link_attribs** the link attributes specifying where this outline links to 183 | # - **flags** outline item flags 184 | # 185 | # ###Returns 186 | # The id for the added item. 187 | def add_outline(parent_id : Int32, name : String, link_attribs : String, flags : PdfOutlineFlags): Int 188 | LibCairo.pdf_surface_add_outline(to_unsafe, parent_id, name.to_unsafe, link_attribs.to_unsafe, LibCairo.PdfOutlineFlagsT.new(flags.value)) 189 | end 190 | 191 | # Set document metadata. The `PdfMetadata::CreateDate` 192 | # and `PdfMetadata::ModDate` values must be in ISO-8601 format: YYYY-MM-DDThh:mm:ss. 193 | # An optional timezone of the form "[+/-]hh:mm" or "Z" for UTC time can be appended. 194 | # All other metadata values can be any UTF-8 string. 195 | # 196 | # For example: 197 | # ``` 198 | # surface.set_metadata(PdfMetadata::MetadataTitle, "My Document") 199 | # surface.set_metadata(PdfMetadata::CreateDate, "2015-12-31T23:59+02:00") 200 | # ``` 201 | # 202 | # ###Parameters 203 | # - **metadata** The metadata item to set. 204 | # - **value** metadata value 205 | def set_metadata(metadata : PdfMetadata, value : String) 206 | LibCairo.pdf_surface_set_metadata(to_unsafe, LibCairo.PdfMetadataT.new(metadata.value), value.to_unsafe) 207 | self 208 | end 209 | 210 | # Set page label for the current page. 211 | # 212 | # ###Parameters 213 | # - **label** The page label. 214 | def page_label=(label : String) 215 | LibCairo.pdf_surface_set_label(to_unsafe, label.to_unsafe) 216 | self 217 | end 218 | 219 | # Set the thumbnail image size for the current and all subsequent pages. 220 | # Setting a width or height of 0 disables thumbnails for the current and subsequent pages. 221 | # 222 | # ###Parameters 223 | # - **width** Thumbnail width. 224 | # - **height** Thumbnail height 225 | def set_thumbnail_size(width : Int32, height : Int32) 226 | LibCairo.pdf_surface_set_thumbnail_size(to_unsafe, width, height) 227 | self 228 | end 229 | end 230 | end 231 | 232 | {% end %} 233 | -------------------------------------------------------------------------------- /src/cairo/pdf_version.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | require "./c/pdf" 4 | 5 | {% if Cairo::C::HAS_PDF_SURFACE %} 6 | 7 | module Cairo 8 | # `PdfVersion` is used to describe the version number of the 9 | # PDF specification that a generated PDF file will conform to. 10 | enum PdfVersion 11 | # The version 1.4 of the PDF specification. 12 | V_1_4 13 | 14 | # The version 1.5 of the PDF specification. 15 | V_1_5 16 | 17 | # Get the string representation of the given version id. 18 | # This function will return `nil` if version isn't valid. 19 | # See `PdfSurface#versions` for a way to get the list of valid version ids. 20 | # 21 | # ###Returns 22 | # The string associated to given version. 23 | def to_string : String 24 | String.new(LibCairo.pdf_version_to_string(LibCairo::PdfVersionT.new(self))) 25 | end 26 | end 27 | end 28 | 29 | {% end %} 30 | -------------------------------------------------------------------------------- /src/cairo/point.cr: -------------------------------------------------------------------------------- 1 | require "./c//lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | struct Point 7 | property x : Float64 = 0.0 8 | property y : Float64 = 0.0 9 | 10 | def initialize 11 | end 12 | 13 | def initialize(@x : Float64, @y : Float64) 14 | end 15 | 16 | def initialize(point : LibCairo::PathDataPointT) 17 | @x = point.x 18 | @y = point.y 19 | end 20 | 21 | def to_path_data_point : LibCairo::PathDataPointT 22 | point = LibCairo::PathDataPointT.new 23 | point.x = @x 24 | point.y = @y 25 | point 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/cairo/ps_level.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | require "./c/ps" 4 | 5 | {% if Cairo::C::HAS_PS_SURFACE %} 6 | 7 | module Cairo 8 | # Describes the language level of the PostScript Language Reference 9 | # that a generated PostScript file will conform to. 10 | enum PsLevel 11 | # The language level 2 of the PostScript specification. 12 | Level2 13 | 14 | # The language level 3 of the PostScript specification. 15 | Level3 16 | 17 | # Get the string representation of the given level id. 18 | # This function will return empty string if level id isn't valid. 19 | # See `PsSurface#levels` for a way to get the list of valid level ids. 20 | # 21 | # ###Returns 22 | # The string associated to given level. 23 | def to_string : String 24 | String.new(LibCairo.ps_level_to_string(LibCairo::PsLevelT.new(self))) 25 | end 26 | end 27 | end 28 | 29 | {% end %} 30 | -------------------------------------------------------------------------------- /src/cairo/ps_surface.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | require "./c/ps" 4 | 5 | {% if Cairo::C::HAS_PS_SURFACE %} 6 | 7 | module Cairo 8 | include Cairo::C 9 | 10 | # The PostScript surface is used to render cairo graphics to Adobe PostScript 11 | # files and is a multi-page vector surface backend. 12 | # 13 | # The following mime types are supported: 14 | # - `Cairo::C::LibCairo::MIME_TYPE_JPEG`, 15 | # - `Cairo::C::LibCairo::MIME_TYPE_UNIQUE_ID`, 16 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX`, 17 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS`, 18 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX`, 19 | # - `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS`, 20 | # - `Cairo::C::LibCairo::MIME_TYPE_EPS`, 21 | # - `Cairo::C::LibCairo::MIME_TYPE_EPS_PARAMS`. 22 | # 23 | # Source surfaces used by the PostScript surface that have a 24 | # `Cairo::C::LibCairo::MIME_TYPE_UNIQUE_ID` mime type will be stored in 25 | # PostScript printer memory for the duration of the print job. 26 | # `Cairo::C::LibCairo::MIME_TYPE_UNIQUE_ID` should only be used for small 27 | # frequently used sources. 28 | # 29 | # The `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX` and 30 | # `Cairo::C::LibCairo::MIME_TYPE_CCITT_FAX_PARAMS` mime types are documented in 31 | # [CCITT Fax Images](https://cairographics.org/manual/cairo-PDF-Surfaces.html#ccitt). 32 | # 33 | # ##Embedding EPS files 34 | # Encapsulated PostScript files can be embedded in the PS output by setting the 35 | # `Cairo::C::LibCairo::MIME_TYPE_EPS` mime data on a surface to the EPS data 36 | # and painting the surface. The EPS will be scaled and translated to the 37 | # extents of the surface the EPS data is attached to. 38 | # 39 | # The `Cairo::C::LibCairo::MIME_TYPE_EPS` mime type requires the 40 | # `Cairo::C::LibCairo::MIME_TYPE_EPS_PARAMS` mime data to also be provided 41 | # in order to specify the embeddding parameters. 42 | # `Cairo::C::LibCairo::MIME_TYPE_EPS_PARAMS` mime data must contain a string 43 | # of the form `"bbox=[llx lly urx ury]"` that specifies the bounding box 44 | # (in PS coordinates) of the EPS graphics. The parameters are: lower left x, 45 | # lower left y, upper right x, upper right y. Normally the bbox data is 46 | # identical to the `%%BoundingBox` data in the EPS file. 47 | class PsSurface < Surface 48 | # Creates a PostScript surface of the specified size in points to be written 49 | # to filename. 50 | # 51 | # NOTE: that the size of individual pages of the PostScript output can vary. 52 | # See `PsSurface#set_size`. 53 | # 54 | # ###Parameters 55 | # - **filename** a filename for the PS output (must be writable), 56 | # `nil` may be used to specify no output. This will generate a PS surface 57 | # that may be queried and used as a source, without generating a temporary file. 58 | # - **width_in_points** width of the surface, in points (1 point == 1/72.0 inch) 59 | # - **height_in_points** height of the surface, in points (1 point == 1/72.0 inch) 60 | # 61 | # ###Returns 62 | # A pointer to the newly created surface. The caller owns the surface and 63 | # should call `Surface#finalize` when done with it. 64 | # 65 | # This function always returns a valid pointer, but it will return a 66 | # pointer to a "nil" surface if an error such as out of memory occurs. 67 | # You can use `Surface#status` to check for this. 68 | def initialize(filename : String, width_in_points : Float64, height_in_points : Float64) 69 | super(LibCairo.ps_surface_create(filename.to_unsafe, width_in_points, height_in_points)) 70 | end 71 | 72 | # Creates a PostScript surface of the specified size in points to be 73 | # written incrementally to the stream represented by *write_func* and 74 | # closure. See `PsSurface#initialize` for a more convenient way to 75 | # simply direct the PostScript output to a named file. 76 | # 77 | # NOTE: that the size of individual pages of the PostScript output can vary. 78 | # See `PsSurface#set_size`. 79 | # 80 | # ###Parameters 81 | # - **write_func** a `Cairo::C::LibCairo::WriteFuncT` to accept the output 82 | # data, may be `nil` to indicate a no-op *write_func*. 83 | # With a no-op *write_func*, the surface may be queried or used as a 84 | # source without generating any temporary files. 85 | # - **closure** the closure argument for *write_func* 86 | # - **width_in_points** width of the surface, in points (1 point == 1/72.0 inch) 87 | # - **height_in_points** height of the surface, in points (1 point == 1/72.0 inch) 88 | # 89 | # ###Returns 90 | # A pointer to the newly created surface. The caller owns the surface and 91 | # should call `Surface#finalize` when done with it. 92 | # 93 | # This function always returns a valid pointer, but it will return a pointer 94 | # to a "nil" surface if an error such as out of memory occurs. 95 | # You can use `Surface#status` to check for this. 96 | def initialize(write_func : LibCairo::WriteFuncT, closure : Void*, width_in_points : Float64, height_in_points : Float64) 97 | super(LibCairo.ps_surface_create_for_stream(write_func, closure, width_in_points, height_in_points)) 98 | end 99 | 100 | # Restricts the generated PostSript file to level. 101 | # See `PsSurface#levels` for a list of available level values that can be used here. 102 | # 103 | # This function should only be called before any drawing operations have 104 | # been performed on the given surface. The simplest way to do this is to 105 | # call this function immediately after creating the surface. 106 | # 107 | # ###Parameters 108 | # - **level** PostScript level 109 | def restrict_to_level(level : PsLevel) 110 | LibCairo.ps_surface_restrict_to_level(to_unsafe, LibCairo::PsLevelT.new(level.value)) 111 | self 112 | end 113 | 114 | # Used to retrieve the list of supported levels. 115 | # See `PsSurface#restrict_to_level`. 116 | # 117 | # ###Returns 118 | # Supported level list. 119 | def self.levels : Array(PsLevel) 120 | LibCairo.ps_get_levels(out levels, out num_levels) 121 | return [] of PsLevel if num_levels == 0 122 | Array(PsLevel).new(num_levels) do |i| 123 | PsLevel.new(levels[i].value) 124 | end 125 | end 126 | 127 | # Check whether the PostScript surface will output Encapsulated PostScript. 128 | # 129 | # ###Returns 130 | # `true` if the surface will output Encapsulated PostScript. 131 | def eps : Bool 132 | LibCairo.ps_surface_get_eps(to_unsafe) == 1 133 | end 134 | 135 | # If eps is `true`, the PostScript surface will output Encapsulated PostScript. 136 | # 137 | # This function should only be called before any drawing operations have been 138 | # performed on the current page. The simplest way to do this is to call this 139 | # function immediately after creating the surface. An Encapsulated PostScript 140 | # file should never contain more than one page. 141 | # 142 | # ###Parameters 143 | # - **eps** `true` to output EPS format PostScript. 144 | def eps=(eps : Bool) 145 | LibCairo.ps_surface_set_eps(to_unsafe, eps ? 1 : 0) 146 | self 147 | end 148 | 149 | # Changes the size of a PostScript surface for the current (and subsequent) pages. 150 | # 151 | # This function should only be called before any drawing operations have been 152 | # performed on the current page. The simplest way to do this is to call this 153 | # function immediately after creating the surface or immediately after 154 | # completing a page with either `Context#show_page` or `Context#copy_page`. 155 | # 156 | # ###Parameters 157 | # - **width_in_points** new surface width, in points (1 point == 1/72.0 inch) 158 | # - **height_in_points** new surface height, in points (1 point == 1/72.0 inch) 159 | def set_size(width_in_points : Float64, height_in_points : Float64) 160 | LibCairo.ps_surface_set_size(to_unsafe, width_in_points, height_in_points) 161 | self 162 | end 163 | 164 | # Emit a comment into the PostScript output for the given surface. 165 | # 166 | # The comment is expected to conform to the PostScript Language Document 167 | # Structuring Conventions (DSC). Please see that manual for details on 168 | # the available comments and their meanings. In particular, 169 | # the `%%IncludeFeature` comment allows a device-independent means of 170 | # controlling printer device features. So the PostScript Printer 171 | # Description Files Specification will also be a useful reference. 172 | # 173 | # The comment string must begin with a percent character (%) and the total 174 | # length of the string (including any initial percent characters) must not 175 | # exceed 255 characters. Violating either of these conditions will place 176 | # *surface* into an error state. But beyond these two conditions, this 177 | # function will not enforce conformance of the comment with any particular specification. 178 | # 179 | # The comment string should not have a trailing newline. 180 | # 181 | # The DSC specifies different sections in which particular comments can 182 | # appear. This function provides for comments to be emitted within three 183 | # sections: the header, the Setup section, and the PageSetup section. 184 | # Comments appearing in the first two sections apply to the entire document 185 | # while comments in the BeginPageSetup section apply only to a single page. 186 | # 187 | # For comments to appear in the header section, this function should be 188 | # called after the surface is created, but before a call to 189 | #`PsSurface#dsc_begin_setup`. 190 | # 191 | # For comments to appear in the Setup section, this function should be 192 | # called after a call to `PsSurface#dsc_begin_setup` but before a call 193 | # to `PsSurface#dsc_begin_page_setup`. 194 | # 195 | # For comments to appear in the PageSetup section, this function should 196 | # be called after a call to `PsSurface#dsc_begin_page_setup`. 197 | # 198 | # NOTE: that it is only necessary to call `PsSurface#dsc_begin_page_setup` 199 | # for the first page of any surface. After a call to `Context#show_page` or 200 | # `Context#copy_page` comments are unambiguously directed to the PageSetup 201 | # section of the current page. But it doesn't hurt to call this function at 202 | # the beginning of every page as that consistency may make the calling code simpler. 203 | # 204 | # As a final note, cairo automatically generates several comments on its own. 205 | # As such, applications must not manually generate any of the following comments: 206 | # 207 | # Header section: `%!PS-Adobe-3.0`, `%%Creator`, `%%CreationDate`, `%%Pages`, 208 | # `%%BoundingBox`, `%%DocumentData`, `%%LanguageLevel`, `%%EndComments`. 209 | # 210 | # Setup section: `%%BeginSetup`, `%%EndSetup` 211 | # 212 | # PageSetup section: `%%BeginPageSetup`, `%%PageBoundingBox`, `%%EndPageSetup`. 213 | # 214 | # Other sections: `%%BeginProlog`, `%%EndProlog`, `%%Page`, `%%Trailer`, `%%EOF` 215 | # 216 | # Here is an example sequence showing how this function might be used: 217 | # ``` 218 | # surface = PsSurface.new(filename, width, height) 219 | # ... 220 | # surface.dsc_comment("%%Title: My excellent document") 221 | # surface.dsc_comment("%%Copyright: Copyright (C) 2006 Cairo Lover") 222 | # ... 223 | # surface.dsc_begin_setup 224 | # surface.dsc_comment("%%IncludeFeature: *MediaColor White") 225 | # ... 226 | # surface.dsc_begin_page_setup 227 | # surface.dsc_comment("%%IncludeFeature: *PageSize A3") 228 | # surface.dsc_comment("%%IncludeFeature: *InputSlot LargeCapacity") 229 | # surface.dsc_comment("%%IncludeFeature: *MediaType Glossy") 230 | # surface.dsc_comment("%%IncludeFeature: *MediaColor Blue") 231 | # ... draw to first page here .. 232 | # cr.show_page 233 | # ... 234 | # surface.dsc_comment("%%IncludeFeature: *PageSize A5") 235 | # ``` 236 | # 237 | # ###Parameters 238 | # - **comment** a comment string to be emitted into the PostScript output 239 | def dsc_comment(comment : String) 240 | LibCairo.ps_surface_dsc_comment(to_unsafe, comment.to_unsafe) 241 | self 242 | end 243 | 244 | # This function indicates that subsequent calls to 245 | # `PsSurface#dsc_comment` should direct comments to 246 | # the Setup section of the PostScript output. 247 | # 248 | # This function should be called at most once per surface, 249 | # and must be called before any call to `PsSurface#dsc_begin_page_setup` 250 | # and before any drawing is performed to the surface. 251 | # 252 | # See `PsSurface#dsc_comment` for more details. 253 | def dsc_begin_setup 254 | LibCairo.ps_surface_dsc_begin_setup(to_unsafe) 255 | self 256 | end 257 | 258 | # This function indicates that subsequent calls to 259 | # `PsSurface#dsc_comment` should direct comments to the 260 | # PageSetup section of the PostScript output. 261 | # 262 | # This function call is only needed for the first page of a surface. 263 | # It should be called after any call to `PsSurface#dsc_begin_setup` 264 | # and before any drawing is performed to the surface. 265 | # 266 | # See `PsSurface#dsc_comment` for more details. 267 | def dsc_begin_page_setup 268 | LibCairo.ps_surface_dsc_begin_page_setup(to_unsafe) 269 | self 270 | end 271 | end 272 | end 273 | 274 | {% end %} 275 | -------------------------------------------------------------------------------- /src/cairo/rectangle.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # A data structure for holding a rectangle. 7 | # 8 | # Wrapper for `LibCairo::RectangleT` structure. 9 | struct Rectangle 10 | # Creates uninitialized rectangle. 11 | def initialize 12 | @rect = LibCairo::RectangleT.new 13 | end 14 | 15 | # Creates new rectangle using specified coordinates of top left corner (x, y), width and height. 16 | def initialize(x : Float64, y : Float64, width : Float64, height : Float64) 17 | @rect = LibCairo::RectangleT.new 18 | @rect.x = x 19 | @rect.y = y 20 | @rect.width = width 21 | @rect.height = height 22 | end 23 | 24 | # Creates new rectangle from `LibCairo::RectangleT`. 25 | def initialize(@rect : LibCairo::RectangleT) 26 | end 27 | 28 | # X coordinate of the left side of the rectangle. 29 | def x : Float64 30 | @rect.x 31 | end 32 | 33 | # Setter for X coordinate. 34 | def x=(x : Float64) 35 | @rect.x = x 36 | end 37 | 38 | # Y coordinate of the the top side of the rectangle. 39 | def y : Float64 40 | @rect.y 41 | end 42 | 43 | # Setter for Y coordinate. 44 | def y=(y : Float64) 45 | @rect.y = y 46 | end 47 | 48 | # Width of the rectangle. 49 | def width : Float64 50 | @rect.width 51 | end 52 | 53 | # Setter for width. 54 | def width=(width : Float64) 55 | @rect.width = width 56 | end 57 | 58 | # Height of the rectangle. 59 | def height : Float64 60 | @rect.height 61 | end 62 | 63 | # Setter for height. 64 | def height=(height : Float64) 65 | @rect.height = height 66 | end 67 | 68 | # Returns underlying `LibCairo::RectangleT` structure. 69 | def to_cairo_rectange : LibCairo::RectangleT 70 | @rect 71 | end 72 | 73 | # Pointer of underlying `LibCairo::RectangleT` structure. 74 | def to_unsafe : LibCairo::PRectangleT 75 | pointerof(@rect) 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /src/cairo/rectangle_int.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # A data structure for holding a rectangle. 7 | # 8 | # Wrapper for LibCairo::RectangleIntT 9 | struct RectangleInt 10 | # Creates uninitialized rectangle. 11 | def initialize 12 | @rect = LibCairo::RectangleIntT.new 13 | end 14 | 15 | # Creates new rectangle using specified coordinates of top left corner (x, y), width and height. 16 | def initialize(x : Int32, y : Int32, width : Int32, height : Int32) 17 | @rect = LibCairo::RectangleIntT.new 18 | @rect.x = x 19 | @rect.y = y 20 | @rect.width = width 21 | @rect.height = height 22 | end 23 | 24 | # Creates new rectangle from `LibCairo::RectangleT`. 25 | def initialize(@rect : LibCairo::RectangleIntT) 26 | end 27 | 28 | # X coordinate of the left side of the rectangle. 29 | def x : Int32 30 | @rect.x 31 | end 32 | 33 | # Setter for X coordinate. 34 | def x=(x : Int32) 35 | @rect.x = x 36 | end 37 | 38 | # Y coordinate of the the top side of the rectangle. 39 | def y : Int32 40 | @rect.y 41 | end 42 | 43 | # Setter for Y coordinate. 44 | def y=(y : Int32) 45 | @rect.y = y 46 | end 47 | 48 | # Width of the rectangle. 49 | def width : Int32 50 | @rect.width 51 | end 52 | 53 | # Setter for width. 54 | def width=(width : Int32) 55 | @rect.width = width 56 | end 57 | 58 | # Height of the rectangle. 59 | def height : Int32 60 | @rect.height 61 | end 62 | 63 | # Setter for height. 64 | def height=(height : Int32) 65 | @rect.height = height 66 | end 67 | 68 | # Returns underlying `LibCairo::RectangleIntT` structure. 69 | def to_cairo_rectangle : LibCairo::RectangleIntT 70 | @rect 71 | end 72 | 73 | # Pointer of underlying `LibCairo::RectangleIntT` structure. 74 | def to_unsafe : LibCairo::PRectangleIntT 75 | pointerof(@rect) 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /src/cairo/rectangle_list.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./rectangle" 3 | require "./status" 4 | 5 | module Cairo 6 | include Cairo::C 7 | 8 | # A data structure for holding a dynamically allocated array of rectangles. 9 | # 10 | # Wraper for LibCairo::RectangleListT 11 | class RectangleList 12 | include Indexable(Rectangle) 13 | 14 | def initialize(list : LibCairo::PRectangleListT) 15 | raise ArgumentError.new("'list' cannot be null") if list.null? 16 | @list = list 17 | end 18 | 19 | def finalize 20 | LibCairo.rectangle_list_destroy(@list) 21 | end 22 | 23 | # Error status of the rectangle list 24 | def status : Status 25 | Status.new(@list.value.status.value) 26 | end 27 | 28 | # Number of rectangles in this list 29 | @[AlwaysInline] 30 | def size : Int32 31 | @list.value.num_rectangles 32 | end 33 | 34 | # Returns rectangle at the given index. 35 | @[AlwaysInline] 36 | def unsafe_fetch(index : Int) : Rectangle 37 | Rectangle.new(@list.value.rectangles[index]) 38 | end 39 | 40 | # Returns underlying `LibCairo::RectangleIntT` structure. 41 | def to_cairo_rectangle_list : LibCairo::RectangleListT 42 | @list.value 43 | end 44 | 45 | # Pointer of list. 46 | def to_unsafe : LibCairo::PRectangleListT 47 | @list 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /src/cairo/region.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # A `Region` represents a set of integer-aligned rectangles. 7 | # 8 | # It allows set-theoretical operations like `Region#union` and `Region#intersect` to be performed on them. 9 | # 10 | # Memory management of `Region` is done with `Region#reference` and `Region#finalize`. 11 | # 12 | # Wrapper for LibCairo::PRegionT 13 | class Region 14 | def initialize(region : LibCairo::PRegionT) 15 | raise ArgumentError.new("'region' cannot be null.") unless region.null? 16 | @region = region 17 | end 18 | 19 | # Allocates a new empty region object. 20 | def initialize 21 | @region = LibCairo.region_create 22 | end 23 | 24 | # Allocates a new region object containing rectangle. 25 | def initialize(rectangle : RectangleInt) 26 | @region = LibCairo.region_create_rectangle(rectangle.to_cairo_rectangle) 27 | end 28 | 29 | # Allocates a new region object containing the union of all given rects. 30 | # 31 | # ###Parameters 32 | # - **rects** an array of count rectangles 33 | def initialize(rects : Array(RectangleInt)) 34 | @region = LibCairo.region_create_rectangles( 35 | rect.to_unsafe.as(LibCairo::PRectangleT), rects.size) 36 | end 37 | 38 | # Destroys a `Region` object created with `Region#initialize`, `Region#dup`, or `Region#initialize(rectangle)`. 39 | def finalize 40 | LibCairo.region_destroy(@region) 41 | end 42 | 43 | # Allocates a new region object copying the area from original. 44 | def dup : Region 45 | Region.new(LibCairo.region_copy(@region)) 46 | end 47 | 48 | #Increases the reference count on region by one. This prevents region from being destroyed until a matching call 49 | # to `Region#finalize` is made. 50 | # 51 | # ###Returns 52 | # The referenced `Region`. 53 | def reference : Region 54 | Region.new(LibCairo.region_reference(@region)) 55 | end 56 | 57 | # Compares whether region is equivalent to *other*. 58 | # 59 | # ###Parameters 60 | # - **other* a `Region` object 61 | # 62 | # ###Returns 63 | # `true` if both regions contained the same coverage, `false` if it is not or any region is in an error status. 64 | def ==(other : Region) : Bool 65 | LibCairo.region_equal(@region, other.to_unsafe) == 1 66 | end 67 | 68 | # Checks whether an error has previous occurred for this region object. 69 | # 70 | # ###Returns 71 | # `Status::Success` or `Status::NoMemory` 72 | def status : Status 73 | Status.new(LibCairo.region_status(@region).value) 74 | end 75 | 76 | # Gets the bounding rectangle of region as a `RectangleInt`. 77 | # 78 | # ###Parameters 79 | # - **extents** rectangle into which to store the extents 80 | def extents : RectangleInt 81 | LibCairo.region_get_extents(@region, out extents) 82 | RectangleInt.new(extents) 83 | end 84 | 85 | # Returns the number of rectangles contained in region. 86 | # 87 | # ###Returns 88 | # The number of rectangles contained in region. 89 | def num_rectangles : Int32 90 | LibCairo.region_num_rectangles(@region) 91 | end 92 | 93 | # Stores the nth rectangle from the region in rectangle. 94 | # 95 | # ###Parameters 96 | # - **nth** a number indicating which rectangle should be returned 97 | # 98 | # ###Returns 99 | # The location for a `RectangleInt`. 100 | def rectangle(nth : Int32) : RectangleInt 101 | LibCairo.region_get_rectangle(@region, nth, out rectangle) 102 | RectangleInt.new(rectangle) 103 | end 104 | 105 | # Checks whether region is empty. 106 | # 107 | # ###Returns 108 | # `true` if region is empty, `false` if it isn't. 109 | def empty? : Bool 110 | LibCairo.region_is_empty(@region) == 1 111 | end 112 | 113 | # Checks whether rectangle is inside, outside or partially contained in region. 114 | # 115 | # ###Parameters 116 | # - **rectangle** a `RectangleInt` 117 | # 118 | # ###Returns 119 | # - `RegionOverlap::In` if rectangle is entirely inside region 120 | # - `RegionOverlap::Out` if rectangle is entirely outside region 121 | # - `RegionOVerlap::Part` if rectangle is partially inside and partially outside region 122 | def contains?(rectangle : RectangleInt) : RegionOverlap 123 | RegionOverlap.new(LibCairo.region_contains_rectangle(@region, rectangle.to_unsafe).value) 124 | end 125 | 126 | # Checks whether *(x, y)* is contained in region. 127 | # 128 | # ###Parameters 129 | # - *x* the x coordinate of a point 130 | # - *y* the y coordinate of a point 131 | # 132 | # ###Returns 133 | # `true` if *(x, y)* is contained in region, `false` if it is not. 134 | def contains?(x : Int32, y : Int32) : Bool 135 | LibCairo.region_contains_point(@region, x, y) == 1 136 | end 137 | 138 | def contains?(p : Point) : Bool 139 | LibCairo.region_contains_point(@region, p.x, p.y) == 1 140 | end 141 | 142 | # Translates region by *(dx, dy)*. 143 | # 144 | # ###Parameters 145 | # - **dx** Amount to translate in the x direction 146 | # - **dy** Amount to translate in the y direction 147 | def translate(dx : Int32, dy : Int32) 148 | LibCairo.region_translate(@region, dx, dy) 149 | self 150 | end 151 | 152 | def translate(d : Point) 153 | LibCairo.region_translate(@region, d.x, d.y) 154 | self 155 | end 156 | 157 | # Subtracts other from `self` and places the result in `self`. 158 | # 159 | # ###Parameters 160 | # - **other** another `Region` 161 | # 162 | # ###Raises 163 | # `StatusException` with status of `Status::NoMemory`. 164 | def subtract(other : Region) 165 | status = Status.new(LibCairo.region_subtract(@region, other.to_unsafe).value) 166 | raise new StatusException.new(status) unless status.success? 167 | self 168 | end 169 | 170 | # Subtracts rectangle from `self` and places the result in `self`. 171 | # 172 | # ###Parameters 173 | # - **rectangle** a `RectangleInt` 174 | # 175 | # ###Raises 176 | # `StatusException` with status of `Status::NoMemory`. 177 | def subtract(rectangle : RectangleInt) 178 | status = Status.new(LibCairo.region_subtract_rectangle(@region, rectangle.to_unsafe).value) 179 | raise new StatusException.new(status) unless status.success? 180 | self 181 | end 182 | 183 | # Computes the intersection of `self` with other and places the result in `self`. 184 | # 185 | # ###Parameters 186 | # - **other** another `Region` 187 | # 188 | # ##Raises 189 | # `StatusException` with status of `Status::NoMemory`. 190 | def intersect(other : Region) 191 | status = Status.new(LibCairo.region_intersect(@region, other.to_unsafe).value) 192 | raise new StatusException.new(status) unless status.success? 193 | self 194 | end 195 | 196 | # Computes the intersection of `self` with rectangle and places the result in `self`. 197 | # 198 | # ###Parameters 199 | # - **rectangle** a `RectangleInt` 200 | # 201 | # ###Raises 202 | # `StatusException` with status of `Status::NoMemory`. 203 | def intersect(rectangle : RectangleInt) 204 | status = Status.new(LibCairo.region_intersect_rectangle(@region, rectangle.to_unsafe).value) 205 | raise new StatusException.new(status) unless status.success? 206 | self 207 | end 208 | 209 | # Computes the union of `self` with other and places the result in `self`. 210 | # 211 | # ###Parameters 212 | # - **other** another `Region` 213 | # 214 | # ###Raises 215 | # `StatusException` with status of `Status::NoMemory`. 216 | def union(other : Region) 217 | status = Status.new(LibCairo.region_union(@region, other.to_unsafe).value) 218 | raise new StatusException.new(status) unless status.success? 219 | self 220 | end 221 | 222 | # Computes the union of `self` with rectangle and places the result in `self`. 223 | # 224 | # ###Parameters 225 | # - **rectangle** a RectangleInt 226 | # 227 | # ###Raises 228 | # `StatusException` with status of `Status::NoMemory`. 229 | def union(rectangle : RectangleInt) 230 | status = Status.new(LibCairo.region_union_rectangle(@region, rectangle.to_unsafe).value) 231 | raise new StatusException.new(status) unless status.success? 232 | self 233 | end 234 | 235 | # Computes the exclusive difference of `self` with other and places the result in `self`. 236 | # That is, `self` will be set to contain all areas that are either in `self` or in other , but not in both. 237 | # 238 | # ###Parameters 239 | # - **other** another `Region` 240 | # 241 | # ###Raises 242 | # `StatusException` with status of `Status::NoMemory`. 243 | def xor(other : Region) 244 | status = Status.new(LibCairo.region_xor(@region, other.to_unsafe).value) 245 | raise new StatusException.new(status) unless status.success? 246 | self 247 | end 248 | 249 | # Computes the exclusive difference of `self` with rectangle and places the result in `self`. 250 | # That is, `self` will be set to contain all areas that are either in `self` or in rectangle, but not in both. 251 | # 252 | # ###Parameters 253 | # - **rectangle** a `RectangleInt` 254 | # 255 | # ###Raises 256 | # `StatusException` with status of `Status::NoMemory`. 257 | def xor_rectangle(rectangle : RectangleInt) 258 | status = Status.new(LibCairo.region_xor_rectangle(@region, rectangle.to_unsafe).value) 259 | raise new StatusException.new(status) unless status.success? 260 | self 261 | end 262 | 263 | def to_unsafe : LibCairo::PRegionT 264 | @region 265 | end 266 | end 267 | end 268 | -------------------------------------------------------------------------------- /src/cairo/region_overlap.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Used as the return value for `Region#contains_rectangle`. 3 | enum RegionOverlap 4 | # The contents are entirely inside the region. 5 | In 6 | 7 | # The contents are entirely outside the region. 8 | Out 9 | 10 | # The contents are partially inside and partially outside the region. 11 | Part 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/cairo/rgba.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | struct RGBA 3 | property red : Float64 4 | property green : Float64 5 | property blue : Float64 6 | property alpha : Float64 7 | 8 | def initialize(@red : Float64, @green : Float64, @blue : Float64, @alpha : Float64) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /src/cairo/scaled_font.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./glyph_array" 3 | require "./text_cluster_array" 4 | 5 | module Cairo 6 | include Cairo::C 7 | 8 | # A `ScaledFont` is a font scaled to a particular size and device resolution. 9 | # A `ScaledFont` is most useful for low-level font usage where a library or 10 | # application wants to cache a reference to a scaled font to speed up the computation of metrics. 11 | # 12 | # There are various types of scaled fonts, depending on the font backend they use. 13 | # The type of a scaled font can be queried using `ScaledFont#type`. 14 | # 15 | # Memory management of `ScaledFont` is done with `ScaledFont#reference` and `ScaledFont#finalize`. 16 | class ScaledFont 17 | # Creates a `ScaledFont` object from a font face and matrices that describe the size of the font and the environment in which it will be used. 18 | # 19 | # ###Parameters 20 | # 21 | # - **font_face** a `FontFace` 22 | # - **font_matrix** font space to user space transformation matrix for the font. 23 | # In the simplest case of a N point font, this matrix is just a scale by N, 24 | # but it can also be used to shear the font or stretch it unequally along the two axes. See `Context#font_matrix=`. 25 | # - **ctm** user to device transformation matrix with which the font will be used. 26 | # - **options** options to use when getting metrics for the font and rendering with it. 27 | # 28 | # ###Returns 29 | # A newly created `ScaledFont`. Destroy with `ScaledFont#finalize`. 30 | def initialize(font_face : FontFace, font_matrix : Matrix, ctm : Matrix, options : FontOptions) 31 | @scaled_font = LibCairo.scaled_font_create(font_face.to_unsafe, font_matrix.to_unsafe, ctm.to_unsafe, options.to_unsafe) 32 | end 33 | 34 | def initialize(scaled_font : LibCairo::PScaledFontT) 35 | raise ArgumentError.new("'scaled_font' cannot be null.") if scaled_font.null? 36 | @scaled_font = scaled_font 37 | end 38 | 39 | # Decreases the reference count on font by one. If the result is zero, 40 | # then font and all associated resources are freed. See `ScaledFont#reference`. 41 | def finalize 42 | LibCairo.scaled_font_destroy(@scaled_font) 43 | end 44 | 45 | # Increases the reference count on `ScaledFont` by one. This prevents scaled_font from being destroyed 46 | # until a matching call to `ScaledFont#finalize` is made. 47 | # 48 | # Use `ScaledFont#reference_count` to get the number of references to a `ScaledFont`. 49 | # 50 | # ###Returns 51 | # The referenced `ScaledFont`. 52 | def reference : ScaledFont 53 | ScaledFont.new(LibCairo.scaled_font_reference(@scaled_font)) 54 | end 55 | 56 | # Returns the current reference count of `ScaledFont`. 57 | # 58 | # ###Returns 59 | # The current reference count of `ScaledFont`. If the object is a *nil* object, 0 will be returned. 60 | def reference_count : UInt32 61 | LibCairo.scaled_font_get_reference_count(@scaled_font) 62 | end 63 | 64 | # Checks whether an error has previously occurred for this `ScaledFont`. 65 | # 66 | # ###Returns 67 | # `Status::Success` or another error such as `Status::NoMemory`. 68 | def status : Status 69 | Status.new(LibCairo.scaled_font_status(@scaled_font).value) 70 | end 71 | 72 | # This function returns the type of the backend used to create a scaled font. 73 | # See `FontType` for available types. However, this function never returns `FontType::Toy`. 74 | # 75 | # ###Returns 76 | # The type of `ScaledFont`. 77 | def type : FontType 78 | FontType.new(LibCairo.scaled_font_get_type(@scaled_font).value) 79 | end 80 | 81 | # Return user data previously attached to `ScaledFont` using the specified key. 82 | # If no user data has been attached with the given key this function returns *Nil*. 83 | # 84 | # ###Parameters 85 | # - **key** the address of the `UserDataKey` the user data was attached to 86 | # 87 | # ###Returns 88 | # The user data previously attached or *Nil*. 89 | def user_data(key : UserDataKey) : Void* 90 | LibCairo.scaled_font_get_user_data(@scaled_font, key.to_unsafe) 91 | end 92 | 93 | # Attach user data to `ScaledFont`. To remove user data from a surface, 94 | # call this function with the key that was used to set it and *Nil* for data . 95 | # 96 | # ###Parameters 97 | # - **key** the address of a `UserDataKey` to attach the user data to 98 | # - **user_data** the user data to attach to the `ScaledFont` 99 | # - **destroy** a `DestroyFuncT` which will be called when the `Context` is destroyed or when new user data is attached using the same key. 100 | # 101 | # ###Returns 102 | # `Status::Success` or `Status::NoMemory` if a slot could not be allocated for the user data. 103 | def set_user_data(key : UserDataKey, user_data : Void*, destroy : DestroyFuncT) : Status 104 | Status.new(LibCairo.scaled_font_set_user_data(@scaled_font, key.to_unsafe, user_data, destroy).value) 105 | end 106 | 107 | # Gets the metrics for a `ScaledFont`. 108 | # 109 | # ###Returns 110 | # A `FontExtents` which to store the retrieved extents. 111 | def extents : FontExtents 112 | LibCairo.scaled_font_extents(@scaled_font, out font_extents) 113 | FontExtents.new(font_extents) 114 | end 115 | 116 | # Gets the extents for a string of text. The extents describe a user-space rectangle 117 | # that encloses the "inked" portion of the text drawn at the origin (0,0) 118 | # (as it would be drawn by `Context#show_text` if the cairo graphics state were set 119 | # to the same `font_face`, `font_matrix`, `ctm`, and `font_options`). Additionally, 120 | # the `x_advance` and `y_advance` values indicate the amount by which the current point would be advanced by `Context#show_text`. 121 | # 122 | # NOTE that whitespace characters do not directly contribute to the size of the rectangle 123 | # (`extents.width` and `extents.height`). They do contribute indirectly by changing the position 124 | # of non-whitespace characters. In particular, trailing whitespace characters are likely to not affect 125 | # the size of the rectangle, though they will affect the `x_advance` and `y_advance` values. 126 | # 127 | # ###Parameters 128 | # - **text** string of text 129 | # 130 | # ###Returns 131 | # A `TextExtents` which to store the retrieved extents. 132 | def text_extents(text : String) : TextExtents 133 | LibCairo.scaled_font_text_extents(@scaled_font, text.to_unsafe, out text_extents) 134 | TextExtents.new(text_extents) 135 | end 136 | 137 | # Gets the extents for an array of glyphs. The extents describe a user-space rectangle 138 | # that encloses the "inked" portion of the glyphs, (as they would be drawn by `Context#show_glyphs` 139 | # if the cairo graphics state were set to the same `font_face`, `font_matrix`, `ctm`, and `font_options`). 140 | # Additionally, the `x_advance` and `y_advance` values indicate the amount by which the current 141 | # point would be advanced by `Context#show_glyphs`. 142 | # 143 | # NOTE that whitespace glyphs do not contribute to the size of the rectangle (`extents.width` and `extents.height`). 144 | # 145 | # ###Parameters 146 | # - **glyphs** an array of glyph IDs with X and Y offsets. 147 | # 148 | # ###Returns 149 | # A `TextExtents` which to store the retrieved extents. 150 | def glyph_extents(glyphs : GlyphArray) : TextExtents 151 | LibCairo.glyph_extents(@scaled_font, glyphs.to_unsafe, glyphs.size, out extents) 152 | TextExtents.new(extents) 153 | end 154 | 155 | # Converts UTF-8 text to an array of glyphs. 156 | # 157 | # ###Parameters 158 | # - **x** X position to place first glyph 159 | # - **y** Y position to place first glyph 160 | # - **text** a string of text encoded in UTF-8 161 | # 162 | # ###Returns 163 | # - **glyphs** array of glyphs to fill 164 | # - **clusters** array of cluster mapping information to fill 165 | # - **cluster_flags** cluster flags corresponding to the output clusters 166 | # - **status** `Status::Success` upon success, or an error status if the input values are wrong or if conversion failed. 167 | # If the input values are correct but the conversion failed, the error status is also set on `ScaledFont`. 168 | def text_to_glyphs(x : Float64, y : Float64, text : String) : NamedTuple(glyphs: GlyphArray, clusters: TextClusterArray, cluster_flags: TextClusterFlags, status: Status) 169 | status = LibCairo.scaled_font_text_to_glyphs( 170 | reference.to_unsafe, x, y, text.to_unsafe, text.size, 171 | out glyphs, out num_glyphs, out clusters, out num_clusters, out cluster_flags) 172 | { 173 | glyphs: GlyphArray.new(glyphs, num_glyphs), 174 | clusters: TextClusterArray.new(clusters, num_clusters), 175 | cluster_flags: TextClusterFlags.new(cluster_flags.value), 176 | status: Status.new(status.value) 177 | } 178 | end 179 | 180 | # Gets the font face that this scaled font uses. This might be the font face passed to `ScaledFont#initialize`, 181 | # but this does not hold true for all possible cases. 182 | # 183 | # ###Returns 184 | # The `FontFace` with which `ScaledFont` was created. This object is owned by cairo. 185 | # To keep a reference to it, you must call `ScaledFont#reference`. 186 | def font_face : FontFace 187 | FontFace.new(LibCairo.scaled_font_get_font_face(@scaled_font)) 188 | end 189 | 190 | # Stores the font matrix with which scaled_font was created into matrix. 191 | # 192 | # ###Returns 193 | # The value for the matrix. 194 | def font_matrix : Matrix 195 | LibCairo.scaled_font_get_font_matrix(@scaled_font, out matrix) 196 | Matrix.new(matrix) 197 | end 198 | 199 | # Stores the CTM with which `ScaledFont` was created into *ctm*. 200 | # NOTE that the translation offsets *(x0, y0)* of the CTM are ignored by `ScaledFont#initialize`. 201 | # So, the matrix this function returns always has *0,0* as *x0,y0*. 202 | # 203 | # ###Returns 204 | # The value for the CTM. 205 | def ctm : Matrix 206 | LibCairo.scaled_font_get_ctm(@scaled_font, out ctm) 207 | Matrix.new(ctm) 208 | end 209 | 210 | # Stores the scale matrix of `ScaledFont` into matrix. 211 | # The scale matrix is product of the font matrix and the *ctm* associated with the scaled font, 212 | # and hence is the matrix mapping from font space to device space. 213 | # 214 | # ###Returns 215 | # The value for the matrix. 216 | def scale_matrix : Matrix 217 | LibCairo.scaled_font_get_scale_matrix(@scaled_font, out matrix) 218 | Matrix.new(matrix) 219 | end 220 | 221 | # Stores the font options with which `ScaledFont` was created into options. 222 | # 223 | # ###Returns 224 | # The value for the font options. 225 | def font_options : FontOptions 226 | font_options = FontOptions.new 227 | LibCairo.scaled_font_get_font_options(@scaled_font, font_options.to_unsafe) 228 | font_options 229 | end 230 | 231 | def to_unsafe : LibCairo::PScaledFontT 232 | @scaled_font 233 | end 234 | end 235 | end 236 | -------------------------------------------------------------------------------- /src/cairo/script.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./c/features" 3 | require "./c/script" 4 | 5 | {% if Cairo::C::HAS_SCRIPT_SURFACE %} 6 | 7 | module Cairo 8 | include Cairo::C 9 | 10 | # The script surface provides the ability to render to a native script 11 | # that matches the cairo drawing model. The scripts can be replayed using 12 | # tools under the util/cairo-script directory, or with cairo-perf-trace. 13 | class Script < Device 14 | # Creates a output device for emitting the script, 15 | # used when creating the individual surfaces. 16 | # 17 | # ###Parameters 18 | # - **filename** the name (path) of the file to write the script to 19 | # 20 | # ###Returns 21 | # The newly created Script-Surface. The caller owns the surface 22 | # and should call `Script#finalize` when done with it. 23 | # 24 | # This function always returns a valid pointer, 25 | # but it will return a pointer to a `nil` device if an error such 26 | # as out of memory occurs. You can use `Context#status` to check for this. 27 | def initialize(filename : String) 28 | super(LibCairo.script_create(filename.to_unsafe)) 29 | end 30 | 31 | # Creates a output device for emitting the script, 32 | # used when creating the individual surfaces. 33 | # 34 | # ###Parameters 35 | # - **write_func** callback function passed the bytes written to the script 36 | # - **closure** user data to be passed to the callback 37 | # 38 | # ###Returns 39 | # The newly created device. The caller owns the surface and 40 | # should call `Script#finalze` when done with it. 41 | # 42 | # This function always returns a valid pointer, 43 | # but it will return a pointer to a `nil` device if an error such 44 | # as out of memory occurs. You can use `Context#status` to check for this. 45 | def initialize(write_func : LibCairo::WriteFuncT, closure : Void*) 46 | super(LibCairo.script_create_for_stream(write_func, closure)) 47 | end 48 | 49 | # Emit a string verbatim into the script. 50 | # 51 | # ###Parameters 52 | # - **comment** the string to emit 53 | # - **len** the length of the sting to write, or -1 to use `comment.size` 54 | def write_comment(comment : String, len : Int32 = -1) 55 | LibCairo.script_write_comment(to_unsafe, comment.to_unsafe, len) 56 | self 57 | end 58 | 59 | # Queries the script for its current output mode. 60 | # 61 | # ###Returns 62 | # The current output mode of the script. 63 | def mode : ScriptMode 64 | ScriptMode.new(LibCairo.script_get_mode(to_unsafe).value) 65 | end 66 | 67 | # Change the output mode of the script. 68 | # 69 | # ###Parameters 70 | # - **mode** the new mode 71 | def mode=(mode : ScriptMode) 72 | LibCairo.script_set_mode(to_unsafe, LibCairo::ScriptModeT.new(mode.value)) 73 | self 74 | end 75 | 76 | # Create a new surface that will emit its rendering through script. 77 | # 78 | # ###Parameters 79 | # - **content** the content of the surface 80 | # - **width** width in pixels 81 | # - **height** height in pixels 82 | # 83 | # ###Returns 84 | # A pointer to the newly created `Surface`. The caller owns the surface and 85 | # should call `Surface#finalize` when done with it. 86 | # 87 | # This function always returns a valid pointer, but it will return a pointer 88 | # to a `nil` surface if an error such as out of memory occurs. 89 | # You can use `Surface#status` to check for this. 90 | def create_script_surface(content : Content, width : Float64, height : Float64) : Surface 91 | Surface.new(LibCairo.script_surface_create(to_unsafe, LibCairo::ContentT.new(content.value), width, height)) 92 | end 93 | 94 | # Create a pxoy surface that will render to *target* and record the operations to *device*. 95 | # 96 | # ###Parameters 97 | # - **target** a target surface to wrap 98 | # 99 | # ###Returns 100 | # A pointer to the newly created `Surface`. The caller owns the surface and 101 | # should call `Surface#finalize` when done with it. 102 | # 103 | # This function always returns a valid pointer, but it will return a pointer 104 | # to a `nil` surface if an error such as out of memory occurs. 105 | # You can use `Surface#status` to check for this. 106 | def create_script_surface_for_target(target : Surface) : Surface 107 | Surface.new(LibCairo.script_surface_create_for_target(to_unsafe, target.to_unsafe)) 108 | end 109 | 110 | # Converts the record operations in *recording_surface* into a script. 111 | # 112 | # ###Parameters 113 | # - **script** the script (output device) 114 | # - **recording_surface** the recording surface to replay 115 | # 116 | # ###Returns 117 | # `Status::Success` on successful completion or an error code. 118 | def from_recording_surface(recording_surface : Surface) : Status 119 | Status.new(LibCairo.script_from_recording_surface(to_unsafe, recording_surface.to_unsafe).value) 120 | end 121 | end 122 | end 123 | 124 | {% end %} 125 | -------------------------------------------------------------------------------- /src/cairo/script_interpreter.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./c/script_interpreter" 3 | 4 | module Cairo 5 | include Cairo::C 6 | 7 | # Wrapper for LibCairo::PScriptInterpreterT 8 | class ScriptInterpreter 9 | def initialize(script_interpreter : LibCairo::PScriptInterpreterT) 10 | raise ArgumentError.new("'script_interpreter' cannot be null.") unless script_interpreter.null? 11 | @script_interpreter = script_interpreter 12 | end 13 | 14 | def initialize 15 | @script_interpreter = LibCairo.script_interpreter_create 16 | end 17 | 18 | def finalize 19 | LibCairo.script_interpreter_destroy(@script_interpreter) 20 | end 21 | 22 | def install_hooks(hooks : ScriptInterpreterHooksT) 23 | LibCairo.script_interpreter_install_hooks(@script_interpreter, pointerof(hooks)) 24 | end 25 | 26 | def run(filename : String) : Status 27 | Status.new(LibCairo.script_interpreter_run(@script_interpreter, filename.to_unsafe).value) 28 | end 29 | 30 | def feed_stream(stream : Int32) : Status 31 | Status.new(LibCairo.script_interpreter_feed_stream(@script_interpreter, stream).value) 32 | end 33 | 34 | def feed_string(line : String, len : Int32 = -1) : Status 35 | Status.new(LibCairo.script_interpreter_feed_string(@script_interpreter, line_to_unsafe, len).value) 36 | end 37 | 38 | def line_number : UInt32 39 | LibCairo.script_interpreter_get_line_number 40 | end 41 | 42 | def reference : ScriptInterpreter 43 | ScriptInterpreter.new(script_interpreter_reference(@script_interpreter)) 44 | end 45 | 46 | def finish : Status 47 | Status.new(LibCairo.script_interpreter_finish(@script_interpreter).value) 48 | end 49 | 50 | def self.translate_stream(stream : Int32, write_func : LibCairo::WriteFuncT, closure : Void*) : Status 51 | Status.new(LibCairo.script_interpreter_translate_stream(stream, write_func, closure).value) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /src/cairo/script_mode.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./c/features" 3 | 4 | {% if Cairo::C::HAS_SCRIPT_SURFACE %} 5 | 6 | module Cairo 7 | # A set of script output variants. 8 | enum ScriptMode 9 | # The output will be in readable text (default). 10 | Ascii 11 | 12 | # The output will use byte codes. 13 | Binary 14 | end 15 | end 16 | 17 | {% end %} 18 | -------------------------------------------------------------------------------- /src/cairo/status.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Cairo uses a single status type to represent all kinds of errors. A status value of `Success` represents no error and has an integer 7 | # value of zero. All other status values represent an error. 8 | # 9 | # Cairo's error handling is designed to be easy to use and safe. All major cairo objects retain an error status internally 10 | # which can be queried anytime by the users using `status` calls. In the mean time, 11 | # it is safe to call all cairo functions normally even if the underlying object is in an error status. 12 | # This means that no error handling code is required before or after each individual cairo function call. 13 | # 14 | # 15 | # `Status` is used to indicate errors that can occur when using `Context`. In some cases it is returned directly by functions. 16 | # But when using `Context`, the last error, if any, is stored in the context and can be retrieved with `Context#status`. 17 | # 18 | # New entries may be added in future versions. Use `Status#to_string` to get a human-readable representation of an error message. 19 | enum Status 20 | # No error has occurred. 21 | Success = 0 22 | 23 | # Out of memory. 24 | NoMemory 25 | 26 | # `Context#restore` called without matching `Context#save`. 27 | InvalidRestore 28 | 29 | # No saved group to pop, i.e. `Context#pop_group` without matching `Context#push_group`. 30 | InvalidPopGroup 31 | 32 | # No current point defined. 33 | NoCurrentPoint 34 | 35 | # Invalid matrix (not invertible). 36 | InvalidMatrix 37 | 38 | # Invalid value for an input `Status`. 39 | InvalidStatus 40 | 41 | # NULL pointer. 42 | NullPointer 43 | 44 | # Input string not valid UTF-8. 45 | InvalidString 46 | 47 | # Input path data not valid. 48 | InvalidPathData 49 | 50 | # Error while reading from input stream. 51 | ReadError 52 | 53 | # Error while writing to output stream. 54 | WriteError 55 | 56 | # Target surface has been finished. 57 | SurfaceFinished 58 | 59 | # The surface type is not appropriate for the operation. 60 | SurfaceTypeMismatch 61 | 62 | # The pattern type is not appropriate for the operation. 63 | PatternTypeMismatch 64 | 65 | # Invalid value for an input `Content`. 66 | InvalidContent 67 | 68 | # Invalid value for an input `Format`. 69 | InvalidFormat 70 | 71 | # Invalid value for an input `Visual`. 72 | InvalidVisual 73 | 74 | # File not found. 75 | FileNotFound 76 | 77 | # Invalid value for a dash setting. 78 | InvalidDash 79 | 80 | # Invalid value for a DSC comment. 81 | InvalidDscComment 82 | 83 | # Invalid index passed to getter. 84 | InvalidIndex 85 | 86 | # Clip region not representable in desired format. 87 | ClipNotRepresentable 88 | 89 | # Error creating or writing to a temporary file. 90 | TempFileRrror 91 | 92 | # Invalid value for stride. 93 | InvalidStride 94 | 95 | # The font type is not appropriate for the operation. 96 | FontTypeMismatch 97 | 98 | # The user-font is immutable. 99 | UserFontImmutable 100 | 101 | # Error occurred in a user-font callback function. 102 | UserFontError 103 | 104 | # Negative number used where it is not allowed. 105 | NegativeCount 106 | 107 | # Input clusters do not represent the accompanying text and glyph array. 108 | InvalidClusters 109 | 110 | # Invalid value for an input `FontSlant`. 111 | InvalidSlant 112 | 113 | # Invalid value for an input `FontWeight`. 114 | InvalidWeight 115 | 116 | # Invalid value (typically too big) for the size of the input (surface, pattern, etc.). 117 | InvalidSize 118 | 119 | # User-font method not implemented. 120 | UserFontNotImplemented 121 | 122 | # The device type is not appropriate for the operation. 123 | DeviceTypeMismatch 124 | 125 | # An operation to the device caused an unspecified error. 126 | DeviceError 127 | 128 | # A mesh pattern construction operation was used outside of a 129 | # `Pattern#begin_patch`/`Pattern#end_patch` pair. 130 | InvalidMeshConstruction 131 | 132 | # Target device has been finished. 133 | DeviceFinished 134 | 135 | # `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL_ID` has been used on at least one image but no image provided `Cairo::C::LibCairo::MIME_TYPE_JBIG2_GLOBAL`. 136 | Jbig2GlobalMissing 137 | 138 | # Error occurred in libpng while reading from or writing to a PNG file. 139 | PngError 140 | 141 | # Error occurred in libfreetype. 142 | FreeTypeError 143 | 144 | # Error occurred in the Windows Graphics Device Interface. 145 | Win32GdiError 146 | 147 | # Invalid tag name, attributes, or nesting. 148 | TagError 149 | 150 | # This is a special value indicating the number of status values defined in this enumeration. 151 | # When using this value, NOTE that the version of cairo at run-time may have additional status values defined 152 | # than the value of this symbol at compile-time. 153 | LastStatus 154 | 155 | # Provides a human-readable description. 156 | def to_string : String 157 | String.new(LibCairo.status_to_string(LibCairo::StatusT.new(self))) 158 | end 159 | end 160 | end 161 | -------------------------------------------------------------------------------- /src/cairo/status_exception.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | class StatusException < Exception 3 | getter status : Status 4 | 5 | def initialize(@status : Status, message : String? = nil, cause : Exception? = nil) 6 | super(message, cause) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/cairo/subpixel_order.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # The subpixel order specifies the order of color elements within each 3 | # pixel on the display device when rendering with an antialiasing mode of `Antialias::Subpixel`. 4 | enum SubpixelOrder 5 | # Use the default subpixel order for for the target device. 6 | Default 7 | 8 | # Subpixel elements are arranged horizontally with red at the left. 9 | RGB 10 | 11 | # Subpixel elements are arranged horizontally with blue at the left. 12 | BGR 13 | 14 | # Subpixel elements are arranged vertically with red at the top. 15 | VRGB 16 | 17 | # Subpixel elements are arranged vertically with blue at the top. 18 | VBGR 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /src/cairo/surface_observer_mode.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | enum SurfaceObserverMode 3 | Normal = 0 4 | RecordOperations = 0x1 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /src/cairo/surface_type.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # `SurfaceType` is used to describe the type of a given surface. 3 | # The surface types are also known as "backends" or "surface backends" within cairo. 4 | # 5 | # The type of a surface is determined by the function used to create it, 6 | # which will generally be of the form `Surface#initialize`, (though see `Surface#create_similar` as well). 7 | # 8 | # The surface type can be queried with `Surface#type`. 9 | # 10 | # The various `Surface` functions can be used with surfaces of any type, 11 | # but some backends also provide type-specific functions that must only 12 | # be called with a surface of the appropriate type. These functions have names 13 | # that begin with cairo_type_surface such as `Surface#width`. 14 | # 15 | # The behavior of calling a type-specific function with a surface of the wrong type is undefined. 16 | # 17 | # New entries may be added in future versions. 18 | enum SurfaceType 19 | # The surface is of type image. 20 | Image 21 | 22 | # The surface is of type pdf. 23 | Pdf 24 | 25 | # The surface is of type ps. 26 | Ps 27 | 28 | # The surface is of type xlib. 29 | XLib 30 | 31 | # The surface is of type xcb. 32 | Xcb 33 | 34 | # The surface is of type glitz. 35 | Glitz 36 | 37 | # The surface is of type quartz. 38 | Quartz 39 | 40 | # The surface is of type win32. 41 | Win32 42 | 43 | # The surface is of type beos. 44 | BeOS 45 | 46 | # The surface is of type directfb. 47 | DirectFB 48 | 49 | # The surface is of type svg. 50 | Svg 51 | 52 | # The surface is of type os2. 53 | OS2 54 | 55 | # The surface is a win32 printing surface. 56 | Win32Printing 57 | 58 | # The surface is of type quartz_image. 59 | QuartzImage 60 | 61 | # The surface is of type scrip. 62 | Script 63 | 64 | # The surface is of type Qt. 65 | Qt 66 | 67 | # The surface is of type recording. 68 | Recording 69 | 70 | # The surface is a OpenVG surface. 71 | VG 72 | 73 | # The surface is of type OpenGL. 74 | GL 75 | 76 | # The surface is of type Direct Render Manager. 77 | DRM 78 | 79 | # The surface is of type 'tee' (a multiplexing surface). 80 | Tee 81 | 82 | # The surface is of type XML (for debugging). 83 | XML 84 | 85 | # The surface is of type Skia. 86 | Skia 87 | 88 | # The surface is a subsurface created with `Surface#create_for_rectangle`. 89 | Subsurface 90 | 91 | # This surface is of type Cogl. 92 | COGL 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /src/cairo/svg_surface.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | require "./svg_unit" 4 | require "./svg_version" 5 | 6 | {% if Cairo::C::HAS_SVG_SURFACE %} 7 | 8 | module Cairo 9 | include Cairo::C 10 | 11 | # The SVG surface is used to render cairo graphics to SVG files and is a 12 | # multi-page vector surface backend. 13 | class SvgSurface < Surface 14 | # Creates a SVG surface of the specified size in 15 | # points to be written to *filename*. 16 | # 17 | # The SVG surface backend recognizes the following MIME types for the data 18 | # attached to a surface (see `Surface#set_mime_data`) when it is used as a 19 | # source pattern for drawing on this surface: 20 | # - `Cairo::C::LibCairo::MIME_TYPE_JPEG`, 21 | # - `Cairo::C::LibCairo::MIME_TYPE_PNG`, 22 | # - `Cairo::C::LibCairo::MIME_TYPE_URI`. 23 | # If any of them is specified, the SVG backend emits a href with the content 24 | # of MIME data instead of a surface snapshot (PNG, Base64-encoded) 25 | # in the corresponding image tag. 26 | # 27 | # The unofficial MIME type `Cairo::C::LibCairo::MIME_TYPE_URI` is examined 28 | # first. If present, the URI is emitted as is: assuring the correctness of 29 | # URI is left to the client code. 30 | # 31 | # If `Cairo::C::LibCairo::MIME_TYPE_URI` is not present, 32 | # but `Cairo::C::LibCairo::MIME_TYPE_JPEG` or 33 | # `Cairo::C::LibCairo::MIME_TYPE_PNG` is specified, 34 | # the corresponding data is Base64-encoded and emitted. 35 | # 36 | # If `Cairo::C::LibCairo::MIME_TYPE_UNIQUE_ID` is present, all surfaces 37 | # with the same unique identifier will only be embedded once. 38 | # 39 | # ###Parameters 40 | # - **filename** a filename for the SVG output (must be writable), 41 | # `nil` may be used to specify no output. This will generate a SVG surface 42 | # that may be queried and used as a source, without generating a temporary file. 43 | # - **width_in_points** width of the surface, in points (1 point == 1/72.0 inch) 44 | # - **height_in_points** height of the surface, in points (1 point == 1/72.0 inch) 45 | # 46 | # ###Returns 47 | # A pointer to the newly created surface. The caller owns the surface and 48 | # should call `Surface#finalize` when done with it. 49 | # 50 | # This function always returns a valid pointer, but it will return a pointer 51 | # to a `nil` surface if an error such as out of memory occurs. 52 | # You can use `Surface#status` to check for this. 53 | def initialize(filename : String, width_in_points : Float64, height_in_points : Float64) 54 | super(LibCairo.svg_surface_create(filename.to_unsafe, width_in_points, height_in_points)) 55 | end 56 | 57 | # Creates a SVG surface of the specified size in points to be written 58 | # incrementally to the stream represented by write_func and closure . 59 | # 60 | # ###Parameters 61 | # - **write_func** a `Cairo::C::LibCairo::WriteFuncT` to accept the output 62 | # data, may be `nil` to indicate a no-op *write_func*. 63 | # With a no-op *write_func*, the surface may be queried or used as a source 64 | # without generating any temporary files. 65 | # - **closure** the closure argument for *write_func* 66 | # - **width_in_points** width of the surface, in points (1 point == 1/72.0 inch) 67 | # - **height_in_points** height of the surface, in points (1 point == 1/72.0 inch) 68 | # 69 | # ###Returns 70 | # A pointer to the newly created surface. The caller owns the surface and 71 | # should call `Surface#finalize` when done with it. 72 | # 73 | # This function always returns a valid pointer, but it will return a pointer 74 | # to a `nil` surface if an error such as out of memory occurs. 75 | # You can use Surface#status` to check for this. 76 | def initialize(write_func : LibCairo::WriteFuncT, closure : Void*, width_in_points : Float64, height_in_points : Float64) 77 | super(LibCairo.svg_surface_create_for_stream(write_func, closure, width_in_points, height_in_points)) 78 | end 79 | 80 | # Get the unit of the SVG surface. 81 | # 82 | # If the surface passed as an argument is not a SVG surface, 83 | # the function sets the error status to 84 | # `Status::SurfaceTypeMismatch` and returns `SvgUnit::User`. 85 | # 86 | # ###Returns 87 | # The SVG unit of the SVG surface. 88 | def document_unit : SvgUnit 89 | SvgUnit.new(LibCairo.svg_surface_get_document_unit(to_unsafe).value) 90 | end 91 | 92 | # Use the specified unit for the width and height of the generated SVG file. 93 | # See `SvgUnit` for a list of available unit values that can be used here. 94 | # 95 | # This function can be called at any time before generating the SVG file. 96 | # 97 | # However to minimize the risk of ambiguities it's recommended to call it 98 | # before any drawing operations have been performed on the given surface, 99 | # to make it clearer what the unit used in the drawing operations is. 100 | # 101 | # The simplest way to do this is to call this function immediately after 102 | # creating the SVG surface. 103 | # 104 | # NOTE: if this function is never called, the default unit for SVG documents 105 | # generated by cairo will be "pt". This is for historical reasons. 106 | # 107 | # ###Parameters 108 | # - **unit** SVG unit 109 | def ducument_unit=(unit : SvgUnit) 110 | LibCairo.svg_surface_set_document_unit(to_unsafe, LibCairo::SvgUnitT.new(unit.value)) 111 | self 112 | end 113 | 114 | # Restricts the generated SVG file to version. 115 | # See `SvgSurface#versions` for a list of available version 116 | # values that can be used here. 117 | # 118 | # This function should only be called before any drawing operations have 119 | # been performed on the given surface. The simplest way to do this is to 120 | # call this function immediately after creating the surface. 121 | # 122 | # ###Parameters 123 | # - **version** SVG version 124 | def restrict_to_version(version : SvgVersion) 125 | LibCairo.svg_surface_restrict_to_version(to_unsafe, LibCairo::SvgVersionT.new(version.value)) 126 | self 127 | end 128 | 129 | # Used to retrieve the list of supported versions. 130 | # See `SvgSurface#restrict_to_version`. 131 | # 132 | # ###Returns 133 | # The supported version list. 134 | def self.versions : Array(SvgVersion) 135 | LibCairo.svg_get_versions(out version, out num_versions) 136 | return [] of SvgVersion if num_versions == 0 137 | Array(SvgVersion).new(num_versions) do |i| 138 | SvgVersion.new(version[i].value) 139 | end 140 | end 141 | end 142 | end 143 | 144 | {% end %} 145 | -------------------------------------------------------------------------------- /src/cairo/svg_unit.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | 4 | {% if Cairo::C::HAS_SVG_SURFACE %} 5 | 6 | module Cairo 7 | include Cairo::C 8 | 9 | # `SvgUnit` used to describe the units valid for coordinates and 10 | # lengths in the SVG specification. 11 | # 12 | # ###See also 13 | # - [https://www.w3.org/TR/SVG/coords.html#Units](https://www.w3.org/TR/SVG/coords.html#Units) 14 | # - [https://www.w3.org/TR/SVG/types.html#DataTypeLength](https://www.w3.org/TR/SVG/types.html#DataTypeLength) 15 | # - [https://www.w3.org/TR/css-values-3/#lengths](https://www.w3.org/TR/css-values-3/#lengths) 16 | enum SvgUnit 17 | # User unit, a value in the current coordinate system. 18 | # If used in the root element for the initial coordinate systems it 19 | # corresponds to pixels. 20 | User = 0 21 | 22 | # The size of the element's font. 23 | Em 24 | 25 | # The x-height of the element’s font. 26 | Ex 27 | 28 | # Pixels (1px = 1/96th of 1in). 29 | Px 30 | 31 | # Inches (1in = 2.54cm = 96px). 32 | In 33 | 34 | # Centimeters (1cm = 96px/2.54). 35 | Cm 36 | 37 | # Millimeters (1mm = 1/10th of 1cm). 38 | Mm 39 | 40 | # Points (1pt = 1/72th of 1in). 41 | Pt 42 | 43 | # Picas (1pc = 1/6th of 1in). 44 | Pc 45 | 46 | # Percent, a value that is some fraction of another reference value. 47 | Percent 48 | end 49 | end 50 | 51 | {% end %} 52 | -------------------------------------------------------------------------------- /src/cairo/svg_version.cr: -------------------------------------------------------------------------------- 1 | require "./c/features" 2 | require "./c/lib_cairo" 3 | 4 | {% if Cairo::C::HAS_SVG_SURFACE %} 5 | 6 | module Cairo 7 | include Cairo::C 8 | 9 | # `SvgVersion` is used to describe the version number of the 10 | # SVG specification that a generated SVG file will conform to. 11 | enum SvgVersion 12 | # The version 1.1 of the SVG specification. 13 | V_1_1 14 | 15 | # The version 1.2 of the SVG specification. 16 | V_1_2 17 | 18 | # Get the string representation of the given version id. 19 | # This function will return `nil` if version isn't valid. 20 | # See `SvgSurface#versions` for a way to get the list of valid version ids. 21 | # 22 | # ###Returns 23 | # The string associated to given version. 24 | def to_string : String 25 | String.new(LibCairo.svg_version_to_string(LibCairo::SvgVersionT.new(self.value))) 26 | end 27 | end 28 | end 29 | 30 | {% end %} 31 | -------------------------------------------------------------------------------- /src/cairo/tee_surface.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./c/features" 3 | 4 | {% if Cairo::C::HAS_TEE_SURFACE %} 5 | 6 | module Cairo 7 | include Cairo::C 8 | 9 | class TeeSurface < Surface 10 | def tee_surface_create(master : Surface) 11 | super(LibCairo.tee_surface_create(master.to_unsafe)) 12 | end 13 | 14 | def add(target : Surface) 15 | LibCairo.tee_surface_add(to_unsafe, target.to_unsafe) 16 | self 17 | end 18 | 19 | def remove(target : Surface) 20 | LibCairo.tee_surface_remove(to_unsafe, target.to_unsafe) 21 | self 22 | end 23 | 24 | def index(index : UInt32) : Surface 25 | Surface.new(LibCairo.tee_surface_index(to_unsafe, index)) 26 | end 27 | end 28 | end 29 | 30 | {% end %} 31 | -------------------------------------------------------------------------------- /src/cairo/text_cluster.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # Wrapper for LibCairo::TextClusterT. 7 | # 8 | # The `TextCluster` class holds information about a single *text cluster*. 9 | # A text cluster is a minimal mapping of some glyphs corresponding to some UTF-8 text. 10 | # 11 | # For a cluster to be valid, both *num_bytes* and *num_glyphs* should be non-negative, 12 | # and at least one should be non-zero. Note that clusters with zero glyphs are not as 13 | # well supported as normal clusters. For example, PDF rendering applications typically 14 | # ignore those clusters when PDF text is being selected. 15 | # 16 | # See `Context#show_text_glyphs` for how clusters are used in advanced text operations. 17 | struct TextCluster 18 | def initialize 19 | @cluster = uninitialized LibCairo::TextClusterT 20 | @cluster.num_bytes = 0 21 | @cluster.num_glyphs = 0 22 | end 23 | 24 | def initialize(num_bytes : Int32, num_glyphs : Int32) 25 | @cluster = uninitialized LibCairo::TextClusterT 26 | @cluster.num_bytes = num_bytes 27 | @cluster.num_glyphs = num_glyphs 28 | end 29 | 30 | def initialize(@cluster : LibCairo::TextClusterT) 31 | end 32 | 33 | def initialize(cluster : LibCairo::PTextClusterT) 34 | raise ArgumentError.new("'cluster' cannot be null.") if cluster.null? 35 | @cluster = cluster.value 36 | end 37 | 38 | # The number of bytes of UTF-8 text covered by cluster. 39 | def num_bytes : Int32 40 | @cluster.num_bytes 41 | end 42 | 43 | def num_bytes=(num_bytes : Int32) 44 | @cluster.num_bytes = num_bytes 45 | end 46 | 47 | # The number of glyphs covered by cluster. 48 | def num_glyphs : Int32 49 | @cluster.num_glyphs 50 | end 51 | 52 | def num_glyphs=(num_glyphs : Int32) 53 | @cluster.num_glyphs = num_glyphs 54 | end 55 | 56 | def to_cairo_cluster : LibCairo::TextClusterT 57 | @cluster 58 | end 59 | 60 | def to_unsafe : LibCairo::PTextClusterT 61 | pointerof(@cluster) 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /src/cairo/text_cluster_array.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./text_cluster" 3 | 4 | module Cairo 5 | include Cairo::C 6 | 7 | class TextClusterArray 8 | include Indexable(TextCluster) 9 | 10 | def initialize(num_clusters : Int) 11 | @clusters = LibCairo.text_cluster_allocate(num_clusters) 12 | raise "Can't allocate clusters." if @clusters.null? 13 | @num_clusters = num_clusters 14 | end 15 | 16 | def initialize(clusters : LibCairo::PTextClusterT, num_clusters : Int32) 17 | raise ArgumentError.new("'clusters' cannot be null.") if clusters.null? 18 | raise ArgumentError.new("'num_clusters' must be positive.") unless num_clusters > 0 19 | 20 | @clusters = clusters 21 | @num_clusters = num_clusters 22 | end 23 | 24 | def finalize 25 | LibCairo.text_cluster_free(@clusters) 26 | @num_clusters = 0 27 | end 28 | 29 | # :inherit: 30 | def size 31 | @num_clusters 32 | end 33 | 34 | # :inherit: 35 | def unsafe_fetch(index : Int) 36 | (@clusters + index).value 37 | end 38 | 39 | def []=(index : Int, cluster : TextCluster) 40 | check_index_out_of_bounds index 41 | (@clusters + index).value = cluster.to_unsafe.value 42 | end 43 | 44 | def to_unsafe : LibCairo::PTextClusterT 45 | @clusters 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /src/cairo/text_cluster_flags.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Specifies properties of a text cluster mapping. 3 | enum TextClusterFlags 4 | # The clusters in the cluster array map to glyphs in the glyph array from end to start. 5 | Backward = 0x00000001 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/cairo/text_extents.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # The `TextExtents` structure stores the extents of a single glyph or a string of glyphs in user-space coordinates. 7 | # Because text extents are in user-space coordinates, they are mostly, but not entirely, 8 | # independent of the current transformation matrix. If you call `context.scale(2.0, 2.0)`, 9 | # text will be drawn twice as big, but the reported text extents will not be doubled. 10 | # They will change slightly due to hinting (so you can't assume that metrics are independent of the transformation matrix), 11 | # but otherwise will remain unchanged. 12 | class TextExtents 13 | def initialize 14 | @text_extents = LibCairo::TextExtentsT.new 15 | end 16 | 17 | def initialize(x_bearing : Float64, y_bearing : Float64, 18 | width : Float64, height : Float64, 19 | x_advance : Float64, y_advance : Float64) 20 | @text_extents = LibCairo::TextExtentsT.new 21 | @text_extents.x_bearing = x_bearing 22 | @text_extents.y_bearing = y_bearing 23 | @text_extents.width = width 24 | @text_extents.height = height 25 | @text_extents.x_advance = x_advance 26 | @text_extents.y_advance = y_advance 27 | end 28 | 29 | def initialize(@text_extents : LibCairo::TextExtentsT) 30 | end 31 | 32 | # The horizontal distance from the origin to the leftmost part of the glyphs as drawn. 33 | # Positive if the glyphs lie entirely to the right of the origin. 34 | @[AlwaysInline] 35 | def x_bearing : Float64 36 | @text_extents.x_bearing 37 | end 38 | 39 | @[AlwaysInline] 40 | def x_bearing=(x_bearing : Float64) 41 | @text_extents.x_bearing = x_bearing 42 | end 43 | 44 | # The vertical distance from the origin to the topmost part of the glyphs as drawn. 45 | # Positive only if the glyphs lie completely below the origin; will usually be negative. 46 | @[AlwaysInline] 47 | def y_bearing : Float64 48 | @text_extents.y_bearing 49 | end 50 | 51 | @[AlwaysInline] 52 | def y_bearing=(y_bearing : Float64) 53 | @text_extents.y_bearing = y_bearing 54 | end 55 | 56 | # Width of the glyphs as drawn. 57 | @[AlwaysInline] 58 | def width : Float64 59 | @text_extents.width 60 | end 61 | 62 | @[AlwaysInline] 63 | def width=(width : Float64) 64 | @text_extents.width = width 65 | end 66 | 67 | # Height of the glyphs as drawn. 68 | @[AlwaysInline] 69 | def height : Float64 70 | @text_extents.height 71 | end 72 | 73 | @[AlwaysInline] 74 | def height=(height : Float64) 75 | @text_extents.height = height 76 | end 77 | 78 | # Distance to advance in the X direction after drawing these glyphs. 79 | @[AlwaysInline] 80 | def x_advance : Float64 81 | @text_extents.x_advance 82 | end 83 | 84 | @[AlwaysInline] 85 | def x_advance=(x_advance : Float64) 86 | @text_extents.x_advance = x_advance 87 | end 88 | 89 | # Distance to advance in the Y direction after drawing these glyphs. 90 | # 91 | # Will typically be zero except for vertical text layout as found in East-Asian languages. 92 | @[AlwaysInline] 93 | def y_advance : Float64 94 | @text_extents.y_advance 95 | end 96 | 97 | @[AlwaysInline] 98 | def y_advance=(y_advance : Float64) 99 | @text_extents.y_advance = y_advance 100 | end 101 | 102 | def to_cairo_text_extents : LibCairo::TextExtentsT 103 | @text_extents 104 | end 105 | 106 | def to_unsafe : LibCairo::PTextExtentsT 107 | pointerof(@text_extents) 108 | end 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /src/cairo/user_data_key.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | 3 | module Cairo 4 | include Cairo::C 5 | 6 | # `UserDataKey` is used for attaching user data to cairo data structures. 7 | # The actual contents of the struct is never used, and there is no need 8 | # to initialize the object; only the unique address of a `UserDataKey` object 9 | # is used. Typically, you would just use the address of a static `UserDataKey` object. 10 | class UserDataKey 11 | def initialize 12 | @key = LibCairo::UserDataKeyT.new 13 | end 14 | 15 | def initialize(unused : Int32) 16 | @key = LibCairo::UserDataKeyT.new 17 | @key.unused = unused 18 | end 19 | 20 | def initialize(@key : LibCairo::UserDataKeyT) 21 | end 22 | 23 | # Not used. 24 | def unused : Int32 25 | @key.unused 26 | end 27 | 28 | def unused=(unused : Int32) 29 | @key.unused = unused 30 | end 31 | 32 | # Returns the underlieing structure. 33 | def user_data_key : LibCairo::UserDataKeyT 34 | @key 35 | end 36 | 37 | # Returns the pointer of the underlieing structure. 38 | def to_unsafe : LibCairo::PUserDataKeyT 39 | pointerof(@key) 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/cairo/version.cr: -------------------------------------------------------------------------------- 1 | module Cairo 2 | # Version of **cairo-cr** package. 3 | VERSION = "1.0.0" 4 | 5 | CAIRO_VERSION_MAJOR = 1 6 | CAIRO_VERSION_MINOR = 17 7 | CAIRO_VERSION_MICRO = 4 8 | end 9 | -------------------------------------------------------------------------------- /src/cairo/xlib_surface.cr: -------------------------------------------------------------------------------- 1 | require "./c/lib_cairo" 2 | require "./c/features" 3 | require "./c/xlib" 4 | 5 | {% if Cairo::C::HAS_XLIB_SURFACE %} 6 | 7 | require "x11" 8 | 9 | module Cairo 10 | include X11 11 | include Cairo::C 12 | 13 | # The Xlib surface is used to render cairo graphics to 14 | # X Window System windows and pixmaps using the XLib library. 15 | # 16 | # NOTE: that the XLib surface automatically takes advantage 17 | # of X render extension if it is available. 18 | class XlibSurface < Surface 19 | # Creates an Xlib surface that draws to the given drawable. The way that 20 | # colors are represented in the drawable is specified by the provided visual. 21 | # 22 | # NOTE: If drawable is a Window, then the function `XlibSurface#set_size` 23 | # must be called whenever the size of the window changes. 24 | # 25 | # When drawable is a Window containing child windows then drawing to the 26 | # created surface will be clipped by those child windows. When the created 27 | # surface is used as a source, the contents of the children will be included. 28 | # 29 | # ###Parameters 30 | # - **dpy** an X Display 31 | # - **drawable** an X Drawable, (a `Pixmap` or a `Window`) 32 | # - **visual** the visual to use for drawing to *drawable*. 33 | # The depth of the visual must match the depth of the drawable. 34 | # Currently, only TrueColor visuals are fully supported. 35 | # - **width** the current width of *drawable*. 36 | # - **height** the current height of *drawable*. 37 | # 38 | # ###Returns 39 | # The newly created surface. 40 | def initialize(dpy : Display, drawable : Drawable, visual : Visual, width : Int32, height : Int32) 41 | super(LibCairo.xlib_surface_create(dpy.to_unsafe, drawable, visual.to_unsafe, width, height)) 42 | end 43 | 44 | # Creates an Xlib surface that draws to the given bitmap. 45 | # This will be drawn to as a `Format::A1` object. 46 | # 47 | # ###Parameters 48 | # - **dpy** an X Display 49 | # - **bitmap** an X Drawable, (a depth-1 `Pixmap`) 50 | # - **screen** the X Screen associated with bitmap 51 | # - **width** the current width of *bitmap*. 52 | # - **height** the current height of *bitmap*. 53 | # 54 | # ###Returns 55 | # The newly created surface. 56 | def initialize(dpy : Display, bitmap : Pixmap, screen : Screen, width : Int32, height : Int32) 57 | super(LibCairo.xlib_surface_create_for_bitmap(dpy.to_unsafe, bitmap, screen.to_unsafe, width, height)) 58 | end 59 | 60 | # Informs cairo of the new size of the X Drawable underlying the surface. 61 | # For a surface created for a Window (rather than a `Pixmap`), 62 | # this function must be called each time the size of the window changes. 63 | # (For a subwindow, you are normally resizing the window yourself, but for 64 | # a toplevel window, it is necessary to listen for ConfigureNotify events.) 65 | # 66 | # A `Pixmap` can never change size, so it is never necessary to call this 67 | # function on a surface created for a `Pixmap`. 68 | # 69 | # ###Parameters 70 | # - **width** the new width of the surface 71 | # - **height** the new height of the surface 72 | def set_size(width : Int32, height : Int32) 73 | LibCairo.xlib_surface_set_size(to_unsafe, width, height) 74 | self 75 | end 76 | 77 | # Informs cairo of a new X Drawable underlying the surface. 78 | # The drawable must match the display, screen and format of the existing 79 | # drawable or the application will get X protocol errors and will probably 80 | # terminate. No checks are done by this function to ensure this compatibility. 81 | # 82 | # ###Parameters 83 | # - **drawable** the new drawable for the surface 84 | # - **width** the width of the new drawable 85 | # - **height** the height of the new drawable 86 | def set_drawable(drawable : Drawable, width : Int32, height : Int32) 87 | LibCairo.xlib_surface_set_drawable(to_unsafe, drawable, width, height) 88 | self 89 | end 90 | 91 | # Get the X Display for the underlying X Drawable. 92 | # 93 | # ###Returns 94 | # The display. 95 | def display : Display 96 | Display.new(LibCairo.xlib_surface_get_display(to_unsafe)) 97 | end 98 | 99 | # Get the underlying X Drawable used for the surface. 100 | # 101 | # ###Returns 102 | # The drawable. 103 | def drawable : Drawable 104 | LibCairo.xlib_surface_get_drawable(to_unsafe) 105 | end 106 | 107 | # Get the X Screen for the underlying X Drawable. 108 | # 109 | # ###Returns 110 | # The screen. 111 | def screen : Screen 112 | Screen.new(LibCairo.xlib_surface_get_screen(to_unsafe)) 113 | end 114 | 115 | # Gets the X Visual associated with *surface*, suitable for use with 116 | # the underlying X Drawable. If *surface* was created by 117 | # `XlibSurface#initialize`, the return value is the Visual passed 118 | # to that constructor. 119 | # 120 | # ###Returns 121 | # The Visual or `nil` if there is no appropriate Visual for *surface*. 122 | def visual : Visual 123 | Visual.new(LibCairo.xlib_surface_get_visual(to_unsafe)) 124 | end 125 | 126 | # Get the number of bits used to represent each pixel value. 127 | # 128 | # ###Returns 129 | # The depth of the surface in bits. 130 | def depth : Int32 131 | LibCairo.xlib_surface_get_depth(to_unsafe) 132 | end 133 | 134 | # Get the width of the X Drawable underlying the surface in pixels. 135 | # 136 | # ###Returns 137 | # The width of the surface in pixels. 138 | def width : Int32 139 | LibCairo.xlib_surface_get_width(to_unsafe) 140 | end 141 | 142 | # Get the height of the X Drawable underlying the surface in pixels. 143 | # 144 | # ###Returns 145 | # The height of the surface in pixels. 146 | def height : Int32 147 | LibCairo.xlib_surface_get_height(to_unsafe) 148 | end 149 | end 150 | end 151 | 152 | {% end %} 153 | --------------------------------------------------------------------------------