├── .codecov.yml ├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ └── test.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── DrawBot.py ├── README.md ├── Resources ├── English.lproj │ ├── Credits.rtf │ ├── DrawBot.icns │ ├── MainMenu.nib │ │ ├── designable.nib │ │ └── keyedobjects.nib │ ├── drawbotPackageIcon.icns │ ├── pythonIcon.icns │ ├── toolbarComment.pdf │ ├── toolbarDedent.pdf │ ├── toolbarIndent.pdf │ ├── toolbarRun.pdf │ └── toolbarUncomment.pdf ├── Images │ ├── icon_left_0.png │ ├── icon_left_1.png │ ├── icon_left_10.png │ ├── icon_left_11.png │ ├── icon_left_12.png │ ├── icon_left_13.png │ ├── icon_left_14.png │ ├── icon_left_15.png │ ├── icon_left_16.png │ ├── icon_left_17.png │ ├── icon_left_18.png │ ├── icon_left_19.png │ ├── icon_left_2.png │ ├── icon_left_20.png │ ├── icon_left_3.png │ ├── icon_left_4.png │ ├── icon_left_5.png │ ├── icon_left_6.png │ ├── icon_left_7.png │ ├── icon_left_8.png │ ├── icon_left_9.png │ ├── icon_right_0.png │ ├── icon_right_1.png │ ├── icon_right_10.png │ ├── icon_right_11.png │ ├── icon_right_12.png │ ├── icon_right_13.png │ ├── icon_right_14.png │ ├── icon_right_15.png │ ├── icon_right_16.png │ ├── icon_right_17.png │ ├── icon_right_18.png │ ├── icon_right_19.png │ ├── icon_right_2.png │ ├── icon_right_20.png │ ├── icon_right_3.png │ ├── icon_right_4.png │ ├── icon_right_5.png │ ├── icon_right_6.png │ ├── icon_right_7.png │ ├── icon_right_8.png │ └── icon_right_9.png └── externalTools │ ├── ffmpeg │ ├── gifsicle │ ├── mkbitmap │ └── potrace ├── app ├── codesign-app.sh ├── customWheels │ └── README.md ├── ensure_universal_wheels.py ├── entitlements.xml └── extract_changes.py ├── docs ├── Makefile ├── _static │ └── .gitkeep ├── _themes │ └── drawBotTheme │ │ ├── layout.html │ │ ├── relations.html │ │ ├── search.html │ │ ├── searchbox.html │ │ ├── static │ │ ├── drawBot.css_t │ │ ├── drawBotIcon.svg │ │ ├── drawBotURLhandler.js │ │ ├── favicon.ico │ │ ├── favicons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── browserconfig.xml │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon.ico │ │ │ ├── mstile-150x150.png │ │ │ ├── safari-pinned-tab.svg │ │ │ └── site.webmanifest │ │ ├── pygments.css │ │ └── skeleton │ │ │ ├── base.css │ │ │ ├── layout.css │ │ │ └── skeleton.css │ │ └── theme.conf ├── conf.py ├── content │ ├── assets │ │ ├── drawBot.jpg │ │ ├── drawBotApp.png │ │ ├── packageBuilder.png │ │ ├── preferences.png │ │ └── variables.png │ ├── canvas.rst │ ├── canvas │ │ ├── pages.rst │ │ ├── saveImage.rst │ │ └── state.rst │ ├── color.rst │ ├── color │ │ ├── cmykFill.rst │ │ ├── cmykStroke.rst │ │ ├── fill.rst │ │ └── stroke.rst │ ├── courseware.rst │ ├── credits.rst │ ├── download.rst │ ├── drawBotApp.rst │ ├── drawBotApp │ │ ├── codeEditor.rst │ │ ├── drawBotPackage.rst │ │ ├── preferences.rst │ │ └── preview.rst │ ├── drawBotIcon.rst │ ├── history.rst │ ├── image │ │ ├── drawingImages.rst │ │ ├── imageObject.rst │ │ └── imageProperties.rst │ ├── images.rst │ ├── quickReference.rst │ ├── shapes.rst │ ├── shapes │ │ ├── bezierPath.rst │ │ ├── drawingPath.rst │ │ ├── pathProperties.rst │ │ └── primitives.rst │ ├── text.rst │ ├── text │ │ ├── drawingText.rst │ │ ├── formattedString.rst │ │ └── textProperties.rst │ └── variables.rst ├── index.rst └── requirements.txt ├── drawBot ├── __init__.py ├── aliases.py ├── context │ ├── __init__.py │ ├── baseContext.py │ ├── drawBotContext.py │ ├── dummyContext.py │ ├── gifContext.py │ ├── icnsContext.py │ ├── imageContext.py │ ├── imageObjectContext.py │ ├── mp4Context.py │ ├── pdfContext.py │ ├── printContext.py │ ├── svgContext.py │ └── tools │ │ ├── SFNTLayoutTypes.py │ │ ├── __init__.py │ │ ├── drawBotbuiltins.py │ │ ├── gifTools.py │ │ ├── gifsicleLicense │ │ ├── imageObject.py │ │ ├── mp4Tools.py │ │ ├── openType.py │ │ ├── traceImage.py │ │ └── variation.py ├── drawBotDrawingTools.py ├── drawBotPackage.py ├── drawBotPageDrawingTools.py ├── drawBotSettings.py ├── macOSVersion.py ├── misc.py ├── pipInstaller.py ├── scriptTools.py ├── ui │ ├── __init__.py │ ├── codeEditor.py │ ├── debug.py │ ├── drawBotController.py │ ├── drawBotPackageController.py │ ├── drawView.py │ ├── lineNumberRulerView.py │ ├── preferencesController.py │ └── splitView.py └── updater.py ├── examples ├── roundedRect.py └── star.py ├── license.txt ├── requirements.txt ├── ruff.toml ├── scripting ├── generateDrawbotInit.py └── imageObjectCodeExtractor.py ├── setup.py ├── setupApp.py ├── test-requirements.txt └── tests ├── data ├── MutatorSans.ttc ├── MutatorSans.ttf ├── drawBot.bmp ├── drawBot.jpg ├── drawBot.pdf ├── drawBot.png ├── drawBot144.png ├── example_appendGlyphFormattedString.png ├── example_bezierPath.png ├── example_blendMode.png ├── example_clipPath.png ├── example_cmykFill.png ├── example_cmykLinearGradient.png ├── example_cmykRadialGradient.png ├── example_cmykShadow.png ├── example_cmykStroke.png ├── example_colorSpace.png ├── example_drawPath.png ├── example_fill.png ├── example_fontNamedInstance.png ├── example_fontVariations.png ├── example_formattedString.png ├── example_frameDuration.png ├── example_hyphenation.png ├── example_image.png ├── example_imageObject.png ├── example_indent.png ├── example_installFont.png ├── example_language.png ├── example_line.png ├── example_lineCap.png ├── example_lineDash.png ├── example_lineHeight.png ├── example_lineJoin.png ├── example_linearGradient.png ├── example_miterLimit.png ├── example_newDrawing.png ├── example_newPage.png ├── example_opacity.png ├── example_openTypeFeatures.png ├── example_openTypeFeaturesFormattedString.png ├── example_oval.png ├── example_overflowText.png ├── example_pages.png ├── example_pixelColor.png ├── example_polygon.png ├── example_printImage.png ├── example_radialGradient.png ├── example_rect.png ├── example_saveImage.png ├── example_saveImageResolutionExample.png ├── example_savedState.png ├── example_shadow.png ├── example_size.png ├── example_strikethrough.png ├── example_stroke.png ├── example_strokeWidth.png ├── example_tabs.png ├── example_tabsFormattedString.png ├── example_text.png ├── example_textBox.png ├── example_textBoxInPath.png ├── example_textRTL.png ├── example_tracking.png ├── example_underline.png ├── example_url.png ├── example_variablesUI.png ├── expected_appendGlyphWithFontVariations.pdf ├── expected_appendGlyphWithFontVariations.png ├── expected_appendGlyphWithFontVariations.svg ├── expected_appendGlyphWithTracking.pdf ├── expected_appendGlyphWithTracking.png ├── expected_appendGlyphWithTracking.svg ├── expected_booleanOperations.pdf ├── expected_booleanOperations.png ├── expected_booleanOperations.svg ├── expected_booleanOperations2.pdf ├── expected_booleanOperations2.png ├── expected_booleanOperations2.svg ├── expected_centeredTransform.pdf ├── expected_centeredTransform.png ├── expected_centeredTransform.svg ├── expected_centeredTransformBezierPath.pdf ├── expected_centeredTransformBezierPath.png ├── expected_centeredTransformBezierPath.svg ├── expected_cmykFill.pdf ├── expected_cmykFill.png ├── expected_cmykFill.svg ├── expected_cmykLinearGradient.pdf ├── expected_cmykLinearGradient.png ├── expected_cmykLinearGradient.svg ├── expected_cmykRadialGradient.pdf ├── expected_cmykRadialGradient.png ├── expected_cmykRadialGradient.svg ├── expected_dashStroke.pdf ├── expected_dashStroke.png ├── expected_dashStroke.svg ├── expected_fill.pdf ├── expected_fill.png ├── expected_fill.svg ├── expected_fontAttributes.pdf ├── expected_fontAttributes.png ├── expected_fontAttributes.svg ├── expected_fontAttributes.txt ├── expected_fontPath.pdf ├── expected_fontPath.png ├── expected_fontVariations.pdf ├── expected_fontVariations.png ├── expected_fontVariations.svg ├── expected_fontVariations.txt ├── expected_fontVariations2.pdf ├── expected_fontVariations2.png ├── expected_fontVariations2.svg ├── expected_fontVariations2.txt ├── expected_formattedStringURL.svg ├── expected_image.pdf ├── expected_image.png ├── expected_image.svg ├── expected_image2.pdf ├── expected_image2.png ├── expected_image2.svg ├── expected_image3.pdf ├── expected_image3.png ├── expected_image3.svg ├── expected_image4.pdf ├── expected_image4.png ├── expected_image4.svg ├── expected_imageAntiAliasing.png ├── expected_imageFontSubpixelQuantization.png ├── expected_imageHTTP.pdf ├── expected_imageHTTP.png ├── expected_imageHTTP.svg ├── expected_imagePixelColor.pdf ├── expected_imagePixelColor.png ├── expected_imagePixelColor.svg ├── expected_imagePixelColor.txt ├── expected_line.pdf ├── expected_line.png ├── expected_line.svg ├── expected_linearGradient.pdf ├── expected_linearGradient.png ├── expected_linearGradient.svg ├── expected_openTypeFeatures.pdf ├── expected_openTypeFeatures.png ├── expected_openTypeFeatures.svg ├── expected_openTypeFeatures.txt ├── expected_openTypeFeatures2.pdf ├── expected_openTypeFeatures2.png ├── expected_openTypeFeatures2.svg ├── expected_openTypeFeatures2.txt ├── expected_openTypeFeatures_kern.pdf ├── expected_openTypeFeatures_kern.png ├── expected_openTypeFeatures_kern.svg ├── expected_openTypeFeatures_kern.txt ├── expected_oval.pdf ├── expected_oval.png ├── expected_oval.svg ├── expected_path.pdf ├── expected_path.png ├── expected_path.svg ├── expected_pathWithCounter.pdf ├── expected_pathWithCounter.png ├── expected_pathWithCounter.svg ├── expected_polygon.pdf ├── expected_polygon.png ├── expected_polygon.svg ├── expected_radialGradient.pdf ├── expected_radialGradient.png ├── expected_radialGradient.svg ├── expected_rect.pdf ├── expected_rect.png ├── expected_rect.svg ├── expected_removeOverlap.pdf ├── expected_removeOverlap.png ├── expected_removeOverlap.svg ├── expected_save.pdf ├── expected_save.png ├── expected_save.svg ├── expected_save1.pdf ├── expected_save1.png ├── expected_save1.svg ├── expected_savedState.pdf ├── expected_savedState.png ├── expected_savedState.svg ├── expected_savedState1.pdf ├── expected_savedState1.png ├── expected_savedState1.svg ├── expected_shapes.pdf ├── expected_shapes.png ├── expected_shapes.svg ├── expected_svgLinkURL.svg ├── expected_svgMixin.svg ├── expected_svgSaveFallback.svg ├── expected_text.pdf ├── expected_text.png ├── expected_text.svg ├── expected_text2.pdf ├── expected_text2.png ├── expected_text2.svg ├── expected_textBox.pdf ├── expected_textBox.png ├── expected_textBox.svg ├── expected_textBoxLongText.pdf ├── expected_textBoxLongText.png ├── expected_textBoxLongText.svg ├── expected_traceback.pdf ├── expected_traceback.png ├── expected_traceback.svg ├── expected_traceback.txt ├── fontVariations.png └── scriptRunnerTest.py ├── differenceBuilder.py ├── drawBotScripts ├── appendGlyphWithFontVariations.py ├── appendGlyphWithTracking.py ├── booleanOperations.py ├── booleanOperations2.py ├── centeredTransform.py ├── centeredTransformBezierPath.py ├── cmykFill.py ├── cmykLinearGradient.py ├── cmykRadialGradient.py ├── dashStroke.py ├── fill.py ├── fontAttributes.py ├── fontPath.py ├── fontVariations.py ├── fontVariations2.py ├── image.py ├── image2.py ├── image3.py ├── image4.py ├── imageHTTP.py ├── imagePixelColor.py ├── line.py ├── linearGradient.py ├── openTypeFeatures.py ├── openTypeFeatures2.py ├── openTypeFeatures_kern.py ├── oval.py ├── path.py ├── pathWithCounter.py ├── polygon.py ├── radialGradient.py ├── rect.py ├── removeOverlap.py ├── save.py ├── save1.py ├── savedState.py ├── savedState1.py ├── shapes.py ├── text.py ├── text2.py ├── textBox.py ├── textBoxLongText.py └── traceback.py ├── package ├── empty.drawbot │ └── lib │ │ └── main.py ├── missingMainScript.drawbot │ └── info.plist └── simple.drawbot │ ├── info.plist │ └── lib │ └── main.py ├── runAllTests.py ├── testAutomaticallyGeneratedCode.py ├── testExamples.py ├── testExport.py ├── testImageObject.py ├── testMisc.py ├── testPackage.py ├── testScripts.py ├── testSupport.py └── textContextMixin.py /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | parsers: 16 | gcov: 17 | branch_detection: 18 | conditional: yes 19 | loop: yes 20 | method: no 21 | macro: no 22 | 23 | comment: false 24 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [justvanrossum, typemytype] 4 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: DrawBot Test Bench 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | 14 | runs-on: macos-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | 20 | - name: Set up Python 3.12 21 | run: | 22 | curl https://www.python.org/ftp/python/3.12.1/python-3.12.1-macos11.pkg --output pythonInstaller.pkg 23 | sudo installer -pkg pythonInstaller.pkg -target / 24 | # Somehow using plain "python3" gives us the runner's homebrew Python, 25 | # so let's be explicit about the path: 26 | ourpython=/Library/Frameworks/Python.framework/Versions/3.12/bin/python3.12 27 | ls -l $ourpython 28 | $ourpython --version 29 | $ourpython -c "import platform; print('platform:', platform.platform())" 30 | $ourpython -c "import platform; print('macOS version:', platform.mac_ver()[0])" 31 | $ourpython -m venv venv 32 | source venv/bin/activate 33 | python -c "print('venv')" 34 | python -c "import sys; print('\n'.join(sys.path))" 35 | python -c "import platform; print('platform:', platform.platform())" 36 | python -c "import platform; print('macOS version:', platform.mac_ver()[0])" 37 | 38 | - name: Install dependencies 39 | run: | 40 | source venv/bin/activate 41 | pip install -r ./test-requirements.txt 42 | pip install . 43 | pip install codecov 44 | 45 | - name: Run MyPy on public API 46 | run: | 47 | source venv/bin/activate 48 | mypy --follow-imports=skip drawBot/drawBotDrawingTools.py 49 | mypy --follow-imports=skip drawBot/context/baseContext.py 50 | mypy --follow-imports=skip drawBot/context/tools/imageObject.py 51 | 52 | - name: Run tests 53 | run: | 54 | source venv/bin/activate 55 | coverage run ./tests/runAllTests.py 56 | 57 | - name: Storing Test Data Artifacts 58 | if: failure() 59 | uses: actions/upload-artifact@master 60 | with: 61 | name: DrawBot Temp Data Results 62 | path: ./tests/tempTestData 63 | 64 | - name: Building Test Differences 65 | if: failure() 66 | run: | 67 | source venv/bin/activate 68 | python ./tests/differenceBuilder.py ./tests/tempTestData ./tests/differences.pdf 69 | 70 | - name: Storing Test Differences 71 | if: failure() 72 | uses: actions/upload-artifact@master 73 | with: 74 | name: DrawBot Test Differences 75 | path: ./tests/differences.pdf 76 | 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ruff_cache 2 | .venv 3 | .vscode 4 | *.py[cod] 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Packages 10 | *.egg 11 | *.egg-info 12 | dist 13 | build 14 | eggs 15 | parts 16 | bin 17 | var 18 | sdist 19 | develop-eggs 20 | .installed.cfg 21 | 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | 39 | *.sublime-workspace 40 | *.sublime-project 41 | 42 | docs/_build 43 | docs/downloads 44 | local 45 | 46 | *.command 47 | env/* 48 | 49 | # Finder turds 50 | .DS_Store 51 | 52 | # DrawBot tests 53 | tests/temp_data/* # obsolete 54 | tests/tempTestData/* 55 | 56 | # Virtual Environments 57 | /venv*/ 58 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3" 13 | 14 | # Build documentation in the "docs/" directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # Optional but recommended, declare the Python requirements required 19 | # to build your documentation 20 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 21 | python: 22 | install: 23 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /Resources/English.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \margl1440\margr1440\vieww9000\viewh9000\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc 6 | 7 | \f0\fs24 \cf0 DrawBot is written by Just van Rossum and Frederik Berlaen\ 8 | just@letterror.com\ 9 | frederik@typemytype.com\ 10 | \ 11 | http://www.DrawBot.com} -------------------------------------------------------------------------------- /Resources/English.lproj/DrawBot.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/DrawBot.icns -------------------------------------------------------------------------------- /Resources/English.lproj/MainMenu.nib/keyedobjects.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/MainMenu.nib/keyedobjects.nib -------------------------------------------------------------------------------- /Resources/English.lproj/drawbotPackageIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/drawbotPackageIcon.icns -------------------------------------------------------------------------------- /Resources/English.lproj/pythonIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/pythonIcon.icns -------------------------------------------------------------------------------- /Resources/English.lproj/toolbarComment.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/toolbarComment.pdf -------------------------------------------------------------------------------- /Resources/English.lproj/toolbarDedent.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/toolbarDedent.pdf -------------------------------------------------------------------------------- /Resources/English.lproj/toolbarIndent.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/toolbarIndent.pdf -------------------------------------------------------------------------------- /Resources/English.lproj/toolbarRun.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/toolbarRun.pdf -------------------------------------------------------------------------------- /Resources/English.lproj/toolbarUncomment.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/English.lproj/toolbarUncomment.pdf -------------------------------------------------------------------------------- /Resources/Images/icon_left_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_0.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_1.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_10.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_11.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_12.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_13.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_14.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_15.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_16.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_17.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_18.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_19.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_2.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_20.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_3.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_4.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_5.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_6.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_7.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_8.png -------------------------------------------------------------------------------- /Resources/Images/icon_left_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_left_9.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_0.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_1.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_10.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_11.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_12.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_13.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_14.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_15.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_16.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_17.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_18.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_19.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_2.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_20.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_3.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_4.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_5.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_6.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_7.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_8.png -------------------------------------------------------------------------------- /Resources/Images/icon_right_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/Images/icon_right_9.png -------------------------------------------------------------------------------- /Resources/externalTools/ffmpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/externalTools/ffmpeg -------------------------------------------------------------------------------- /Resources/externalTools/gifsicle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/externalTools/gifsicle -------------------------------------------------------------------------------- /Resources/externalTools/mkbitmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/externalTools/mkbitmap -------------------------------------------------------------------------------- /Resources/externalTools/potrace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/Resources/externalTools/potrace -------------------------------------------------------------------------------- /app/codesign-app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # abort on errors 4 | 5 | DEV_ID=$1 6 | APP_PATH=$2 7 | ENTITLEMENTS=$3 8 | 9 | echo "start codesign..." 10 | 11 | # Explicitly codesign all embedded *.so and *.dylib files 12 | find "$APP_PATH" -iname '*.so' -or -iname '*.dylib' | 13 | while read libfile; do 14 | codesign --sign "$DEV_ID" \ 15 | --entitlements "$ENTITLEMENTS" \ 16 | --deep "${libfile}" \ 17 | --force \ 18 | --options runtime; 19 | done; 20 | 21 | 22 | codesign --sign "$DEV_ID" --entitlements "$ENTITLEMENTS" --deep "${APP_PATH}/Contents/Resources/ffmpeg" --force --options runtime 23 | codesign --sign "$DEV_ID" --entitlements "$ENTITLEMENTS" --deep "${APP_PATH}/Contents/Resources/gifsicle" --force --options runtime 24 | codesign --sign "$DEV_ID" --entitlements "$ENTITLEMENTS" --deep "${APP_PATH}/Contents/Resources/mkbitmap" --force --options runtime 25 | codesign --sign "$DEV_ID" --entitlements "$ENTITLEMENTS" --deep "${APP_PATH}/Contents/Resources/potrace" --force --options runtime 26 | 27 | 28 | # Codesign the app 29 | codesign --sign "$DEV_ID" \ 30 | --entitlements "$ENTITLEMENTS" \ 31 | --deep "$APP_PATH" \ 32 | --force \ 33 | --options runtime; 34 | 35 | echo "verify with codesign" 36 | # verify 37 | codesign --verify --verbose=4 "$APP_PATH" 38 | 39 | echo "verify with spctl" 40 | # verify with spctl 41 | spctl --verbose=4 --raw --assess --type execute "$APP_PATH" 42 | 43 | echo "Done codesign" -------------------------------------------------------------------------------- /app/customWheels/README.md: -------------------------------------------------------------------------------- 1 | This folder contains custom wheels, because the ones on PyPI do not qualify or work when codesigning and notarizing the FontGoggles application. 2 | 3 | # lxml 4 | 5 | The official wheel blocks notarizing: 6 | 7 | "The binary uses an SDK older than the 10.9 SDK." 8 | 9 | # uharfbuzz 10 | 11 | Codesigning and notarizing works, validating the code signatures works, yet when uharfbuzz gets imported upon running the application on macOS 10.10 (maybe also others, but not 10.15) it results in an dyld ImportError, claiming that the signature is invalid. If I build uharfbuzz from the source, this does not happen. I have no idea what the difference could be. 12 | 13 | # xattr 14 | 15 | same as uharfbuzz 16 | -------------------------------------------------------------------------------- /app/entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.disable-executable-page-protection 6 | 7 | com.apple.security.cs.disable-library-validation 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/extract_changes.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import re 4 | 5 | 6 | changelogVersionPattern = re.compile(r"## \[(.+)\]") 7 | githubRefPattern = re.compile(r"refs/tags/(.*)") 8 | 9 | 10 | changelogPath = pathlib.Path(__file__).resolve().parent.parent / "CHANGELOG.md" 11 | changelog = changelogPath.read_text("utf-8") 12 | 13 | m = githubRefPattern.match(os.getenv("GITHUB_REF")) 14 | version = m.group(1) 15 | 16 | notes = [] 17 | 18 | collecting = False 19 | for line in changelog.splitlines(): 20 | m = changelogVersionPattern.match(line) 21 | if m is not None: 22 | if collecting: 23 | break 24 | elif m.group(1) == version: 25 | collecting = True 26 | elif collecting: 27 | notes.append(line) 28 | 29 | # print("\n".join(notes).strip().replace("\n", "%0A")) 30 | print("\n".join(notes).strip()) 31 | -------------------------------------------------------------------------------- /docs/_static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_static/.gitkeep -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/relations.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/relations.html -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/search.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% set title = _('Search') %} 3 | {% set script_files = script_files + ['_static/searchtools.js'] %} 4 | {% block extrahead %} 5 | 6 | 7 | 10 | {{ super() }} 11 | {% endblock %} 12 | {% block body %} 13 |

{{ _('Search') }}

14 |
15 | 16 |

17 | {% trans %}Please activate JavaScript to enable the search 18 | functionality.{% endtrans %} 19 |

20 |
21 |

22 | {% trans %}From here you can search these documents. Enter your search 23 | words into the box below and click "search". Note that the search 24 | function will automatically search for all of the words. Pages 25 | containing fewer words won't appear in the result list.{% endtrans %} 26 |

27 | {% if search_performed %} 28 |

{{ _('Search Results') }}

29 | {% if not search_results %} 30 |

{{ _('Your search did not match any results.') }}

31 | {% endif %} 32 | {% endif %} 33 |
34 | {% if search_results %} 35 | 42 | {% endif %} 43 |
44 | {% endblock %} -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/searchbox.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/drawBotURLhandler.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $(".drawbotlink").each(function () { 3 | this.protocol = "drawbot"; 4 | }); 5 | }); -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicon.ico -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2d89ef 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/favicon.ico -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/_themes/drawBotTheme/static/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/favicons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Drawbot Docs", 3 | "short_name": "Drawbot Docs", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/static/skeleton/layout.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.2 3 | * Copyright 2011, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 6/20/2012 8 | */ 9 | 10 | /* Table of Content 11 | ================================================== 12 | #Site Styles 13 | #Page Styles 14 | #Media Queries 15 | #Font-Face */ 16 | 17 | /* #Site Styles 18 | ================================================== */ 19 | 20 | /* #Page Styles 21 | ================================================== */ 22 | 23 | /* #Media Queries 24 | ================================================== */ 25 | 26 | /* Smaller than standard 960 (devices and browsers) */ 27 | @media only screen and (max-width: 959px) {} 28 | 29 | /* Tablet Portrait size to standard 960 (devices and browsers) */ 30 | @media only screen and (min-width: 768px) and (max-width: 959px) {} 31 | 32 | /* All Mobile Sizes (devices and browser) */ 33 | @media only screen and (max-width: 767px) {} 34 | 35 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ 36 | @media only screen and (min-width: 480px) and (max-width: 767px) {} 37 | 38 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ 39 | @media only screen and (max-width: 479px) {} 40 | 41 | 42 | /* #Font-Face 43 | ================================================== */ 44 | /* This is the proper syntax for an @font-face file 45 | Just create a "fonts" folder at the root, 46 | copy your FontName into code below and remove 47 | comment brackets */ 48 | 49 | /* @font-face { 50 | font-family: 'FontName'; 51 | src: url('../fonts/FontName.eot'); 52 | src: url('../fonts/FontName.eot?iefix') format('eot'), 53 | url('../fonts/FontName.woff') format('woff'), 54 | url('../fonts/FontName.ttf') format('truetype'), 55 | url('../fonts/FontName.svg#webfontZam02nTh') format('svg'); 56 | font-weight: normal; 57 | font-style: normal; } 58 | */ -------------------------------------------------------------------------------- /docs/_themes/drawBotTheme/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = drawBot.css 4 | 5 | [options] 6 | rightsidebar = true 7 | stickysidebar = true 8 | collapsiblesidebar = true 9 | externalrefs = true 10 | 11 | bodyfont = "DBRegular", Monaco, Monospace 12 | headerfont = "DBRegular", Monaco, Monospace 13 | 14 | bgcolor = #FFFFFF 15 | textcolor = #3B3A3A 16 | linkcolor = #2CB7F2 17 | headercolor1 = #FF8400 18 | headercolor2 = #FF8400 19 | headerlinkcolor = #F2462C 20 | 21 | codebgcolor = #FFFFFF 22 | codetextcolor = #3B3A3A -------------------------------------------------------------------------------- /docs/content/assets/drawBot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/content/assets/drawBot.jpg -------------------------------------------------------------------------------- /docs/content/assets/drawBotApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/content/assets/drawBotApp.png -------------------------------------------------------------------------------- /docs/content/assets/packageBuilder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/content/assets/packageBuilder.png -------------------------------------------------------------------------------- /docs/content/assets/preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/content/assets/preferences.png -------------------------------------------------------------------------------- /docs/content/assets/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/docs/content/assets/variables.png -------------------------------------------------------------------------------- /docs/content/canvas.rst: -------------------------------------------------------------------------------- 1 | Canvas 2 | ====== 3 | 4 | The canvas is the thing DrawBot draws on. It's the document size, the art board. It has a height and a width which can be set. The dimensions of the canvas are not related to the size of the window. 5 | 6 | .. toctree:: 7 | :titlesonly: 8 | :glob: 9 | 10 | canvas/pages 11 | canvas/state 12 | canvas/saveImage -------------------------------------------------------------------------------- /docs/content/canvas/pages.rst: -------------------------------------------------------------------------------- 1 | Pages 2 | ===== 3 | 4 | **The origin of the drawing board is at the bottom left.** 5 | 6 | .. autofunction:: drawBot.newPage 7 | .. autofunction:: drawBot.newDrawing 8 | .. autofunction:: drawBot.endDrawing 9 | 10 | Size 11 | ---- 12 | 13 | .. autofunction:: drawBot.size 14 | .. autofunction:: drawBot.sizes 15 | 16 | Page Attributes 17 | --------------- 18 | 19 | .. autofunction:: drawBot.width 20 | .. autofunction:: drawBot.height 21 | .. autofunction:: drawBot.pageCount 22 | .. autofunction:: drawBot.pages 23 | .. autofunction:: drawBot.frameDuration 24 | .. autofunction:: drawBot.linkURL(url, (x, y, w, h)) 25 | .. autofunction:: drawBot.linkRect(name, (x, y, w, h)) 26 | .. autofunction:: drawBot.linkDestination(name, (x, y)) 27 | -------------------------------------------------------------------------------- /docs/content/canvas/saveImage.rst: -------------------------------------------------------------------------------- 1 | Saving 2 | ====== 3 | 4 | .. autofunction:: drawBot.saveImage(paths, **options) 5 | .. autofunction:: drawBot.printImage 6 | .. autofunction:: drawBot.pdfImage -------------------------------------------------------------------------------- /docs/content/canvas/state.rst: -------------------------------------------------------------------------------- 1 | Transformations 2 | =============== 3 | 4 | .. autofunction:: drawBot.translate 5 | .. autofunction:: drawBot.rotate 6 | .. autofunction:: drawBot.scale 7 | .. autofunction:: drawBot.skew 8 | .. autofunction:: drawBot.transform((xx, xy, yx, yy, x, y)) 9 | 10 | Managing the Graphics State 11 | --------------------------- 12 | 13 | .. autofunction:: drawBot.savedState 14 | .. autofunction:: drawBot.save 15 | .. autofunction:: drawBot.restore 16 | -------------------------------------------------------------------------------- /docs/content/color.rst: -------------------------------------------------------------------------------- 1 | Colors 2 | ====== 3 | 4 | .. toctree:: 5 | :titlesonly: 6 | 7 | color/fill 8 | color/stroke 9 | color/cmykFill 10 | color/cmykStroke 11 | 12 | Opacity 13 | ------- 14 | 15 | .. autofunction:: drawBot.opacity 16 | 17 | Color Blend 18 | ----------- 19 | 20 | .. autofunction:: drawBot.blendMode 21 | 22 | Color Spaces 23 | ------------ 24 | 25 | Set a `colorSpace` before setting a color. Color spaces are only aviable for RGB colors. 26 | 27 | .. autofunction:: drawBot.colorSpace 28 | .. autofunction:: drawBot.listColorSpaces -------------------------------------------------------------------------------- /docs/content/color/cmykFill.rst: -------------------------------------------------------------------------------- 1 | CMYK Fill 2 | ========= 3 | 4 | Set a `fill` before drawing a shape. 5 | A cmyk color used while exporting to a .pdf or an image. 6 | Handy if the file is used for print. 7 | 8 | .. autofunction:: drawBot.cmykFill 9 | .. autofunction:: drawBot.cmykLinearGradient 10 | .. autofunction:: drawBot.cmykRadialGradient 11 | .. autofunction:: drawBot.cmykShadow 12 | -------------------------------------------------------------------------------- /docs/content/color/cmykStroke.rst: -------------------------------------------------------------------------------- 1 | CMYK Stroke 2 | =========== 3 | 4 | Set a `stroke` before drawing a shape. 5 | A cmyk color used while exporting to a .pdf or an image. 6 | Handy if the file is used for print. 7 | 8 | .. autofunction:: drawBot.cmykStroke -------------------------------------------------------------------------------- /docs/content/color/fill.rst: -------------------------------------------------------------------------------- 1 | Fill 2 | ==== 3 | 4 | Set a `fill` before drawing a shape. 5 | 6 | .. autofunction:: drawBot.fill 7 | .. autofunction:: drawBot.linearGradient 8 | .. autofunction:: drawBot.radialGradient 9 | .. autofunction:: drawBot.shadow 10 | 11 | -------------------------------------------------------------------------------- /docs/content/color/stroke.rst: -------------------------------------------------------------------------------- 1 | Stroke 2 | ====== 3 | 4 | Set a `stroke` before drawing a shape. 5 | 6 | .. autofunction:: drawBot.stroke -------------------------------------------------------------------------------- /docs/content/credits.rst: -------------------------------------------------------------------------------- 1 | Credits 2 | ======= 3 | 4 | Thanks to Python_ and PyObjC_ for making this possible and `Tal Leming`_ for wrapping PyObjC_ in vanilla_. 5 | 6 | A tip of the hat to `John Maeda`_ for showing the way with `Design By Numbers`_, Casey Reas and Ben Fry, the folks from Processing_. 7 | 8 | Finally thanks for the support and feedback from the users! 9 | 10 | Thanks Andy for the :doc:`icon`! 11 | 12 | .. _Python: http://www.python.org/ 13 | .. _PyObjC: http://pythonhosted.org/pyobjc/ 14 | .. _John Maeda: http://www.maedastudio.com/ 15 | .. _Design By Numbers: http://dbn.media.mit.edu 16 | .. _Processing: http://www.processing.org 17 | .. _Tal Leming: http://www.typesupply.com/ 18 | .. _vanilla: https://github.com/typesupply/vanilla/ 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/content/download.rst: -------------------------------------------------------------------------------- 1 | Download 2 | ======== 3 | 4 | .. cssclass:: app-download-link 5 | 6 | > `Download DrawBot `_ 7 | 8 | 9 | requirements: osX 10.12+ 10 | 11 | Older Downloads 12 | --------------- 13 | 14 | `Version History `_ 15 | 16 | `Very Old Version History `_ 17 | 18 | License 19 | ------- 20 | 21 | .. include:: /../license.txt 22 | -------------------------------------------------------------------------------- /docs/content/drawBotApp.rst: -------------------------------------------------------------------------------- 1 | DrawBot App 2 | =========== 3 | 4 | .. image:: assets/drawBotApp.png 5 | 6 | Drawbot has three main views: 7 | 8 | * A :doc:`drawBotApp/codeEditor`: the place to write code. 9 | * An Output View for `print` statements and tracebacks (reports for when your script fails). 10 | * The :doc:`drawBotApp/preview` will preview the current page – and all generated pages, in the case of documents with multiple pages. 11 | 12 | The :doc:`drawBotApp/preferences` window contains some settings related to the appearance of the DrawBot editor. 13 | 14 | .. toctree:: 15 | :titlesonly: 16 | :hidden: 17 | 18 | drawBotApp/codeEditor 19 | drawBotApp/preview 20 | drawBotApp/preferences 21 | drawBotApp/drawBotPackage -------------------------------------------------------------------------------- /docs/content/drawBotApp/codeEditor.rst: -------------------------------------------------------------------------------- 1 | Code Editor 2 | =========== 3 | 4 | The place where you can tell Python to draw things on the page and/or print things in the console. 5 | 6 | The syntax colors can be customized in the :doc:`preferences` window. 7 | 8 | Code interaction 9 | ---------------- 10 | 11 | The code editor also makes it easy and fun to interact with values in your program. When selected, some kinds of Python objects can be modified dynamically by pressing the Cmd key. The effects depend on the type of object: 12 | 13 | - `bool`: select and Cmd-click to turn the value on/off like a switch. 14 | - `int` or `float`: select the number, press Cmd and move the mouse up/down or right/left to increase/decrease the number. The default step is 1, by pressing alt the step is changed to 0.1. Additional shift can be pressed to multiply the steps by 10. Using the arrow keys also works. 15 | - in `tuples` with numbers it is possible to select two neighbouring numbers and modify them together at the same time – this is specially useful when working with coordinate pairs or dimensions. 16 | 17 | .. raw:: html :: 18 | 19 | 20 | 21 | Live coding 22 | ----------- 23 | 24 | The live coding mode executes the code as you type, so you can see changes without having to re-run the program every time. This is useful when working with text or making demonstrations. 25 | 26 | This feature can be turned on/off in the Python menu. 27 | 28 | Use it with caution: depending on the size of your program and the amount of interaction, Drawbot can get a bit slow. -------------------------------------------------------------------------------- /docs/content/drawBotApp/drawBotPackage.rst: -------------------------------------------------------------------------------- 1 | DrawBot Package 2 | =============== 3 | 4 | A `.drawbot` package is a DrawBot app readable file containing python files. 5 | Making it easy to share and exchange drawbot scripts. 6 | 7 | Use a .drawbot package 8 | ---------------------- 9 | 10 | Double click the or drop the .drawbot file on top of DrawBot. 11 | 12 | Build a .drawbot package 13 | ------------------------ 14 | 15 | Use the build in package builder to build a `.drawbot` package. 16 | 17 | .. image:: ../assets/packageBuilder.png 18 | 19 | 20 | drawBot package specification 21 | ------------------------------ 22 | 23 | A `.drawbot` package is a folder with an extension. 24 | 25 | .. code-block:: console 26 | 27 | .drawbot (package) 28 | info.plist 29 | lib/ 30 | main.py 31 | anotherScript.py 32 | anImage.jpg 33 | ... 34 | 35 | 36 | The info plist dictionary can have the following keywords: 37 | 38 | * `name`: optional, default to .drawBot 39 | * `version`: optional, default to 0.0, but advised to set 40 | * `developer`: optional, default to None 41 | * `developerURL`: optional, default to None 42 | * `requiresVersion`: optional, default to all versions 43 | * `mainScript`: optional, default to 'lib/main.py' if this isn't specified?) 44 | 45 | -------------------------------------------------------------------------------- /docs/content/drawBotApp/preferences.rst: -------------------------------------------------------------------------------- 1 | Preferences 2 | =========== 3 | 4 | The Preferences window offers fine-grained control over the code editor's syntax colors and font. 5 | 6 | .. image:: ../assets/preferences.png 7 | 8 | Additional options include turning the animation of the icon and the auto-update feature on/off. -------------------------------------------------------------------------------- /docs/content/drawBotApp/preview.rst: -------------------------------------------------------------------------------- 1 | Preview 2 | ======= 3 | 4 | The Preview area is where your generated graphics are displayed. 5 | 6 | Current page 7 | ------------ 8 | 9 | The main preview area shows the drawing canvas or current page. 10 | 11 | The zoom level can be increased with `Cmd+` and decreased with `Cmd-`. 12 | 13 | In case of multi-page documents, the visualization settings can be changed by right-clicking on the page and choosing between single or double pages and continuous or individual. 14 | 15 | Pages overview 16 | -------------- 17 | 18 | Besides the current page there is also a secondary pane to the left where all pages can be seen at once (in case of multi-page documents). This pane is hidden by default, and can be opened by pulling the vertical division to the right. 19 | -------------------------------------------------------------------------------- /docs/content/history.rst: -------------------------------------------------------------------------------- 1 | History 2 | ======= 3 | 4 | The DrawBot project started in 2003 as a program named "DesignRobots", written for the occasion of a Python workshop at the TypoTechnica conference. Since then the application evolved into a Cocoa application with a powerful API and image export functionality. 5 | 6 | Version 0.9a 7 | ------------ 8 | 9 | First release as Cocoa application. Supports rectangles, ovals, bezier paths, but not text. 10 | Unofficial Fork of Version 0.9a 11 | 12 | There is an unofficial forked version of DrawBot around. Unfortunately this version does not document the differences with the current DrawBot. This has led to considerable confusion and frustration with users. 13 | 14 | Version 2.0 15 | ----------- 16 | 17 | In use at the TypeMedia department of the Royal Academy in The Hague for about then 10 years!. Many Improvements on the API and text support. (2007) 18 | 19 | Version 3+ 20 | ---------- 21 | 22 | Complete rewritten and many improvements on the API. 23 | 24 | -------------------------------------------------------------------------------- /docs/content/image/drawingImages.rst: -------------------------------------------------------------------------------- 1 | Drawing Images 2 | ============== 3 | 4 | .. autofunction:: drawBot.image(path, (x, y), alpha=1, pageNumber=None) 5 | -------------------------------------------------------------------------------- /docs/content/image/imageObject.rst: -------------------------------------------------------------------------------- 1 | Image Objects 2 | ============= 3 | 4 | .. autoclass:: drawBot.ImageObject 5 | :members: -------------------------------------------------------------------------------- /docs/content/image/imageProperties.rst: -------------------------------------------------------------------------------- 1 | Image Properties 2 | ================ 3 | 4 | .. autofunction:: drawBot.imageSize(path) 5 | .. autofunction:: drawBot.imagePixelColor(path, (x, y)) 6 | .. autofunction:: drawBot.imageResolution(path) 7 | .. autofunction:: drawBot.numberOfPages(path) 8 | -------------------------------------------------------------------------------- /docs/content/images.rst: -------------------------------------------------------------------------------- 1 | Images 2 | ====== 3 | 4 | .. toctree:: 5 | :titlesonly: 6 | :glob: 7 | 8 | image/drawingImages 9 | image/imageProperties 10 | image/imageObject -------------------------------------------------------------------------------- /docs/content/shapes.rst: -------------------------------------------------------------------------------- 1 | Shapes 2 | ======== 3 | 4 | Different shapes and how to make them. 5 | 6 | .. toctree:: 7 | :titlesonly: 8 | :glob: 9 | 10 | shapes/primitives 11 | shapes/drawingPath 12 | shapes/pathProperties 13 | shapes/bezierPath -------------------------------------------------------------------------------- /docs/content/shapes/bezierPath.rst: -------------------------------------------------------------------------------- 1 | Bezier Paths 2 | ============ 3 | 4 | .. autoclass:: drawBot.BezierPath 5 | :members: 6 | :undoc-members: 7 | :inherited-members: 8 | :show-inheritance: 9 | :exclude-members: copyContextProperties, add_note, args, with_traceback, log, MissingComponentError, svgClass, svgID, svgLink -------------------------------------------------------------------------------- /docs/content/shapes/drawingPath.rst: -------------------------------------------------------------------------------- 1 | Drawing Paths 2 | ============= 3 | 4 | Using bezier paths. 5 | 6 | .. autofunction:: drawBot.newPath 7 | .. autofunction:: drawBot.moveTo 8 | .. autofunction:: drawBot.lineTo 9 | .. autofunction:: drawBot.curveTo 10 | .. autofunction:: drawBot.qCurveTo 11 | .. autofunction:: drawBot.arc 12 | .. autofunction:: drawBot.arcTo 13 | .. autofunction:: drawBot.closePath 14 | .. autofunction:: drawBot.drawPath 15 | .. autofunction:: drawBot.clipPath -------------------------------------------------------------------------------- /docs/content/shapes/pathProperties.rst: -------------------------------------------------------------------------------- 1 | Path Properties 2 | =============== 3 | 4 | .. autofunction:: drawBot.strokeWidth 5 | .. autofunction:: drawBot.miterLimit 6 | .. autofunction:: drawBot.lineJoin 7 | .. autofunction:: drawBot.lineCap 8 | .. autofunction:: drawBot.lineDash -------------------------------------------------------------------------------- /docs/content/shapes/primitives.rst: -------------------------------------------------------------------------------- 1 | Primitives 2 | ========== 3 | 4 | .. autofunction:: drawBot.rect 5 | .. autofunction:: drawBot.oval 6 | .. autofunction:: drawBot.line((x1, y1), (x2, y2))) 7 | .. autofunction:: drawBot.polygon((x1, y1), (x2, y2), ..., close=True) -------------------------------------------------------------------------------- /docs/content/text.rst: -------------------------------------------------------------------------------- 1 | Text 2 | ==== 3 | 4 | .. toctree:: 5 | :titlesonly: 6 | :glob: 7 | 8 | text/drawingText 9 | text/textProperties 10 | text/formattedString -------------------------------------------------------------------------------- /docs/content/text/drawingText.rst: -------------------------------------------------------------------------------- 1 | Drawing Text 2 | ============ 3 | 4 | .. autofunction:: drawBot.text(txt, (x, y), align=None) 5 | .. autofunction:: drawBot.textBox(text, (x, y, w, y), align=None) 6 | 7 | Helpers 8 | ------- 9 | 10 | .. autofunction:: drawBot.textSize 11 | .. autofunction:: drawBot.textOverflow 12 | .. autofunction:: drawBot.textBoxBaselines 13 | .. autofunction:: drawBot.textBoxCharacterBounds 14 | .. autofunction:: drawBot.installedFonts 15 | .. autofunction:: drawBot.installFont 16 | .. autofunction:: drawBot.uninstallFont 17 | -------------------------------------------------------------------------------- /docs/content/text/formattedString.rst: -------------------------------------------------------------------------------- 1 | Formatted Strings 2 | ================= 3 | 4 | .. autoclass:: drawBot.FormattedString(txt=None, font=None, fontSize=10, fallbackFont=None, fill=(0, 0, 0), cmykFill=None, stroke=None, cmykStroke=None, strokeWidth=1, align=None, lineHeight=None, tracking=None, baselineShift=None, openTypeFeatures=None, tabs=None, language=None, indent=None, tailIndent=None, firstLineIndent=None, paragraphTopSpacing=None, paragraphBottomSpacing=None) 5 | :members: 6 | :undoc-members: 7 | :inherited-members: 8 | :show-inheritance: 9 | :exclude-members: copyContextProperties, svgClass, svgID, svgLink -------------------------------------------------------------------------------- /docs/content/text/textProperties.rst: -------------------------------------------------------------------------------- 1 | Text Properties 2 | =============== 3 | 4 | .. autofunction:: drawBot.font 5 | .. autofunction:: drawBot.fontSize 6 | .. autofunction:: drawBot.fallbackFont 7 | .. autofunction:: drawBot.underline 8 | .. autofunction:: drawBot.strikethrough 9 | .. autofunction:: drawBot.hyphenation 10 | .. autofunction:: drawBot.lineHeight 11 | .. autofunction:: drawBot.tracking 12 | .. autofunction:: drawBot.baselineShift 13 | .. autofunction:: drawBot.openTypeFeatures(frac=True, case=True, ...) 14 | .. autofunction:: drawBot.listOpenTypeFeatures 15 | .. autofunction:: drawBot.fontVariations(wdth=0.6, wght=0.1, ...) 16 | .. autofunction:: drawBot.listFontVariations 17 | .. autofunction:: drawBot.fontNamedInstance 18 | .. autofunction:: drawBot.listNamedInstances 19 | .. autofunction:: drawBot.tabs 20 | .. autofunction:: drawBot.language 21 | .. autofunction:: drawBot.textProperties 22 | 23 | Font Properties 24 | --------------- 25 | 26 | .. autofunction:: drawBot.fontContainsCharacters 27 | .. autofunction:: drawBot.fontContainsGlyph 28 | .. autofunction:: drawBot.fontFilePath 29 | .. autofunction:: drawBot.listFontGlyphNames 30 | .. autofunction:: drawBot.fontDescender 31 | .. autofunction:: drawBot.fontAscender 32 | .. autofunction:: drawBot.fontXHeight 33 | .. autofunction:: drawBot.fontCapHeight 34 | .. autofunction:: drawBot.fontLeading 35 | .. autofunction:: drawBot.fontLineHeight 36 | 37 | .. downloadcode:: fontMetrics.py 38 | 39 | txt = "Hello World" 40 | x, y = 10, 100 41 | 42 | # set a font 43 | font("Helvetica") 44 | # set a font size 45 | fontSize(100) 46 | # draw the text 47 | text(txt, (x, y)) 48 | 49 | # calculate the size of the text 50 | textWidth, textHeight = textSize(txt) 51 | 52 | # set a red stroke color 53 | stroke(1, 0, 0) 54 | # loop over all font metrics 55 | for metric in (0, fontDescender(), fontAscender(), fontXHeight(), fontCapHeight()): 56 | # draw a red line with the size of the drawn text 57 | line((x, y+metric), (x+textWidth, y+metric)) 58 | 59 | -------------------------------------------------------------------------------- /docs/content/variables.rst: -------------------------------------------------------------------------------- 1 | Variables 2 | ========= 3 | 4 | .. autofunction:: drawBot.Variable -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: python 2 | :linenothreshold: 5 3 | 4 | .. toctree:: 5 | :hidden: 6 | 7 | DrawBot Documentation 8 | ===================== 9 | 10 | DrawBot is a powerful, free application for MacOSX that invites you to write simple Python scripts to generate two-dimensional graphics. The builtin graphics primitives support rectangles, ovals, (bezier) paths, polygons, text objects and transparency. 11 | 12 | Education 13 | --------- 14 | 15 | DrawBot is an ideal tool to teach the basics of programming. Students get colorful graphic treats while getting familiar with variables, conditional statements, functions and what have you. Results can be saved in a selection of different file formats, including as high resolution, scaleable PDF, svg, movie, png, jpeg, tiff... 16 | 17 | DrawBot has proven itself as part of the curriculum at selected courses at the Royal Academy in The Hague. 18 | 19 | Python 20 | ------ 21 | 22 | DrawBot is written in Python_. The binary download is fully self-contained (ie. it doesn't need a Python install around), but the `source code`_ is available if you want to roll your own. 23 | 24 | 25 | .. toctree:: 26 | :titlesonly: 27 | :hidden: 28 | 29 | content/shapes 30 | content/color 31 | content/canvas 32 | content/text 33 | content/images 34 | content/variables 35 | content/quickReference 36 | 37 | .. toctree:: 38 | :titlesonly: 39 | :hidden: 40 | 41 | content/drawBotApp 42 | content/download 43 | content/drawBotIcon 44 | 45 | .. toctree:: 46 | :titlesonly: 47 | :hidden: 48 | 49 | content/courseware 50 | content/history 51 | content/credits 52 | 53 | 54 | .. _Python: http://www.python.org/ 55 | .. _source code: https://github.com/typemytype/drawbot/ -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==8.1.3 2 | fonttools -------------------------------------------------------------------------------- /drawBot/aliases.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Sequence 3 | 4 | Size = tuple[int, int] 5 | Point = tuple[float, float] 6 | Points = Sequence[Point] 7 | SomePath = os.PathLike | str 8 | CMYKColor = float | tuple[float, ...] 9 | RGBAColorTuple = tuple[float, float, float, float] 10 | CMYKColorTuple = tuple[float, float, float, float] 11 | RGBColorTuple = tuple[float, float, float] 12 | RGBColor = float | tuple[float, ...] 13 | BoundingBox = tuple[float, float, float, float] 14 | TransformTuple = tuple[float, float, float, float, float, float] 15 | -------------------------------------------------------------------------------- /drawBot/context/__init__.py: -------------------------------------------------------------------------------- 1 | from .gifContext import GIFContext 2 | from .icnsContext import ICNSContext 3 | from .imageContext import BMPContext, JPEGContext, PNGContext, TIFFContext 4 | from .imageObjectContext import NSImageContext, PILContext 5 | from .mp4Context import MP4Context 6 | from .pdfContext import PDFContext 7 | from .printContext import PrintContext 8 | from .svgContext import SVGContext 9 | 10 | allContexts = [ 11 | PDFContext, 12 | PNGContext, 13 | JPEGContext, 14 | TIFFContext, 15 | SVGContext, 16 | GIFContext, 17 | BMPContext, 18 | MP4Context, 19 | ICNSContext, 20 | PrintContext, 21 | PILContext, 22 | NSImageContext, 23 | ] 24 | 25 | 26 | def subscribeContext(context): 27 | for ctx in list(allContexts): 28 | if ctx.__name__ == context.__name__: 29 | allContexts.remove(ctx) 30 | allContexts.append(context) 31 | 32 | 33 | def getContextForFileExt(ext): 34 | for context in allContexts: 35 | if ext in context.fileExtensions: 36 | return context() 37 | return None 38 | 39 | 40 | def getContextOptions(): 41 | options = set() 42 | for context in allContexts: 43 | for key, _ in context.saveImageOptions: 44 | options.add(key) 45 | return options 46 | 47 | 48 | def getFileExtensions() -> list[str]: 49 | extensions = [] 50 | for context in allContexts: 51 | for ext in context.fileExtensions: 52 | if ext not in extensions: 53 | extensions.append(ext) 54 | return extensions 55 | 56 | 57 | def getContextOptionsDocs(formatter="* `%s`: %s") -> list[str]: 58 | docs = [] 59 | for context in allContexts: 60 | if context.saveImageOptions: 61 | ext = ", ".join(context.fileExtensions) 62 | docs.append("*%s options:*" % ext) 63 | docs.append("") 64 | for key, doc in context.saveImageOptions: 65 | docs.append(formatter % (key, doc)) 66 | docs.append("") 67 | return docs 68 | -------------------------------------------------------------------------------- /drawBot/context/drawBotContext.py: -------------------------------------------------------------------------------- 1 | import Quartz # type: ignore 2 | 3 | from .pdfContext import PDFContext 4 | 5 | 6 | class DrawBotContext(PDFContext): 7 | def getNSPDFDocument(self): 8 | if not self._hasContext: 9 | return None 10 | Quartz.CGPDFContextEndPage(self._pdfContext) 11 | Quartz.CGPDFContextClose(self._pdfContext) 12 | doc = Quartz.PDFDocument.alloc().initWithData_(self._pdfData) 13 | self._hasContext = False 14 | self._pdfContext = None 15 | self._pdfData = None 16 | return doc 17 | -------------------------------------------------------------------------------- /drawBot/context/dummyContext.py: -------------------------------------------------------------------------------- 1 | from .baseContext import BaseContext 2 | 3 | 4 | class DummyContext(BaseContext): 5 | pass 6 | -------------------------------------------------------------------------------- /drawBot/context/gifContext.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | 3 | import Quartz # type: ignore 4 | 5 | from .imageContext import ImageContext, getSaveImageOptions 6 | from .tools.gifTools import generateGif 7 | 8 | 9 | class GIFContext(ImageContext): 10 | fileExtensions = ["gif"] 11 | 12 | saveImageOptions = getSaveImageOptions( 13 | [ 14 | "imageGIFDitherTransparency", 15 | "imageGIFRGBColorTable", 16 | "imageColorSyncProfileData", 17 | ] 18 | ) 19 | saveImageOptions.append(("imageGIFLoop", "Boolean that indicates whether the animated gif should loop")) 20 | 21 | _delay = 10 22 | 23 | def __init__(self): 24 | super(GIFContext, self).__init__() 25 | self._delayData = [] 26 | 27 | def _frameDuration(self, seconds): 28 | # gifsicle -h: Set frame delay to TIME (in 1/100sec). 29 | self._delayData[-1] = int(seconds * 100) 30 | 31 | def _newPage(self, width, height): 32 | super(GIFContext, self)._newPage(width, height) 33 | self._delayData.append(self._delay) 34 | 35 | def _writeDataToFile(self, data, path, options): 36 | pdfDocument = Quartz.PDFDocument.alloc().initWithData_(data) 37 | pageCount = pdfDocument.pageCount() 38 | shouldBeAnimated = pageCount > 1 39 | 40 | tempPath = path 41 | if shouldBeAnimated: 42 | options["multipage"] = True 43 | tempPath = tempfile.mkstemp(suffix=".gif")[1] 44 | 45 | self._inputPaths = [] 46 | super()._writeDataToFile(data, tempPath, options) 47 | 48 | if shouldBeAnimated: 49 | generateGif(self._inputPaths, path, self._delayData, options.get("imageGIFLoop", True)) 50 | del self._inputPaths 51 | 52 | def _storeImageData(self, imageData, imagePath): 53 | super()._storeImageData(imageData, imagePath) 54 | self._inputPaths.append(imagePath) 55 | -------------------------------------------------------------------------------- /drawBot/context/icnsContext.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tempfile 4 | 5 | import Quartz # type: ignore 6 | 7 | from drawBot.context.imageContext import ImageContext 8 | from drawBot.misc import DrawBotError, executeExternalProcess 9 | 10 | 11 | class ICNSContext(ImageContext): 12 | fileExtensions = ["icns"] 13 | 14 | allowedPageSizes = [16, 32, 128, 256, 512, 1024] 15 | 16 | def _writeDataToFile(self, data, path, options): 17 | # create a iconset folder 18 | iconsetPath = tempfile.mkdtemp(suffix=".iconset") 19 | try: 20 | # get the complete pdf 21 | pdfDocument = Quartz.PDFDocument.alloc().initWithData_(data) 22 | pageCount = pdfDocument.pageCount() 23 | # set the image resolution 24 | options["imageResolution"] = 72 25 | # make a copy and alter the resolution 26 | options_2x = dict(options) 27 | options_2x["imageResolution"] = 144 28 | # start loop over all pages 29 | for index in range(pageCount): 30 | # get the pdf page 31 | page = pdfDocument.pageAtIndex_(index) 32 | # get the pdf page, this acts also as pdf document... 33 | pageData = page.dataRepresentation() 34 | # extract the size of the page 35 | _, (w, h) = page.boundsForBox_(Quartz.kPDFDisplayBoxArtBox) 36 | w = int(round(w)) 37 | h = int(round(h)) 38 | # dont allow any other size, the command iconutil will not work otherwise 39 | if w not in self.allowedPageSizes or w != h: 40 | raise DrawBotError( 41 | "The .icns can not be build with the size '%sx%s'. Must be either: %s" 42 | % (w, h, ", ".join(["%sx%s" % (i, i) for i in self.allowedPageSizes])) 43 | ) 44 | # generate a 72 dpi png in the iconset path 45 | pngPath = os.path.join(iconsetPath, "icon_%sx%s.png" % (w, h)) 46 | super(ICNSContext, self)._writeDataToFile(pageData, pngPath, options) 47 | # generate a 144 dpi png in the iconset path 48 | pngPath_2x = os.path.join(iconsetPath, "icon_%sx%s@2x.png" % (w, h)) 49 | super(ICNSContext, self)._writeDataToFile(pageData, pngPath_2x, options_2x) 50 | # collect all iconutil commands 51 | cmds = [ 52 | "iconutil", 53 | "--convert", 54 | "icns", 55 | "--output", 56 | path, 57 | iconsetPath, 58 | ] 59 | # execute the commands 60 | stdout, stderr = executeExternalProcess(cmds) 61 | finally: 62 | # always remove the iconset 63 | shutil.rmtree(iconsetPath) 64 | -------------------------------------------------------------------------------- /drawBot/context/imageObjectContext.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import AppKit # type: ignore 4 | 5 | try: 6 | from PIL import Image 7 | 8 | hasPIL = True 9 | except ImportError: 10 | hasPIL = False 11 | 12 | from drawBot.misc import DrawBotError 13 | 14 | from .imageContext import ImageContext 15 | 16 | 17 | class BaseImageObjectContext(ImageContext): 18 | def _writeDataToFile(self, data, path, options): 19 | self._imageObjects = [] 20 | # we just need a path with a file extension 21 | # nothing will be written to disk 22 | super()._writeDataToFile(data, "temp.tiff", options) 23 | imageObjects = self._imageObjects 24 | del self._imageObjects 25 | if not options.get("multipage"): 26 | imageObjects = imageObjects[0] 27 | return imageObjects 28 | 29 | def _storeImageData(self, imageData, imagePath): 30 | obj = self._getObjectForData(imageData) 31 | self._imageObjects.append(obj) 32 | 33 | def _getObjectForData(self, data): 34 | raise NotImplementedError 35 | 36 | 37 | class PILContext(BaseImageObjectContext): 38 | fileExtensions = ["PIL"] 39 | 40 | def __init__(self): 41 | if not hasPIL: 42 | raise DrawBotError("The package PIL is required.") 43 | super().__init__() 44 | 45 | def _getObjectForData(self, data): 46 | file = io.BytesIO(data.bytes()) 47 | return Image.open(file) 48 | 49 | 50 | class NSImageContext(BaseImageObjectContext): 51 | fileExtensions = ["NSImage"] 52 | 53 | def _getObjectForData(self, data): 54 | return AppKit.NSImage.alloc().initWithData_(data) 55 | -------------------------------------------------------------------------------- /drawBot/context/mp4Context.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tempfile 4 | 5 | from drawBot.misc import warnings 6 | 7 | from .imageContext import PNGContext 8 | from .tools.mp4Tools import generateMP4 9 | 10 | 11 | class MP4Context(PNGContext): 12 | fileExtensions = ["mp4"] 13 | 14 | saveImageOptions = [ 15 | ( 16 | "ffmpegCodec", 17 | "The codec to be used by ffmpeg. By default it is 'libx264' (for H.264). The 'mpeg4' codec gives better results when importing the movie into After Effects, at the expense of a larger file size.", 18 | ), 19 | ] 20 | saveImageOptions.extend((key, doc) for key, doc in PNGContext.saveImageOptions if key != "multipage") 21 | 22 | _defaultFrameDuration = 1 / 10 23 | 24 | ensureEvenPixelDimensions = True 25 | 26 | def __init__(self): 27 | super(MP4Context, self).__init__() 28 | self._frameDurations = [] 29 | 30 | def _frameDuration(self, frameDuration): 31 | self._frameDurations[-1] = frameDuration 32 | 33 | def _newPage(self, width, height): 34 | super(MP4Context, self)._newPage(width, height) 35 | self._frameDurations.append(self._defaultFrameDuration) 36 | # https://github.com/typemytype/drawbot/issues/391 37 | # draw a solid white background by default 38 | # ffmpeg converts transparency to a black background color 39 | self.save() 40 | self.fill(1) 41 | self.rect(0, 0, width, height) 42 | self.restore() 43 | 44 | def _writeDataToFile(self, data, path, options): 45 | frameRate = round(1.0 / self._frameDurations[0], 3) 46 | frameDurations = set(self._frameDurations) 47 | if len(frameDurations) > 1: 48 | warnings.warn("Exporting to mp4 doesn't support varying frame durations, only the first value was used.") 49 | options["multipage"] = True 50 | codec = options.get("ffmpegCodec", "libx264") 51 | tempDir = tempfile.mkdtemp(suffix=".mp4tmp") 52 | try: 53 | super(MP4Context, self)._writeDataToFile(data, os.path.join(tempDir, "frame.png"), options) 54 | generateMP4(os.path.join(tempDir, "frame_%d.png"), path, frameRate, codec) 55 | finally: 56 | shutil.rmtree(tempDir) 57 | -------------------------------------------------------------------------------- /drawBot/context/printContext.py: -------------------------------------------------------------------------------- 1 | import AppKit # type: ignore 2 | from fontTools.pens.basePen import AbstractPen 3 | 4 | from .baseContext import BaseContext 5 | 6 | 7 | class StringPen(AbstractPen): 8 | def __init__(self, seperator=None): 9 | self.data = [] 10 | if seperator is None: 11 | seperator = " " 12 | self.seperator = seperator 13 | 14 | def moveTo(self, pt): 15 | x, y = pt 16 | self.data.append("moveTo %s %s" % (x, y)) 17 | 18 | def lineTo(self, pt): 19 | x, y = pt 20 | self.data.append("lineTo %s %s" % (x, y)) 21 | 22 | def curveTo(self, *pts): 23 | self.data.append("curveTo %s" % " ".join(["%s %s" % (x, y) for x, y in pts])) 24 | 25 | def qCurveTo(self, *pts): 26 | self.data.append("qCurveTo %s" % " ".join(["%s %s" % (x, y) for x, y in pts])) 27 | 28 | def closePath(self): 29 | self.data.append("closePath") 30 | 31 | def endPath(self): 32 | self.data.append("endPath") 33 | 34 | def __repr__(self): 35 | return self.seperator.join(self.data) 36 | 37 | 38 | class PrintContext(BaseContext): 39 | fileExtensions = ["*"] 40 | validateSaveImageOptions = False 41 | 42 | def _newPage(self, width, height): 43 | print("newPage %s %s" % (width, height)) 44 | 45 | def _save(self): 46 | print("save") 47 | 48 | def _restore(self): 49 | print("restore") 50 | 51 | def _blendMode(self, operation): 52 | print("blendMode %s" % operation) 53 | 54 | def _opacity(self, value): 55 | print("opacity %s" % value) 56 | 57 | def _drawPath(self): 58 | pen = StringPen() 59 | self._state.path.drawToPen(pen) 60 | print("drawPath %s" % pen) 61 | 62 | def _clipPath(self): 63 | pen = StringPen() 64 | self._state.path.drawToPen(pen) 65 | print("clipPath %s" % pen) 66 | 67 | def _transform(self, matrix): 68 | print("transform %s" % " ".join(["%s" % i for i in matrix])) 69 | 70 | def _textBox(self, txt, xywh, align): 71 | # XXX 72 | # should a formatted string be printed in parts??? 73 | x, y, w, h = xywh 74 | print("textBox %s %r %r %r %r %s" % (txt, x, y, w, h, align)) 75 | 76 | def _image(self, path, xy, alpha, pageNumber): 77 | x, y = xy 78 | if isinstance(path, AppKit.NSImage): 79 | path = "Image Object" 80 | print("image %s %s %s %s %s" % (path, x, y, alpha, pageNumber)) 81 | 82 | def _frameDuration(self, seconds): 83 | print("frameDuration %s" % seconds) 84 | 85 | def _reset(self, other=None): 86 | print("reset %s" % other) 87 | 88 | def _saveImage(self, path, options): 89 | print("saveImage %s %s" % (path, options)) 90 | 91 | def _printImage(self, pdf=None): 92 | print("printImage %s" % pdf) 93 | 94 | def _linkURL(self, url, xywh): 95 | x, y, w, h = xywh 96 | print("linkURL %s %s %s %s %s" % (url, x, y, w, h)) 97 | 98 | def _linkDestination(self, name, xy): 99 | x, y = xy 100 | print("linkDestination %s %s %s" % (name, x, y)) 101 | 102 | def _linkRect(self, name, xywh): 103 | x, y, w, h = xywh 104 | print("linkRect %s %s %s %s %s" % (name, x, y, w, h)) 105 | -------------------------------------------------------------------------------- /drawBot/context/tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/drawBot/context/tools/__init__.py -------------------------------------------------------------------------------- /drawBot/context/tools/drawBotbuiltins.py: -------------------------------------------------------------------------------- 1 | def norm(value: float, start: float, stop: float) -> float: 2 | """ 3 | Return the interpolation factor (between 0 and 1) of a `value` between `start` and `stop`. 4 | """ 5 | return (value - start) / (stop - start) 6 | 7 | 8 | def lerp(start: float, stop: float, factor: float) -> float: 9 | """ 10 | Return an interpolated value between `start` and `stop` using interpolation factor `factor`. 11 | """ 12 | return start + (stop - start) * factor 13 | 14 | 15 | def remap(value: float, start1: float, stop1: float, start2: float, stop2: float, clamp: bool = False) -> float: 16 | """ 17 | Re-maps a number from one range to another. 18 | """ 19 | factor = norm(value, start1, stop1) 20 | if clamp: 21 | if factor < 0: 22 | factor = 0 23 | elif factor > 1: 24 | factor = 1 25 | return lerp(start2, stop2, factor) 26 | -------------------------------------------------------------------------------- /drawBot/context/tools/gifTools.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tempfile 4 | 5 | import AppKit # type: ignore 6 | 7 | from drawBot.misc import executeExternalProcess, getExternalToolPath 8 | 9 | 10 | def generateGif(sourcePaths, destPath, delays, loop=True): 11 | gifsiclePath = getExternalToolPath(os.path.dirname(__file__), "gifsicle") 12 | assert gifsiclePath is not None 13 | cmds = [ 14 | # gifsicle path 15 | gifsiclePath, 16 | # optimize level 17 | # "-O3", 18 | # ignore warnings 19 | "-w", 20 | # force to 256 colors 21 | "--colors", 22 | "256", 23 | ] 24 | if loop: 25 | # make it loop 26 | cmds.append("--loop") 27 | # add source paths with delay for each frame 28 | for i, inputPath in enumerate(sourcePaths): 29 | cmds += [ 30 | # add the frame duration 31 | "--delay", 32 | "%i" % delays[i], 33 | # add the input gif for each frame 34 | inputPath, 35 | ] 36 | 37 | cmds += [ 38 | # output path 39 | "--output", 40 | destPath, 41 | ] 42 | executeExternalProcess(cmds) 43 | # remove the temp input gifs 44 | for inputPath in sourcePaths: 45 | os.remove(inputPath) 46 | 47 | 48 | _explodedGifCache = {} 49 | 50 | 51 | def _explodeGif(path): 52 | gifsiclePath = getExternalToolPath(os.path.dirname(__file__), "gifsicle") 53 | if isinstance(path, AppKit.NSURL): 54 | path = path.path() 55 | destRoot = tempfile.mkdtemp() 56 | cmds = [ 57 | gifsiclePath, 58 | # explode 59 | "--explode", 60 | # source path 61 | path, 62 | ] 63 | executeExternalProcess(cmds, cwd=destRoot) 64 | files = os.listdir(destRoot) 65 | _explodedGifCache[path] = dict( 66 | source=destRoot, 67 | fileNames=sorted(files), 68 | ) 69 | 70 | 71 | def clearExplodedGifCache(): 72 | for path, info in _explodedGifCache.items(): 73 | shutil.rmtree(info["source"]) 74 | _explodedGifCache.clear() 75 | 76 | 77 | def gifFrameCount(path): 78 | if isinstance(path, AppKit.NSURL): 79 | path = path.path() 80 | if path not in _explodedGifCache: 81 | _explodeGif(path) 82 | frameCount = len(_explodedGifCache[path]["fileNames"]) 83 | if frameCount == 0: 84 | return None 85 | return frameCount 86 | 87 | 88 | def gifFrameAtIndex(path, index): 89 | if isinstance(path, AppKit.NSURL): 90 | path = path.path() 91 | if path not in _explodedGifCache: 92 | _explodeGif(path) 93 | source = _explodedGifCache[path]["source"] 94 | fileNames = _explodedGifCache[path]["fileNames"] 95 | fileName = os.path.join(source, fileNames[index]) 96 | url = AppKit.NSURL.fileURLWithPath_(fileName) 97 | return AppKit.NSImage.alloc().initByReferencingURL_(url) 98 | -------------------------------------------------------------------------------- /drawBot/context/tools/gifsicleLicense: -------------------------------------------------------------------------------- 1 | Copyright/License 2 | 3 | All source code is Copyright (C) 1997-2013 Eddie Kohler. 4 | 5 | IF YOU PLAN TO USE GIFSICLE ONLY TO CREATE OR MODIFY GIF IMAGES, DON'T WORRY ABOUT THE REST OF THIS SECTION. Anyone can use Gifsicle however they wish; the license applies only to those who plan to copy, distribute, or alter its code. If you use Gifsicle for an organizational or commercial Web site, I would appreciate a link to the Gifsicle home page on any 'About This Server' page, but it's not required. 6 | 7 | This code is distributed under the GNU General Public License, Version 2 (and only Version 2). The GNU General Public License is available via the Web at http://www.gnu.org/licenses/gpl.html or in the 'COPYING' file in this directory. 8 | 9 | The following alternative license may be used at your discretion. 10 | 11 | Permission is granted to copy, distribute, or alter Gifsicle, whole or in part, as long as source code copyright notices are kept intact, with the following restriction: Developers or distributors who plan to use Gifsicle code, whole or in part, in a product whose source code will not be made available to the end user -- more precisely, in a context which would violate the GPL -- MUST contact the author and obtain permission before doing so. -------------------------------------------------------------------------------- /drawBot/context/tools/mp4Tools.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from drawBot.misc import executeExternalProcess, getExternalToolPath 4 | 5 | 6 | def generateMP4(imageTemplate, mp4path, frameRate, codec="libx264"): 7 | ffmpegPath = getExternalToolPath(os.path.dirname(__file__), "ffmpeg") 8 | assert ffmpegPath is not None 9 | cmds = [ 10 | # ffmpeg path 11 | ffmpegPath, 12 | "-y", # overwrite existing files 13 | "-loglevel", 14 | "16", # 'error, 16' Show all errors, including ones which can be recovered from. 15 | "-r", 16 | str(frameRate), # frame rate 17 | "-i", 18 | imageTemplate, # input sequence 19 | "-c:v", 20 | codec, # codec 21 | "-crf", 22 | "20", # Constant Rate Factor 23 | "-pix_fmt", 24 | "yuv420p", # pixel format 25 | mp4path, # output path 26 | ] 27 | executeExternalProcess(cmds) 28 | -------------------------------------------------------------------------------- /drawBot/drawBotPageDrawingTools.py: -------------------------------------------------------------------------------- 1 | from .drawBotDrawingTools import _drawBotDrawingTool, DrawBotDrawingTool 2 | 3 | 4 | class DummyDrawBotDrawingTool(DrawBotDrawingTool): 5 | def __init__(self, instructionSet): 6 | super(DummyDrawBotDrawingTool, self).__init__() 7 | # add the instruction set 8 | self._instructionsStack.append(instructionSet) 9 | # draw all instructions into it self 10 | # just to set all attributes into the dummycontext 11 | # this is important for the current state 12 | self._drawInContext(self) 13 | 14 | def _addInstruction(self, callback, *args, **kwargs): 15 | # dont add any instructions 16 | pass 17 | 18 | 19 | class DrawBotPage: 20 | def __init__(self, instructionSet): 21 | self._instructionSet = instructionSet 22 | 23 | def __enter__(self): 24 | # copy/save a state of the existing drawing tool 25 | self._originalTool = _drawBotDrawingTool._copy() 26 | # load the instructions 27 | pageTool = DummyDrawBotDrawingTool(self._instructionSet) 28 | # overwrite the globals newPage and size 29 | _drawBotDrawingTool._isSinglePage = True 30 | # reset the existing one, with the page tool 31 | _drawBotDrawingTool._reset(pageTool) 32 | return self 33 | 34 | def __exit__(self, type, value, traceback): 35 | # reset the main drawing tool with a saved state of the tool 36 | _drawBotDrawingTool._reset(self._originalTool) 37 | # reset the globals newPage and size 38 | _drawBotDrawingTool._isSinglePage = False 39 | -------------------------------------------------------------------------------- /drawBot/drawBotSettings.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.132" 2 | -------------------------------------------------------------------------------- /drawBot/macOSVersion.py: -------------------------------------------------------------------------------- 1 | from packaging.version import Version 2 | import platform 3 | 4 | macOSVersion = Version(platform.mac_ver("0.0.0")[0]) 5 | -------------------------------------------------------------------------------- /drawBot/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/drawBot/ui/__init__.py -------------------------------------------------------------------------------- /drawBot/ui/debug.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from AppKit import NSPanel # type: ignore 4 | from Foundation import NSLog # type: ignore 5 | from vanilla import FloatingWindow 6 | 7 | from .codeEditor import OutPutEditor 8 | 9 | 10 | class ShowHideNSPanel(NSPanel): 11 | def close(self): 12 | self.orderOut_(None) 13 | 14 | 15 | class ShowHideFloatingWindow(FloatingWindow): 16 | nsWindowClass = ShowHideNSPanel 17 | 18 | 19 | class DebugWindowController: 20 | """ 21 | Debugger catching all sys.stdout and sys.sterr outside a script. 22 | """ 23 | 24 | def __init__(self): 25 | self.w = ShowHideFloatingWindow( 26 | (300, 500), "Debugger", minSize=(200, 300), autosaveName="DrawBotDebugWindow", initiallyVisible=False 27 | ) 28 | 29 | self.w.debugText = OutPutEditor((0, 0, -0, -0), readOnly=True) 30 | 31 | self._savedStdout = sys.stdout 32 | self._savedStderr = sys.stderr 33 | 34 | sys.stdout = self 35 | sys.stderr = self 36 | 37 | self.w.open() 38 | 39 | def showHide(self): 40 | if self.w.isVisible(): 41 | self.w.hide() 42 | else: 43 | self.show() 44 | 45 | def show(self): 46 | self.w.show() 47 | self.w.select() 48 | 49 | def clear(self, sender=None): 50 | """ 51 | Clear all text in the output window. 52 | """ 53 | self.w.debugText.clear() 54 | 55 | def write(self, inputText): 56 | """ 57 | Write text in the output window. 58 | Duplicate the text also in the default logging system 59 | so it will appear in the console.app. 60 | """ 61 | NSLog(inputText) 62 | self.w.debugText.append(inputText) 63 | self.w.debugText.scrollToEnd() 64 | 65 | def flush(self): 66 | pass 67 | -------------------------------------------------------------------------------- /drawBot/ui/drawBotPackageController.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from defconAppKit.windows.baseWindow import BaseWindowController 4 | 5 | import vanilla 6 | 7 | from drawBot.drawBotPackage import DrawBotPackage 8 | 9 | 10 | class DrawBotPackageController(BaseWindowController): 11 | packageInfo = [ 12 | "name", 13 | "version", 14 | "developer", 15 | "developerURL", 16 | "requiresVersion", 17 | "mainScript", 18 | ] 19 | 20 | def __init__(self): 21 | self.bundle = DrawBotPackage() 22 | 23 | self.w = vanilla.Window((350, 320), "Package builder") 24 | 25 | y = 10 26 | m = 120 27 | for attr in self.packageInfo: 28 | text = vanilla.TextBox((10, y, m - 15, 22), "%s:" % attr, alignment="right") 29 | edit = vanilla.EditText((m, y, -10, 22), placeholder=getattr(self.bundle.info, attr)) 30 | 31 | setattr(self.w, "%s_text" % attr, text) 32 | setattr(self.w, "%s_edit" % attr, edit) 33 | y += 30 34 | 35 | self.w.note = vanilla.TextBox((m, y, -10, 22), "Everything is optional.", sizeStyle="mini") 36 | y += 30 37 | self.w.h1 = vanilla.HorizontalLine((0, y, 0, 1)) 38 | y += 10 39 | self.w.scriptRoot_text = vanilla.TextBox((10, y, m - 15, 22), "Script Root:", alignment="right") 40 | self.w.scriptRoot = vanilla.PathControl( 41 | (m, y - 2, -10, 22), None, pathStyle="popUp", callback=self.scriptRootCallback 42 | ) 43 | y += 25 44 | self.w.scriptRoot_note = vanilla.TextBox( 45 | (m, y, -10, 22), "A folder containing all required python files.", sizeStyle="mini" 46 | ) 47 | 48 | self.w.buildButton = vanilla.Button((-120, -30, -10, 22), "Build", callback=self.buildCallback) 49 | self.w.open() 50 | 51 | def scriptRootCallback(self, sender): 52 | url = sender.get() 53 | if url and not os.path.isdir(url): 54 | sender.set(None) 55 | self.showMessage("Package error.", "The script root must be a folder.") 56 | 57 | def buildCallback(self, sender): 58 | for attr in self.packageInfo: 59 | control = getattr(self.w, "%s_edit" % attr) 60 | value = str(control.get()) 61 | if value: 62 | setattr(self.bundle.info, attr, value) 63 | root = self.w.scriptRoot.get() 64 | if root is None: 65 | self.showMessage("Package error.", "A scripting root must be provided.") 66 | return 67 | 68 | def saveBundle(path): 69 | if path: 70 | succes, report = self.bundle.buildPackage(path, root) 71 | if not succes: 72 | self.showMessage("Package error.", report) 73 | 74 | self.showPutFile(["drawbot"], saveBundle) 75 | -------------------------------------------------------------------------------- /examples/roundedRect.py: -------------------------------------------------------------------------------- 1 | import drawBot as db 2 | 3 | 4 | def roundedRect( 5 | x: float, 6 | y: float, 7 | w: float, 8 | h: float, 9 | radius: float, 10 | radiusBottomRight: float | None = None, 11 | radiusTopRight: float | None = None, 12 | radiusTopLeft: float | None = None, 13 | ): 14 | """ 15 | Draw a rounded rect from position `x`, `y` with given width and height and given `radius`. 16 | 17 | A radiuses that exceeds the width or height of the rectangle will be clipped. 18 | 19 | Optionally a radius could be provided for each corner the following order: 20 | bottom left, bottom right, top right, top left 21 | 22 | .. downloadcode:: roundedRect.py 23 | 24 | # draw a rounding rect 25 | # x y w h radius 26 | roundedRect(100, 100, 200, 200, 10) 27 | 28 | # x y w h bl br tr tl 29 | roundedRect(100, 330, 200, 200, 10, 30, 40, 50) 30 | """ 31 | # do some checking on the radiuses 32 | radiusBottomLeft = radius 33 | if radiusTopLeft is None and radiusTopRight is None and radiusBottomRight is None: 34 | radiusTopLeft = radiusTopRight = radiusBottomRight = radius 35 | 36 | assert radius and radiusBottomRight and radiusTopRight and radiusTopLeft 37 | if radiusBottomLeft + radiusBottomRight > w: 38 | diff = (radiusBottomLeft + radiusBottomRight - w) * 0.5 39 | radiusBottomLeft -= diff 40 | radiusBottomRight -= diff 41 | if radiusTopLeft + radiusTopRight > w: 42 | diff = (radiusTopLeft + radiusTopRight - w) * 0.5 43 | radiusTopLeft -= diff 44 | radiusTopRight -= diff 45 | if radiusBottomLeft + radiusTopLeft > h: 46 | diff = (radiusBottomLeft + radiusTopLeft - h) * 0.5 47 | radiusBottomLeft -= diff 48 | radiusTopLeft -= diff 49 | if radiusBottomRight + radiusTopRight > h: 50 | diff = (radiusBottomRight + radiusTopRight - h) * 0.5 51 | radiusBottomRight -= diff 52 | radiusTopRight -= diff 53 | 54 | minValue = min(w, h) 55 | 56 | if radiusBottomRight < 0: 57 | radiusBottomRight = 0 58 | if radiusTopRight < 0: 59 | radiusTopRight = 0 60 | if radiusBottomLeft < 0: 61 | radiusBottomLeft = 0 62 | if radiusTopLeft < 0: 63 | radiusTopLeft = 0 64 | 65 | if radiusBottomRight > minValue: 66 | radiusBottomRight = minValue 67 | if radiusTopRight > minValue: 68 | radiusTopRight = minValue 69 | if radiusBottomLeft > minValue: 70 | radiusBottomLeft = minValue 71 | if radiusTopLeft > minValue: 72 | radiusTopLeft = minValue 73 | 74 | # start drawing 75 | path = db.BezierPath() 76 | path.moveTo((x + radiusBottomLeft, y)) 77 | path.lineTo((x + w - radiusBottomRight, y)) 78 | path.arcTo((x + w, y), (x + w, y + radiusBottomRight), radiusBottomRight) 79 | path.lineTo((x + w, y + h - radiusTopRight)) 80 | path.arcTo((x + w, y + h), (x + w - radiusTopRight, y + h), radiusTopRight) 81 | path.lineTo((x + radiusTopLeft, y + h)) 82 | path.arcTo((x, y + h), (x, y + h - radiusTopLeft), radiusTopLeft) 83 | path.lineTo((x, y + radiusBottomLeft)) 84 | path.arcTo((x, y), (x + radiusBottomLeft, y), radiusBottomLeft) 85 | path.closePath() 86 | db.drawPath(path) 87 | 88 | 89 | if __name__ == "__main__": 90 | # draw a rounded rect 91 | roundedRect(10, 10, 100, 100, 20, 20, 70, 90) 92 | -------------------------------------------------------------------------------- /examples/star.py: -------------------------------------------------------------------------------- 1 | from math import cos, pi, sin 2 | 3 | import drawBot as db 4 | 5 | 6 | def star(center, points, inner, outer): 7 | # create a new path 8 | db.newPath() 9 | # move the pen to the initial position 10 | X, Y = center 11 | db.moveTo((X, Y + outer)) 12 | for i in range(1, int(2 * points)): 13 | angle = i * pi / points 14 | x = sin(angle) 15 | y = cos(angle) 16 | if i % 2: 17 | radius = inner 18 | else: 19 | radius = outer 20 | x = X + radius * x 21 | y = Y + radius * y 22 | db.lineTo((x, y)) 23 | db.closePath() 24 | db.drawPath() 25 | 26 | 27 | if __name__ == "__main__": 28 | star((312, 344), 5, 60, 110) 29 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The BSD License 2 | 3 | Copyright (c) 2003-2019 Just van Rossum, Erik van Blokland, Frederik Berlaen 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 9 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # https://stackoverflow.com/questions/78859635/py2app-error-17-file-exists-when-running-py2app-for-the-first-time 2 | setuptools==70.3.0 3 | packaging 4 | pyobjc 5 | corefoundationasyncio 6 | py2app 7 | cocoa-vanilla==0.5.0 8 | defcon 9 | git+https://github.com/robotools/defconAppKit 10 | fontTools[ufo,lxml,woff,unicode,type1] 11 | fs 12 | brotli 13 | pygments 14 | jedi 15 | pillow==10.1.0 # 10.2.0 has an incompatibility with older x86 macOS: https://github.com/python-pillow/Pillow/issues/6862#issuecomment-1913552472 16 | attrs 17 | booleanOperations 18 | mutatorMath 19 | git+https://github.com/robotools/fontParts 20 | fontMath 21 | git+https://github.com/robotools/fontPens 22 | git+https://github.com/typesupply/woffTools 23 | git+https://github.com/robotools/compositor 24 | git+https://github.com/robotools/extractor 25 | git+https://github.com/typesupply/ufo2svg 26 | git+https://github.com/robotools/ufo2fdk 27 | git+https://github.com/typesupply/feaPyFoFum 28 | git+https://github.com/typesupply/feaTools2 29 | pip 30 | packaging 31 | ruff-api 32 | pytz 33 | delocate==0.10.7 # for merging intel+silicon wheels into universal2 34 | -------------------------------------------------------------------------------- /ruff.toml: -------------------------------------------------------------------------------- 1 | line-length = 120 2 | target-version = "py311" 3 | -------------------------------------------------------------------------------- /scripting/generateDrawbotInit.py: -------------------------------------------------------------------------------- 1 | """ 2 | We need to "physically" write the names of the functions/methods that are exposed 3 | with the drawBot module to allow static analysis by tools like mypy or pyright 4 | to leverage the hints we have in the interfaces 5 | 6 | """ 7 | 8 | from pathlib import Path 9 | 10 | import ruff_api 11 | 12 | from drawBot import _drawBotDrawingTool 13 | from drawBot.context.tools import drawBotbuiltins 14 | from drawBot.misc import ruff_options 15 | 16 | INIT_PATH = Path(__file__).parent.parent / "drawBot/__init__.py" 17 | 18 | 19 | def generateInitCode(): 20 | code = [] 21 | for name in _drawBotDrawingTool.__all__: 22 | if name.startswith("_"): 23 | continue 24 | code.append(f"{name} = _drawBotDrawingTool.{name}") 25 | 26 | code.append("") 27 | code.append("# directly import FormattedString, BezierPath, and ImageObject as classes") 28 | code.append("from drawBot.context.baseContext import FormattedString, BezierPath") 29 | code.append("from drawBot.context.tools.imageObject import ImageObject") 30 | 31 | code.append("") 32 | code.append("from drawBot.context.tools import drawBotbuiltins") 33 | for name in dir(drawBotbuiltins): 34 | if name.startswith("_"): 35 | continue 36 | code.append(f"{name} = drawBotbuiltins.{name}") 37 | 38 | initText = INIT_PATH.read_text() 39 | before = [] 40 | for eachLine in initText.splitlines(): 41 | before.append(eachLine) 42 | if eachLine == "# --- section automatically generated --- #": 43 | break 44 | 45 | return ruff_api.format_string("__init__.py", "\n".join(before) + "\n" + "\n".join(code), ruff_options()) 46 | 47 | 48 | if __name__ == "__main__": 49 | initCode = generateInitCode() 50 | INIT_PATH.write_text(initCode) 51 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import absolute_import, division, print_function 3 | 4 | import os 5 | import re 6 | import shutil 7 | 8 | from setuptools import setup 9 | 10 | _versionRE = re.compile(r"__version__\s*=\s*\"([^\"]+)\"") 11 | # read the version number for the settings file 12 | with open("drawBot/drawBotSettings.py", "r") as settings: 13 | code = settings.read() 14 | found = _versionRE.search(code) 15 | assert found is not None, "drawBot __version__ not found" 16 | __version__ = found.group(1) 17 | 18 | 19 | externalTools = ("ffmpeg", "gifsicle", "mkbitmap", "potrace") 20 | externalToolsSourceRoot = os.path.join(os.path.dirname(__file__), "Resources", "externalTools") 21 | externalToolsDestRoot = os.path.join(os.path.dirname(__file__), "drawBot", "context", "tools") 22 | 23 | # copy all external tools into drawBot.context.tools folder 24 | for externalTool in externalTools: 25 | source = os.path.join(externalToolsSourceRoot, externalTool) 26 | dest = os.path.join(externalToolsDestRoot, externalTool) 27 | shutil.copyfile(source, dest) 28 | os.chmod(dest, 0o775) 29 | 30 | 31 | setup( 32 | name="drawBot", 33 | version=__version__, 34 | description="DrawBot is a powerful tool that invites you to write simple Python scripts to generate two-dimensional graphics. The builtin graphics primitives support rectangles, ovals, (bezier) paths, polygons, text objects and transparency.", 35 | author="Just van Rossum, Erik van Blokland, Frederik Berlaen", 36 | author_email="frederik@typemytype.com", 37 | url="http://drawbot.com", 38 | license="BSD", 39 | python_requires=">=3.11", 40 | packages=["drawBot", "drawBot.context", "drawBot.context.tools", "drawBot.ui"], 41 | package_data={ 42 | "drawBot": ["context/tools/ffmpeg", "context/tools/gifsicle", "context/tools/mkbitmap", "context/tools/potrace"] 43 | }, 44 | install_requires=[ 45 | "pyobjc", 46 | "fontTools", 47 | "booleanOperations", 48 | "pillow", 49 | "packaging", 50 | ], 51 | include_package_data=True, 52 | ) 53 | 54 | # remove all external tools 55 | for externalTool in externalTools: 56 | dest = os.path.join(externalToolsDestRoot, externalTool) 57 | os.remove(dest) 58 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | pillow 2 | attrs 3 | packaging 4 | mypy 5 | ruff 6 | ruff-api 7 | -------------------------------------------------------------------------------- /tests/data/MutatorSans.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/MutatorSans.ttc -------------------------------------------------------------------------------- /tests/data/MutatorSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/MutatorSans.ttf -------------------------------------------------------------------------------- /tests/data/drawBot.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/drawBot.bmp -------------------------------------------------------------------------------- /tests/data/drawBot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/drawBot.jpg -------------------------------------------------------------------------------- /tests/data/drawBot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/drawBot.pdf -------------------------------------------------------------------------------- /tests/data/drawBot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/drawBot.png -------------------------------------------------------------------------------- /tests/data/drawBot144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/drawBot144.png -------------------------------------------------------------------------------- /tests/data/example_appendGlyphFormattedString.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_appendGlyphFormattedString.png -------------------------------------------------------------------------------- /tests/data/example_bezierPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_bezierPath.png -------------------------------------------------------------------------------- /tests/data/example_blendMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_blendMode.png -------------------------------------------------------------------------------- /tests/data/example_clipPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_clipPath.png -------------------------------------------------------------------------------- /tests/data/example_cmykFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_cmykFill.png -------------------------------------------------------------------------------- /tests/data/example_cmykLinearGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_cmykLinearGradient.png -------------------------------------------------------------------------------- /tests/data/example_cmykRadialGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_cmykRadialGradient.png -------------------------------------------------------------------------------- /tests/data/example_cmykShadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_cmykShadow.png -------------------------------------------------------------------------------- /tests/data/example_cmykStroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_cmykStroke.png -------------------------------------------------------------------------------- /tests/data/example_colorSpace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_colorSpace.png -------------------------------------------------------------------------------- /tests/data/example_drawPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_drawPath.png -------------------------------------------------------------------------------- /tests/data/example_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_fill.png -------------------------------------------------------------------------------- /tests/data/example_fontNamedInstance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_fontNamedInstance.png -------------------------------------------------------------------------------- /tests/data/example_fontVariations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_fontVariations.png -------------------------------------------------------------------------------- /tests/data/example_formattedString.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_formattedString.png -------------------------------------------------------------------------------- /tests/data/example_frameDuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_frameDuration.png -------------------------------------------------------------------------------- /tests/data/example_hyphenation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_hyphenation.png -------------------------------------------------------------------------------- /tests/data/example_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_image.png -------------------------------------------------------------------------------- /tests/data/example_imageObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_imageObject.png -------------------------------------------------------------------------------- /tests/data/example_indent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_indent.png -------------------------------------------------------------------------------- /tests/data/example_installFont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_installFont.png -------------------------------------------------------------------------------- /tests/data/example_language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_language.png -------------------------------------------------------------------------------- /tests/data/example_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_line.png -------------------------------------------------------------------------------- /tests/data/example_lineCap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_lineCap.png -------------------------------------------------------------------------------- /tests/data/example_lineDash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_lineDash.png -------------------------------------------------------------------------------- /tests/data/example_lineHeight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_lineHeight.png -------------------------------------------------------------------------------- /tests/data/example_lineJoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_lineJoin.png -------------------------------------------------------------------------------- /tests/data/example_linearGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_linearGradient.png -------------------------------------------------------------------------------- /tests/data/example_miterLimit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_miterLimit.png -------------------------------------------------------------------------------- /tests/data/example_newDrawing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_newDrawing.png -------------------------------------------------------------------------------- /tests/data/example_newPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_newPage.png -------------------------------------------------------------------------------- /tests/data/example_opacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_opacity.png -------------------------------------------------------------------------------- /tests/data/example_openTypeFeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_openTypeFeatures.png -------------------------------------------------------------------------------- /tests/data/example_openTypeFeaturesFormattedString.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_openTypeFeaturesFormattedString.png -------------------------------------------------------------------------------- /tests/data/example_oval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_oval.png -------------------------------------------------------------------------------- /tests/data/example_overflowText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_overflowText.png -------------------------------------------------------------------------------- /tests/data/example_pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_pages.png -------------------------------------------------------------------------------- /tests/data/example_pixelColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_pixelColor.png -------------------------------------------------------------------------------- /tests/data/example_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_polygon.png -------------------------------------------------------------------------------- /tests/data/example_printImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_printImage.png -------------------------------------------------------------------------------- /tests/data/example_radialGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_radialGradient.png -------------------------------------------------------------------------------- /tests/data/example_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_rect.png -------------------------------------------------------------------------------- /tests/data/example_saveImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_saveImage.png -------------------------------------------------------------------------------- /tests/data/example_saveImageResolutionExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_saveImageResolutionExample.png -------------------------------------------------------------------------------- /tests/data/example_savedState.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_savedState.png -------------------------------------------------------------------------------- /tests/data/example_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_shadow.png -------------------------------------------------------------------------------- /tests/data/example_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_size.png -------------------------------------------------------------------------------- /tests/data/example_strikethrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_strikethrough.png -------------------------------------------------------------------------------- /tests/data/example_stroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_stroke.png -------------------------------------------------------------------------------- /tests/data/example_strokeWidth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_strokeWidth.png -------------------------------------------------------------------------------- /tests/data/example_tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_tabs.png -------------------------------------------------------------------------------- /tests/data/example_tabsFormattedString.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_tabsFormattedString.png -------------------------------------------------------------------------------- /tests/data/example_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_text.png -------------------------------------------------------------------------------- /tests/data/example_textBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_textBox.png -------------------------------------------------------------------------------- /tests/data/example_textBoxInPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_textBoxInPath.png -------------------------------------------------------------------------------- /tests/data/example_textRTL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_textRTL.png -------------------------------------------------------------------------------- /tests/data/example_tracking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_tracking.png -------------------------------------------------------------------------------- /tests/data/example_underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_underline.png -------------------------------------------------------------------------------- /tests/data/example_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_url.png -------------------------------------------------------------------------------- /tests/data/example_variablesUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/example_variablesUI.png -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithFontVariations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_appendGlyphWithFontVariations.pdf -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithFontVariations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_appendGlyphWithFontVariations.png -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithFontVariations.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | & 6 | 7 | 8 | � 9 | 10 | 11 | � 12 | 13 | 14 | & 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithTracking.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_appendGlyphWithTracking.pdf -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithTracking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_appendGlyphWithTracking.png -------------------------------------------------------------------------------- /tests/data/expected_appendGlyphWithTracking.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | � 6 | 7 | 8 | � 9 | 10 | 11 | 12 | 13 | � 14 | 15 | 16 | � 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_booleanOperations.pdf -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_booleanOperations.png -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_booleanOperations2.pdf -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_booleanOperations2.png -------------------------------------------------------------------------------- /tests/data/expected_booleanOperations2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/data/expected_centeredTransform.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_centeredTransform.pdf -------------------------------------------------------------------------------- /tests/data/expected_centeredTransform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_centeredTransform.png -------------------------------------------------------------------------------- /tests/data/expected_centeredTransform.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/data/expected_centeredTransformBezierPath.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_centeredTransformBezierPath.pdf -------------------------------------------------------------------------------- /tests/data/expected_centeredTransformBezierPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_centeredTransformBezierPath.png -------------------------------------------------------------------------------- /tests/data/expected_centeredTransformBezierPath.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/data/expected_cmykFill.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykFill.pdf -------------------------------------------------------------------------------- /tests/data/expected_cmykFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykFill.png -------------------------------------------------------------------------------- /tests/data/expected_cmykLinearGradient.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykLinearGradient.pdf -------------------------------------------------------------------------------- /tests/data/expected_cmykLinearGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykLinearGradient.png -------------------------------------------------------------------------------- /tests/data/expected_cmykLinearGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/data/expected_cmykRadialGradient.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykRadialGradient.pdf -------------------------------------------------------------------------------- /tests/data/expected_cmykRadialGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_cmykRadialGradient.png -------------------------------------------------------------------------------- /tests/data/expected_cmykRadialGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/data/expected_dashStroke.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_dashStroke.pdf -------------------------------------------------------------------------------- /tests/data/expected_dashStroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_dashStroke.png -------------------------------------------------------------------------------- /tests/data/expected_dashStroke.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/data/expected_fill.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fill.pdf -------------------------------------------------------------------------------- /tests/data/expected_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fill.png -------------------------------------------------------------------------------- /tests/data/expected_fontAttributes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontAttributes.pdf -------------------------------------------------------------------------------- /tests/data/expected_fontAttributes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontAttributes.png -------------------------------------------------------------------------------- /tests/data/expected_fontAttributes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tests/data/expected_fontAttributes.txt: -------------------------------------------------------------------------------- 1 | Times 2 | Times-Roman 3 | True 4 | True 5 | False 6 | True 7 | True 8 | False 9 | Times.ttc 10 | ['.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign'] 11 | 37.5 12 | -12.5 13 | 22.6806640625 14 | 33.0810546875 15 | 0.0 16 | 61.0 17 | 18 | ../data/MutatorSans.ttf 19 | MutatorMathTest-LightCondensed 20 | True 21 | False 22 | False 23 | True 24 | False 25 | False 26 | MutatorSans.ttf 27 | ['A', 'B', 'C', 'D', 'E', 'F'] 28 | 40.000152587890625 29 | -9.999847412109375 30 | 25.0 31 | 35.0 32 | 9.999847412109375 33 | 60.0 34 | 35 | AppleColorEmoji 36 | True 37 | 38 | MutatorMathTest-LightCondensed 39 | MutatorSans.ttc 0 40 | MutatorMathTest-LightWide 41 | MutatorSans.ttc 1 42 | MutatorMathTest-BoldCondensed 43 | MutatorSans.ttc 2 44 | MutatorMathTest-BoldWide 45 | MutatorSans.ttc 3 46 | 47 | Courier Courier.ttc 0 48 | Courier-Bold Courier.ttc 1 49 | Courier-Oblique Courier.ttc 2 50 | -------------------------------------------------------------------------------- /tests/data/expected_fontPath.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontPath.pdf -------------------------------------------------------------------------------- /tests/data/expected_fontPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontPath.png -------------------------------------------------------------------------------- /tests/data/expected_fontVariations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontVariations.pdf -------------------------------------------------------------------------------- /tests/data/expected_fontVariations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontVariations.png -------------------------------------------------------------------------------- /tests/data/expected_fontVariations.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello Q 6 | 7 | 8 | 9 | 10 | Hello Q 11 | 12 | 13 | 14 | 15 | Hello Q 16 | 17 | 18 | 19 | 20 | Hello Q 21 | 22 | 23 | 24 | 25 | Hello Q 26 | 27 | 28 | 29 | 30 | Hello Q 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/data/expected_fontVariations.txt: -------------------------------------------------------------------------------- 1 | *** DrawBot warning: fontVariations(None) is deprecated, use fontVariations(resetVariations=True) instead. *** 2 | wdth [('defaultValue', 1.0), ('maxValue', 1.3), ('minValue', 0.62), ('name', 'Width')] 3 | wght [('defaultValue', 1.0), ('maxValue', 3.2), ('minValue', 0.48), ('name', 'Weight')] 4 | -------------------------------------------------------------------------------- /tests/data/expected_fontVariations2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontVariations2.pdf -------------------------------------------------------------------------------- /tests/data/expected_fontVariations2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_fontVariations2.png -------------------------------------------------------------------------------- /tests/data/expected_fontVariations2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello Q 6 | 7 | 8 | Hello Q 9 | 10 | 11 | Hello Q 12 | 13 | 14 | Hello Q 15 | 16 | 17 | Hello Q 18 | 19 | 20 | Hello Q 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/data/expected_fontVariations2.txt: -------------------------------------------------------------------------------- 1 | *** DrawBot warning: fontVariations(None) is deprecated, use fontVariations(resetVariations=True) instead. *** 2 | -------------------------------------------------------------------------------- /tests/data/expected_formattedStringURL.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | foo 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/data/expected_image.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image.pdf -------------------------------------------------------------------------------- /tests/data/expected_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image.png -------------------------------------------------------------------------------- /tests/data/expected_image2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image2.pdf -------------------------------------------------------------------------------- /tests/data/expected_image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image2.png -------------------------------------------------------------------------------- /tests/data/expected_image3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image3.pdf -------------------------------------------------------------------------------- /tests/data/expected_image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image3.png -------------------------------------------------------------------------------- /tests/data/expected_image4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image4.pdf -------------------------------------------------------------------------------- /tests/data/expected_image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_image4.png -------------------------------------------------------------------------------- /tests/data/expected_imageAntiAliasing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imageAntiAliasing.png -------------------------------------------------------------------------------- /tests/data/expected_imageFontSubpixelQuantization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imageFontSubpixelQuantization.png -------------------------------------------------------------------------------- /tests/data/expected_imageHTTP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imageHTTP.pdf -------------------------------------------------------------------------------- /tests/data/expected_imageHTTP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imageHTTP.png -------------------------------------------------------------------------------- /tests/data/expected_imagePixelColor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imagePixelColor.pdf -------------------------------------------------------------------------------- /tests/data/expected_imagePixelColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_imagePixelColor.png -------------------------------------------------------------------------------- /tests/data/expected_imagePixelColor.txt: -------------------------------------------------------------------------------- 1 | CG: 0.0 0.0 0.502 2 | PIL: 0.0 0.0 0.502 3 | 4 | CG: 0.0 0.251 0.502 5 | PIL: 0.0 0.251 0.502 6 | 7 | CG: 0.0 0.502 0.502 8 | PIL: 0.0 0.502 0.502 9 | 10 | CG: 0.0 0.749 0.502 11 | PIL: 0.0 0.749 0.502 12 | 13 | CG: 0.251 0.0 0.502 14 | PIL: 0.251 0.0 0.502 15 | 16 | CG: 0.251 0.251 0.502 17 | PIL: 0.251 0.251 0.502 18 | 19 | CG: 0.251 0.502 0.502 20 | PIL: 0.251 0.502 0.502 21 | 22 | CG: 0.251 0.749 0.502 23 | PIL: 0.251 0.749 0.502 24 | 25 | CG: 0.502 0.0 0.502 26 | PIL: 0.502 0.0 0.502 27 | 28 | CG: 0.502 0.251 0.502 29 | PIL: 0.502 0.251 0.502 30 | 31 | CG: 0.502 0.502 0.502 32 | PIL: 0.502 0.502 0.502 33 | 34 | CG: 0.502 0.749 0.502 35 | PIL: 0.502 0.749 0.502 36 | 37 | CG: 0.749 0.0 0.502 38 | PIL: 0.749 0.0 0.502 39 | 40 | CG: 0.749 0.251 0.502 41 | PIL: 0.749 0.251 0.502 42 | 43 | CG: 0.749 0.502 0.502 44 | PIL: 0.749 0.502 0.502 45 | 46 | CG: 0.749 0.749 0.502 47 | PIL: 0.749 0.749 0.502 48 | 49 | -------------------------------------------------------------------------------- /tests/data/expected_line.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_line.pdf -------------------------------------------------------------------------------- /tests/data/expected_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_line.png -------------------------------------------------------------------------------- /tests/data/expected_line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/data/expected_linearGradient.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_linearGradient.pdf -------------------------------------------------------------------------------- /tests/data/expected_linearGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_linearGradient.png -------------------------------------------------------------------------------- /tests/data/expected_linearGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures.pdf -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures.png -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hoefler Fact #123 6 | 7 | 8 | 9 | 10 | Hoefler Fact #123 11 | 12 | 13 | 14 | 15 | Hoefler Fact #123 16 | 17 | 18 | 19 | 20 | Hoefler Fact #123 21 | 22 | 23 | 24 | 25 | Hoefler Fact #123 26 | 27 | 28 | 29 | 30 | Hoefler Fact #123 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures.txt: -------------------------------------------------------------------------------- 1 | ['dlig', 'liga', 'lnum', 'onum', 'pnum', 'titl', 'tnum'] 2 | *** DrawBot warning: openTypeFeatures(None) is deprecated, use openTypeFeatures(resetFeatures=True) instead. *** 3 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures2.pdf -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures2.png -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hoefler Fact #123 6 | 7 | 8 | Hoefler Fact #123 9 | 10 | 11 | Hoefler Fact #123 12 | 13 | 14 | Hoefler Fact #123 15 | 16 | 17 | Hoefler Fact #123 18 | 19 | 20 | Hoefler Fact #123 21 | 22 | 23 | Hoefler Fact #123 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures2.txt: -------------------------------------------------------------------------------- 1 | *** DrawBot warning: openTypeFeatures(None) is deprecated, use openTypeFeatures(resetFeatures=True) instead. *** 2 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures_kern.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures_kern.pdf -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures_kern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_openTypeFeatures_kern.png -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures_kern.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ToTAVAT. 6 | 7 | 8 | 9 | 10 | ToTAVAT. 11 | 12 | 13 | 14 | 15 | ToTAVAT. 16 | 17 | 18 | 19 | 20 | ToTAVAT. 21 | 22 | 23 | 24 | 25 | ToTAVAT. 26 | 27 | 28 | 29 | 30 | ToTAVAT. 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/data/expected_openTypeFeatures_kern.txt: -------------------------------------------------------------------------------- 1 | *** DrawBot warning: OpenType feature 'kern' not available for 'Times' *** 2 | -------------------------------------------------------------------------------- /tests/data/expected_oval.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_oval.pdf -------------------------------------------------------------------------------- /tests/data/expected_oval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_oval.png -------------------------------------------------------------------------------- /tests/data/expected_path.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_path.pdf -------------------------------------------------------------------------------- /tests/data/expected_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_path.png -------------------------------------------------------------------------------- /tests/data/expected_path.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/data/expected_pathWithCounter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_pathWithCounter.pdf -------------------------------------------------------------------------------- /tests/data/expected_pathWithCounter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_pathWithCounter.png -------------------------------------------------------------------------------- /tests/data/expected_pathWithCounter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/data/expected_polygon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_polygon.pdf -------------------------------------------------------------------------------- /tests/data/expected_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_polygon.png -------------------------------------------------------------------------------- /tests/data/expected_polygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/data/expected_radialGradient.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_radialGradient.pdf -------------------------------------------------------------------------------- /tests/data/expected_radialGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_radialGradient.png -------------------------------------------------------------------------------- /tests/data/expected_radialGradient.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/expected_rect.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_rect.pdf -------------------------------------------------------------------------------- /tests/data/expected_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_rect.png -------------------------------------------------------------------------------- /tests/data/expected_rect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/data/expected_removeOverlap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_removeOverlap.pdf -------------------------------------------------------------------------------- /tests/data/expected_removeOverlap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_removeOverlap.png -------------------------------------------------------------------------------- /tests/data/expected_removeOverlap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/data/expected_save.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_save.pdf -------------------------------------------------------------------------------- /tests/data/expected_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_save.png -------------------------------------------------------------------------------- /tests/data/expected_save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/data/expected_save1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_save1.pdf -------------------------------------------------------------------------------- /tests/data/expected_save1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_save1.png -------------------------------------------------------------------------------- /tests/data/expected_save1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/data/expected_savedState.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_savedState.pdf -------------------------------------------------------------------------------- /tests/data/expected_savedState.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_savedState.png -------------------------------------------------------------------------------- /tests/data/expected_savedState.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/data/expected_savedState1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_savedState1.pdf -------------------------------------------------------------------------------- /tests/data/expected_savedState1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_savedState1.png -------------------------------------------------------------------------------- /tests/data/expected_savedState1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/data/expected_shapes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_shapes.pdf -------------------------------------------------------------------------------- /tests/data/expected_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_shapes.png -------------------------------------------------------------------------------- /tests/data/expected_shapes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/data/expected_svgLinkURL.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/data/expected_svgMixin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | world 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/data/expected_svgSaveFallback.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | a 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/data/expected_text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_text.pdf -------------------------------------------------------------------------------- /tests/data/expected_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_text.png -------------------------------------------------------------------------------- /tests/data/expected_text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | hello world 6 | 7 | 8 | 9 | 10 | foo bar 11 | 12 | 13 | 14 | 15 | foo bar 16 | 17 | 18 | 19 | 20 | 21 | foo bar 22 | 23 | 24 | 25 | 26 | foo bar 27 | 28 | 29 | 30 | 31 | foo bar 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/data/expected_text2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_text2.pdf -------------------------------------------------------------------------------- /tests/data/expected_text2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_text2.png -------------------------------------------------------------------------------- /tests/data/expected_textBox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_textBox.pdf -------------------------------------------------------------------------------- /tests/data/expected_textBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_textBox.png -------------------------------------------------------------------------------- /tests/data/expected_textBox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello there, 7 | 8 | 9 | hi people, 10 | 11 | 12 | dear reader. 13 | 14 | 15 | 16 | 17 | 18 | Hello there, 19 | 20 | 21 | hi people, 22 | 23 | 24 | dear reader. 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/data/expected_textBoxLongText.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_textBoxLongText.pdf -------------------------------------------------------------------------------- /tests/data/expected_textBoxLongText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_textBoxLongText.png -------------------------------------------------------------------------------- /tests/data/expected_textBoxLongText.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fiflfiflfiflfiflfiflfiflfiflfiflfi 6 | 7 | 8 | flfiflfiflfiflfiflfiflfiflfiflfifl 9 | 10 | 11 | fiflfiflfiflfiflfiflfiflfiflfiflfi 12 | 13 | 14 | flfiflfiflfiflfiflfiflfiflfiflfifl 15 | 16 | 17 | fiflfiflfiflfiflfiflfiflfiflfiflfi 18 | 19 | 20 | flfiflfiflfiflfiflfiflfiflfiflfifl 21 | 22 | 23 | fiflfiflfiflfiflfiflfiflfiflfiflfi 24 | 25 | 26 | flfiflfiflfiflfiflfiflfiflfiflfifl 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/data/expected_traceback.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_traceback.pdf -------------------------------------------------------------------------------- /tests/data/expected_traceback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/expected_traceback.png -------------------------------------------------------------------------------- /tests/data/expected_traceback.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tests/data/expected_traceback.txt: -------------------------------------------------------------------------------- 1 | Traceback (most recent call last): 2 | ... 3 | ZeroDivisionError: division by zero 4 | -------------------------------------------------------------------------------- /tests/data/fontVariations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typemytype/drawbot/68255e32cba97b0fcc65507f3fdd1598f42b9150/tests/data/fontVariations.png -------------------------------------------------------------------------------- /tests/data/scriptRunnerTest.py: -------------------------------------------------------------------------------- 1 | # test file used by testMisc.MiscTest.test_ScriptRunner_fromPath 2 | print(__file__) 3 | print(__name__) 4 | print("Åbenrå") 5 | -------------------------------------------------------------------------------- /tests/drawBotScripts/appendGlyphWithFontVariations.py: -------------------------------------------------------------------------------- 1 | # https://github.com/typemytype/drawbot/issues/402 2 | import drawBot 3 | 4 | drawBot.size(640, 160) 5 | 6 | fs = drawBot.FormattedString() 7 | fs.font("Skia") 8 | fs.fontSize(200) 9 | fs.fontVariations(wght=1) 10 | fs += "&" 11 | fs.appendGlyph("ampersand") 12 | fs.fontVariations(wght=2) 13 | fs.appendGlyph("ampersand") 14 | fs += "&" 15 | 16 | drawBot.text(fs, (10, 10)) 17 | -------------------------------------------------------------------------------- /tests/drawBotScripts/appendGlyphWithTracking.py: -------------------------------------------------------------------------------- 1 | # https://github.com/typemytype/drawbot/issues/427 2 | import drawBot 3 | 4 | drawBot.size(200, 200) 5 | 6 | fs = drawBot.FormattedString() 7 | fs.font("Lucida Grande") 8 | fs.fontSize(50) 9 | fs.appendGlyph("H") 10 | fs.appendGlyph("i") 11 | drawBot.text(fs, (30, 110)) 12 | 13 | fs = drawBot.FormattedString() 14 | fs.font("Lucida Grande") 15 | fs.fontSize(50) 16 | fs.tracking(10) 17 | fs.appendGlyph("H") 18 | fs.appendGlyph("i") 19 | drawBot.text(fs, (30, 50)) 20 | -------------------------------------------------------------------------------- /tests/drawBotScripts/booleanOperations.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.size(600, 100) 5 | p1 = drawBot.BezierPath() 6 | p1.oval(5, 5, 70, 70) 7 | p2 = drawBot.BezierPath() 8 | p2.rect(25, 25, 70, 70) 9 | drawBot.fill(0, 0.3) 10 | drawBot.stroke(0) 11 | 12 | drawBot.drawPath(p1) 13 | drawBot.drawPath(p2) 14 | 15 | pUnion = p1.union(p2) 16 | pIntersection = p1.intersection(p2) 17 | pXor = p1.xor(p2) 18 | pDiff1 = p1.difference(p2) 19 | pDiff2 = p2.difference(p1) 20 | 21 | for p in [pUnion, pIntersection, pXor, pDiff1, pDiff2]: 22 | drawBot.translate(100, 0) 23 | drawBot.drawPath(p) 24 | -------------------------------------------------------------------------------- /tests/drawBotScripts/booleanOperations2.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.size(600, 100) 5 | p1 = drawBot.BezierPath() 6 | p1.oval(5, 5, 70, 70) 7 | p2 = drawBot.BezierPath() 8 | p2.rect(25, 25, 70, 70) 9 | drawBot.fill(0, 0.3) 10 | drawBot.stroke(0) 11 | 12 | drawBot.drawPath(p1) 13 | drawBot.drawPath(p2) 14 | 15 | pUnion = p1 | p2 16 | pIntersection = p1 & p2 17 | pXor = p1 ^ p2 18 | pDiff1 = p1 % p2 19 | pDiff2 = p2 % p1 20 | 21 | for p in [pUnion, pIntersection, pXor, pDiff1, pDiff2]: 22 | drawBot.translate(100, 0) 23 | drawBot.drawPath(p) 24 | -------------------------------------------------------------------------------- /tests/drawBotScripts/centeredTransform.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.size(200, 200) 5 | 6 | 7 | def rotateScale(r, s, center): 8 | drawBot.rotate(r, center=center) 9 | drawBot.scale(s, center=center) 10 | 11 | 12 | testData = [ 13 | ((25, 25, 50, 50), drawBot.rotate, (20,), (25, 25)), 14 | ((125, 25, 50, 50), drawBot.skew, (10, 10), (175, 25)), 15 | ((25, 125, 50, 50), drawBot.scale, (1.2, 1.4), (25, 175)), 16 | ((125, 125, 50, 50), rotateScale, (20, 0.8), (175, 175)), 17 | ] 18 | 19 | for r, op, args, center in testData: 20 | drawBot.fill(0) 21 | drawBot.rect(*r) 22 | with drawBot.savedState(): 23 | drawBot.fill(1, 0, 0, 0.5) 24 | op(*args, center=center) 25 | drawBot.rect(*r) 26 | -------------------------------------------------------------------------------- /tests/drawBotScripts/centeredTransformBezierPath.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.size(200, 200) 5 | 6 | testData = [ 7 | ((25, 25, 50, 50), "rotate", (20,), (25, 25)), 8 | ((125, 25, 50, 50), "skew", (10, 10), (175, 25)), 9 | ((25, 125, 50, 50), "scale", (1.2, 1.4), (25, 175)), 10 | ] 11 | 12 | for r, op, args, center in testData: 13 | drawBot.fill(0) 14 | bez = drawBot.BezierPath() 15 | bez.rect(*r) 16 | drawBot.drawPath(bez) 17 | with drawBot.savedState(): 18 | drawBot.fill(1, 0, 0, 0.5) 19 | bez = drawBot.BezierPath() 20 | bez.rect(*r) 21 | getattr(bez, op)(*args, center=center) 22 | drawBot.drawPath(bez) 23 | -------------------------------------------------------------------------------- /tests/drawBotScripts/cmykFill.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(100, 100) 4 | for x in range(10): 5 | for y in range(10): 6 | drawBot.cmykFill(x / 10, 1 - y / 10, y / 10, 0) 7 | drawBot.rect(x * 10, y * 10, 5, 10) 8 | drawBot.cmykFill(x / 10, 1 - y / 10, y / 10, 0.2) 9 | drawBot.rect(x * 10 + 5, y * 10, 5, 5) 10 | drawBot.cmykFill(x / 10, 1 - y / 10, y / 10, 0, 0.55) 11 | drawBot.rect(x * 10 + 5, y * 10 + 5, 5, 5) 12 | -------------------------------------------------------------------------------- /tests/drawBotScripts/cmykLinearGradient.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.cmykLinearGradient( 5 | (100, 100), # startPoint 6 | (200, 200), # endPoint 7 | [(1, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0.2)], # cmyk colors 8 | [0, 0.2, 1], # locations 9 | ) 10 | drawBot.rect(0, 0, 200, 200) 11 | -------------------------------------------------------------------------------- /tests/drawBotScripts/cmykRadialGradient.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.cmykRadialGradient( 5 | (0, 0), # startPoint 6 | (200, 200), # endPoint 7 | [(1, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0.2)], # colors 8 | [0, 0.2, 1], # locations 9 | 0, # startRadius 10 | 200, # endRadius 11 | ) 12 | drawBot.rect(0, 0, 200, 200) 13 | -------------------------------------------------------------------------------- /tests/drawBotScripts/dashStroke.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.newPage(40, 40) 5 | path = drawBot.BezierPath() 6 | path.rect(10, 10, 20, 20) 7 | 8 | dashedPath = path.dashStroke(5, 5) 9 | 10 | drawBot.fill(None) 11 | drawBot.stroke(0) 12 | drawBot.drawPath(dashedPath) 13 | -------------------------------------------------------------------------------- /tests/drawBotScripts/fill.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(100, 100) 4 | drawBot.fill(0.5, 0.5) 5 | drawBot.oval(0, 0, 100, 100) 6 | for x in range(10): 7 | for y in range(10): 8 | drawBot.fill(x / 10, 1 - y / 10, y / 10, y / 20 + 0.5) 9 | drawBot.rect(x * 10, y * 10, 10, 10) 10 | -------------------------------------------------------------------------------- /tests/drawBotScripts/fontAttributes.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import drawBot 4 | 5 | drawBot.size(50, 50) 6 | characters = "Aa今" 7 | glyphNames = ["A", "a", "zzz"] 8 | for fontName in ["Times", "../data/MutatorSans.ttf"]: 9 | print(fontName) 10 | print(drawBot.font(fontName)) 11 | drawBot.fontSize(50) 12 | for char in characters: 13 | print(drawBot.fontContainsCharacters(char)) 14 | for glyphName in glyphNames: 15 | print(drawBot.fontContainsGlyph(glyphName)) 16 | print(os.path.basename(drawBot.fontFilePath())) 17 | print(drawBot.listFontGlyphNames()[:6]) 18 | print(drawBot.fontAscender()) 19 | print(drawBot.fontDescender()) 20 | print(drawBot.fontXHeight()) 21 | print(drawBot.fontCapHeight()) 22 | print(drawBot.fontLeading()) 23 | print(drawBot.fontLineHeight()) 24 | print() 25 | 26 | # https://github.com/typemytype/drawbot/issues/524 27 | print(drawBot.font("Apple Color Emoji")) 28 | print(drawBot.fontContainsCharacters(chr(0x1F004))) 29 | print() 30 | 31 | for i in range(4): 32 | print(drawBot.font("../data/MutatorSans.ttc", fontNumber=i)) 33 | print(os.path.basename(drawBot.fontFilePath()), drawBot.fontFileFontNumber()) 34 | assert drawBot.fontFileFontNumber() == i 35 | 36 | print() 37 | for fontName in ["Courier", "Courier-Bold", "Courier-Oblique"]: 38 | drawBot.font(fontName) 39 | print(fontName, os.path.basename(drawBot.fontFilePath()), drawBot.fontFileFontNumber()) 40 | -------------------------------------------------------------------------------- /tests/drawBotScripts/fontPath.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(500, 70) 4 | fontPath = "../data/MutatorSans.ttf" 5 | drawBot.font(fontPath) 6 | drawBot.fontSize(20) 7 | drawBot.text("HELLO MUTATOR", (10, 10)) 8 | drawBot.fontVariations(wdth=500, wght=900) 9 | drawBot.text("HELLO MUTATOR", (10, 40)) 10 | -------------------------------------------------------------------------------- /tests/drawBotScripts/fontVariations.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | drawBot.font("Skia") 6 | drawBot.fontSize(30) 7 | 8 | drawBot.fontVariations(None) 9 | 10 | variations = drawBot.listFontVariations() 11 | for axisTag in sorted(variations): 12 | data = variations[axisTag] 13 | # we're rounding the values so we don't trip over small differences between OSes 14 | data["defaultValue"] = round(float(data["defaultValue"]), 3) # we need floats to make sure that 1 becomes 1.0 15 | data["minValue"] = round(float(data["minValue"]), 3) 16 | data["maxValue"] = round(float(data["maxValue"]), 3) 17 | data["name"] = str(data["name"]) 18 | print(axisTag, [(k, data[k]) for k in sorted(data)]) 19 | 20 | drawBot.text("Hello Q", (20, 170)) 21 | drawBot.fontVariations(wght=0.6) 22 | drawBot.text("Hello Q", (20, 140)) 23 | drawBot.fontVariations(wght=2.4) 24 | drawBot.text("Hello Q", (20, 110)) 25 | 26 | drawBot.fontVariations(wdth=1.29) 27 | drawBot.text("Hello Q", (20, 80)) 28 | 29 | drawBot.fontVariations(wdth=0.6, resetVariations=True) 30 | drawBot.text("Hello Q", (20, 50)) 31 | 32 | drawBot.fontVariations(wght=2.8, resetVariations=False) 33 | drawBot.text("Hello Q", (20, 20)) 34 | -------------------------------------------------------------------------------- /tests/drawBotScripts/fontVariations2.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | s = drawBot.FormattedString() 6 | 7 | s.font("Skia") 8 | s.fontSize(30) 9 | s.lineHeight(30) 10 | s.fontVariations(None) 11 | 12 | s.append("Hello Q\n") 13 | s.fontVariations(wght=0.6) 14 | s.append("Hello Q\n") 15 | s.fontVariations(wght=2.4) 16 | s.append("Hello Q\n") 17 | 18 | s.append("Hello Q\n", fontVariations=dict(wdth=1.29)) 19 | 20 | s.append("Hello Q\n", fontVariations=dict(wdth=0.6, resetVariations=True)) 21 | 22 | s.fontVariations(wght=2.8, resetVariations=False) 23 | s.append("Hello Q\n") 24 | 25 | drawBot.textBox(s, (10, 0, 190, 193)) 26 | -------------------------------------------------------------------------------- /tests/drawBotScripts/image.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(500, 500) 4 | imagePath = "../data/drawBot.jpg" 5 | w, h = drawBot.imageSize(imagePath) 6 | drawBot.scale(250 / w) 7 | drawBot.image(imagePath, (0, 0)) 8 | drawBot.image(imagePath, (w, 0), alpha=0.5) 9 | drawBot.image(imagePath, (0, h), alpha=0.25) 10 | drawBot.image(imagePath, (w, h), alpha=0.75) 11 | -------------------------------------------------------------------------------- /tests/drawBotScripts/image2.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(500, 500) 4 | imagePath = "../data/drawBot.png" 5 | w, h = drawBot.imageSize(imagePath) 6 | drawBot.scale(250 / w) 7 | drawBot.image(imagePath, (0, 0)) 8 | drawBot.image(imagePath, (w, 0), alpha=0.5) 9 | drawBot.image(imagePath, (0, h), alpha=0.25) 10 | drawBot.image(imagePath, (w, h), alpha=0.75) 11 | -------------------------------------------------------------------------------- /tests/drawBotScripts/image3.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(500, 500) 4 | imagePath = "../data/drawBot.pdf" 5 | w, h = drawBot.imageSize(imagePath) 6 | drawBot.scale(250 / w) 7 | drawBot.image(imagePath, (0, 0)) 8 | drawBot.image(imagePath, (w, 0), alpha=0.5) 9 | drawBot.image(imagePath, (0, h), alpha=0.25) 10 | drawBot.image(imagePath, (w, h), alpha=0.75) 11 | -------------------------------------------------------------------------------- /tests/drawBotScripts/image4.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | import drawBot 4 | 5 | drawBot.size(500, 500) 6 | imagePath = "../data/drawBot.pdf" 7 | w, h = drawBot.imageSize(imagePath) 8 | drawBot.save() 9 | drawBot.scale(250 / w) 10 | drawBot.image(imagePath, (0, 0)) 11 | drawBot.restore() 12 | 13 | imagePath = "../data/drawBot.png" 14 | w, h = drawBot.imageSize(imagePath) 15 | drawBot.save() 16 | drawBot.scale(250 / w) 17 | drawBot.image(imagePath, (w, 0)) 18 | drawBot.restore() 19 | 20 | imagePath = "../data/drawBot.jpg" 21 | w, h = drawBot.imageSize(imagePath) 22 | drawBot.save() 23 | drawBot.scale(250 / w) 24 | drawBot.image(imagePath, (0, h)) 25 | drawBot.restore() 26 | 27 | imagePath = "../data/drawBot.bmp" 28 | w, h = drawBot.imageSize(imagePath) 29 | drawBot.save() 30 | drawBot.scale(250 / w) 31 | drawBot.image(pathlib.Path(imagePath), (w, h)) # verify that pathlib.Path objects work 32 | drawBot.restore() 33 | -------------------------------------------------------------------------------- /tests/drawBotScripts/imageHTTP.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(250, 250) 4 | imagePath = "https://github.com/typemytype/drawbot/raw/master/docs/content/assets/drawBot.jpg" 5 | drawBot.scale(250 / 700) 6 | drawBot.image(imagePath, (20, 20)) 7 | -------------------------------------------------------------------------------- /tests/drawBotScripts/imagePixelColor.py: -------------------------------------------------------------------------------- 1 | # This is a test case derived from https://github.com/typemytype/drawbot/issues/171 2 | # It ensures that rgb values specified in fill() end up in image output without 3 | # being mangled by a color space (within 8-bit resulution). 4 | 5 | from PIL import Image 6 | 7 | import drawBot 8 | 9 | canvasSize = 400 10 | drawBot.size(canvasSize, canvasSize) 11 | 12 | # colorSpace("sRGB") 13 | # colorSpace("genericRGB") 14 | # colorSpace("adobeRGB1998") 15 | 16 | bands = 4 17 | bandWidth = canvasSize / bands 18 | 19 | drawBot.fontSize(10) 20 | 21 | for i in range(bands): 22 | x = i * bandWidth 23 | for j in range(bands): 24 | y = j * bandWidth 25 | r = i / bands 26 | g = j / bands 27 | b = 0.5 28 | drawBot.fill(r, g, b) 29 | drawBot.rect(x, y, bandWidth, bandWidth) 30 | drawBot.fill(0) 31 | drawBot.text("%s,%s,%s" % (r, g, b), (x + 3, y + 5)) 32 | 33 | fn = "../tempTestData/tmp_imagePixelColor.png" 34 | drawBot.saveImage(fn) 35 | 36 | im = Image.open(fn) 37 | 38 | for i in range(bands): 39 | x = (i + 0.5) * bandWidth 40 | for j in range(bands): 41 | y = (j + 0.5) * bandWidth 42 | r, g, b, a = drawBot.imagePixelColor(fn, (x, y)) 43 | print(" CG:", round(r, 4), round(g, 4), round(b, 4)) 44 | r, g, b, a = im.getpixel((x, canvasSize - y)) 45 | print("PIL:", round(r / 255, 4), round(g / 255, 4), round(b / 255, 4)) 46 | print() 47 | -------------------------------------------------------------------------------- /tests/drawBotScripts/line.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.stroke(0) 5 | drawBot.strokeWidth(10) 6 | drawBot.fill(None) 7 | drawBot.line((40, 40), (40, 160)) 8 | drawBot.line((100, 40), (160, 160)) 9 | -------------------------------------------------------------------------------- /tests/drawBotScripts/linearGradient.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.linearGradient( 5 | (100, 100), # startPoint 6 | (200, 200), # endPoint 7 | [(1, 0, 0), (0, 0, 1), (0, 1, 0)], # colors 8 | [0, 0.2, 1], # locations 9 | ) 10 | drawBot.rect(0, 0, 200, 200) 11 | -------------------------------------------------------------------------------- /tests/drawBotScripts/openTypeFeatures.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | # ['liga', 'dlig', 'tnum', 'pnum', 'titl', 'onum', 'lnum'] 6 | 7 | drawBot.font("HoeflerText-Regular") 8 | drawBot.fontSize(20) 9 | print(drawBot.listOpenTypeFeatures()) 10 | 11 | drawBot.text("Hoefler Fact #123", (20, 170)) 12 | 13 | drawBot.openTypeFeatures(None) 14 | 15 | drawBot.openTypeFeatures(dlig=True) 16 | drawBot.text("Hoefler Fact #123", (20, 140)) 17 | 18 | drawBot.openTypeFeatures(lnum=True) 19 | drawBot.text("Hoefler Fact #123", (20, 110)) 20 | 21 | drawBot.openTypeFeatures(liga=False) 22 | drawBot.text("Hoefler Fact #123", (20, 80)) 23 | 24 | drawBot.openTypeFeatures(liga=True, resetFeatures=False) 25 | drawBot.text("Hoefler Fact #123", (20, 50)) 26 | 27 | drawBot.openTypeFeatures(liga=False, resetFeatures=True) 28 | drawBot.text("Hoefler Fact #123", (20, 20)) 29 | -------------------------------------------------------------------------------- /tests/drawBotScripts/openTypeFeatures2.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | s = drawBot.FormattedString() 6 | s.font("HoeflerText-Regular") 7 | s.fontSize(20) 8 | 9 | s.append("Hoefler Fact #123\n") 10 | 11 | s.openTypeFeatures(None) 12 | 13 | s.openTypeFeatures(dlig=True) 14 | s.append("Hoefler Fact #123\n") 15 | 16 | s.openTypeFeatures(lnum=True) 17 | s.append("Hoefler Fact #123\n") 18 | 19 | s.openTypeFeatures(liga=False) 20 | s.append("Hoefler Fact #123\n") 21 | 22 | s.openTypeFeatures(liga=False, dlig=True, resetFeatures=True) 23 | s.append("Hoefler Fact #123\n") 24 | 25 | s.append("Hoefler Fact #123\n", openTypeFeatures=dict(liga=False, resetFeatures=True)) 26 | 27 | s.append("Hoefler Fact #123\n", openTypeFeatures=dict(dlig=True, resetFeatures=False)) 28 | 29 | drawBot.textBox(s, (20, 0, 200, 190)) 30 | -------------------------------------------------------------------------------- /tests/drawBotScripts/openTypeFeatures_kern.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newPage(130, 130) 4 | drawBot.font("Times") 5 | drawBot.text("ToTAVAT.", (10, 10)) 6 | drawBot.openTypeFeatures(kern=False) 7 | drawBot.text("ToTAVAT.", (10, 30)) 8 | drawBot.openTypeFeatures(kern=True) 9 | drawBot.text("ToTAVAT.", (10, 50)) 10 | # add tracking 11 | drawBot.tracking(10) 12 | drawBot.text("ToTAVAT.", (10, 70)) 13 | drawBot.openTypeFeatures(kern=False) 14 | drawBot.text("ToTAVAT.", (10, 90)) 15 | drawBot.openTypeFeatures(kern=True) 16 | drawBot.text("ToTAVAT.", (10, 110)) 17 | -------------------------------------------------------------------------------- /tests/drawBotScripts/oval.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | for i in range(14): 5 | f = i / 14.0 6 | drawBot.fill(1 - f, 1 - f, 0) 7 | drawBot.oval(10, 10, 50, 50) 8 | drawBot.translate(10, 10) 9 | -------------------------------------------------------------------------------- /tests/drawBotScripts/path.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | drawBot.newPath() 6 | drawBot.moveTo((20, 20)) 7 | drawBot.lineTo((20, 100)) 8 | drawBot.lineTo((100, 100)) 9 | drawBot.lineTo((100, 180)) 10 | drawBot.curveTo((150, 180), (180, 150), (180, 100)) 11 | drawBot.lineTo((180, 50)) 12 | drawBot.qCurveTo((180, 20), (150, 20)) 13 | 14 | drawBot.fill(1, 0, 0) 15 | drawBot.stroke(0) 16 | drawBot.strokeWidth(10) 17 | drawBot.drawPath() 18 | 19 | drawBot.closePath() 20 | 21 | drawBot.fill(None) 22 | drawBot.stroke(1) 23 | drawBot.translate(40, 15) 24 | drawBot.scale(0.7) 25 | drawBot.lineCap("round") 26 | drawBot.lineJoin("round") 27 | 28 | drawBot.drawPath() 29 | -------------------------------------------------------------------------------- /tests/drawBotScripts/pathWithCounter.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 5 | drawBot.newPath() 6 | drawBot.moveTo((20, 20)) 7 | drawBot.lineTo((20, 100)) 8 | drawBot.lineTo((100, 100)) 9 | drawBot.lineTo((100, 180)) 10 | drawBot.curveTo((150, 180), (180, 150), (180, 100)) 11 | drawBot.lineTo((180, 20)) 12 | drawBot.closePath() 13 | 14 | drawBot.moveTo((40, 40)) 15 | drawBot.lineTo((160, 40)) 16 | drawBot.curveTo((160, 65), (145, 80), (120, 80)) 17 | drawBot.lineTo((40, 80)) 18 | drawBot.closePath() 19 | 20 | drawBot.fill(0.5, 0, 0) 21 | drawBot.stroke(None) 22 | drawBot.strokeWidth(10) 23 | drawBot.drawPath() 24 | -------------------------------------------------------------------------------- /tests/drawBotScripts/polygon.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.stroke(0) 5 | drawBot.strokeWidth(10) 6 | drawBot.fill(1, 0.3, 0) 7 | drawBot.polygon((40, 40), (40, 160)) 8 | drawBot.polygon((60, 40), (60, 160), (130, 160)) 9 | drawBot.polygon((100, 40), (160, 160), (160, 40), close=False) 10 | -------------------------------------------------------------------------------- /tests/drawBotScripts/radialGradient.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.radialGradient( 5 | (0, 0), # startPoint 6 | (200, 200), # endPoint 7 | [(1, 0, 0), (0, 0, 1), (0, 1, 0)], # colors 8 | [0, 0.2, 1], # locations 9 | 0, # startRadius 10 | 200, # endRadius 11 | ) 12 | drawBot.rect(0, 0, 200, 200) 13 | -------------------------------------------------------------------------------- /tests/drawBotScripts/rect.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | for i in range(14): 5 | f = i / 14.0 6 | drawBot.fill(f, 1 - f, 0) 7 | drawBot.rect(10, 10, 50, 50) 8 | drawBot.translate(10, 10) 9 | -------------------------------------------------------------------------------- /tests/drawBotScripts/removeOverlap.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.newDrawing() 4 | drawBot.size(200, 100) 5 | p = drawBot.BezierPath() 6 | p.oval(5, 5, 70, 70) 7 | p.rect(25, 25, 70, 70) 8 | drawBot.fill(0, 0.3) 9 | drawBot.stroke(0) 10 | drawBot.drawPath(p) 11 | p.removeOverlap() 12 | drawBot.translate(100, 0) 13 | drawBot.drawPath(p) 14 | -------------------------------------------------------------------------------- /tests/drawBotScripts/save.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.stroke(0, 0, 1) 5 | drawBot.strokeWidth(5) 6 | drawBot.save() 7 | drawBot.fill(1, 0, 0) 8 | drawBot.translate(100, 100) 9 | drawBot.rect(0, 0, 100, 100) 10 | drawBot.restore() 11 | drawBot.rect(0, 0, 100, 100) 12 | drawBot.save() 13 | drawBot.fill(0, 1, 0) 14 | drawBot.translate(100, 0) 15 | drawBot.rect(0, 0, 100, 100) 16 | drawBot.restore() 17 | drawBot.rect(0, 100, 100, 100) 18 | -------------------------------------------------------------------------------- /tests/drawBotScripts/save1.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(300, 300) 4 | drawBot.save() 5 | drawBot.fill(1, 0, 0) 6 | drawBot.translate(150, 150) 7 | drawBot.rect(0, 0, 100, 100) 8 | drawBot.save() 9 | drawBot.rotate(45) 10 | drawBot.fill(0, 1, 0) 11 | drawBot.rect(0, 0, 100, 100) 12 | drawBot.restore() 13 | drawBot.restore() 14 | drawBot.rect(0, 0, 100, 100) 15 | -------------------------------------------------------------------------------- /tests/drawBotScripts/savedState.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.stroke(0, 0, 1) 5 | drawBot.strokeWidth(5) 6 | with drawBot.savedState(): 7 | drawBot.fill(1, 0, 0) 8 | drawBot.translate(100, 100) 9 | drawBot.rect(0, 0, 100, 100) 10 | drawBot.rect(0, 0, 100, 100) 11 | with drawBot.savedState(): 12 | drawBot.fill(0, 1, 0) 13 | drawBot.translate(100, 0) 14 | drawBot.rect(0, 0, 100, 100) 15 | drawBot.rect(0, 100, 100, 100) 16 | -------------------------------------------------------------------------------- /tests/drawBotScripts/savedState1.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(300, 300) 4 | with drawBot.savedState(): 5 | drawBot.fill(1, 0, 0) 6 | drawBot.translate(150, 150) 7 | drawBot.rect(0, 0, 100, 100) 8 | with drawBot.savedState(): 9 | drawBot.rotate(45) 10 | drawBot.fill(0, 1, 0) 11 | drawBot.rect(0, 0, 100, 100) 12 | drawBot.rect(0, 0, 100, 100) 13 | -------------------------------------------------------------------------------- /tests/drawBotScripts/shapes.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.fill(0) 5 | drawBot.rect(10, 10, 100, 100) 6 | drawBot.fill(None) 7 | drawBot.stroke(1, 0, 0) 8 | drawBot.strokeWidth(5) 9 | drawBot.oval(50, 50, 100, 100) 10 | -------------------------------------------------------------------------------- /tests/drawBotScripts/text.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | drawBot.text("hello world", (10, 10)) 5 | drawBot.fill(1, 0, 0) 6 | drawBot.text("foo bar", (10, 30)) 7 | drawBot.fill(1, 0, 1) 8 | drawBot.stroke(0, 1, 0) 9 | drawBot.strokeWidth(2) 10 | drawBot.font("Times", 50) 11 | drawBot.text("foo bar", (10, 50)) 12 | drawBot.fill(None) 13 | drawBot.stroke(0, 1, 0) 14 | drawBot.strokeWidth(1) 15 | drawBot.line((0, 50), (drawBot.width(), 50)) 16 | drawBot.stroke(None) 17 | drawBot.fill(0, 1, 1) 18 | drawBot.fontSize(20) 19 | drawBot.text("foo bar", (drawBot.width() * 0.5, 100), align="right") 20 | drawBot.text("foo bar", (drawBot.width() * 0.5, 120), align="center") 21 | drawBot.text("foo bar", (drawBot.width() * 0.5, 140), align="left") 22 | # test empty text https://github.com/typemytype/drawbot/issues/389 23 | drawBot.text("", (0, 0)) 24 | -------------------------------------------------------------------------------- /tests/drawBotScripts/text2.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | f = drawBot.FormattedString() 4 | f.fontSize(40) 5 | f.font("Helvetica") 6 | f.align("left") 7 | f.append("left\n") 8 | f.align("center") 9 | f.append("center\n") 10 | f.font("Times") 11 | f.align("right") 12 | f.append("right\n") 13 | 14 | _, height = f.size() 15 | x, y = drawBot.width() * 0.25, 200.0 16 | 17 | with drawBot.savedState(): 18 | drawBot.stroke(0) 19 | drawBot.line((x, 0), (x, 1000)) 20 | 21 | 22 | drawBot.text(f, (x, y)) 23 | y += height 24 | drawBot.text(f, (x, y), align="left") 25 | y += height 26 | drawBot.text(f, (x, y), align="center") 27 | y += height 28 | drawBot.text(f, (x, y), align="right") 29 | 30 | x, y = drawBot.width() * 0.75, 200 31 | with drawBot.savedState(): 32 | drawBot.stroke(0) 33 | drawBot.line((x, 0), (x, 1000)) 34 | 35 | b = drawBot.BezierPath() 36 | b.text(f) 37 | b.text(f, offset=(0, height), align="left") 38 | b.text(f, offset=(0, height * 2), align="center") 39 | b.text(f, offset=(0, height * 3), align="right") 40 | drawBot.translate(x, y) 41 | drawBot.fill(1, 0, 0) 42 | drawBot.drawPath(b) 43 | -------------------------------------------------------------------------------- /tests/drawBotScripts/textBox.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 400) 4 | box = (10, 10, 180, 180) 5 | drawBot.fill(0) 6 | drawBot.rect(*box) 7 | drawBot.fill(1) 8 | drawBot.fontSize(30) 9 | drawBot.textBox("Hello there, hi people, dear reader.", box) 10 | drawBot.translate(0, 200) 11 | box = (190, 190, -180, -180) 12 | drawBot.fill(0) 13 | drawBot.rect(*box) 14 | drawBot.fill(1) 15 | drawBot.textBox("Hello there, hi people, dear reader.", box) 16 | -------------------------------------------------------------------------------- /tests/drawBotScripts/textBoxLongText.py: -------------------------------------------------------------------------------- 1 | # See bug: https://github.com/typemytype/drawbot/issues/585 2 | import drawBot 3 | 4 | drawBot.size(200, 200) 5 | box = (10, 10, 180, 180) 6 | drawBot.fontSize(18) 7 | drawBot.font("Hoefler Text") 8 | drawBot.textBox("fifl" * 3000, box) 9 | -------------------------------------------------------------------------------- /tests/drawBotScripts/traceback.py: -------------------------------------------------------------------------------- 1 | import drawBot 2 | 3 | drawBot.size(200, 200) 4 | 1 / 0 5 | -------------------------------------------------------------------------------- /tests/package/empty.drawbot/lib/main.py: -------------------------------------------------------------------------------- 1 | print("hello world") 2 | -------------------------------------------------------------------------------- /tests/package/missingMainScript.drawbot/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | developer 6 | drawbot 7 | developerURL 8 | http://www.drawbot.com 9 | name 10 | drawbot 11 | requiresVersion 12 | 3.0 13 | version 14 | 1.0 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/package/simple.drawbot/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | developer 6 | drawbot 7 | developerURL 8 | http://www.drawbot.com 9 | name 10 | drawbot 11 | requiresVersion 12 | 3.0 13 | version 14 | 1.0 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/package/simple.drawbot/lib/main.py: -------------------------------------------------------------------------------- 1 | print("hello world") 2 | -------------------------------------------------------------------------------- /tests/runAllTests.py: -------------------------------------------------------------------------------- 1 | import doctest 2 | import glob 3 | import importlib 4 | import os 5 | import sys 6 | import unittest 7 | 8 | inDrawBotApp = "drawBot.ui.codeEditor" in sys.modules 9 | 10 | testRootDir = os.path.dirname(os.path.abspath(__file__)) 11 | if testRootDir not in sys.path: 12 | sys.path.append(testRootDir) 13 | 14 | testModules = glob.glob(os.path.join(testRootDir, "test*.py")) 15 | modulesWithDocTests = ["drawBot.misc", "testSupport"] # TODO: doctest discovery 16 | 17 | loader = unittest.TestLoader() 18 | suite = unittest.TestSuite() 19 | for path in testModules: 20 | moduleName, ext = os.path.splitext(os.path.basename(path)) 21 | suite.addTest(loader.loadTestsFromName(moduleName)) 22 | 23 | for moduleName in modulesWithDocTests: 24 | m = importlib.import_module(moduleName) 25 | suite.addTest(doctest.DocTestSuite(m)) 26 | 27 | result = unittest.TextTestRunner(verbosity=1).run(suite) 28 | if not inDrawBotApp and not result.wasSuccessful(): 29 | sys.exit(1) 30 | -------------------------------------------------------------------------------- /tests/testAutomaticallyGeneratedCode.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | from pathlib import Path 4 | 5 | sys.path.append(str((Path(__file__).parent.parent / "scripting").resolve())) 6 | 7 | from generateDrawbotInit import INIT_PATH, generateInitCode 8 | from imageObjectCodeExtractor import IMAGE_OBJECT_PATH, generateImageObjectCode 9 | 10 | 11 | class AutomaticallyGeneratedCodeTester(unittest.TestCase): 12 | def test_init(self): 13 | initCode = generateInitCode() 14 | self.assertEqual(INIT_PATH.read_text(), initCode) 15 | 16 | def test_imageObject(self): 17 | imageObjectCode, _ = generateImageObjectCode() 18 | self.assertEqual(IMAGE_OBJECT_PATH.read_text(), imageObjectCode) 19 | 20 | 21 | if __name__ == "__main__": 22 | import doctest 23 | 24 | doctest.testmod() 25 | sys.exit(unittest.main()) 26 | -------------------------------------------------------------------------------- /tests/testPackage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | 5 | from testSupport import StdOutCollector, TempFile, TempFolder 6 | 7 | from drawBot.drawBotPackage import DrawBotPackage 8 | 9 | 10 | class PackageTest(unittest.TestCase): 11 | def test_buildPackage(self): 12 | package = DrawBotPackage() 13 | package.info.name = "demo" 14 | package.info.developer = "drawbot" 15 | package.info.developerURL = "http://www.drawbot.com" 16 | package.info.requiresVersion = "3.0" 17 | package.info.mainScript = "main.py" 18 | 19 | succes, _ = package.buildPackage("does/not/exists", "does/not/exists") 20 | self.assertFalse(succes) 21 | 22 | with TempFolder(suffix=".drawbot") as tempPath: 23 | succes, _ = package.buildPackage(tempPath.path, "does/not/exists") 24 | self.assertFalse(succes) 25 | 26 | with TempFolder() as tempScriptRoot: 27 | succes, _ = package.buildPackage(tempPath.path, tempScriptRoot.path) 28 | self.assertFalse(succes) 29 | 30 | with TempFile(suffix=".py", dir=tempScriptRoot.path) as tmp: 31 | with open(tmp.path, "w") as f: 32 | f.write("print('hello world'") 33 | package.info.mainScript = os.path.basename(tmp.path) 34 | succes, _ = package.buildPackage(tempPath.path, tempScriptRoot.path) 35 | self.assertTrue(succes) 36 | 37 | def test_readPackage(self): 38 | path = os.path.join(os.path.dirname(__file__), "package/empty.drawbot") 39 | 40 | package = DrawBotPackage(path) 41 | self.assertEqual(package.info.asDict(), {}) 42 | self.assertEqual(package.info.version, "0.0") 43 | self.assertEqual(package.info.developer, "") 44 | self.assertEqual(package.info.developerURL, "") 45 | self.assertEqual(package.info.requiresVersion, "0.0") 46 | self.assertEqual(package.info.mainScript, "main.py") 47 | 48 | path = os.path.join(os.path.dirname(__file__), "package/simple.drawbot") 49 | 50 | package = DrawBotPackage(path) 51 | self.assertEqual(package.info.version, "1.0") 52 | self.assertEqual(package.info.developer, "drawbot") 53 | self.assertEqual(package.info.developerURL, "http://www.drawbot.com") 54 | self.assertEqual(package.info.requiresVersion, "3.0") 55 | self.assertEqual(package.info.mainScript, "main.py") 56 | 57 | def test_runPackages(self): 58 | path = os.path.join(os.path.dirname(__file__), "package/empty.drawbot") 59 | 60 | package = DrawBotPackage(path) 61 | with StdOutCollector() as output: 62 | succes, _ = package.run() 63 | 64 | self.assertEqual(output.lines(), ["hello world"]) 65 | 66 | def test_missingMainScript(self): 67 | path = os.path.join(os.path.dirname(__file__), "package/missingMainScript.drawbot") 68 | package = DrawBotPackage(path) 69 | succes, message = package.run() 70 | self.assertEqual(succes, False) 71 | self.assertTrue(message.startswith("Cannot find")) 72 | 73 | 74 | if __name__ == "__main__": 75 | sys.exit(unittest.main()) 76 | --------------------------------------------------------------------------------