Compare commits

...

133 Commits

Author SHA1 Message Date
Curtis Hard 8f84aa9070 Modern syntax 2019-08-15 13:16:20 +01:00
Curtis Hard 200fd6893d Fixes memory leak 2019-08-14 23:04:01 +01:00
Curtis Hard 01ad4eaeb2 Fixes clipping issue when drawing into a context 2019-07-21 22:17:58 +01:00
Curtis Hard 6b1c988d89 Added shorthand function for chcking export types 2019-07-17 22:31:13 +01:00
Curtis Hard c91ac95bc2 Swaps over normal attribute setting to a rendering style object instead 2019-07-14 15:35:40 +01:00
Curtis Hard cf14f27560 More color list features 2019-07-07 21:01:38 +01:00
Curtis Hard cef1de35d7 Inital colour sstuff 2019-07-07 20:26:39 +01:00
Curtis Hard c1a98ef5a6 Update all things! 2019-07-07 11:27:20 +01:00
Curtis Hard 690e1c8619 visibleColors now also returns if it has patternFills 2019-07-06 16:55:07 +01:00
Curtis Hard eda2b73eb2 More fixes for gradients 2019-07-06 15:52:41 +01:00
Curtis Hard f00ede11f0 More gradient fixes 2019-07-06 15:31:17 +01:00
Curtis Hard 169da55131 More fixes 2019-07-05 22:34:05 +01:00
Curtis Hard acfec29765 Fixes project for latest master 2019-07-05 15:18:14 +01:00
Curtis Hard a44cc7c098 Fixes objectBoundBox values 2019-07-05 15:16:56 +01:00
Curtis Hard 171e97451b Initial fixes for userSpaceOnUse 2019-07-05 13:27:18 +01:00
Curtis Hard 27e096350e Fixes issue with RGB being parsed incorrectly 2019-07-04 10:04:27 +01:00
Curtis Hard 04646fe4ec Fixes color bug with predefined colours 2019-07-03 21:06:58 +01:00
Curtis Hard a092b612a8 Added translateX and translateY to available transforms
- also fixes more gradient issues
2019-07-03 20:59:47 +01:00
Curtis Hard d176fe6396 This fixes userSpaceOnUse issues with gradients (i think and hope - fingers crossed) 2019-07-03 18:29:12 +01:00
Curtis Hard c94de1d241 Fixes URL parsing and scaling for gradients 2019-07-02 22:27:51 +01:00
Curtis Hard 1294372daa Moved [self class] over to modern syntax 2019-06-22 16:24:32 +01:00
Curtis Hard 60e5c6b68a Slight refactor 2019-06-16 14:00:47 +01:00
Curtis Hard 06c8191732 Added image by maintaining aspect ratio 2019-06-16 12:56:36 +01:00
Curtis Hard 2f0bead7a4 Sets initial stroke width to 1.0, should not be 0.f! 2019-06-10 15:10:52 +01:00
Curtis Hard ee46609165 Merge branch 'master' of https://github.com/IconJar/IJSVG 2019-06-07 10:04:50 +01:00
Curtis Hard 9e58ae6e19 Added string additions 2019-06-07 10:04:47 +01:00
Curtis Hard 199d1a5707 This fixes issue with strokes being set to 0 and not being interpreted correctly 2019-05-22 18:14:29 +01:00
Curtis Hard f72ae8b401 RGB values now support percentage values 2019-05-13 15:58:36 +01:00
Curtis Hard c126f511d6 Merge branch 'features/performance-increases' 2019-03-27 08:25:47 +00:00
Curtis Hard 399e9271b4 Pretty much working 2019-03-19 21:43:09 +00:00
Curtis Hard f9107094a4 Added IJSVGImageRep 2019-03-15 21:41:03 +00:00
Curtis Hard 7a64c122cf #oops 2019-03-15 09:45:18 +00:00
Curtis Hard 8ee96c4a5b Fixes gradient clipping and masking issues 2019-03-15 09:41:24 +00:00
Curtis Hard 7cace854bd Fixes duplicate colors 2019-03-14 21:37:17 +00:00
Curtis Hard 91cf59bd32 Gradient layer now works out if it can be opaque or not 2019-03-14 20:51:19 +00:00
Curtis Hard b5e15445a5 Added renderingQuality property to IJSVG 2019-03-14 20:11:49 +00:00
Curtis Hard e7577a3e76 Various performance increases
- mainly due to gradients having a party off-screen
2019-03-14 16:50:34 +00:00
Curtis Hard 25b38fa128 Various performance increases 2019-03-13 22:19:30 +00:00
Curtis Hard 8ef14224dd Fixes memory crash 2019-03-11 09:44:39 +00:00
Curtis Hard ebfc31cdb1 Ongoing performance increases 2019-03-10 21:24:45 +00:00
Curtis Hard ccfcfbf228 This fixes fillOpacity not inheriting correctly 2019-03-08 15:43:11 +00:00
Curtis Hard 4fe1d594b0 Some reason, this is not needed on 10.14
- removed for perf reasons, still does if needed, does the check for the OS
2019-03-06 21:38:57 +00:00
Curtis Hard 61d5bb99d5 Swappwd strtod over to strtod_l to use POSIX
- reuses memory instead of malloc every string, massive performance increase
2019-03-02 19:49:36 +00:00
Curtis Hard faccec3e01 Swappted atof with strtod - performs alot better 2019-03-02 14:17:28 +00:00
Curtis Hard 66e9c9000e This improves performance by using a prebuild switch of command classes instead of registering from the command class iteself 2019-03-01 21:45:19 +00:00
Curtis Hard 2006e68c2a Updated for 10.14 2018-12-02 21:52:49 +00:00
Curtis Hard 01aea1129d Added tint color 2018-10-09 15:58:59 +01:00
Curtis Hard 388982d37b Added IJSVGExporterOptionRemoveWidthHeightAttributes option to exporter 2018-08-24 21:55:51 +01:00
Curtis Hard 941130d1f2 Removed DOM discard 2018-06-03 21:27:43 +01:00
Curtis Hard b9e964dc50 Style over attribute order 2018-05-20 22:08:30 +01:00
Curtis Hard 8532819b6a Updated generator 2018-05-07 22:03:00 +01:00
Curtis Hard e576803bb7 Fixes opacity issue, defaults to 1.0 unless specified otherwise 2018-04-30 21:48:01 +01:00
Curtis Hard a6a802a36b Fixes crashes for use elements that cannot find their linked object 2018-04-14 18:41:41 +01:00
Curtis Hard b50963292c Fixes crash with restoring context 2018-03-27 19:16:20 +01:00
Curtis Hard c40c63c48d Fixes compiler error -_- 2018-03-04 13:44:38 +00:00
Curtis Hard 6d21b56416 Fixes nested SVG’s origins 2018-03-02 15:45:07 +00:00
Curtis Hard dbdd8a6971 Removed useless defintion 2018-03-02 15:32:52 +00:00
Curtis Hard b7ba91aa82 Moves frame positions over to transforms 2018-03-02 15:31:41 +00:00
Curtis Hard 98efacf93c Fixes Sub SVG rendering 2018-03-02 14:56:30 +00:00
Curtis Hard 1b3cf5a1a0 Updated Example 2018-03-02 14:12:57 +00:00
Curtis Hard 35f8663631 Gradient stroke SVG 2018-03-02 14:09:50 +00:00
Curtis Hard 6d4eb76803 Squashed commit of the following:
commit ffb55b0f31
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Mar 2 13:28:40 2018 +0000

    Fixes viewBox origin translate

commit a4c032afa2
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:29:11 2018 +0000

    Added clip to viewport

commit abe8f4cba5
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:00:20 2018 +0000

    Fixes drawInRect not obeying origin

commit a16842271b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 26 13:46:41 2018 +0000

    Resolves namespaces correctly + added common HTML list to be parsed as groups

commit 58126e06e4
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 25 21:58:49 2018 +0000

    Fixes!

commit 5af5e054ab
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 22:37:53 2018 +0000

    Fixed defNode being removed

commit edd3aa1f33
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 16:29:54 2018 +0000

    excluded various elements from diff

commit 3366bc4fa5
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 14:05:03 2018 +0000

    Better optimaztion

commit 104002183b
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 22:17:50 2018 +0000

    Added rudimenatry inline styles -> stylesheet

commit 7010b7ea50
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 13:33:32 2018 +0000

    Correct order of cleanup

commit 5266a8c07a
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 08:22:17 2018 +0000

    corrent length of string

commit caf55e8bdf
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 21 20:45:17 2018 +0000

    removes useless def if required

commit 8160d05eba
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 14:12:02 2018 +0000

    Refactor of a few methods

commit a6d6a06521
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 09:40:21 2018 +0000

    Added collpasing of gradients

commit 103a4d71f6
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 19:07:30 2018 +0000

    Reduced floats even more

commit 98874b1d2c
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 18:53:02 2018 +0000

    More compression goodness

commit e742db31e0
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 14:02:15 2018 +0000

    Added intermediateParent

commit 198fd09f07
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 11:51:37 2018 +0000

    Fixes! and performance increases

commit 3493194b1b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 08:20:02 2018 +0000

    Scale computation

commit 0016775eaf
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:33:26 2018 +0000

    More goodness

commit 304a04cc22
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:32:04 2018 +0000

    Vastly improved the exporter

commit e4fd0af582
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 15:20:28 2018 +0000

    This is insanely important!

commit 69a2a0c97e
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 22:02:19 2018 +0000

    Refactor

commit 5299bb0479
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:58:21 2018 +0000

    will continue to use CoreAnimation for the time being

commit 4f1943cad1
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:57:46 2018 +0000

    Fixes gradient strokes

commit f02d186293
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 11:15:04 2018 +0000

    trying to get masks to work

commit 3291718cfb
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 2 22:35:22 2018 +0000

    Beginning of quartz renderer

commit 6fbaaf5884
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 22:32:08 2018 +0000

    Removed useless log

commit abc65797ea
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 21:37:45 2018 +0000

    I think gradients work :D

commit af5a1c2718
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 22:18:02 2018 +0000

    Possible fx and fy things…

commit fb9a5282b9
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 19:22:40 2018 +0000

    Even more gradient fixes

commit d83933a103
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 14:21:50 2018 +0000

    Various improvements

commit bd7a0d5021
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 22:26:33 2018 +0000

    Start to linear

commit a9a038568c
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 21:14:25 2018 +0000

    This kind of actually works...

commit 77fbb38b6f
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 20:31:36 2018 +0000

    I guess this could be a good start?

    Posssible start of fixes?

commit 12c3191569
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 15:32:15 2018 +0000

    Added method for findind absolute position

commit e3e9626ef7
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 14:25:03 2018 +0000

    Fixes crash due to parentNode on temp groups being released

commit 1160d89f16
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 22:29:22 2018 +0000

    Fixes use statements with transforms

commit 1575cbfde8
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 18:16:03 2018 +0000

    Moved color tree over to modern syntax

commit 5c4c2eee91
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Jan 25 18:23:53 2018 +0000

    Added HSL/HSLA support

commit 087b13e58f
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 22:24:43 2018 +0000

    Various image loading issues resolved from base64 images

commit 1183e167aa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:21:41 2018 +0000

    Rect issue fix

commit 4dbfc59437
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:19:24 2018 +0000

    Moved transforms over from being concatinated to seperate calls

commit 409bd509fa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 20:30:38 2018 +0000

    Fixes color issue

commit 8ae1d1b4e0
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:41:08 2018 +0000

    Removed check as its not needed here

commit 7243fbe5ff
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:35:43 2018 +0000

    Added excludeAttributes list to parseCommonAttributes

    added x and y to that list for rect

commit 51b9a5e85f
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Jan 23 19:53:04 2018 +0000

    Added isSubcommand to IJSVGCommand

    - Fixes move command going awol when preceding move commands are not subcommands (woah)

commit 40098589de
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:04:48 2018 +0000

    removed reverseObjectEnumerator

    IJSVGTransform already deals with this at parse stage (was a test from earlier), spec states transforms are applied in reverse order (which parser already dealth with :-))

commit 7cb96b21f2
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:01:56 2018 +0000

    Removed use of origin here as its computed in apply defaults

commit 1bff7c6970
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 21:48:07 2018 +0000

    Various fixes… still going…
2018-03-02 13:51:49 +00:00
Curtis Hard 36dae3ad1b Revert "Various fixes… still going…"
This reverts commit 8149293b7b.
2018-01-22 21:48:21 +00:00
Curtis Hard 8149293b7b Various fixes… still going… 2018-01-22 21:48:07 +00:00
Curtis Hard 1993c55cb8 Fixed bounds issue + colors with new line not parsing correctly 2018-01-21 21:25:36 +00:00
Curtis Hard 1f13134ccd Refactored various font things
- added CGPath methods to IJSVGUtils
2018-01-20 12:48:54 +00:00
Curtis Hard 435489f65f Removed multipass 2018-01-19 22:07:29 +00:00
Curtis Hard 4bcbcc374b Check full detail …
- adds convenience method for grabbing an SVG string from an IJSVG object
- Completely swapped IJSVGFontConverter over to use IJSVG and the IJSVGExporter
- Fixed memory leak of Defs element when exporting
2018-01-19 21:55:47 +00:00
Curtis Hard cb544d7a6b Added begin and end vector draw so they are not private 2018-01-16 22:18:25 +00:00
Curtis Hard a4cd0bcc4e Fixes issue with comments being parsed incorrectly in defs 2018-01-16 21:15:24 +00:00
Curtis Hard 02b03d8862 Fixes issue with defined elements causing infinate loop when exported from latest Sketch version 2017-12-06 20:45:24 +00:00
Curtis Hard 94ae7c2757 Added easy method for replacing whole dictionary 2017-11-14 13:29:06 +00:00
Curtis Hard 27371a9d78 Fixes issue with default fill color not being able to be user defined/replaced 2017-11-13 22:00:33 +00:00
Curtis Hard 3c1422a65f Initial color replacement start 2017-11-11 22:50:14 +00:00
Curtis Hard 8ed817aa43 Merge pull request #9 from Deadpikle/master
Fix missing files and macOS SDK setting
2017-11-07 17:55:29 +00:00
Deadpikle ca754ff61c Fix missing files and macOS SDK setting 2017-11-07 12:14:22 -05:00
Curtis Hard 53da0fca4b Refactor of shape layer and default layer 2017-09-13 11:31:58 +01:00
Curtis Hard 1259ce1e63 method name changes 2017-09-12 23:30:58 +01:00
Curtis Hard 70cd111b1c Neatness change 2017-09-12 23:11:31 +01:00
Curtis Hard 15b0805bf9 PDF!!!!!!!!
- This is nuts, so we work out way through the layers working out which are masks, working out the actual path that the mask shape would eventually have amd clip the context when it draws, hell yehs…
2017-09-12 23:00:44 +01:00
Curtis Hard e11e28c54f Here we go.. 2017-09-12 16:23:37 +01:00
Curtis Hard f320bd4684 Added compression options to export SVG 2017-09-11 21:05:51 +01:00
Curtis Hard 2faeda560f More performance 2017-09-10 18:00:06 +01:00
Curtis Hard c56a5ecca1 Faster export 2017-09-07 13:17:48 +01:00
Curtis Hard e85f67358e Initial changes for icon size to export 2017-09-05 16:03:38 +01:00
Curtis Hard 0fb27d4e94 Fixed issue where a color was not specified but a fill opacity was if no overiding color was set. 2017-09-03 20:01:30 +01:00
Curtis Hard 9bce41afff Various memory fixes 2017-07-28 21:55:49 +01:00
Curtis Hard 09b0cc6d96 Added ability to customise strokeWidth, lineCapStyle and lineJoinStyle on the root SVG object
- These will override any given styles/attributes on any element in the SVG
2017-07-04 21:25:41 +01:00
Curtis Hard 58fbb01ff2 Moved command char checker over to C call, believe it or not, this is alot faster then using a characterSet 2017-06-05 21:36:01 +01:00
Curtis Hard 5a5b144ab1 Fixes infinate loop with invalid selector characters 2017-06-05 19:31:22 +01:00
Curtis Hard 359cff7569 Squashed commit of the following:
commit d6b14b9aadc8295512f9a5513d9a3f4169d5965d
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Apr 9 22:37:15 2017 +0100

    Changes to valid chars for a selector
2017-04-16 20:40:32 +01:00
Curtis Hard 57bfe633e7 Fixes issue with capitals in CSS selectors 2017-04-07 14:17:24 +01:00
Curtis Hard c757fb4b33 Merge remote-tracking branch 'origin/fixes/stroke-gradients' 2017-04-05 09:09:26 +01:00
Curtis Hard 4d1141a889 Added methods for dealing with drawing in views 2017-04-04 14:50:07 +01:00
Curtis Hard 481359ec58 Added IJSVGView - easy way to set SVG image from bundle in IB 2017-04-04 10:08:01 +01:00
Curtis Hard fb14d7be65 Added viewPort to the layer tree 2017-03-30 09:55:22 +01:00
Curtis Hard 0e4a5528f7 Added gradient unit length 2017-03-29 16:17:58 +01:00
Curtis Hard 36216a51ed Fixed dashes offset being wrong attribute key 2017-03-28 12:30:49 +01:00
Curtis Hard 9e1ffd5d46 Fixes parsing issues for DEF’s
- Some defs were not being picked up due to people sticking them at the bottom of the file, IJSVG works top down, so they were ignored, now every group or parent element will be checked for defs, parsed and then will worry about being parsed afterwards :)
2017-03-17 14:46:18 +00:00
Curtis Hard 05d0b6e173 Fixes strokes not being exported of no stroke color is set 2017-03-13 22:23:35 +00:00
Curtis Hard 9cecea923c Comments... 2017-03-13 22:02:42 +00:00
Curtis Hard 8ff1fc860e Various fixes to gradient and pattern strokes 2017-03-13 21:59:50 +00:00
Curtis Hard edef84274d Merge branch 'feature/currentcolorsupport' 2017-03-06 12:50:04 +00:00
Curtis Hard 484675f666 removed miterLimit, added currentColor to being 000 2017-03-01 14:22:50 +00:00
Curtis Hard 2f574e3cbb Fix for end char being wrong when parsing a style 2017-02-22 23:05:52 +00:00
Curtis Hard b64b0f3735 Set theme jekyll-theme-cayman 2017-02-21 13:20:09 +00:00
Curtis Hard c0cdb41ddc Set theme jekyll-theme-minimal 2017-02-21 13:18:43 +00:00
Curtis Hard 258a617564 Added X and Y to pattern node 2017-02-20 11:00:40 +00:00
Curtis Hard bf40002fe0 Adds size option to the exporter 2017-02-19 21:35:42 +00:00
Curtis Hard 2ef0bd88ef Fixes NAN issue on Arc command 2017-02-16 15:41:31 +00:00
Curtis Hard 0aca44ef76 Added offsets to pattern and gradients 2017-02-16 15:26:02 +00:00
Curtis Hard a3e512d7b8 Added fill opacity to pattern layers 2017-02-15 13:44:15 +00:00
Curtis Hard 0ffd20e87c Fixes and better gradient support 2017-02-09 21:18:30 +00:00
Curtis Hard 0f0943816c Provided a color stop if none were provided 2017-02-09 14:37:33 +00:00
Curtis Hard ddb5b2f746 Remove comment 2017-02-08 21:23:01 +00:00
Curtis Hard 80bc3ed1d8 Fixes various drawing and export issues
- Fixes transform being incorrect on export
- Fixes incorrect collapasing of groups with transforms
- Fixes incorrect alpha value in RGBA being used when exporting
- Fixes masking issue on groups (basically never applied them)
- Fixed incorrect parsing of “none” on dash count
2017-02-08 21:22:54 +00:00
Curtis Hard 1a7a7b4d7b Told image layer to need help with rasterizing 2017-02-07 10:04:42 +00:00
Curtis Hard 0876a1e976 Fixes switches that needed parsing
- Basically just parses the things we actually support, nothing more, nothing less
2017-02-07 09:52:05 +00:00
Curtis Hard 6747160504 Fixes issue with Stylesheets that are embedded inside defs not being parsed 2017-02-06 14:01:02 +00:00
Curtis Hard d2059e4d2f Removed switch elements as they are pretty useless in context of what this is used for:
- Also moved styls element and defs element into the default parsing process, which actually speeds up parsing a fair bit (when dealing with loading of 100’s of SVG’s at once)
2017-02-04 23:04:56 +00:00
Curtis Hard 71c47a313e Fixes various export issues
- Fixed issue with exporting SVG where elements that should be hidden were not being given the display:none style.
- Added option for completely removing any elements that are technically hidden (as long as they are not in the defs)
2017-01-27 23:49:08 +00:00
Curtis Hard 70f9c29fe5 This fixes hidden layers from showing
- Basically not obbeying the hidden node properly
- Also fixes CSS parser from beach balling when parsing @ selectors
- Also dramatically improves parsing of key value pairs in CSS, by dramatically, i mean took a file down from 300ms parse to 5ms… woah.
2017-01-27 19:10:01 +00:00
Curtis Hard 5f8f3d8be5 Initial blending mode support 2017-01-24 15:38:17 +00:00
Curtis Hard e26ebe300f Merge branch 'feature/pattern_gradient_strokes' 2017-01-19 15:44:13 +00:00
Curtis Hard c0c46ad2b7 Fixes overriding stroke colour not being applied to gradient or pattern strokes 2017-01-19 15:43:26 +00:00
Curtis Hard abade39e2a Fixes a huge bug with duplication on use elements being parsed and reparsed over and over 2017-01-18 16:32:57 +00:00
Curtis Hard 2f7a6aa213 Fix for gradient units not being applied 2017-01-18 15:31:08 +00:00
Curtis Hard 2598046369 Fixes string issue with linear gradients 2017-01-18 15:20:11 +00:00
Curtis Hard 5424e32a63 Various refactors for stroke pattern and gradient pattern 2017-01-18 14:59:48 +00:00
Curtis Hard a8a7f8d356 Unit computation fixes 2017-01-17 10:46:46 +00:00
Curtis Hard a3bde2f710 Fixed value working out issue 2017-01-17 09:22:19 +00:00
Curtis Hard 0cc22cad44 Update README.md 2017-01-15 21:02:35 +00:00
Curtis Hard 448d46e8ec Update README.md 2017-01-15 12:28:14 +00:00
97 changed files with 30008 additions and 10081 deletions
@@ -7,6 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */; };
59069A2922D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */; };
59069A2B22D0EE0E004DDEA5 /* test (1).svg in Resources */ = {isa = PBXBuildFile; fileRef = 59069A2A22D0EE0E004DDEA5 /* test (1).svg */; };
590C87EB201F9888004A1554 /* json.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EA201F9888004A1554 /* json.svg */; };
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EC201FA08C004A1554 /* intertwingly.svg */; };
590C87EF201FA093004A1554 /* NewTux.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87EE201FA092004A1554 /* NewTux.svg */; };
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */; };
590C87F4201FC9E4004A1554 /* radialgradient2.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F3201FC9E3004A1554 /* radialgradient2.svg */; };
590C87F6201FD0D4004A1554 /* car.svg in Resources */ = {isa = PBXBuildFile; fileRef = 590C87F5201FD0D4004A1554 /* car.svg */; };
591704CC1E2016E400012644 /* IJSVGExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 591704CB1E2016E400012644 /* IJSVGExporter.m */; };
591A13E11E19838F001D1629 /* IJSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 591A13E01E19838F001D1629 /* IJSVGText.m */; };
59265CE81C4F840400F333F0 /* css.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59265CE71C4F840400F333F0 /* css.svg */; };
@@ -28,10 +37,13 @@
595665DE19B6309C00D805FF /* test.svg in Resources */ = {isa = PBXBuildFile; fileRef = 595665DD19B6309C00D805FF /* test.svg */; };
595665E119B630B600D805FF /* SVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 595665E019B630B600D805FF /* SVGView.m */; };
597046A21E24352700A60138 /* IJSVGStrokeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 597046A11E24352700A60138 /* IJSVGStrokeLayer.m */; };
597AC83322CFD0FC007C0E42 /* home.svg in Resources */ = {isa = PBXBuildFile; fileRef = 597AC83222CFD0FC007C0E42 /* home.svg */; };
5986308719BA104800CF15EA /* linecap.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5986308619BA104800CF15EA /* linecap.svg */; };
5986308A19BA106D00CF15EA /* SVGExampleView5.m in Sources */ = {isa = PBXBuildFile; fileRef = 5986308919BA106D00CF15EA /* SVGExampleView5.m */; };
5986308C19BA180E00CF15EA /* dashed.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5986308B19BA180E00CF15EA /* dashed.svg */; };
598759F61E242C850024CC3F /* IJSVGExporterPathInstruction.m in Sources */ = {isa = PBXBuildFile; fileRef = 598759F51E242C850024CC3F /* IJSVGExporterPathInstruction.m */; };
5991A2A9201E30E600913E3B /* gradients.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5991A2A8201E30E600913E3B /* gradients.svg */; };
5991A2AB201E310200913E3B /* heart.svg in Resources */ = {isa = PBXBuildFile; fileRef = 5991A2AA201E310200913E3B /* heart.svg */; };
599465DC1C4AA87200A2EEF3 /* IJSVGStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D51C4AA87200A2EEF3 /* IJSVGStyleSheet.m */; };
599465DD1C4AA87200A2EEF3 /* IJSVGStyleSheetRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D71C4AA87200A2EEF3 /* IJSVGStyleSheetRule.m */; };
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 599465D91C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m */; };
@@ -42,6 +54,7 @@
59A3DA6D1E283022003E59A9 /* IJSVGTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */; };
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6C19B7D1840063E823 /* paperplane.svg */; };
59B93C6F19B7D32C0063E823 /* products.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59B93C6E19B7D32C0063E823 /* products.svg */; };
59D1E3A0202279CA00C54672 /* Group.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D1E39F202279CA00C54672 /* Group.svg */; };
59E0F5ED1E29964700F757F7 /* IJSVGUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */; };
59E2645119BA240D008A6FDB /* IJSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E2641C19BA240D008A6FDB /* IJSVG.m */; };
59E2645219BA240D008A6FDB /* IJSVGBezierPathAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E2641E19BA240D008A6FDB /* IJSVGBezierPathAdditions.m */; };
@@ -76,6 +89,10 @@
59E8ABF31E2167D90032A80C /* IJSVGImageLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF21E2167D90032A80C /* IJSVGImageLayer.m */; };
59E8ABF61E2176340032A80C /* IJSVGGroupLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF51E2176340032A80C /* IJSVGGroupLayer.m */; };
59E8ABF91E219C860032A80C /* IJSVGMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E8ABF81E219C860032A80C /* IJSVGMath.m */; };
59EA311622CF395400DAB3B7 /* IJSVGStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */; };
59EA311722CF395400DAB3B7 /* IJSVGRendering.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311022CF395400DAB3B7 /* IJSVGRendering.m */; };
59EA311822CF395400DAB3B7 /* IJSVGImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */; };
59EA311922CF395400DAB3B7 /* IJSVGView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA311422CF395400DAB3B7 /* IJSVGView.m */; };
59F799E219B880CE00096CB7 /* htc_one.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59F799E119B880CE00096CB7 /* htc_one.svg */; };
/* End PBXBuildFile section */
@@ -90,6 +107,16 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
343A19161FB2212C000652A2 /* IJSVGGradientUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGGradientUnitLength.h; sourceTree = "<group>"; };
343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGradientUnitLength.m; sourceTree = "<group>"; };
59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = compuserver_msn_Ford_Focus.svg; sourceTree = "<group>"; };
59069A2A22D0EE0E004DDEA5 /* test (1).svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "test (1).svg"; sourceTree = "<group>"; };
590C87EA201F9888004A1554 /* json.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json.svg; sourceTree = "<group>"; };
590C87EC201FA08C004A1554 /* intertwingly.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = intertwingly.svg; sourceTree = "<group>"; };
590C87EE201FA092004A1554 /* NewTux.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = NewTux.svg; sourceTree = "<group>"; };
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AJ_Digital_Camera.svg; sourceTree = "<group>"; };
590C87F3201FC9E3004A1554 /* radialgradient2.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = radialgradient2.svg; sourceTree = "<group>"; };
590C87F5201FD0D4004A1554 /* car.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = car.svg; sourceTree = "<group>"; };
591704CA1E2016E400012644 /* IJSVGExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporter.h; sourceTree = "<group>"; };
591704CB1E2016E400012644 /* IJSVGExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporter.m; sourceTree = "<group>"; };
591A13DF1E19838F001D1629 /* IJSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGText.h; sourceTree = "<group>"; };
@@ -130,12 +157,15 @@
595665E019B630B600D805FF /* SVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVGView.m; sourceTree = "<group>"; };
597046A01E24352700A60138 /* IJSVGStrokeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStrokeLayer.h; sourceTree = "<group>"; };
597046A11E24352700A60138 /* IJSVGStrokeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStrokeLayer.m; sourceTree = "<group>"; };
597AC83222CFD0FC007C0E42 /* home.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = home.svg; sourceTree = "<group>"; };
5986308619BA104800CF15EA /* linecap.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = linecap.svg; sourceTree = "<group>"; };
5986308819BA106D00CF15EA /* SVGExampleView5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGExampleView5.h; sourceTree = "<group>"; };
5986308919BA106D00CF15EA /* SVGExampleView5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVGExampleView5.m; sourceTree = "<group>"; };
5986308B19BA180E00CF15EA /* dashed.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dashed.svg; sourceTree = "<group>"; };
598759F41E242C850024CC3F /* IJSVGExporterPathInstruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGExporterPathInstruction.h; sourceTree = "<group>"; };
598759F51E242C850024CC3F /* IJSVGExporterPathInstruction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGExporterPathInstruction.m; sourceTree = "<group>"; };
5991A2A8201E30E600913E3B /* gradients.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = gradients.svg; sourceTree = "<group>"; };
5991A2AA201E310200913E3B /* heart.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = heart.svg; sourceTree = "<group>"; };
599465D41C4AA87200A2EEF3 /* IJSVGStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheet.h; sourceTree = "<group>"; };
599465D51C4AA87200A2EEF3 /* IJSVGStyleSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStyleSheet.m; sourceTree = "<group>"; };
599465D61C4AA87200A2EEF3 /* IJSVGStyleSheetRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStyleSheetRule.h; sourceTree = "<group>"; };
@@ -154,6 +184,7 @@
59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGTransaction.m; sourceTree = "<group>"; };
59B93C6C19B7D1840063E823 /* paperplane.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = paperplane.svg; sourceTree = "<group>"; };
59B93C6E19B7D32C0063E823 /* products.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = products.svg; sourceTree = "<group>"; };
59D1E39F202279CA00C54672 /* Group.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Group.svg; sourceTree = "<group>"; };
59E0F5EB1E29964700F757F7 /* IJSVGUnitLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGUnitLength.h; sourceTree = "<group>"; };
59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGUnitLength.m; sourceTree = "<group>"; };
59E2641B19BA240D008A6FDB /* IJSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVG.h; sourceTree = "<group>"; };
@@ -222,6 +253,14 @@
59E8ABF51E2176340032A80C /* IJSVGGroupLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGGroupLayer.m; sourceTree = "<group>"; };
59E8ABF71E219C860032A80C /* IJSVGMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGMath.h; sourceTree = "<group>"; };
59E8ABF81E219C860032A80C /* IJSVGMath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGMath.m; sourceTree = "<group>"; };
59EA310E22CF395300DAB3B7 /* IJSVGImageRep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGImageRep.h; sourceTree = "<group>"; };
59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGStringAdditions.m; sourceTree = "<group>"; };
59EA311022CF395400DAB3B7 /* IJSVGRendering.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGRendering.m; sourceTree = "<group>"; };
59EA311122CF395400DAB3B7 /* IJSVGRendering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGRendering.h; sourceTree = "<group>"; };
59EA311222CF395400DAB3B7 /* IJSVGView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGView.h; sourceTree = "<group>"; };
59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGImageRep.m; sourceTree = "<group>"; };
59EA311422CF395400DAB3B7 /* IJSVGView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJSVGView.m; sourceTree = "<group>"; };
59EA311522CF395400DAB3B7 /* IJSVGStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJSVGStringAdditions.h; sourceTree = "<group>"; };
59F799E119B880CE00096CB7 /* htc_one.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = htc_one.svg; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -291,6 +330,18 @@
5956657A19B62F4600D805FF /* Supporting Files */ = {
isa = PBXGroup;
children = (
59069A2A22D0EE0E004DDEA5 /* test (1).svg */,
59069A2822D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg */,
597AC83222CFD0FC007C0E42 /* home.svg */,
59D1E39F202279CA00C54672 /* Group.svg */,
590C87F5201FD0D4004A1554 /* car.svg */,
590C87F3201FC9E3004A1554 /* radialgradient2.svg */,
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */,
590C87EC201FA08C004A1554 /* intertwingly.svg */,
590C87EE201FA092004A1554 /* NewTux.svg */,
590C87EA201F9888004A1554 /* json.svg */,
5991A2AA201E310200913E3B /* heart.svg */,
5991A2A8201E30E600913E3B /* gradients.svg */,
59265CE71C4F840400F333F0 /* css.svg */,
59459CEB19B906FE00CE493B /* clipped.svg */,
59F799E119B880CE00096CB7 /* htc_one.svg */,
@@ -335,6 +386,14 @@
59E2641A19BA240D008A6FDB /* source */ = {
isa = PBXGroup;
children = (
59EA310E22CF395300DAB3B7 /* IJSVGImageRep.h */,
59EA311322CF395400DAB3B7 /* IJSVGImageRep.m */,
59EA311122CF395400DAB3B7 /* IJSVGRendering.h */,
59EA311022CF395400DAB3B7 /* IJSVGRendering.m */,
59EA311522CF395400DAB3B7 /* IJSVGStringAdditions.h */,
59EA310F22CF395400DAB3B7 /* IJSVGStringAdditions.m */,
59EA311222CF395400DAB3B7 /* IJSVGView.h */,
59EA311422CF395400DAB3B7 /* IJSVGView.m */,
59A3DA6B1E283022003E59A9 /* IJSVGTransaction.h */,
59A3DA6C1E283022003E59A9 /* IJSVGTransaction.m */,
598759F41E242C850024CC3F /* IJSVGExporterPathInstruction.h */,
@@ -392,6 +451,8 @@
59E2643C19BA240D008A6FDB /* IJSVGForeignObject.m */,
59E2643D19BA240D008A6FDB /* IJSVGGradient.h */,
59E2643E19BA240D008A6FDB /* IJSVGGradient.m */,
343A19161FB2212C000652A2 /* IJSVGGradientUnitLength.h */,
343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */,
59E2643F19BA240D008A6FDB /* IJSVGGroup.h */,
59E2644019BA240D008A6FDB /* IJSVGGroup.m */,
59E2644119BA240D008A6FDB /* IJSVGLinearGradient.h */,
@@ -483,7 +544,7 @@
5956656F19B62F4600D805FF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = "Curtis Hard";
TargetAttributes = {
5956657619B62F4600D805FF = {
@@ -500,6 +561,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
@@ -521,13 +583,25 @@
files = (
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */,
5956658219B62F4600D805FF /* Images.xcassets in Resources */,
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */,
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */,
59069A2B22D0EE0E004DDEA5 /* test (1).svg in Resources */,
590C87EF201FA093004A1554 /* NewTux.svg in Resources */,
59265CE81C4F840400F333F0 /* css.svg in Resources */,
595665DE19B6309C00D805FF /* test.svg in Resources */,
597AC83322CFD0FC007C0E42 /* home.svg in Resources */,
590C87EB201F9888004A1554 /* json.svg in Resources */,
59D1E3A0202279CA00C54672 /* Group.svg in Resources */,
59F799E219B880CE00096CB7 /* htc_one.svg in Resources */,
59B93C6F19B7D32C0063E823 /* products.svg in Resources */,
5991A2A9201E30E600913E3B /* gradients.svg in Resources */,
59069A2922D0ED85004DDEA5 /* compuserver_msn_Ford_Focus.svg in Resources */,
5986308719BA104800CF15EA /* linecap.svg in Resources */,
5956658519B62F4600D805FF /* MainMenu.xib in Resources */,
590C87F4201FC9E4004A1554 /* radialgradient2.svg in Resources */,
59459CEC19B906FE00CE493B /* clipped.svg in Resources */,
590C87F6201FD0D4004A1554 /* car.svg in Resources */,
5991A2AB201E310200913E3B /* heart.svg in Resources */,
5986308C19BA180E00CF15EA /* dashed.svg in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -550,6 +624,7 @@
59E2646919BA240D008A6FDB /* IJSVGStyle.m in Sources */,
59E2646419BA240D008A6FDB /* IJSVGLinearGradient.m in Sources */,
595665DC19B6302600D805FF /* README.md in Sources */,
59EA311922CF395400DAB3B7 /* IJSVGView.m in Sources */,
5941DAFD1CF9BC9B00B3A911 /* IJSVGImage.m in Sources */,
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */,
5948DED61BB2BFE5004156FF /* IJSVGWriter.m in Sources */,
@@ -557,6 +632,7 @@
5986308A19BA106D00CF15EA /* SVGExampleView5.m in Sources */,
59E2645619BA240D008A6FDB /* IJSVGCommandArc.m in Sources */,
59E8ABF91E219C860032A80C /* IJSVGMath.m in Sources */,
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */,
59265CEB1C4F843E00F333F0 /* SVGExampleView6.m in Sources */,
5941DAFE1CF9BC9B00B3A911 /* IJSVGPattern.m in Sources */,
59E8ABF01E211EDB0032A80C /* IJSVGShapeLayer.m in Sources */,
@@ -577,6 +653,7 @@
5956658019B62F4600D805FF /* AppDelegate.m in Sources */,
59E2646519BA240D008A6FDB /* IJSVGNode.m in Sources */,
591A13E11E19838F001D1629 /* IJSVGText.m in Sources */,
59EA311822CF395400DAB3B7 /* IJSVGImageRep.m in Sources */,
59A11E6C19B89CEA00E44498 /* SVGExampleView1.m in Sources */,
59A3DA6D1E283022003E59A9 /* IJSVGTransaction.m in Sources */,
59E2646A19BA240D008A6FDB /* IJSVGTransform.m in Sources */,
@@ -588,6 +665,7 @@
598759F61E242C850024CC3F /* IJSVGExporterPathInstruction.m in Sources */,
59E2645E19BA240D008A6FDB /* IJSVGCommandSmoothCurve.m in Sources */,
59E2645819BA240D008A6FDB /* IJSVGCommandCommandSmoothQuadraticCurve.m in Sources */,
59EA311622CF395400DAB3B7 /* IJSVGStringAdditions.m in Sources */,
59E2645D19BA240D008A6FDB /* IJSVGCommandQuadraticCurve.m in Sources */,
59E2646719BA240D008A6FDB /* IJSVGPath.m in Sources */,
59E8ABED1E211EBE0032A80C /* IJSVGLayer.m in Sources */,
@@ -596,6 +674,7 @@
59A11E7219B89D6600E44498 /* SVGExampleView3.m in Sources */,
59E0F5ED1E29964700F757F7 /* IJSVGUnitLength.m in Sources */,
5956657D19B62F4600D805FF /* main.m in Sources */,
59EA311722CF395400DAB3B7 /* IJSVGRendering.m in Sources */,
59A11E6F19B89D2000E44498 /* SVGExampleView2.m in Sources */,
5948DED51BB2BFE5004156FF /* IJSVGFontConverter.m in Sources */,
59E2646319BA240D008A6FDB /* IJSVGGroup.m in Sources */,
@@ -676,7 +755,7 @@
MACOSX_DEPLOYMENT_TARGET = 10.7;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx10.12;
SDKROOT = macosx;
};
name = Debug;
};
@@ -712,7 +791,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx10.12;
SDKROOT = macosx;
};
name = Release;
};
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,30 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596" : 0,
"91965C60FB9217304DAC6A57C88233440365843F" : 9223372036854775807
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "83EE8FFF-CAF0-4D33-92A0-4CA5D3A6A33C",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596" : "IJSVG\/",
"91965C60FB9217304DAC6A57C88233440365843F" : "..\/..\/.."
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "IJSVGExample",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "IJSVGExample\/IJSVGExample.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/daveyheuser\/Iconjar-mac.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "91965C60FB9217304DAC6A57C88233440365843F"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/curthard89\/IJSVG.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D72EFE5A8E718DCC42CFCBCE6A16E2165A4F6596"
}
]
}
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "21141E92-29FD-4CF6-AB04-0D4E4FD9A4AC"
type = "1"
version = "2.0">
</Bucket>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0600"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -37,10 +37,11 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
@@ -62,17 +63,22 @@
ReferencedContainer = "container:IJSVGExample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5956657619B62F4600D805FF"
@@ -85,12 +91,13 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5956657619B62F4600D805FF"
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 515 KiB

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14835.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14835.7"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -666,23 +667,24 @@
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="139" y="154"/>
</menu>
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" appearanceType="aqua" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="556" height="679"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<rect key="contentRect" x="335" y="390" width="600" height="479"/>
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1669"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="479"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView misplaced="YES" id="hhC-1S-CCX" customClass="SVGView">
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hhC-1S-CCX" customClass="SVGView">
<rect key="frame" x="0.0" y="0.0" width="600" height="479"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
</view>
<point key="canvasLocation" x="550" y="495.5"/>
<point key="canvasLocation" x="98" y="496.5"/>
</window>
</objects>
</document>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="193px" height="172px" viewBox="0 0 193 172" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group">
<rect id="Rectangle-Copy" fill="#E80000" x="53" y="41" width="140" height="131"></rect>
<rect id="Rectangle" fill="#1813DF" x="0" y="0" width="140" height="131"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 679 B

+72
View File
@@ -0,0 +1,72 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500pt" height="800">
<defs>
<linearGradient id="a">
<stop offset="0" stop-color="#3f2600" stop-opacity=".6"/>
<stop offset="1" stop-color="#3f2600" stop-opacity="0"/>
</linearGradient>
<linearGradient id="d">
<stop offset="0" stop-color="#fff" stop-opacity=".65"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<linearGradient id="e">
<stop offset="0" stop-color="#ffa63f"/>
<stop offset="1" stop-color="#ff0"/>
</linearGradient>
<linearGradient id="b">
<stop offset="0" stop-color="#ffeed7"/>
<stop offset="1" stop-color="#bdbfc2"/>
</linearGradient>
<linearGradient id="c">
<stop offset="0" stop-color="#fff" stop-opacity=".8"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<radialGradient id="f" cx="446.77762" cy="1219.4125" r="195.07191" fx="446.77762" fy="1219.4125" gradientTransform="scale(1.04523 .95673)" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
<linearGradient id="g" x1="400.57785" x2="400.84448" y1="369.53015" y2="304.07886" gradientTransform="scale(.57526 1.73834)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
<linearGradient id="h" x1="303.01761" x2="297.0856" y1="237.93179" y2="330.09561" gradientTransform="scale(1.11607 .896)" gradientUnits="userSpaceOnUse" xlink:href="#c"/>
<linearGradient id="i" x1="378.93771" x2="380.27319" y1="278.60202" y2="243.91606" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
<linearGradient id="j" x1="381.38742" x2="380.5517" y1="277.495" y2="245.68338" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
<linearGradient id="k" x1="379.09573" x2="376.79556" y1="240.92712" y2="281.01636" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="l" x1="389.63535" x2="387.06866" y1="242.28218" y2="281.32513" gradientTransform="scale(.8165 1.22474)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="m" x1="437.57941" x2="437.57941" y1="528.87177" y2="394.10361" gradientTransform="scale(.81285 1.23023)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#b"/>
<linearGradient id="n" x1="375.17325" x2="377.48541" y1="419.78485" y2="324.03815" gradientTransform="scale(.64978 1.53897)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
<linearGradient id="o" x1="320.75104" x2="321.32224" y1="498.17776" y2="614.50439" gradientTransform="scale(1.0748 .9304)" gradientUnits="userSpaceOnUse" xlink:href="#c"/>
<linearGradient id="p" x1="322.48257" x2="323.2514" y1="435.26761" y2="488.48251" gradientTransform="scale(1.077 .9285)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="q" x1="411.2215" x2="411.2215" y1="242.94365" y2="331.44858" gradientTransform="scale(.5717 1.74915)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="r" x1="867.34546" x2="867.33453" y1="234.73897" y2="314.83911" gradientTransform="scale(.57267 1.74621)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="s" x1="236.25362" x2="212.5099" y1="657.11133" y2="737.41229" gradientTransform="scale(1.01151 .98862)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
<linearGradient id="t" x1="381.56607" x2="279.64313" y1="655.73102" y2="386.66583" gradientTransform="scale(1.0655 .93853)" gradientUnits="userSpaceOnUse" xlink:href="#b"/>
<linearGradient id="u" x1="218.11714" x2="203.12654" y1="630.30475" y2="737.8537" gradientTransform="scale(1.00985 .99025)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
<linearGradient id="v" x1="117.88966" x2="182.24524" y1="587.23602" y2="704.73077" gradientTransform="scale(1.00772 .99233)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="w" x1="223.10072" x2="230.53499" y1="570.41809" y2="710.97723" gradientTransform="scale(.9995 1.0005)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="x" x1="316.93988" x2="371.60889" y1="474.01779" y2="582.63507" gradientTransform="scale(1.0655 .93853)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
<linearGradient id="y" x1="284.68652" x2="285.45923" y1="410.46326" y2="485.69934" gradientTransform="scale(1.21868 .82056)" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
<linearGradient id="z" x1="288.82358" x2="288.37628" y1="398.85422" y2="482.55939" gradientTransform="scale(1.22194 .81837)" gradientUnits="userSpaceOnUse" xlink:href="#d"/>
</defs>
<path fill="url(#f)" d="M670.88202 1166.6423a203.89551 186.63016 0 1 1-407.79102 0 203.89551 186.63016 0 1 1 407.79102 0z" transform="matrix(1.4177 0 0 .41474 -349.5468 157.94132)"/>
<path d="M154.23535 558.54232c-27.985-40.27875-33.4425-171.23 31.85875-251.7875 32.3575-38.6475 40.6125-65.58125 43.16375-101.74125 1.73625-41.22375-29.15625-164.3025 87.35375-173.68 118.0075-9.415 111.67 107.075 110.99125 168.71875-.56375 52.05 38.2175 81.55125 64.745 122.11875 49.09875 74.5375 44.94625 202.875-9.24875 272.34-68.64625 86.96-127.44125 49.2475-166.4875 52.4125-73.11625 4.0025-75.53375 42.98875-162.37625-88.38125z"/>
<path fill="url(#g)" d="M246.571 470.864c-12.239 12.496-44.396 69.092 4.869 105.36 17.369 12.633-16.377 59.495-32.005 36.308-27.57-41.618-8.831-106.941 8.315-130.188 11.652-16.487 29.23-22.676 18.821-11.48z" transform="matrix(-1.67739 -.02245 -.02112 1.4709 862.8276 -357.26968)"/>
<path stroke="#000" stroke-width=".97729802" d="M256.513 459.837c-19.915 17.717-56.176 80.091-3.288 120.606 17.37 12.632-15.393 52.463-33.79 32.089-63.963-70.82 1.669-152.254 24.262-180.25 20.192-24.347 38.078 5.752 12.816 27.555z" transform="matrix(-1.67755 0 0 1.52374 863.8676 -382.33468)"/>
<path fill="url(#h)" d="M399.56879 258.15753a58.37323 46.863022 0 1 1-116.74646 0 58.37323 46.863022 0 1 1 116.74646 0z" transform="matrix(1.26626 -.07137 -.04598 1.19574 -108.6094 -190.01368)"/>
<path fill="url(#i)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(1.30445 -.07553 .07713 1.34257 -165.9954 -241.86968)"/>
<path fill="url(#j)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(-1.81082 .04951 .03173 1.55333 896.7076 -349.02968)"/>
<path d="M326.35672821 170.5767474a14.88487384 23.14205282 2.00317994 1 0 29.77908237.06371242 14.88487384 23.14205282 2.00317994 1 0-29.77908237-.06371242zm-52.12561644.13467082a10.82556484 19.2435689-4.93566296 1 1-21.50167273 2.6153013 10.82556484 19.2435689-4.93566296 1 1 21.50167273-2.6153013z"/>
<path fill="url(#k)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(-.48032 -.03645 -.0468 .4756 502.7436 22.75972)"/>
<path fill="url(#l)" d="M328.86324 320.64151a18.087479 27.131195 0 1 1-36.17496 0 18.087479 27.131195 0 1 1 36.17496 0z" transform="matrix(.35691 -.04082 .04132 .39854 138.5816 50.73832)"/>
<path fill="url(#m)" d="M258.702 495.425c12.836-29.103 40.114-80.226 40.695-119.758 0-31.442 94.179-38.951 101.737-7.558 7.558 31.393 26.741 78.483 38.95 101.156 12.208 22.672 47.809 94.695 9.884 157.546-34.157 55.644-137.725 99.666-193.01-7.557-18.603-37.207-15.285-83.315 1.744-123.829z" transform="matrix(1.25 0 0 1.25 -125.2984 -232.48268)"/>
<path fill="url(#n)" d="M242.905 473.815c-11.263 18.967-35.5 69.309 12.137 102.047 51.311 34.82 46.473 97.062-15.607 61.955-56.777-31.789-22.845-137.778-4.51-162.266 12.107-17.214 29.897-38.031 7.98-1.736z" transform="matrix(1.38936 -.11107 .10221 1.30214 -202.3394 -230.19068)"/>
<path stroke="#000" stroke-width="1.5625" d="M195.34285 330.39232c-21.83125 35.635-74.22125 119.76625-4.11 163.40375 94.46125 57.94375 67.71625 115.88875-18.49875 63.7175-121.38625-72.83-14.78125-219.52 33.91375-275.4225 55.555-62.75 10.6925 11.35875-11.305 48.30125z"/>
<path fill="url(#o)" d="M421.481 504.727c0 32.412-29.272 74.516-79.528 74.138-51.828.455-73.949-41.726-73.949-74.138 0-32.412 34.379-58.717 76.739-58.717 42.359 0 76.738 26.305 76.738 58.717z" font-size="12" transform="matrix(1.30209 0 0 1.22525 -140.7104 -217.80968)"/>
<path fill="url(#p)" d="M398.227 412.292c-.612 38.572-23.18 47.671-51.74 47.671-28.561 0-49.292-5.694-51.741-47.671 0-26.314 23.18-41.542 51.741-41.542 28.56 0 51.74 15.228 51.74 41.542z" font-size="12" transform="matrix(1.1868 0 0 1.06708 -100.1294 -164.33068)"/>
<path fill="url(#q)" d="M234.285 456.475c17.716-26.996 55.015-68.364 6.977 5.813-38.951 61.043-14.403 100.273-1.744 111.039 36.527 32.562 34.966 54.349 6.395 37.206-61.625-36.626-48.835-98.248-11.628-154.058z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
<path fill="url(#r)" d="M490.662 467.52c-15.319-31.701-64.134-111.902 2.326-18.603 60.461 84.297 18.022 143.013 10.464 148.827-7.557 5.813-33.137 17.44-25.579-2.907 7.557-20.347 45.234-58.973 12.789-127.317z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
<path fill="url(#s)" stroke="#e68c3f" stroke-width="6.25" d="M220.915 716.921c-40.442-21.416-99.252 4.124-77.902-54.066 4.276-13.238-6.375-33.008.581-45.926 8.139-15.698 25.58-12.209 36.045-22.674 10.318-10.891 16.859-29.649 36.044-26.742 19.184 2.907 31.945 26.461 45.344 55.229 9.883 20.638 44.941 49.664 42.65 72.758-2.696 35.5-43.027 42.19-82.762 21.421z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
<path fill="url(#t)" d="M415.072 495.764c-3.007 24.906-35.813 76.627-69.518 81.534-34.26 5.336-66.432-34.06-74.147-71.114-9.889-41.206 22.587-57.6 71.938-56.627 53.301 1.654 74.121 13.891 71.727 46.207z" font-size="12" transform="matrix(.5982 .26858 -.23962 .61721 389.8156 76.21132)"/>
<path fill="url(#u)" stroke="#e68c3f" stroke-width="6.25067997" d="M220.274 718.402c-41.327-23.59-99.894 5.605-77.261-55.547 4.736-13.068-6.596-33.552.36-46.47 8.139-15.698 25.801-11.665 36.266-22.13 10.318-10.891 18.827-27.868 38.012-24.961 19.184 2.907 29.977 24.68 43.376 53.448 9.883 20.638 43.415 48.971 41.124 72.065-2.696 35.5-42.724 45.471-81.877 23.595z" transform="matrix(-1.1685 .42314 .47528 1.16478 417.5906 -278.07368)"/>
<path fill="url(#v)" d="M216.482 675.68c-86.531-57.503-47.308-70.96-36.843-81.425 10.318-10.891 18.827-27.868 38.012-24.961 19.184 2.907 29.977 24.68 43.376 53.448 9.883 20.638 43.06 48.918 41.124 72.065-2.616 27.11-48.19 5.487-85.669-19.127z" transform="matrix(-.9451 .34375 .42408 .95606 403.5756 -128.59468)"/>
<path fill="url(#w)" d="M216.506 677.071c-86.531-57.503-46.797-73.57-33.946-81.28 15.399-9.942 15.158-30.831 34.343-27.924 19.184 2.907 30.725 26.107 44.124 54.875 9.883 20.638 43.06 48.918 41.124 72.065-2.616 27.11-48.166 6.878-85.645-17.736z" transform="matrix(1.00431 -.05229 -.0174 1.04575 -66.5614 -92.71798)"/>
<path d="M514.16392618 492.89388153c-6.69409764 11.6729672-34.29007759 30.19600752-52.6812594 25.36804862-18.76593057-4.73521422-27.21700072-31.1485461-23.54211688-51.13877146 3.41150018-22.51206827 23.54139341-23.63093696 48.7850296-12.52637614 27.13954878 12.29170413 35.346749 22.8266733 27.43834668 38.29709898z" font-size="12"/>
<path fill="url(#x)" d="M415.072 495.764c-3.007 24.906-35.813 76.627-69.518 81.534-34.26 5.336-66.432-34.06-74.147-71.114-9.889-41.206 22.587-57.6 71.938-56.627 53.301 1.654 74.121 13.891 71.727 46.207z" font-size="12" transform="matrix(.35123 .14946 -.12886 .34347 413.7696 254.03832)"/>
<path fill="url(#y)" stroke="#e68c3f" stroke-width="3.75" d="M309.954 338.729c7.147-6.77 24.811-27.066 57.961-5.755 6.162 4.01 11.162 4.377 23.021 9.455 23.726 9.749 12.382 33.259-12.744 41.108-10.758 3.489-20.536 16.556-40.129 15.439-16.734-.977-21.119-11.874-31.398-17.906-18.269-10.311-20.965-24.254-11.1-31.653 9.866-7.399 13.725-10.059 14.389-10.688z" transform="matrix(1.25 0 0 1.25 -125.2984 -231.75768)"/>
<path fill="none" stroke="#e68c3f" stroke-width="3.125" d="M363.76535 215.29857c-12.35375.72625-39.24125 27.61375-67.5825 27.61375-28.34125 0-45.055-26.16125-49.415-26.16125"/>
<path fill="url(#z)" d="M309.954 338.729c7.147-6.77 29.691-25.348 59.588-6.328 6.299 3.766 12.804 7.865 22.478 13.464 19.162 11.748 9.671 28.678-13.286 39.39-10.418 4.495-27.593 14.415-40.671 13.721-14.533-1.408-23.935-11.399-33.567-17.906-17.67-12.303-16.597-22.237-8.389-30.508 6.205-5.679 13.183-11.204 13.847-11.833z" transform="matrix(.62789 0 0 .59567 81.6136 -12.43538)"/>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="447px" height="336px" viewBox="0 0 447 336" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Rectangle</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#1E54F6" offset="0%"></stop>
<stop stop-color="#EE2323" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="447" height="336"></rect>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rectangle">
<use fill="#D8D8D8" fill-rule="evenodd" xlink:href="#path-2"></use>
<rect stroke="url(#linearGradient-1)" stroke-width="10" x="5" y="5" width="437" height="326"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 992 B

+1 -1
View File
@@ -12,7 +12,7 @@
- (IJSVG *)svg
{
return [[IJSVG svgNamed:@"paperplane"] retain];
return [[IJSVG svgNamed:@"heart"] retain];
}
@end
+1 -2
View File
@@ -11,10 +11,9 @@
@interface SVGView : NSView {
@private
IJSVG * svg;
}
@end
+3 -2
View File
@@ -22,8 +22,9 @@
if( ( self = [super initWithFrame:frameRect] ) != nil )
{
svg = [self svg];
svg.renderQuality = IJSVGRenderQualityFullResolution;
svg.renderingBackingScaleHelper = ^{
return [svg computeBackingScale:self.window.backingScaleFactor];
return self.window.backingScaleFactor;
};
}
return self;
@@ -31,7 +32,7 @@
- (IJSVG *)svg
{
return [[IJSVG svgNamed:@"test"] retain];
return [IJSVG svgNamed:@"test (1)"];
}
- (void)drawRect:(NSRect)dirtyRect
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 515 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 318 KiB

+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595.279px" height="841.89px" viewBox="0 0 595.279 841.89" enable-background="new 0 0 595.279 841.89"
xml:space="preserve">
<radialGradient id="SVGID_1_" cx="229.116" cy="650.3413" r="160.6544" gradientTransform="matrix(0.1736 0.9848 0.4924 -0.0868 -59.0956 137.9539)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.0573" style="stop-color:#CECECE"/>
<stop offset="0.1221" style="stop-color:#9E9E1F"/>
<stop offset="0.1907" style="stop-color:#74D974"/>
<stop offset="0.2638" style="stop-color:#5050D1"/>
<stop offset="0.5767" style="stop-color:#D44033"/>
<stop offset="0.6687" style="stop-color:#D000FF"/>
<stop offset="0.773" style="stop-color:#0C0CE3"/>
<stop offset="0.8528" style="stop-color:#030303"/>
<stop offset="0.9632" style="stop-color:#000000"/>
</radialGradient>
<ellipse fill="url(#SVGID_1_)" stroke="#000000" stroke-miterlimit="10" cx="251.667" cy="315.818" rx="185.064" ry="131.819"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf8" standalone="no"?>
<svg viewBox="0 0 372.77139 350.83377" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="clipPath4110">
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z"/>
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z"/>
</clipPath>
<filter height="1.35511" id="filter4031" width="1.33422" x="-.16711" y="-.17756">
<feGaussianBlur stdDeviation="25.9554"/>
</filter>
<linearGradient id="linearGradient4159">
<stop offset="0" stop-color="#fff"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient4169" x2="0" xlink:href="#linearGradient4159" y1="386.94983" y2="490.03617"/>
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient4165" x2="0" xlink:href="#linearGradient4159" y1="387.32314" y2="490.40948"/>
</defs>
<g transform="translate(-202.18571,-396.94529)">
<g clip-path="url(#clipPath4110)" transform="translate(-960.57649,853.93036)">
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z"/>
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z"/>
</g>
<g clip-path="url(#clipPath4110)" fill="#f00" filter="url(#filter4031)" transform="translate(-960.57649,853.93036)">
<path d="m1349.1479-106.15129v-302.89728c-47.8699-80.88268-146.0391-44.39418-170.2081,0-74.5507,130.56653 130.5076,196.53622 170.2081,302.89728z" fill="#f00"/>
<path d="m1349.1479-106.15129v-302.89728c47.8699-80.88268 146.0391-44.39418 170.2081,0 74.5507,130.56653-130.5076,196.53622-170.2081,302.89728z" fill="#f00"/>
</g>
<path d="m370.99493,455.63757c0,30.71925-28.70788,20.90496-64.58143,20.90496s-65.328,9.81429-65.328-20.90496 29.08123-55.62213 64.95466-55.62213 64.95477,24.90287 64.95477,55.62213z" fill="url(#linearGradient4165)"/>
<path d="m535.62152,455.26427c0,30.71925-28.7079,20.90496-64.5815,20.90496s-65.328,9.81429-65.328-20.90496 29.0813-55.62213 64.9547-55.62213 64.9548,24.90287 64.9548,55.62213z" fill="url(#linearGradient4169)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="508" height="508" version="1.1" viewBox="0 0 508 508" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
<defs>
<linearGradient id="a" x1="0.145454" x2="0.599999" y1="0.257812" y2="0.570312" gradientTransform="matrix(1,0,0,1,-7.61378e-09,-1.86769e-08)">
<stop offset="0%" stop-color="#FBDDB2" stop-opacity="0.99"></stop>
<stop offset="100%" stop-color="#EFA81A" stop-opacity="0.95"></stop>
</linearGradient>
<linearGradient id="b" x1="-0.0270271" x2="0.783784" y1="0.46875" y2="0.476562" gradientTransform="matrix(1,0,0,1,3.52391e-08,-2.90476e-08)">
<stop offset="0%" stop-color="#787878" stop-opacity="0.99"></stop>
<stop offset="100%" stop-color="#FFF" stop-opacity="0.99"></stop>
</linearGradient>
<linearGradient id="c" x1="0.235289" x2="0.672269" y1="0.265619" y2="0.59375" gradientTransform="matrix(1,0,0,1,1.18803e-07,-1.01189e-08)" xlink:href="#b"></linearGradient>
<linearGradient id="d" x1="0.981639" x2="0.146789" y1="0.0312495" y2="0.601562" gradientTransform="matrix(1,0,0,1,-5.18186e-08,1.7497e-08)" xlink:href="#b"></linearGradient>
<linearGradient id="e" x1="1.20507" x2="0.102482" y1="0.523438" y2="0.515617" gradientTransform="matrix(1,0,0,1,8.20491e-05,8.70101e-06)" xlink:href="#b"></linearGradient>
<radialGradient id="f" fx="-0.0123102%" fy="-0.0135221%" cx="-0.000123102" cy="-0.000135221" r="0.981982" gradientTransform="matrix(0.897766,0,0,1.11388,0.194914,0.125151)" xlink:href="#a"></radialGradient>
<linearGradient id="g" x1="0.242009" x2="0.497717" y1="0.382812" y2="0.507812" gradientTransform="matrix(1,0,0,1,5.50934e-10,1.51001e-09)">
<stop offset="0%" stop-color="#CA536D" stop-opacity="0.99"></stop>
<stop offset="100%" stop-color="#A81837" stop-opacity="0.95"></stop>
</linearGradient>
</defs>
<g transform="scale(1.00011)">
<path fill="url(#a)" fill-rule="evenodd" stroke="#580400" stroke-width="11.905" d="M126.604,52.0403h51.3235v120.598h-51.3235Z"></path>
<path fill="none" fill-rule="evenodd" stroke="#154850" stroke-linejoin="round" stroke-width="11.905" d="M111.364,481.507c270.797,-1.602 272.4,0 272.4,0l-1.603,-227.534l-134.597,-132.995l-134.598,136.2c-1.603,1.602 1.42109e-14,222.727 -1.602,224.329Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
<path fill="url(#b)" fill-rule="evenodd" d="M117.773,475.097c59.287,0 59.287,-1.602 59.287,-1.602c0,0 0,-171.451 0,-171.451c0,0 -57.685,-43.264 -57.685,-43.264c-3.205,1.602 -1.602,217.92 -1.602,216.317Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
<path fill="url(#c)" fill-rule="evenodd" d="M117.773,258.78l124.983,-126.586l28.844,84.924l-94.54,84.926l-59.287,-43.264Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
<path fill="url(#d)" fill-rule="evenodd" d="M229.938,205.902l22.433,-75.31l123.381,124.983l-59.288,51.275l-86.526,-100.948Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
<path fill="url(#e)" fill-rule="evenodd" d="M314.862,475.098l-1.602,-173.054l64.094,-48.071l1.603,221.125h-64.095Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
<path fill="url(#f)" fill-rule="evenodd" stroke="#580400" stroke-linejoin="round" stroke-width="11.9213" d="M177.06,486.314l-1.602,-153.826c0,-36.854 20.029,-62.491 62.491,-62.491c44.065,0 65.697,30.444 65.697,62.491v153.826c0,0 -126.586,-1.602 -126.586,0Z" transform="matrix(1.07519,0,0,1.07519,-5.19257,-47.0224)"></path>
<path fill="url(#g)" fill-rule="evenodd" stroke="#580400" stroke-width="11.905" d="M63.293,303.646c150.621,-144.212 150.621,-144.212 150.621,-144.212c0,0 68.901,-1.602 70.503,-1.602c1.603,0 139.405,137.802 139.405,137.802c0,0 32.048,-33.649 32.048,-33.649c0,0 -206.704,-206.704 -206.704,-206.704c0,-1.42109e-14 -216.318,214.716 -216.318,214.716c7.10543e-15,0 30.4448,33.649 30.4448,33.649Z" transform="matrix(1.07519,0,0,1.07519,-12.0839,-29.7941)"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs xmlns:xlink="http://www.w3.org/1999/xlink">
<radialGradient id="s1" fx=".4" fy=".2">
<stop stop-color="#FE8"/><stop stop-color="#D70" offset="1"/>
</radialGradient>
<radialGradient id="s2" fx=".8" fy=".5" xlink:href="#s1"/>
<radialGradient id="s3" fx=".5" fy=".9" xlink:href="#s1"/>
<radialGradient id="s4" fx=".1" fy=".5" xlink:href="#s1"/>
</defs>
<g stroke="#940">
<path d="M73,29c-37-40-62-24-52,4l6-7c-8-16,7-26,42,9z" fill="url(#s1)"/>
<path d="M47,8c33-16,48,21,9,47l-6-5c38-27,20-44,5-37z" fill="url(#s2)"/>
<path d="M77,32c22,30,10,57-39,51l-1-8c3,3,67,5,36-36z" fill="url(#s3)"/>
<path d="M58,84c-4,20-38-4-8-24l-6-5c-36,43,15,56,23,27z" fill="url(#s4)"/>
<path d="M40,14c-40,37-37,52-9,68l1-8c-16-13-29-21,16-56z" fill="url(#s1)"/>
<path d="M31,33c19,23,20,7,35,41l-9,1.7c-4-19-8-14-31-37z" fill="url(#s2)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 962 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 102">
<radialGradient id="jsongrad" cx="65" cy="90" r="100" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#EEF"/><stop offset="1"/></radialGradient>
<path d="M61,02 A 49,49 0,0,0 39,98 C 9,79 10,24 45,25 C 72,24 65,75 50,75 C 93,79 91,21 62,02" id="jsonswirl" fill="url(#jsongrad)"/>
<use xlink:href="#jsonswirl" transform="rotate(180 50,50)"/>
</svg>

After

Width:  |  Height:  |  Size: 472 B

+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="800" height="800" version="1.1" viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
<defs>
<linearGradient id="b" x1="0" x2="1" gradientUnits="userSpaceOnUse" y1="0" y2="0" gradientTransform="matrix(0,1,1,0,0,200)">
<stop offset="0%" stop-color="#D83352"></stop>
<stop offset="50%" stop-color="#F6DC7B"></stop>
<stop offset="100%" stop-color="#F6DC7B"></stop>
</linearGradient>
</defs>
<rect x="100" y="100" width="600" height="600" fill="url(#b)"></rect>
</svg>

After

Width:  |  Height:  |  Size: 691 B

+5 -19
View File
@@ -1,20 +1,6 @@
<?xml version="1.0"?>
<svg width="120" height="120"
viewPort="0 0 120 120" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
<rect x="-3" y="-3" width="6" height="6" />
<line stroke-linecap="butt"
x1="30" y1="30" x2="30" y2="90"
stroke="black" stroke-width="20"/>
<line stroke-linecap="round"
x1="60" y1="30" x2="60" y2="90"
stroke="black" stroke-width="20"/>
<line stroke-linecap="square"
x1="90" y1="30" x2="90" y2="90"
stroke="black" stroke-width="20"/>
<path d="M30,30 L30,90 M60,30 L60,90 M90,30 L90,90"
stroke="white" />
</svg>
<rect x="-3" y="-3" width="6" height="6" fill="red"
transform="skewY(30)" />
</svg>

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 203 B

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docname="drawing.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs id="defs4">
<linearGradient id="linearGradient3193">
<stop style="stop-color:#0000ff;stop-opacity:1;" offset="0" id="stop3195" />
<stop style="stop-color:#ff0000;stop-opacity:1;" offset="1" id="stop3197" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3193"
id="linearGradient3199"
x1="128.57143"
y1="289.50504"
x2="425.71428"
y2="289.50504"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(1.1,1.1) translate(20,20) rotate(10) scale(.9,.9)">
</linearGradient>
<radialGradient id="radialGradient3193">
<stop style="stop-color:#0000ff;stop-opacity:1;" offset="0" />
<stop style="stop-color:#ff0000;stop-opacity:1;" offset="1" />
</radialGradient>
<radialGradient
xlink:href="#radialGradient3193"
id="radialGradient3199"
cx="300.57143"
cy="529.50504"
fx="400.57143"
fy="529.50504"
r="100.71428"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(1.1,1.1) translate(20,20) rotate(10) scale(.9,.9)">
</radialGradient>
</defs>
<g>
<rect
style="fill:url(#linearGradient3199);fill-opacity:1"
id="rect3191"
width="397.14285"
height="157.14285"
x="128.57143"
y="160.93361" />
<rect
style="fill:url(#radialGradient3199);fill-opacity:1"
id="rect3192"
width="397.14285"
height="157.14285"
x="128.57143"
y="400.93361" />
<rect id='myrect' x="400" y="20" width="60" height="60" rx="3" ry="3"
style="opacity:0.5;fill:#0000FF;stroke:rgb(0, 255, 0);stroke-width:10px;stroke-opacity:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:15;stroke-dasharray:5,3,2;stroke-dashoffset:3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="269" height="269" version="1.1" viewBox="0 0 269 269" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!--Generated by IJSVG (https://github.com/iconjar/IJSVG)-->
<defs>
<mask id="a" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox">
<use fill="#FFF" xlink:href="#d"></use>
</mask>
<linearGradient id="b" x1="0" x2="1" gradientUnits="userSpaceOnUse" y1="0" y2="0" gradientTransform="matrix(0,-197.994,-197.994,0,101.4,199.62)">
<stop offset="0%" stop-color="#D83352"></stop>
<stop offset="41.2669%" stop-color="#F6DC7B"></stop>
<stop offset="100%" stop-color="#F6DC7B"></stop>
</linearGradient>
<mask id="c" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox">
<path fill="#FFF" d="M0,202h202v-202h-202Z"></path>
</mask>
<path id="d" d="M2.404,100.624c0,-54.674 44.321,-98.998 98.995,-98.998v-4.88498e-15c54.675,0 98.997,44.324 98.997,98.998v0c0,54.674 -44.322,98.996 -98.997,98.996v0c-54.674,0 -98.995,-44.322 -98.995,-98.996"></path>
</defs>
<g transform="scale(0.998762)">
<g transform="matrix(1.33333,0,0,-1.33333,0,269.333)">
<use mask="url(#a)" fill="url(#b)" stroke="none" xlink:href="#d"></use>
<g mask="url(#c)">
<path fill="#231F20" stroke="none" d="M0,0c0,-6.725 -5.451,-12.175 -12.177,-12.175c-6.725,0 -12.176,5.45 -12.176,12.175c0,6.725 5.451,12.178 12.176,12.178c6.726,0 12.177,-5.453 12.177,-12.178" transform="matrix(1,0,0,1,75.0225,94.2754)"></path>
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="9" d="M0,0c14.428,-16.873 42.352,-15.393 42.352,-15.393" transform="matrix(1,0,0,1,41.2588,117.041)"></path>
<path fill="#231F20" stroke="none" d="M0,0c0,-6.725 -5.453,-12.176 -12.178,-12.176c-6.724,0 -12.176,5.451 -12.176,12.176c0,6.725 5.452,12.178 12.176,12.178c6.725,0 12.178,-5.453 12.178,-12.178" transform="matrix(1,0,0,1,146.952,94.3281)"></path>
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="9" d="M0,0c-14.428,-16.873 -42.352,-15.393 -42.352,-15.393" transform="matrix(1,0,0,1,161.54,117.094)"></path>
<path fill="none" stroke="#231F20" stroke-linecap="round" stroke-width="10" d="M0,0c29.782,24.805 58.656,-1.05 58.656,-1.05" transform="matrix(1,0,0,1,72.0713,41.6172)"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 590 KiB

After

Width:  |  Height:  |  Size: 522 KiB

+39 -14
View File
@@ -6,18 +6,6 @@ Orignaly written for IconJar (in development)
It also supports the NSPasteboards writing protocol, an IJSVG object can be put onto the pasteboard and application like Sketch and Photoshop can paste them into the document as vector objects (generated PDF's on the fly).
Example app
====
There is an example application provided, it will generate this test bed for SVG's
The example screen contains six SVG's rendered in individual views, from left to right.
* First example shows transforms and colours
* Second example shows linear gradients
* Third example shows defined paths being reused
* Forth example shows transforms such as translate being used and stroke colours
* Fith example shows clip paths being used
* Sixth example shows dashed stroke array's being used
Quick Start
====
Add all the IJSVG library files into your project, import the IJSVG.h into the files you wish to use the SVG's. The easiest way to
@@ -39,12 +27,49 @@ IJSVG does allow you to directly draw the SVG into any focused drawing context f
[svg drawInRect:self.bounds];
}
#### Helpers
IJSVG provides a very simple way of helping out the backing scale factor of the drawing context when the SVG is drawn. Due to CALayers defaulting to 1.0 when custom drawing methods are implemented, they do not know about your backing scale factor. Luckily you can simply do this:
__block IJSVG * svg ....
svg.renderingBackingScaleHelper = ^{
return [svg computeBackingScale:someView.window.backingScaleFactor];
};
# Exporting
#### Yes, thats right... CALayers -> SVG (whos idea was this?!)
IJSVG provides a way of exporting the rendered layer tree back to an SVG file. This isnt 100% perfect but it does a good job of generating what IJSVG renders (have yet to find an issue).
Its a simple as doing this:
IJSVG * svg ...
IJSVGExporter * exporter = [[IJSVGExporter alloc] initWithSVG:svg options:IJSVGExporterOptionAll];
NSString * svgString = [exporter SVGString];
Which will give you back the SVG code to put into a file, there are various options you can give it for more XML manipulation such s collpasing groups and converting transform's from matrix's back to their human readable counter parts.
The fun part is you can actually create an SVG object from a IJSVGLayer and work with them without needing to load a file, for example:
// create group layer and a shape layer (subclass of CAShapeLayer)
IJSVGGroupLayer * baseSVGGroup = ....
IJSVGShapeLayer * shapeLayer = ....
[baseSVGGroup addSublayer:shapeLayer];
// create the SVG - note the viewbox!
IJSVG * svg = [[IJSVG alloc] initWithSVGLayer:baseSVGGroup viewBox:NSMakeRect(0.f, 0.f, 50.f, 50.f)];
.... do what you want
and now you would have a usuable SVG to render where ever you would like and more importantly you can now export that back to an SVG file.
All layers must be of generic type IJSVGLayer or IJSVGShapeLayer, it will throw an exception if you do not use these. Also if you go out the scope of what those layers can do, it wont render nor will it export (get malformed results).
# What it supports
* Elements: def, use, g, path, clipPath, circle, elipse, rect, polyline, polygon and line (supports groups heirachy and inheritance, clip-paths etc)
* Commands: A, M, L, H, V, C, S, T, Q and Z and full support for multiple parameters of each type
* Transformations: matrix, rotate (not around a point - currently), translate, scale transformations
* Transformations: matrix, rotate, translate, scale and skew transformations
* Stroking: stroking, stroke color, stroke opacity, dashed, dashed offset and phase, stroke line cap style
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients
* Filling: fill color, fill mode (winding rules), fill opacity, linear gradients, radial gradients and patterns
* Color: supports all predefined colors from the SVG spec and hex values
* Caching: has basic caching implemenation
* CSS: Basic embedded style sheets are support with very basic selectors
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-cayman
+30 -5
View File
@@ -12,8 +12,14 @@
#import "IJSVGLayerTree.h"
#import "IJSVGGroupLayer.h"
#import "IJSVGImageLayer.h"
#import "IJSVGExporter.h"
#import "IJSVGRendering.h"
#import "IJSVGColorList.h"
#import "IJSVGGradientLayer.h"
#import "IJSVGRenderingStyle.h"
@class IJSVG;
@class IJSVGQuartzRenderer;
void IJSVGBeginTransactionLock();
void IJSVGEndTransactionLock();
@@ -33,8 +39,6 @@ withSVGString:(NSString *)subSVGString;
@end
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
@private
@@ -46,6 +50,10 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
CGRect _viewBox;
CGSize _proposedViewSize;
CGFloat _lastProposedBackingScale;
IJSVGRenderQuality _lastProposedRenderQuality;
CGFloat _backingScale;
NSMutableDictionary * _replacementColors;
IJSVGQuartzRenderer * _quartzRenderer;
struct {
unsigned int shouldHandleForeignObject: 1;
@@ -63,16 +71,20 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
// global overwriting rules for when rendering an SVG, this will overide any
// fillColor, strokeColor, pattern and gradient fill
@property (nonatomic, retain) NSColor * fillColor;
@property (nonatomic, retain) NSColor * strokeColor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) BOOL clipToViewport;
@property (nonatomic, retain) IJSVGRenderingStyle * style;
- (void)prepForDrawingInView:(NSView *)view;
- (BOOL)isFont;
- (IJSVGGroup *)rootNode;
- (NSRect)viewBox;
- (NSArray *)glyphs;
- (NSArray<IJSVGPath *> *)glyphs;
- (NSString *)identifier;
- (IJSVGLayer *)layer;
- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree;
- (NSArray<IJSVG *> *)subSVGs:(BOOL)recursive;
- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options;
- (CGFloat)computeBackingScale:(CGFloat)scale;
- (void)discardDOM;
@@ -127,6 +139,9 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
error:(NSError **)error;
- (NSImage *)imageWithSize:(NSSize)aSize
flipped:(BOOL)flipped;
- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
flipped:(BOOL)flipped
error:(NSError **)error;
- (BOOL)drawAtPoint:(NSPoint)point
size:(NSSize)size;
- (BOOL)drawAtPoint:(NSPoint)point
@@ -135,6 +150,8 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
- (BOOL)drawInRect:(NSRect)rect;
- (BOOL)drawInRect:(NSRect)rect
error:(NSError **)error;
- (void)drawInRect:(NSRect)rect
context:(CGContextRef)context;
- (NSData *)PDFData;
- (NSData *)PDFData:(NSError **)error;
@@ -142,4 +159,12 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
- (NSData *)PDFDataWithRect:(NSRect)rect
error:(NSError **)error;
- (void)beginVectorDraw;
- (void)endVectorDraw;
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize;
- (void)setNeedsDisplay;
// colors
- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills;
@end
+302 -96
View File
@@ -9,34 +9,39 @@
#import "IJSVG.h"
#import "IJSVGCache.h"
#import "IJSVGTransaction.h"
#import "IJSVGExporter.h"
@implementation IJSVG
@synthesize fillColor;
@synthesize strokeColor;
@synthesize renderingBackingScaleHelper;
@synthesize clipToViewport;
@synthesize renderQuality;
@synthesize style = _style;
- (void)dealloc
{
IJSVGBeginTransactionLock();
[renderingBackingScaleHelper release], renderingBackingScaleHelper = nil;
[fillColor release], fillColor = nil;
[strokeColor release], strokeColor = nil;
[_group release], _group = nil;
[_layerTree release], _layerTree = nil;
[_replacementColors release], _replacementColors = nil;
[_quartzRenderer release], _quartzRenderer = nil;
[_style release], _style = nil;
[super dealloc];
IJSVGEndTransactionLock();
}
+ (id)svgNamed:(NSString *)string
error:(NSError **)error
{
return [[self class] svgNamed:string
return [self.class svgNamed:string
error:error
delegate:nil];
}
+ (id)svgNamed:(NSString *)string
{
return [[self class] svgNamed:string
return [self.class svgNamed:string
error:nil];
}
@@ -44,7 +49,7 @@
useCache:(BOOL)useCache
delegate:(id<IJSVGDelegate>)delegate
{
return [[self class] svgNamed:string
return [self.class svgNamed:string
useCache:useCache
error:nil
delegate:delegate];
@@ -53,7 +58,7 @@
+ (id)svgNamed:(NSString *)string
delegate:(id<IJSVGDelegate>)delegate
{
return [[self class] svgNamed:string
return [self.class svgNamed:string
error:nil
delegate:delegate];
}
@@ -73,7 +78,7 @@
error:(NSError **)error
delegate:(id<IJSVGDelegate>)delegate
{
NSBundle * bundle = [NSBundle mainBundle];
NSBundle * bundle = NSBundle.mainBundle;
NSString * str = nil;
NSString * ext = [string pathExtension];
if( ext == nil || ext.length == 0 ) {
@@ -257,6 +262,7 @@
[IJSVGCache cacheSVG:self
fileURL:aURL];
}
}
#endif
return self;
@@ -327,7 +333,15 @@
- (void)_setupBasicsFromAnyInitializer
{
_lastProposedBackingScale = 1.f;
self.style = [[[IJSVGRenderingStyle alloc] init] autorelease];
self.clipToViewport = YES;
self.renderQuality = IJSVGRenderQualityFullResolution;
// setup low level backing scale
_lastProposedBackingScale = 0.f;
self.renderingBackingScaleHelper = ^CGFloat{
return 1.f;
};
}
- (NSString *)identifier
@@ -347,12 +361,17 @@
return _viewBox;
}
- (IJSVGGroup *)rootNode
{
return _group;
}
- (BOOL)isFont
{
return [_group isFont];
}
- (NSArray *)glyphs
- (NSArray<IJSVGPath *> *)glyphs
{
return [_group glyphs];
}
@@ -362,6 +381,14 @@
return [_group subSVGs:recursive];
}
- (NSString *)SVGStringWithOptions:(IJSVGExporterOptions)options
{
IJSVGExporter * exporter = [[[IJSVGExporter alloc] initWithSVG:self
size:self.viewBox.size
options:options] autorelease];
return [exporter SVGString];
}
- (NSImage *)imageWithSize:(NSSize)aSize
{
return [self imageWithSize:aSize
@@ -385,13 +412,23 @@
error:nil];
}
- (NSRect)computeOriginalDrawingFrameWithSize:(NSSize)aSize
{
[self _beginDraw:(NSRect) {
.origin = CGPointZero,
.size = aSize
}];
return NSMakeRect(0.f, 0.f, _proposedViewSize.width * _clipScale,
_proposedViewSize.height * _clipScale);
}
- (NSImage *)imageWithSize:(NSSize)aSize
flipped:(BOOL)flipped
error:(NSError **)error
{
NSImage * im = [[[NSImage alloc] initWithSize:aSize] autorelease];
[im lockFocus];
CGContextRef ref = [[NSGraphicsContext currentContext] graphicsPort];
CGContextRef ref = [[NSGraphicsContext currentContext] CGContext];
CGContextSaveGState(ref);
if(flipped) {
CGContextTranslateCTM(ref, 0.f, aSize.height);
@@ -405,6 +442,16 @@
return im;
}
- (NSImage *)imageByMaintainingAspectRatioWithSize:(NSSize)aSize
flipped:(BOOL)flipped
error:(NSError **)error
{
NSRect rect = [self computeOriginalDrawingFrameWithSize:aSize];
return [self imageWithSize:rect.size
flipped:flipped
error:error];
}
- (NSData *)PDFData
{
return [self PDFData:nil];
@@ -444,10 +491,13 @@
CGContextScaleCTM( context, 1, -1 );
CGContextTranslateCTM( context, 0, -box.size.height);
// draw the icon
[self _drawInRect:(NSRect)box
context:context
error:error];
// make sure we set the masks to path bits n bobs
[self _beginVectorDraw]; {
// draw the icon
[self _drawInRect:(NSRect)box
context:context
error:error];
} [self _endVectorDraw];
CGContextEndPage(context);
@@ -458,6 +508,56 @@
return data;
}
- (void)endVectorDraw
{
[self _endVectorDraw];
}
- (void)beginVectorDraw
{
[self _beginVectorDraw];
}
- (void)_beginVectorDraw
{
// turn on converts masks to PDF's
// as PDF context and layer masks dont work
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
((IJSVGLayer *)layer).convertMasksToPaths = YES;
};
[IJSVGLayer recursivelyWalkLayer:self.layer
withBlock:block];
}
- (void)_endVectorDraw
{
// turn of convert masks to paths as not
// needed for generic rendering
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
((IJSVGLayer *)layer).convertMasksToPaths = NO;
};
[IJSVGLayer recursivelyWalkLayer:self.layer
withBlock:block];
}
- (void)prepForDrawingInView:(NSView *)view
{
// kill the render
if(view == nil) {
self.renderingBackingScaleHelper = nil;
return;
}
// construct the layer before drawing
[self layer];
// set the scale
__block NSView * weakView = view;
self.renderingBackingScaleHelper = ^CGFloat{
return weakView.window.screen.backingScaleFactor;
};
}
- (BOOL)drawAtPoint:(NSPoint)point
size:(NSSize)aSize
{
@@ -484,12 +584,13 @@
error:(NSError **)error
{
return [self _drawInRect:rect
context:[[NSGraphicsContext currentContext] graphicsPort]
context:[[NSGraphicsContext currentContext] CGContext]
error:error];
}
- (CGFloat)computeBackingScale:(CGFloat)actualScale
{
_backingScale = actualScale;
return (CGFloat)(_scale + actualScale);
}
@@ -499,8 +600,8 @@
// we also need to calculate the viewport so we can clip
// the drawing if needed
NSRect viewPort = NSZeroRect;
viewPort.origin.x = round(rect.size.width/2-(_proposedViewSize.width/2)*_clipScale);
viewPort.origin.y = round(rect.size.height/2-(_proposedViewSize.height/2)*_clipScale);;
viewPort.origin.x = round((rect.size.width/2-(_proposedViewSize.width/2)*_clipScale) + rect.origin.x);
viewPort.origin.y = round((rect.size.height/2-(_proposedViewSize.height/2)*_clipScale) + rect.origin.y);
viewPort.size.width = _proposedViewSize.width*_clipScale;
viewPort.size.height = _proposedViewSize.height*_clipScale;
@@ -522,6 +623,14 @@
return viewPort;
}
- (void)drawInRect:(NSRect)rect
context:(CGContextRef)context
{
[self _drawInRect:rect
context:context
error:nil];
}
- (BOOL)_drawInRect:(NSRect)rect
context:(CGContextRef)ref
error:(NSError **)error
@@ -530,63 +639,70 @@
@synchronized (self) {
CGContextSaveGState(ref);
@try {
[self _beginDraw:rect];
// scale the whole drawing context, but first, we need
// to translate the context so its centered
CGFloat tX = round(rect.size.width/2-(_viewBox.size.width/2)*_scale);
CGFloat tY = round(rect.size.height/2-(_viewBox.size.height/2)*_scale);
// we also need to calculate the viewport so we can clip
// the drawing if needed
BOOL canDraw = NO;
NSRect viewPort = [self computeRectDrawingInRect:rect
isValid:&canDraw];
NSRect viewPort = [self computeRectDrawingInRect:rect isValid:&canDraw];
// check the viewport
if( !canDraw ) {
if( canDraw == NO ) {
if( error != NULL ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:IJSVGErrorDrawing
userInfo:nil] autorelease];
}
CGContextRestoreGState(ref);
return NO;
} else {
// clip to mask
if(self.clipToViewport == YES) {
CGContextClipToRect( ref, viewPort);
}
// add the origin back onto the viewport
viewPort.origin.x -= (_viewBox.origin.x)*_scale;
viewPort.origin.y -= (_viewBox.origin.y)*_scale;
// transforms
CGContextTranslateCTM( ref, viewPort.origin.x, viewPort.origin.y);
CGContextScaleCTM( ref, _scale, _scale );
// render the layer, its really important we lock
// the transaction when drawing
IJSVGBeginTransactionLock();
// do we need to update the backing scales on the
// layers?
if(self.renderingBackingScaleHelper != nil) {
[self _askHelperForBackingScale];
}
CGInterpolationQuality quality;
switch(self.renderQuality) {
case IJSVGRenderQualityLow: {
quality = kCGInterpolationLow;
break;
}
case IJSVGRenderQualityOptimized: {
quality = kCGInterpolationMedium;
break;
}
default: {
quality = kCGInterpolationHigh;
}
}
CGContextSetInterpolationQuality(ref, quality);
[self.layer renderInContext:ref];
IJSVGEndTransactionLock();
}
// clip to mask
CGContextClipToRect( ref, viewPort);
tX -= (_viewBox.origin.x*_scale);
tY -= (_viewBox.origin.y*_scale);
CGContextTranslateCTM( ref, tX, tY );
CGContextScaleCTM( ref, _scale, _scale );
// render the layer, its really important we lock
// the transaction when drawing
__block IJSVG * weakSelf = self;
IJSVGBeginTransactionLock();
// do we need to update the backing scales on the
// layers?
if(weakSelf.renderingBackingScaleHelper != nil) {
[weakSelf _askHelperForBackingScale];
}
// render the layers
[weakSelf.layer renderInContext:ref];
IJSVGEndTransactionLock();
}
@catch (NSException *exception) {
// just catch and give back a drawing error to the caller
if( error != NULL )
if( error != NULL ) {
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
code:IJSVGErrorDrawing
userInfo:nil] autorelease];
}
}
@finally {
CGContextRestoreGState(ref);
}
CGContextRestoreGState(ref);
}
return (error == nil);
}
@@ -598,47 +714,33 @@
scale = 1.f;
}
// make sure we multiple the scale by the scale of the rendered clip
// or it will be blurry for gradients and other bitmap drawing
scale = (_scale * scale);
// dont do anything, nothing has changed, no point of iterating over
// every layer for no reason!
if(scale == _lastProposedBackingScale) {
if(scale == _lastProposedBackingScale && renderQuality == _lastProposedRenderQuality) {
return;
}
_lastProposedBackingScale = scale;
[self _recursivelySetScale:scale
forLayer:self.layer];
}
- (void)_recursivelySetScale:(CGFloat)scale
forLayer:(IJSVGLayer *)layer
{
// update the backing layer scale
if(layer.requiresBackingScaleHelp == YES) {
layer.backingScaleFactor = scale;
}
// find the next!
for(IJSVGLayer * aLayer in layer.sublayers) {
[self _recursivelySetScale:scale
forLayer:aLayer];
}
}
- (void)setFillColor:(NSColor *)aColor
{
if(fillColor != nil) {
[fillColor release], fillColor = nil;
}
fillColor = [aColor retain];
[_layerTree release], _layerTree = nil;
}
- (void)setStrokeColor:(NSColor *)aColor
{
if(strokeColor != nil) {
[strokeColor release], strokeColor = nil;
}
strokeColor = [aColor retain];
[_layerTree release], _layerTree = nil;
IJSVGRenderQuality quality = self.renderQuality;
_lastProposedBackingScale = scale;
_lastProposedRenderQuality = quality;
// walk the tree
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
IJSVGLayer * propLayer = ((IJSVGLayer *)layer);
propLayer.renderQuality = quality;
if(propLayer.requiresBackingScaleHelp == YES) {
propLayer.backingScaleFactor = scale;
}
};
// gogogo
[IJSVGLayer recursivelyWalkLayer:self.layer
withBlock:block];
}
- (IJSVGLayer *)layerWithTree:(IJSVGLayerTree *)tree
@@ -664,13 +766,116 @@
// create the renderer and assign default values
// from this SVG object
IJSVGLayerTree * renderer = [[[IJSVGLayerTree alloc] init] autorelease];
renderer.fillColor = self.fillColor;
renderer.strokeColor = self.strokeColor;
renderer.viewBox = self.viewBox;
renderer.style = self.style;
// return the rendered layer
return [self layerWithTree:renderer];
}
- (void)setStyle:(IJSVGRenderingStyle *)style
{
[self removeStyleObservers];
[_style release], _style = nil;
_style = style.retain;
[self addStyleObservers];
}
- (void)removeStyleObservers
{
for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) {
@try {
[_style removeObserver:self
forKeyPath:propertyName];
} @catch(NSException * e) {}
}
}
- (void)addStyleObservers
{
for(NSString * propertyName in IJSVGRenderingStyle.observableProperties) {
[_style addObserver:self
forKeyPath:propertyName
options:0
context:nil];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context
{
// invalidate the tree if a style is set
if(object == _style) {
[self invalidateLayerTree];
}
}
- (void)setNeedsDisplay
{
[self invalidateLayerTree];
}
- (void)invalidateLayerTree
{
[_layerTree release], _layerTree = nil;
}
- (IJSVGColorList *)computedColorList:(BOOL *)hasPatternFills
{
IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease];
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO && layer.isHidden == NO) {
IJSVGShapeLayer * sLayer = (IJSVGShapeLayer *)layer;
NSColor * color = nil;
if(sLayer.fillColor != nil) {
color = [NSColor colorWithCGColor:sLayer.fillColor];
if(color.alphaComponent != 0.f) {
[sheet addColor:color];
}
}
if(sLayer.strokeColor != nil) {
color = [NSColor colorWithCGColor:sLayer.strokeColor];
color = [IJSVGColor computeColorSpace:color];
if(color.alphaComponent != 0.f) {
[sheet addColor:color];
}
}
// check for any patterns
if(sLayer.patternFillLayer != nil ||
sLayer.gradientFillLayer != nil ||
sLayer.gradientStrokeLayer != nil ||
sLayer.patternStrokeLayer != nil) {
if(hasPatternFills != nil && *hasPatternFills != YES) {
*hasPatternFills = YES;
}
// add any colors from gradients
IJSVGGradientLayer * gradLayer = nil;
IJSVGGradientLayer * gradStrokeLayer = nil;
if((gradLayer = sLayer.gradientFillLayer) != nil) {
IJSVGColorList * gradSheet = gradLayer.gradient.computedColorList;
[sheet addColorsFromList:gradSheet];
}
if((gradStrokeLayer = sLayer.gradientStrokeLayer) != nil) {
IJSVGColorList * gradSheet = gradStrokeLayer.gradient.computedColorList;
[sheet addColorsFromList:gradSheet];
}
}
}
};
// walk
[IJSVGLayer recursivelyWalkLayer:self.layer
withBlock:block];
// return the colours!
return sheet;
}
- (void)_beginDraw:(NSRect)rect
{
// in order to correctly fit the the SVG into the
@@ -696,8 +901,9 @@
- (id)pasteboardPropertyListForType:(NSString *)type
{
if( [type isEqualToString:NSPasteboardTypePDF] )
if( [type isEqualToString:NSPasteboardTypePDF] ) {
return [self PDFData];
}
return nil;
}
+2 -2
View File
@@ -28,7 +28,7 @@ static BOOL _enabled = YES;
+ (IJSVG *)cachedSVGForFileURL:(NSURL *)aURL
{
if( ![[self class] enabled] || _cache == nil )
if( ![self.class enabled] || _cache == nil )
return nil;
IJSVG * svg = nil;
if( ( svg = [_cache objectForKey:aURL] ) == nil )
@@ -53,7 +53,7 @@ static BOOL _enabled = YES;
{
_enabled = flag;
if( !flag ) {
[[self class] flushCache];
[self.class flushCache];
return;
}
+11 -1
View File
@@ -160,14 +160,24 @@ typedef NS_ENUM( NSInteger, IJSVGPredefinedColor ) {
@interface IJSVGColor : NSObject
CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness);
+ (NSColor *)computeColorSpace:(NSColor *)color;
+ (NSColorSpace *)defaultColorSpace;
+ (BOOL)isColor:(NSString *)string;
+ (NSString *)colorStringFromColor:(NSColor *)color
forceHex:(BOOL)forceHex;
forceHex:(BOOL)forceHex
allowShorthand:(BOOL)allowShorthand;
+ (NSString *)colorStringFromColor:(NSColor *)color;
+ (NSColor *)colorFromHEXInteger:(NSInteger)hex;
+ (NSColor *)computeColor:(id)colour;
+ (NSColor *)colorFromString:(NSString *)string;
+ (NSColor *)colorFromHEXString:(NSString *)string
alpha:(CGFloat)alpha;
+ (NSColor *)colorFromRString:(NSString *)rString
gString:(NSString *)gString
bString:(NSString *)bString
aString:(NSString *)aString;
+ (NSColor *)colorFromPredefinedColorName:(NSString *)name;
+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color;
+ (NSColor *)changeAlphaOnColor:(NSColor *)color
+313 -199
View File
@@ -11,168 +11,198 @@
@implementation IJSVGColor
static NSMutableDictionary * _colorTree = nil;
static NSDictionary * _colorTree = nil;
CGFloat * IJSVGColorCSSHSLToHSB(CGFloat hue, CGFloat saturation, CGFloat lightness)
{
hue *= (1.f/360.f);
hue = (hue - floorf(hue));
saturation *= 0.01;
lightness *= 0.01;
lightness *= 2.f;
CGFloat s = saturation * ((lightness < 1.f) ? lightness : (2.f - lightness));
CGFloat brightness = (lightness + s) * .5f;
if(s != 0.f) {
s = (2.f * s) / (lightness + s);
}
CGFloat * floats = (CGFloat *)malloc(3*sizeof(CGFloat));
floats[0] = hue;
floats[1] = s;
floats[2] = brightness;
return floats;
};
+ (void)load
{
[[self class] _generateTree];
[self.class _generateTree];
}
+ (NSColorSpace *)defaultColorSpace
{
return NSColorSpace.deviceRGBColorSpace;
}
+ (NSColor *)computeColorSpace:(NSColor *)color
{
NSColorSpace * space = [self defaultColorSpace];
if(color.colorSpace != space) {
color = [color colorUsingColorSpace:space];
}
return color;
}
+ (void)_generateTree
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_colorTree = [[NSMutableDictionary alloc] init];
// add the colours in
[_colorTree setObject:@"f0f8ff" forKey:@"aliceblue"];
[_colorTree setObject:@"faebd7" forKey:@"antiquewhite"];
[_colorTree setObject:@"00ffff" forKey:@"aqua"];
[_colorTree setObject:@"7fffd4" forKey:@"aquamarine"];
[_colorTree setObject:@"f0ffff" forKey:@"azure"];
[_colorTree setObject:@"f5f5dc" forKey:@"beige"];
[_colorTree setObject:@"ffe4c4" forKey:@"bisque"];
[_colorTree setObject:@"000000" forKey:@"black"];
[_colorTree setObject:@"ffebcd" forKey:@"blanchedalmond"];
[_colorTree setObject:@"0000ff" forKey:@"blue"];
[_colorTree setObject:@"8a2be2" forKey:@"blueviolet"];
[_colorTree setObject:@"a52a2a" forKey:@"brown"];
[_colorTree setObject:@"deb887" forKey:@"burlywood"];
[_colorTree setObject:@"5f9ea0" forKey:@"cadetblue"];
[_colorTree setObject:@"7fff00" forKey:@"chartreuse"];
[_colorTree setObject:@"d2691e" forKey:@"chocolate"];
[_colorTree setObject:@"ff7f50" forKey:@"coral"];
[_colorTree setObject:@"6495ed" forKey:@"cornflowerblue"];
[_colorTree setObject:@"fff8dc" forKey:@"cornsilk"];
[_colorTree setObject:@"dc143c" forKey:@"crimson"];
[_colorTree setObject:@"00ffff" forKey:@"cyan"];
[_colorTree setObject:@"00008b" forKey:@"darkblue"];
[_colorTree setObject:@"008b8b" forKey:@"darkcyan"];
[_colorTree setObject:@"b8860b" forKey:@"darkgoldenrod"];
[_colorTree setObject:@"a9a9a9" forKey:@"darkgray"];
[_colorTree setObject:@"006400" forKey:@"darkgreen"];
[_colorTree setObject:@"a9a9a9" forKey:@"darkgrey"];
[_colorTree setObject:@"bdb76b" forKey:@"darkkhaki"];
[_colorTree setObject:@"8b008b" forKey:@"darkmagenta"];
[_colorTree setObject:@"556b2f" forKey:@"darkolivegreen"];
[_colorTree setObject:@"ff8c00" forKey:@"darkorange"];
[_colorTree setObject:@"9932cc" forKey:@"darkorchid"];
[_colorTree setObject:@"8b0000" forKey:@"darkred"];
[_colorTree setObject:@"e9967a" forKey:@"darksalmon"];
[_colorTree setObject:@"8fbc8f" forKey:@"darkseagreen"];
[_colorTree setObject:@"483d8b" forKey:@"darkslateblue"];
[_colorTree setObject:@"2f4f4f" forKey:@"darkslategray"];
[_colorTree setObject:@"2f4f4f" forKey:@"darkslategrey"];
[_colorTree setObject:@"00ced1" forKey:@"darkturquoise"];
[_colorTree setObject:@"9400d3" forKey:@"darkviolet"];
[_colorTree setObject:@"ff1493" forKey:@"deeppink"];
[_colorTree setObject:@"00bfff" forKey:@"deepskyblue"];
[_colorTree setObject:@"696969" forKey:@"dimgray"];
[_colorTree setObject:@"696969" forKey:@"dimgrey"];
[_colorTree setObject:@"1e90ff" forKey:@"dodgerblue"];
[_colorTree setObject:@"b22222" forKey:@"firebrick"];
[_colorTree setObject:@"fffaf0" forKey:@"floralwhite"];
[_colorTree setObject:@"228b22" forKey:@"forestgreen"];
[_colorTree setObject:@"ff00ff" forKey:@"fuchsia"];
[_colorTree setObject:@"dcdcdc" forKey:@"gainsboro"];
[_colorTree setObject:@"f8f8ff" forKey:@"ghostwhite"];
[_colorTree setObject:@"ffd700" forKey:@"gold"];
[_colorTree setObject:@"daa520" forKey:@"goldenrod"];
[_colorTree setObject:@"808080" forKey:@"gray"];
[_colorTree setObject:@"008000" forKey:@"green"];
[_colorTree setObject:@"adff2f" forKey:@"greenyellow"];
[_colorTree setObject:@"808080" forKey:@"grey"];
[_colorTree setObject:@"f0fff0" forKey:@"honeydew"];
[_colorTree setObject:@"ff69b4" forKey:@"hotpink"];
[_colorTree setObject:@"cd5c5c" forKey:@"indianred"];
[_colorTree setObject:@"4b0082" forKey:@"indigo"];
[_colorTree setObject:@"fffff0" forKey:@"ivory"];
[_colorTree setObject:@"f0e68c" forKey:@"khaki"];
[_colorTree setObject:@"e6e6fa" forKey:@"lavender"];
[_colorTree setObject:@"fff0f5" forKey:@"lavenderblush"];
[_colorTree setObject:@"7cfc00" forKey:@"lawngreen"];
[_colorTree setObject:@"fffacd" forKey:@"lemonchiffon"];
[_colorTree setObject:@"add8e6" forKey:@"lightblue"];
[_colorTree setObject:@"f08080" forKey:@"lightcoral"];
[_colorTree setObject:@"e0ffff" forKey:@"lightcyan"];
[_colorTree setObject:@"fafad2" forKey:@"lightgoldenrodyellow"];
[_colorTree setObject:@"d3d3d3" forKey:@"lightgray"];
[_colorTree setObject:@"90ee90" forKey:@"lightgreen"];
[_colorTree setObject:@"d3d3d3" forKey:@"lightgrey"];
[_colorTree setObject:@"ffb6c1" forKey:@"lightpink"];
[_colorTree setObject:@"ffa07a" forKey:@"lightsalmon"];
[_colorTree setObject:@"20b2aa" forKey:@"lightseagreen"];
[_colorTree setObject:@"87cefa" forKey:@"lightskyblue"];
[_colorTree setObject:@"778899" forKey:@"lightslategray"];
[_colorTree setObject:@"778899" forKey:@"lightslategrey"];
[_colorTree setObject:@"b0c4de" forKey:@"lightsteelblue"];
[_colorTree setObject:@"ffffe0" forKey:@"lightyellow"];
[_colorTree setObject:@"00ff00" forKey:@"lime"];
[_colorTree setObject:@"32cd32" forKey:@"limegreen"];
[_colorTree setObject:@"faf0e6" forKey:@"linen"];
[_colorTree setObject:@"ff00ff" forKey:@"magenta"];
[_colorTree setObject:@"800000" forKey:@"maroon"];
[_colorTree setObject:@"66cdaa" forKey:@"mediumaquamarine"];
[_colorTree setObject:@"0000cd" forKey:@"mediumblue"];
[_colorTree setObject:@"ba55d3" forKey:@"mediumorchid"];
[_colorTree setObject:@"9370db" forKey:@"mediumpurple"];
[_colorTree setObject:@"3cb371" forKey:@"mediumseagreen"];
[_colorTree setObject:@"7b68ee" forKey:@"mediumslateblue"];
[_colorTree setObject:@"00fa9a" forKey:@"mediumspringgreen"];
[_colorTree setObject:@"48d1cc" forKey:@"mediumturquoise"];
[_colorTree setObject:@"c71585" forKey:@"mediumvioletred"];
[_colorTree setObject:@"191970" forKey:@"midnightblue"];
[_colorTree setObject:@"f5fffa" forKey:@"mintcream"];
[_colorTree setObject:@"ffe4e1" forKey:@"mistyrose"];
[_colorTree setObject:@"ffe4b5" forKey:@"moccasin"];
[_colorTree setObject:@"ffdead" forKey:@"navajowhite"];
[_colorTree setObject:@"000080" forKey:@"navy"];
[_colorTree setObject:@"fdf5e6" forKey:@"oldlace"];
[_colorTree setObject:@"808000" forKey:@"olive"];
[_colorTree setObject:@"6b8e23" forKey:@"olivedrab"];
[_colorTree setObject:@"ffa500" forKey:@"orange"];
[_colorTree setObject:@"ff4500" forKey:@"orangered"];
[_colorTree setObject:@"da70d6" forKey:@"orchid"];
[_colorTree setObject:@"eee8aa" forKey:@"palegoldenrod"];
[_colorTree setObject:@"98fb98" forKey:@"palegreen"];
[_colorTree setObject:@"afeeee" forKey:@"paleturquoise"];
[_colorTree setObject:@"db7093" forKey:@"palevioletred"];
[_colorTree setObject:@"ffefd5" forKey:@"papayawhip"];
[_colorTree setObject:@"ffdab9" forKey:@"peachpuff"];
[_colorTree setObject:@"cd853f" forKey:@"peru"];
[_colorTree setObject:@"ffc0cb" forKey:@"pink"];
[_colorTree setObject:@"dda0dd" forKey:@"plum"];
[_colorTree setObject:@"b0e0e6" forKey:@"powderblue"];
[_colorTree setObject:@"800080" forKey:@"purple"];
[_colorTree setObject:@"ff0000" forKey:@"red"];
[_colorTree setObject:@"bc8f8f" forKey:@"rosybrown"];
[_colorTree setObject:@"4169e1" forKey:@"royalblue"];
[_colorTree setObject:@"8b4513" forKey:@"saddlebrown"];
[_colorTree setObject:@"fa8072" forKey:@"salmon"];
[_colorTree setObject:@"f4a460" forKey:@"sandybrown"];
[_colorTree setObject:@"2e8b57" forKey:@"seagreen"];
[_colorTree setObject:@"fff5ee" forKey:@"seashell"];
[_colorTree setObject:@"a0522d" forKey:@"sienna"];
[_colorTree setObject:@"c0c0c0" forKey:@"silver"];
[_colorTree setObject:@"87ceeb" forKey:@"skyblue"];
[_colorTree setObject:@"6a5acd" forKey:@"slateblue"];
[_colorTree setObject:@"708090" forKey:@"slategray"];
[_colorTree setObject:@"708090" forKey:@"slategrey"];
[_colorTree setObject:@"fffafa" forKey:@"snow"];
[_colorTree setObject:@"00ff7f" forKey:@"springgreen"];
[_colorTree setObject:@"4682b4" forKey:@"steelblue"];
[_colorTree setObject:@"d2b48c" forKey:@"tan"];
[_colorTree setObject:@"008080" forKey:@"teal"];
[_colorTree setObject:@"d8bfd8" forKey:@"thistle"];
[_colorTree setObject:@"ff6347" forKey:@"tomato"];
[_colorTree setObject:@"40e0d0" forKey:@"turquoise"];
[_colorTree setObject:@"ee82ee" forKey:@"violet"];
[_colorTree setObject:@"f5deb3" forKey:@"wheat"];
[_colorTree setObject:@"ffffff" forKey:@"white"];
[_colorTree setObject:@"f5f5f5" forKey:@"whitesmoke"];
[_colorTree setObject:@"ffff00" forKey:@"yellow"];
[_colorTree setObject:@"9acd32" forKey:@"yellowgreen"];
_colorTree = [@{
@"aliceblue":@(0xf0f8ff),
@"antiquewhite":@(0xfaebd7),
@"aqua":@(0x00ffff),
@"aquamarine":@(0x7fffd4),
@"azure":@(0xf0ffff),
@"beige":@(0xf5f5dc),
@"bisque":@(0xffe4c4),
@"black":@(0x000000),
@"blanchedalmond":@(0xffebcd),
@"blue":@(0x0000ff),
@"blueviolet":@(0x8a2be2),
@"brown":@(0xa52a2a),
@"burlywood":@(0xdeb887),
@"cadetblue":@(0x5f9ea0),
@"chartreuse":@(0x7fff00),
@"chocolate":@(0xd2691e),
@"coral":@(0xff7f50),
@"cornflowerblue":@(0x6495ed),
@"cornsilk":@(0xfff8dc),
@"crimson":@(0xdc143c),
@"currentcolor":@(0x000000),
@"cyan":@(0x00ffff),
@"darkblue":@(0x00008b),
@"darkcyan":@(0x008b8b),
@"darkgoldenrod":@(0xb8860b),
@"darkgray":@(0xa9a9a9),
@"darkgreen":@(0x006400),
@"darkgrey":@(0xa9a9a9),
@"darkkhaki":@(0xbdb76b),
@"darkmagenta":@(0x8b008b),
@"darkolivegreen":@(0x556b2f),
@"darkorange":@(0xff8c00),
@"darkorchid":@(0x9932cc),
@"darkred":@(0x8b0000),
@"darksalmon":@(0xe9967a),
@"darkseagreen":@(0x8fbc8f),
@"darkslateblue":@(0x483d8b),
@"darkslategray":@(0x2f4f4f),
@"darkturquoise":@(0x00ced1),
@"darkviolet":@(0x9400d3),
@"deeppink":@(0xff1493),
@"deepskyblue":@(0x00bfff),
@"dimgray":@(0x696969),
@"dimgrey":@(0x696969),
@"dodgerblue":@(0x1e90ff),
@"firebrick":@(0xb22222),
@"floralwhite":@(0xfffaf0),
@"forestgreen":@(0x228b22),
@"fuchsia":@(0xff00ff),
@"gainsboro":@(0xdcdcdc),
@"ghostwhite":@(0xf8f8ff),
@"gold":@(0xffd700),
@"goldenrod":@(0xdaa520),
@"gray":@(0x808080),
@"green":@(0x008000),
@"greenyellow":@(0xadff2f),
@"grey":@(0x808080),
@"honeydew":@(0xf0fff0),
@"hotpink":@(0xff69b4),
@"indianred":@(0xcd5c5c),
@"indigo":@(0x4b0082),
@"ivory":@(0xfffff0),
@"khaki":@(0xf0e68c),
@"lavender":@(0xe6e6fa),
@"lavenderblush":@(0xfff0f5),
@"lawngreen":@(0x7cfc00),
@"lemonchiffon":@(0xfffacd),
@"lightblue":@(0xadd8e6),
@"lightcoral":@(0xf08080),
@"lightcyan":@(0xe0ffff),
@"lightgoldenrodyellow":@(0xfafad2),
@"lightgray":@(0xd3d3d3),
@"lightgreen":@(0x90ee90),
@"lightgrey":@(0xd3d3d3),
@"lightpink":@(0xffb6c1),
@"lightsalmon":@(0xffa07a),
@"lightseagreen":@(0x20b2aa),
@"lightskyblue":@(0x87cefa),
@"lightslategray":@(0x778899),
@"lightsteelblue":@(0xb0c4de),
@"lightyellow":@(0xffffe0),
@"lime":@(0x00ff00),
@"limegreen":@(0x32cd32),
@"linen":@(0xfaf0e6),
@"magenta":@(0xff00ff),
@"maroon":@(0x800000),
@"mediumaquamarine":@(0x66cdaa),
@"mediumblue":@(0x0000cd),
@"mediumorchid":@(0xba55d3),
@"mediumpurple":@(0x9370db),
@"mediumseagreen":@(0x3cb371),
@"mediumslateblue":@(0x7b68ee),
@"mediumspringgreen":@(0x00fa9a),
@"mediumturquoise":@(0x48d1cc),
@"mediumvioletred":@(0xc71585),
@"midnightblue":@(0x191970),
@"mintcream":@(0xf5fffa),
@"mistyrose":@(0xffe4e1),
@"moccasin":@(0xffe4b5),
@"navajowhite":@(0xffdead),
@"navy":@(0x000080),
@"oldlace":@(0xfdf5e6),
@"olive":@(0x808000),
@"olivedrab":@(0x6b8e23),
@"orange":@(0xffa500),
@"orangered":@(0xff4500),
@"orchid":@(0xda70d6),
@"palegoldenrod":@(0xeee8aa),
@"palegreen":@(0x98fb98),
@"paleturquoise":@(0xafeeee),
@"palevioletred":@(0xdb7093),
@"papayawhip":@(0xffefd5),
@"peachpuff":@(0xffdab9),
@"peru":@(0xcd853f),
@"pink":@(0xffc0cb),
@"plum":@(0xdda0dd),
@"powderblue":@(0xb0e0e6),
@"purple":@(0x800080),
@"red":@(0xff0000),
@"rosybrown":@(0xbc8f8f),
@"royalblue":@(0x4169e1),
@"saddlebrown":@(0x8b4513),
@"salmon":@(0xfa8072),
@"sandybrown":@(0xf4a460),
@"seagreen":@(0x2e8b57),
@"seashell":@(0xfff5ee),
@"sienna":@(0xa0522d),
@"silver":@(0xc0c0c0),
@"skyblue":@(0x87ceeb),
@"slateblue":@(0x6a5acd),
@"slategrey":@(0x708090),
@"snow":@(0xfffafa),
@"springgreen":@(0x00ff7f),
@"steelblue":@(0x4682b4),
@"tan":@(0xd2b48c),
@"teal":@(0x008080),
@"thistle":@(0xd8bfd8),
@"tomato":@(0xff6347),
@"turquoise":@(0x40e0d0),
@"violet":@(0xee82ee),
@"wheat":@(0xf5deb3),
@"white":@(0xffffff),
@"whitesmoke":@(0xf5f5f5),
@"yellow":@(0xffff00),
@"yellowgreen":@(0x9acd32)
} retain];
});
}
@@ -183,62 +213,125 @@ static NSMutableDictionary * _colorTree = nil;
return nil;
}
+ (NSColor *)colorFromRString:(NSString *)rString
gString:(NSString *)gString
bString:(NSString *)bString
aString:(NSString *)aString
{
return [self colorFromRUnit:[IJSVGUnitLength unitWithString:rString]
gUnit:[IJSVGUnitLength unitWithString:gString]
bUnit:[IJSVGUnitLength unitWithString:bString]
aUnit:[IJSVGUnitLength unitWithString:aString]];
}
+ (NSColor *)colorFromRUnit:(IJSVGUnitLength *)rUnit
gUnit:(IJSVGUnitLength *)gUnit
bUnit:(IJSVGUnitLength *)bUnit
aUnit:(IJSVGUnitLength *)aUnit
{
CGFloat r = rUnit.type == IJSVGUnitLengthTypePercentage ?
[rUnit computeValue:255.f] : [rUnit computeValue:1.f];
CGFloat g = gUnit.type == IJSVGUnitLengthTypePercentage ?
[gUnit computeValue:255.f] : [gUnit computeValue:1.f];
CGFloat b = bUnit.type == IJSVGUnitLengthTypePercentage ?
[bUnit computeValue:255.f] : [bUnit computeValue:1.f];
CGFloat a = [aUnit computeValue:100.f];
return [self computeColorSpace:[NSColor colorWithDeviceRed:(r/255.f)
green:(g/255.f)
blue:(b/255.f)
alpha:a]];
}
+ (NSColor *)colorFromString:(NSString *)string
{
if( [string length] < 3 )
return nil;
string = [string lowercaseString];
NSColor * color = [[self class] colorFromPredefinedColorName:string];
if( color != nil )
return color;
NSCharacterSet * set = NSCharacterSet.whitespaceAndNewlineCharacterSet;
string = [string stringByTrimmingCharactersInSet:set];
if( [[string lowercaseString] isEqualToString:@"none"] )
return [NSColor clearColor];
if( [string length] < 3 ) {
return nil;
}
NSColor * color = nil;
string = [string lowercaseString];
if([self.class isHex:string] == NO) {
color = [self.class colorFromPredefinedColorName:string];
if( color != nil ) {
return color;
}
}
// is simply a clear color, dont fill
if( [[string lowercaseString] isEqualToString:@"none"] ) {
return [self computeColorSpace:NSColor.clearColor];
}
// is it RGB?
if( [[string substringToIndex:3] isEqualToString:@"rgb"] )
{
if( [[string substringToIndex:3] isEqualToString:@"rgb"] ) {
NSRange range = [IJSVGUtils rangeOfParentheses:string];
NSString * rgbString = [string substringWithRange:range];
NSArray * parts = [rgbString componentsSeparatedByChars:","];
NSString * alpha = @"100%";
if(parts.count == 4) {
alpha = parts[3];
}
return [self colorFromRString:parts[0]
gString:parts[1]
bString:parts[2]
aString:alpha];
}
// is it HSL?
if([[string substringToIndex:3] isEqualToString:@"hsl"]) {
NSInteger count = 0;
CGFloat * params = [IJSVGUtils commandParameters:string
count:&count];
CGFloat alpha = 1;
if( count == 4 )
if(count == 4) {
alpha = params[3];
color = [NSColor colorWithDeviceRed:params[0]/255
green:params[1]/255
blue:params[2]/255
}
// convert HSL to HSB
CGFloat * hsb = IJSVGColorCSSHSLToHSB(params[0], params[1], params[2]);
color = [NSColor colorWithDeviceHue:hsb[0]
saturation:hsb[1]
brightness:hsb[2]
alpha:alpha];
color = [self computeColorSpace:color];
// memory clean!
free(hsb);
free(params);
return color;
}
color = [[self class] colorFromHEXString:string
alpha:1.f];
color = [self.class colorFromHEXString:string alpha:1.f];
return color;
}
+ (NSColor *)colorFromPredefinedColorName:(NSString *)name
{
NSString * hex = nil;
NSNumber * hex = nil;
name = [name.lowercaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if( ( hex = [_colorTree objectForKey:name] ) == nil )
if((hex = _colorTree[name]) == nil ) {
return nil;
return [[self class] colorFromHEXString:hex
alpha:1.f];
}
return [self.class colorFromHEXInteger:hex.integerValue];
}
+ (NSString *)colorStringFromColor:(NSColor *)color
{
return [self colorStringFromColor:color
forceHex:NO];
forceHex:NO
allowShorthand:YES];
}
+ (NSString *)colorStringFromColor:(NSColor *)color
forceHex:(BOOL)forceHex
allowShorthand:(BOOL)allowShorthand
{
// convert to RGB
color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
color = [self computeColorSpace:color];
int red = color.redComponent * 0xFF;
int green = color.greenComponent * 0xFF;
@@ -254,10 +347,23 @@ static NSMutableDictionary * _colorTree = nil;
if(forceHex || alpha == 100 ||
(red == 0 && green == 0 && blue == 0 && alpha == 0) ||
(red == 255 && green == 255 && blue == 255 && alpha == 100)) {
// just return hex
if(allowShorthand == YES) {
NSString * r = [NSString stringWithFormat:@"%02X",red];
NSString * g = [NSString stringWithFormat:@"%02X",green];
NSString * b = [NSString stringWithFormat:@"%02X",blue];
if([r characterAtIndex:0] == [r characterAtIndex:1] &&
[g characterAtIndex:0] == [g characterAtIndex:1] &&
[b characterAtIndex:0] == [b characterAtIndex:1]) {
return [NSString stringWithFormat:@"#%c%c%c",[r characterAtIndex:0],
[g characterAtIndex:0],[b characterAtIndex:0]];
}
}
return [NSString stringWithFormat:@"#%02X%02X%02X",red,green,blue];
}
return [NSString stringWithFormat:@"rgba(%d, %d, %d, %d)",red, green, blue, alpha];
// note the %g, CSS alpha is 0 to 1, not 0 - 100, my bad!
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)",red, green, blue,
((float)alpha/100.f)];
}
+ (NSString *)colorNameFromPredefinedColor:(IJSVGPredefinedColor)color
@@ -565,29 +671,44 @@ static NSMutableDictionary * _colorTree = nil;
+ (NSColor *)changeAlphaOnColor:(NSColor *)color
to:(CGFloat)alphaValue
{
color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
return [NSColor colorWithDeviceRed:[color redComponent]
green:[color greenComponent]
blue:[color blueComponent]
alpha:alphaValue];
color = [self computeColorSpace:color];
return [self computeColorSpace:[NSColor colorWithDeviceRed:[color redComponent]
green:[color greenComponent]
blue:[color blueComponent]
alpha:alphaValue]];
}
+ (BOOL)isColor:(NSString *)string
{
return [[string substringToIndex:1] isEqualToString:@"#"] || [[string substringToIndex:3] isEqualToString:@"rgb"];
return [[string substringToIndex:1] isEqualToString:@"#"] ||
[[string substringToIndex:3] isEqualToString:@"rgb"];
}
+ (BOOL)isHex:(NSString *)string
{
NSCharacterSet *chars = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef#"] invertedSet];
return [string rangeOfCharacterFromSet:chars].location == NSNotFound;
const char * validList = "0123456789ABCDEFabcdef#";
for(NSInteger i = 0; i < string.length; i++) {
char c = [string characterAtIndex:i];
if(strchr(validList, c) == NULL) {
return NO;
}
}
return YES;
}
+ (NSColor *)colorFromHEXInteger:(NSInteger)hex
{
return [self computeColorSpace:[NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f
green:((hex >> 8) & 0xFF) / 255.f
blue:(hex & 0xFF) / 255.f
alpha:1.f]];
}
+ (NSColor *)colorFromHEXString:(NSString *)string
alpha:(CGFloat)alpha
{
// absolutely no string
if( string == nil || string.length == 0 || ![[self class] isHex:string] )
if( string == nil || string.length == 0 || ![self.class isHex:string] )
return nil;
if( [[string substringToIndex:1] isEqualToString:@"#"] )
@@ -605,19 +726,12 @@ static NSMutableDictionary * _colorTree = nil;
string = str;
}
NSScanner * scanner = [NSScanner scannerWithString:string];
unsigned int hex;
if( [scanner scanHexInt:&hex] )
{
NSInteger r = (hex>>16) & 0xFF;
NSInteger g = (hex>>8) & 0xFF;
NSInteger b = (hex) & 0xFF;
return [NSColor colorWithDeviceRed:r/255.f
green:g/255.f
blue:b/255.f
alpha:alpha];
}
return nil;
const char * hexString = [string cStringUsingEncoding:NSUTF8StringEncoding];
unsigned long hex = strtoul(hexString, NULL, 16);
return [self computeColorSpace:[NSColor colorWithDeviceRed:((hex>>16) & 0xFF)/255.f
green:((hex>>8) & 0xFF)/255.f
blue:(hex & 0xFF)/255.f
alpha:alpha]];
}
@end
+31
View File
@@ -0,0 +1,31 @@
//
// IJSVGColorList.h
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IJSVGColor.h"
@interface IJSVGColorList : NSObject <NSCopying> {
@private
NSMutableDictionary<NSColor *, NSColor *> * _replacementColorTree;
NSMutableSet<NSColor *> * _colors;
}
- (NSColor *)proposedColorForColor:(NSColor *)color;
- (void)removeAllReplacementColors;
- (void)removeReplacementColor:(NSColor *)color;
- (void)setReplacementColor:(NSColor *)newColor
forColor:(NSColor *)color;
- (void)setReplacementColors:(NSDictionary<NSColor *, NSColor *> *)colors
clearExistingColors:(BOOL)clearExistingColors;
- (void)addColorsFromList:(IJSVGColorList *)sheet;
- (NSSet<NSColor *> *)colors;
- (void)addColor:(NSColor *)color;
@end
+113
View File
@@ -0,0 +1,113 @@
//
// IJSVGColorList.m
// IconJar
//
// Created by Curtis Hard on 07/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGColorList.h"
@implementation IJSVGColorList
- (void)dealloc
{
[_replacementColorTree release], _replacementColorTree = nil;
[_colors release], _colors = nil;
[super dealloc];
}
- (instancetype)init
{
if((self = [super init]) != nil) {
_replacementColorTree = [[NSMutableDictionary alloc] init];
_colors = [[NSMutableSet alloc] init];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
IJSVGColorList * sheet = [[self.class alloc] init];
[sheet setReplacementColors:[_replacementColorTree.copy autorelease]
clearExistingColors:YES];
return sheet;
}
- (NSColor *)proposedColorForColor:(NSColor *)color
{
// nothing found, just return color
if(_replacementColorTree == nil || _replacementColorTree.count == 0) {
return color;
}
// check the mappings
NSColor * found = nil;
color = [IJSVGColor computeColorSpace:color];
if((found = _replacementColorTree[color]) != nil) {
return found;
}
return color;
}
- (void)_invalidateColorTree
{
[_replacementColorTree release], _replacementColorTree = nil;
_replacementColorTree = [[NSMutableDictionary alloc] init];
}
- (void)removeAllReplacementColors
{
[self _invalidateColorTree];
}
- (void)removeReplacementColor:(NSColor *)color
{
if(_replacementColorTree == nil) {
return;
}
[_replacementColorTree removeObjectForKey:[IJSVGColor computeColorSpace:color]];
}
- (void)setReplacementColor:(NSColor *)newColor
forColor:(NSColor *)color
{
color = [IJSVGColor computeColorSpace:color];
newColor = [IJSVGColor computeColorSpace:newColor];
_replacementColorTree[color] = newColor;
}
- (void)setReplacementColors:(NSDictionary<NSColor *, NSColor *> *)colors
clearExistingColors:(BOOL)clearExistingColors
{
if(clearExistingColors == YES) {
[self _invalidateColorTree];
}
for(NSColor * oldColor in colors) {
[self setReplacementColor:colors[oldColor]
forColor:oldColor];
}
}
- (NSSet<NSColor *> *)colors
{
return [NSSet setWithSet:_colors];
}
- (void)addColorsFromList:(IJSVGColorList *)sheet
{
[_colors addObjectsFromArray:sheet.colors.allObjects];
}
- (void)addColor:(NSColor *)color
{
[_colors addObject:[IJSVGColor computeColorSpace:color]];
}
- (void)removeColor:(NSColor *)color
{
[_colors removeObject:[IJSVGColor computeColorSpace:color]];
}
@end
+2 -5
View File
@@ -41,6 +41,7 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
IJSVGCommand * previousCommand;
NSInteger _currentIndex;
Class<IJSVGCommandProtocol> commandClass;
BOOL isSubCommand;
}
@property ( nonatomic, copy ) NSString * commandString;
@@ -52,17 +53,13 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) {
@property ( nonatomic, retain ) NSMutableArray * subCommands;
@property ( nonatomic, assign ) Class<IJSVGCommandProtocol> commandClass;
@property ( nonatomic, assign ) IJSVGCommand * previousCommand;
@property ( nonatomic, assign ) BOOL isSubCommand;
- (id)initWithCommandString:(NSString *)commandString;
+ (NSPoint)readCoordinatePair:(CGFloat *)pairs
index:(NSInteger)index;
+ (void)registerClass:(Class)aClass
forCommand:(NSString *)command;
+ (NSDictionary *)registeredCommandClasses;
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str;
- (CGFloat)readFloat;
- (NSPoint)readPoint;
- (BOOL)readBOOL;
+33 -27
View File
@@ -9,6 +9,17 @@
#import "IJSVGCommand.h"
#import "IJSVGUtils.h"
#import "IJSVGCommandArc.h"
#import "IJSVGCommandMove.h"
#import "IJSVGCommandClose.h"
#import "IJSVGCommandCurve.h"
#import "IJSVGCommandLineTo.h"
#import "IJSVGCommandVerticalLine.h"
#import "IJSVGCommandHorizontalLine.h"
#import "IJSVGCommandSmoothCurve.h"
#import "IJSVGCommandQuadraticCurve.h"
#import "IJSVGCommandCommandSmoothQuadraticCurve.h"
@implementation IJSVGCommand
@synthesize commandString;
@@ -20,8 +31,7 @@
@synthesize requiredParameters;
@synthesize type;
@synthesize previousCommand;
static NSMutableDictionary * _classes = nil;
@synthesize isSubCommand;
- (void)dealloc
{
@@ -38,10 +48,9 @@ static NSMutableDictionary * _classes = nil;
{
// work out the basics
_currentIndex = 0;
subCommands = [[NSMutableArray alloc] init];
command = [[str substringToIndex:1] copy];
type = [IJSVGUtils typeForCommandString:self.command];
commandClass = [[self class] commandClassForCommandLetter:self.command];
commandClass = [self.class commandClassForCommandChar:[self.command characterAtIndex:0]];
parameters = [IJSVGUtils commandParameters:str count:&parameterCount];
requiredParameters = [self.commandClass requiredParameterCount];
@@ -54,6 +63,8 @@ static NSMutableDictionary * _classes = nil;
sets = self.parameterCount/self.requiredParameters;
}
subCommands = [[NSMutableArray alloc] initWithCapacity:sets];
// interate over the sets
for( NSInteger i = 0; i < sets; i++ ) {
// memory for this will be handled by the created subcommand
@@ -66,13 +77,14 @@ static NSMutableDictionary * _classes = nil;
}
// create a subcommand per set
IJSVGCommand * c = [[[[self class] alloc] init] autorelease];
IJSVGCommand * c = [[[self.class alloc] init] autorelease];
c.parameterCount = self.requiredParameters;
c.parameters = subParams;
c.type = self.type;
c.command = self.command;
c.previousCommand = [self.subCommands lastObject];
c.previousCommand = self.subCommands.lastObject;
c.commandClass = self.commandClass;
c.isSubCommand = i == 0 ? NO : YES;
// add it to our tree
[self.subCommands addObject:c];
@@ -87,33 +99,27 @@ static NSMutableDictionary * _classes = nil;
return NSMakePoint( pairs[index*2], pairs[index*2+1]);
}
+ (void)registerClass:(Class)aClass
forCommand:(NSString *)command
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_classes = [[NSMutableDictionary alloc] init];
});
[_classes setObject:NSStringFromClass(aClass)
forKey:command];
}
+ (NSDictionary *)registeredCommandClasses
{
return _classes;
}
+ (void)load
{
// register here...
}
+ (Class<IJSVGCommandProtocol>)commandClassForCommandLetter:(NSString *)str
+ (Class<IJSVGCommandProtocol>)commandClassForCommandChar:(char)aChar
{
NSString * command = nil;
if( ( command = [_classes objectForKey:[str lowercaseString]] ) == nil )
return nil;
return NSClassFromString(command);
aChar = tolower(aChar);
switch(aChar) {
case 'a': return IJSVGCommandArc.class;
case 'c': return IJSVGCommandCurve.class;
case 'h': return IJSVGCommandHorizontalLine.class;
case 'l': return IJSVGCommandLineTo.class;
case 'm': return IJSVGCommandMove.class;
case 'q': return IJSVGCommandQuadraticCurve.class;
case 's': return IJSVGCommandSmoothCurve.class;
case 't': return IJSVGCommandCommandSmoothQuadraticCurve.class;
case 'v': return IJSVGCommandVerticalLine.class;
case 'z': return IJSVGCommandClose.class;
}
return nil;
}
- (CGFloat)readFloat
+24 -16
View File
@@ -11,11 +11,6 @@
@implementation IJSVGCommandArc
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"a"];
}
+ (NSInteger)requiredParameterCount
{
@@ -29,10 +24,6 @@
type:(IJSVGCommandType)type
path:(IJSVGPath *)path
{
// command was taken from: https://github.com/jmenter/JAMSVGImage/blob/89b375c0c3203355a0c693e3b805458415bf4e29/Classes/JAMSVGImage/Path%20and%20Parser/JAMStyledBezierPathFactory.m
// and modified to purpose inside this to be converted into degrees and not radians
CGPoint radii = CGPointZero;
CGPoint arcEndPoint = CGPointZero;
CGPoint arcStartPoint = path.currentPoint;
@@ -46,7 +37,7 @@
sweepFlag = [currentCommand readBOOL];
arcEndPoint = [currentCommand readPoint];
if ( type == IJSVGCommandTypeRelative ) {
if (type == IJSVGCommandTypeRelative) {
arcEndPoint.x += path.currentPoint.x;
arcEndPoint.y += path.currentPoint.y;
}
@@ -75,15 +66,28 @@
angleDelta = (ratio(deltaU, deltaV) <= -1) ? M_PI : (ratio(deltaU, deltaV) >= 1) ? 0 : angleDelta;
// check for actually numbers, if this is not valid
// kill it, blame WWDC 2017 SVG background for this...
if(isnan(startAngle) || isnan(angleDelta)) {
return;
}
CGFloat radius = MAX(radii.x, radii.y);
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) : CGPointMake(radii.x / radii.y, 1);
CGPoint scale = (radii.x > radii.y) ? CGPointMake(1, radii.y / radii.x) :
CGPointMake(radii.x / radii.y, 1);
NSAffineTransform * trans = [NSAffineTransform transform];
[trans translateXBy:-centerPoint.x yBy:-centerPoint.y];
[trans rotateByRadians:-xAxisRotation];
[trans scaleXBy:(1/scale.x) yBy:(1/scale.y)];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = [NSAffineTransform transform];
[trans rotateByRadians:-xAxisRotation];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = [NSAffineTransform transform];
[trans scaleXBy:(1/scale.x) yBy:(1/scale.y)];
[path.currentSubpath transformUsingAffineTransform:trans];
[path.currentSubpath appendBezierPathWithArcWithCenter:NSZeroPoint
radius:radius
startAngle:radians_to_degrees(startAngle)
@@ -91,12 +95,16 @@
clockwise:!sweepFlag];
trans = [NSAffineTransform transform];
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
[trans rotateByRadians:xAxisRotation];
[trans scaleXBy:scale.x yBy:scale.y];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = [NSAffineTransform transform];
[trans rotateByRadians:xAxisRotation];
[path.currentSubpath transformUsingAffineTransform:trans];
trans = [NSAffineTransform transform];
[trans translateXBy:centerPoint.x yBy:centerPoint.y];
[path.currentSubpath transformUsingAffineTransform:trans];
}
@end
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandClose
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"z"];
}
+ (NSInteger)requiredParameterCount
{
return 0;
@@ -12,12 +12,6 @@
@implementation IJSVGCommandCommandSmoothQuadraticCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"t"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
@@ -46,7 +40,7 @@
commandPoint = CGPointMake(-1*(command.parameters[0] + oldPoint.x) + 2*([path currentSubpath].currentPoint.x),
-1*(command.parameters[1] + oldPoint.y) + 2*[path currentSubpath].currentPoint.y);
}
} else if( command.commandClass == [self class] ) {
} else if( command.commandClass == self.class ) {
// smooth quadratic curve
commandPoint = CGPointMake(-1*(path.lastControlPoint.x) + 2*([path currentSubpath].currentPoint.x),
-1*(path.lastControlPoint.y) + 2*[path currentSubpath].currentPoint.y);
+4 -12
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"c"];
}
+ (NSInteger)requiredParameterCount
{
return 6;
@@ -28,17 +22,15 @@
type:(IJSVGCommandType)type
path:(IJSVGPath *)path
{
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] curveToPoint:NSMakePoint( params[4], params[5])
controlPoint1:NSMakePoint( params[0], params[1])
controlPoint2:NSMakePoint( params[2], params[3])];
return;
}
NSPoint point = [[path currentSubpath] currentPoint];
[[path currentSubpath] curveToPoint:NSMakePoint( point.x + params[4], point.y + params[5])
controlPoint1:NSMakePoint( point.x + params[0], point.y + params[1])
controlPoint2:NSMakePoint( point.x + params[2], point.y + params[3])];
[[path currentSubpath] relativeCurveToPoint:NSMakePoint( params[4], params[5])
controlPoint1:NSMakePoint( params[0], params[1])
controlPoint2:NSMakePoint( params[2], params[3])];
}
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandHorizontalLine
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"h"];
}
+ (NSInteger)requiredParameterCount
{
return 1;
+2 -9
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandLineTo
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"l"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
@@ -28,12 +22,11 @@
type:(IJSVGCommandType)type
path:(IJSVGPath *)path
{
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] lineToPoint:NSMakePoint( params[0], params[1])];
return;
}
NSPoint point = NSMakePoint( [path currentSubpath].currentPoint.x + params[0],
NSPoint point = NSMakePoint([path currentSubpath].currentPoint.x + params[0],
[path currentSubpath].currentPoint.y + params[1]);
[[path currentSubpath] lineToPoint:point];
}
+2 -10
View File
@@ -12,12 +12,6 @@
@implementation IJSVGCommandMove
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"m"];
}
+ (NSInteger)requiredParameterCount
{
return 2;
@@ -32,8 +26,7 @@
{
// move to's allow more then one move to, but if there are more then one,
// we need to run the line to instead...who knew!
if( command.commandClass == [self class])
{
if( command.commandClass == self.class && currentCommand.isSubCommand == YES) {
[IJSVGCommandLineTo runWithParams:params
paramCount:count
command:currentCommand
@@ -44,8 +37,7 @@
}
// actual move to command
if( type == IJSVGCommandTypeAbsolute )
{
if( type == IJSVGCommandTypeAbsolute ) {
[[path currentSubpath] moveToPoint:NSMakePoint( params[0], params[1])];
return;
}
-6
View File
@@ -11,12 +11,6 @@
@implementation IJSVGCommandQuadraticCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"q"];
}
+ (NSInteger)requiredParameterCount
{
return 4;
+1 -7
View File
@@ -12,12 +12,6 @@
@implementation IJSVGCommandSmoothCurve
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"s"];
}
+ (NSInteger)requiredParameterCount
{
return 4;
@@ -33,7 +27,7 @@
NSPoint firstControl = NSMakePoint( [path currentSubpath].currentPoint.x, [path currentSubpath].currentPoint.y );
if( command != nil )
{
if( command.commandClass == [IJSVGCommandCurve class] || command.commandClass == [self class] )
if( command.commandClass == [IJSVGCommandCurve class] || command.commandClass == self.class )
{
if( command.commandClass == [IJSVGCommandCurve class] )
{
-6
View File
@@ -10,12 +10,6 @@
@implementation IJSVGCommandVerticalLine
+ (void)load
{
[IJSVGCommand registerClass:[self class]
forCommand:@"v"];
}
+ (NSInteger)requiredParameterCount
{
return 1;
+21 -8
View File
@@ -15,41 +15,54 @@ typedef void (^IJSVGCGPathHandler)(const CGPathElement * pathElement);
void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement);
typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
IJSVGExporterOptionNone = 1 << 0,
IJSVGExporterOptionRemoveUselessGroups = 1 << 1,
IJSVGExporterOptionRemoveUselessDef = 1 << 2,
IJSVGExporterOptionMoveAttributesToGroup = 1 << 3,
IJSVGExporterOptionCreateUseForPaths = 1 << 4,
IJSVGExporterOptionSortAttributes = 1 << 5,
IJSVGExporterOptionCollapseGroups = 1 << 6,
IJSVGExporteroptionCleanupPaths = 1 << 7,
IJSVGExporterOptionCleanupPaths = 1 << 7,
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
IJSVGExporterOptionCompressOutput = 1 << 10,
IJSVGExporterOptionCollapseGradients = 1 << 11,
IJSVGExporterOptionCreateClasses = 1 << 12,
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef|
IJSVGExporterOptionRemoveUselessGroups|
IJSVGExporterOptionCreateUseForPaths|
IJSVGExporterOptionMoveAttributesToGroup|
IJSVGExporterOptionSortAttributes|
IJSVGExporterOptionCollapseGroups|
IJSVGExporteroptionCleanupPaths
IJSVGExporterOptionCleanupPaths|
IJSVGExporterOptionRemoveHiddenElements|
IJSVGExporterOptionScaleToSizeIfNecessary|
IJSVGExporterOptionCompressOutput|
IJSVGExporterOptionCollapseGradients|
IJSVGExporterOptionRemoveWidthHeightAttributes
};
BOOL IJSVGExporterHasOption(IJSVGExporterOptions options, NSInteger option);
@interface IJSVGExporter : NSObject {
@private
IJSVG * _svg;
CGSize _size;
IJSVGExporterOptions _options;
NSXMLDocument * _dom;
NSXMLElement * _defElement;
NSInteger _gradCount;
NSInteger _patternCount;
NSInteger _imageCount;
NSInteger _maskCount;
NSInteger _pathCount;
NSXMLElement * _scaledRootNode;
NSInteger _idCount;
NSInteger _shortIdCount;
}
@property (nonatomic, copy) NSString * title;
@property (nonatomic, copy) NSString * description;
- (id)initWithSVG:(IJSVG *)svg
size:(CGSize)size
options:(IJSVGExporterOptions)options;
- (NSString *)SVGString;
- (NSData *)SVGData;
+519 -247
View File
File diff suppressed because it is too large Load Diff
+27 -12
View File
@@ -64,8 +64,11 @@
// move
case 'M':
case 'm': {
str = [NSString stringWithFormat:@"%c%g,%g",
instruction.instruction,data[0],data[1]];
char * buffer;
asprintf(&buffer, "%c%g,%g", instruction.instruction, data[0], data[1]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
@@ -75,8 +78,11 @@
case 'v':
case 'H':
case 'h': {
str = [NSString stringWithFormat:@"%c%g",
instruction.instruction,data[0]];
char * buffer;
asprintf(&buffer, "%c%g", instruction.instruction, data[0]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
@@ -84,8 +90,11 @@
// line
case 'L':
case 'l': {
str = [NSString stringWithFormat:@"%c%g,%g",
instruction.instruction, data[0], data[1]];
char * buffer;
asprintf(&buffer, "%c%g,%g",instruction.instruction, data[0], data[1]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
@@ -93,9 +102,12 @@
// curve
case 'C':
case 'c': {
str = [NSString stringWithFormat:@"%c%g,%g %g,%g %g,%g",
instruction.instruction, data[0], data[1],
data[2], data[3], data[4], data[5]];
char * buffer;
asprintf(&buffer, "%c%g,%g %g,%g %g,%g", instruction.instruction,
data[0], data[1], data[2], data[3], data[4], data[5]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
@@ -103,9 +115,12 @@
// quadratic curve
case 'Q':
case 'q': {
str = [NSString stringWithFormat:@"%c%g,%g %g,%g",
instruction.instruction, data[0], data[1],
data[2], data[3]];
char * buffer;
asprintf(&buffer, "%c%g,%g %g,%g", instruction.instruction,
data[0], data[1], data[2], data[3]);
str = [NSString stringWithCString:buffer
encoding:NSUTF8StringEncoding];
free(buffer);
[pathData addObject:str];
break;
}
+8 -3
View File
@@ -7,18 +7,23 @@
//
#import <Foundation/Foundation.h>
#import "IJSVG.h"
typedef void (^IJSVGFontConverterEnumerateBlock)(NSString * unicode, IJSVG * svg);
@interface IJSVGFontConverter : NSObject {
@private
NSURL * _url;
NSFont * _font;
NSMutableDictionary * _paths;
NSMutableDictionary<NSString *, id> * _transformedPaths;
}
- (id)initWithFontAtFileURL:(NSURL *)url;
- (NSDictionary *)paths;
+ (NSBezierPath *)bezierpathFromCGPath:(CGPathRef)path;
- (NSFont *)font;
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block;
+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path;
+ (IJSVG *)convertPathToSVG:(CGPathRef)path;
@end
+46 -97
View File
@@ -8,12 +8,13 @@
#import "IJSVGFontConverter.h"
#import "IJSVGBezierPathAdditions.h"
#import "IJSVGShapeLayer.h"
@implementation IJSVGFontConverter
- (void)dealloc
{
[_paths release], _paths = nil;
[_transformedPaths release], _transformedPaths = nil;
[_url release], _url = nil;
[_font release], _font = nil;
[super dealloc];
@@ -21,8 +22,7 @@
- (id)initWithFontAtFileURL:(NSURL *)url
{
if( ( self = [super init] ) != nil )
{
if( ( self = [super init] ) != nil ) {
_url = [url copy];
// load the font
@@ -48,20 +48,16 @@
{
NSCharacterSet * charSet = _font.coveredCharacterSet;
NSMutableArray * array = [[[NSMutableArray alloc] init] autorelease];
for( int plane = 0; plane <= 16; plane++ )
{
if( [charSet hasMemberInPlane:plane] )
{
NSStringEncoding encoding = NSUTF32LittleEndianStringEncoding;
for( int plane = 0; plane <= 16; plane++ ) {
if( [charSet hasMemberInPlane:plane] ) {
UTF32Char c;
for( c = plane << 16; c < (plane+1) << 16; c++ )
{
if( [charSet longCharacterIsMember:c] )
{
for( c = plane << 16; c < (plane+1) << 16; c++ ) {
if( [charSet longCharacterIsMember:c] ) {
UTF32Char c1 = NSSwapHostIntToLittle(c);
// add it...
[array addObject:[[[NSString alloc] initWithBytes:&c1
length:4
encoding:NSUTF32LittleEndianStringEncoding] autorelease]];
encoding:encoding] autorelease]];
}
}
}
@@ -71,14 +67,8 @@
- (void)generateMap
{
// we have already been made!
if( _paths.count != 0 )
return;
_paths = [[NSMutableDictionary alloc] init];
CTFontRef font = (CTFontRef)_font;
for( NSString * charString in [self allCharacters] )
{
for( NSString * charString in [self allCharacters] ) {
// get the characters in each char
NSUInteger count = charString.length;
unichar characters[count];
@@ -89,93 +79,52 @@
CGGlyph glyphs[count];
CTFontGetGlyphsForCharacters( font, characters, glyphs, count);
CGPathRef path = CTFontCreatePathForGlyph( font, glyphs[0], NULL );
if( path != NULL )
{
NSString * k = [NSString stringWithFormat:@"%04x",[charString characterAtIndex:0]];
[self parseCGPath:path
forCharacterString:k];
if(path != NULL) {
// add SVG to the dictionary
NSString * key = [NSString stringWithFormat:@"%04x",[charString characterAtIndex:0]];
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:path];
_transformedPaths[key] = (id)flippedPath;
CGPathRelease(flippedPath);
}
CGPathRelease(path);
}
}
- (void)parseCGPath:(CGPathRef)path
forCharacterString:(NSString *)string
- (void)enumerateUsingBlock:(IJSVGFontConverterEnumerateBlock)block
{
[_paths setObject:[[self class] bezierpathFromCGPath:path]
forKey:string];
}
- (NSDictionary *)paths
{
[self generateMap];
return _paths;
}
static void IJSVGCGPathCallback(void * info, const CGPathElement * element)
{
NSBezierPath * path = (NSBezierPath *)info;
CGPoint * points = element->points;
switch( element->type )
{
// move to
case kCGPathElementMoveToPoint:
{
[path moveToPoint:NSMakePoint( points[0].x, points[0].y)];
break;
}
// line to
case kCGPathElementAddLineToPoint:
{
[path lineToPoint:NSMakePoint( points[0].x, points[0].y)];;
break;
}
// quad curve
case kCGPathElementAddQuadCurveToPoint:
{
[path addQuadCurveToPoint:points[1] controlPoint:points[0]];
break;
}
// curve to
case kCGPathElementAddCurveToPoint:
{
[path curveToPoint:NSMakePoint(points[2].x, points[2].y)
controlPoint1:NSMakePoint( points[0].x, points[0].y)
controlPoint2:NSMakePoint( points[1].x, points[1].y)];
break;
}
// close
case kCGPathElementCloseSubpath: {
[path closePath];
break;
}
if(_transformedPaths == nil) {
_transformedPaths = [[NSMutableDictionary alloc] init];
[self generateMap];
}
for(NSString * key in _transformedPaths.allKeys) {
block(key, [self.class convertPathToSVG:(CGPathRef)_transformedPaths[key]]);
}
}
+ (NSBezierPath *)bezierpathFromCGPath:(CGPathRef)path
+ (IJSVG *)convertIJSVGPathToSVG:(IJSVGPath *)path
{
NSBezierPath * bezPath = [NSBezierPath bezierPath];
// pass the path
CGPathApply( path, bezPath, IJSVGCGPathCallback );
// the glyph will be upside down, so we need to turn it up the right way!
NSAffineTransform * trans = [NSAffineTransform transform];
// scale -1 on the Y axis so its now correct but to far up
[trans scaleXBy:1.f
yBy:-1.f];
// move it back down by its height
[trans translateXBy:0.f
yBy:bezPath.controlPointBounds.size.height];
[bezPath transformUsingAffineTransform:trans];
return bezPath;
CGPathRef cgPath = [IJSVGUtils newCGPathFromBezierPath:path.path];
CGPathRef flippedPath = [IJSVGUtils newFlippedCGPath:cgPath];
IJSVG * svg = [self convertPathToSVG:flippedPath];
CGPathRelease(flippedPath);
CGPathRelease(cgPath);
return svg;
}
+ (IJSVG *)convertPathToSVG:(CGPathRef)path
{
__block IJSVG * svg = nil;
IJSVGObtainTransactionLock(^{
IJSVGGroupLayer * layer = [[[IJSVGGroupLayer alloc] init] autorelease];
IJSVGShapeLayer * shape = [[[IJSVGShapeLayer alloc] init] autorelease];
[layer addSublayer:shape];
shape.path = path;
CGRect box = CGPathGetPathBoundingBox(path);
svg = [[IJSVG alloc] initWithSVGLayer:layer
viewBox:box];
}, NO);
return [svg autorelease];
}
@end
+11 -4
View File
@@ -9,23 +9,30 @@
#import <Foundation/Foundation.h>
#import "IJSVGDef.h"
#import "IJSVGTransform.h"
#import "IJSVGColorList.h"
@interface IJSVGGradient : IJSVGNode
@property ( nonatomic, retain ) NSGradient * gradient;
@property ( nonatomic, assign ) CGFloat angle;
@property ( nonatomic, assign ) CGPoint startPoint;
@property ( nonatomic, assign ) CGPoint endPoint;
@property ( nonatomic, assign ) CGGradientRef CGGradient;
@property ( nonatomic, retain ) IJSVGUnitLength * x1;
@property ( nonatomic, retain ) IJSVGUnitLength * x2;
@property ( nonatomic, retain ) IJSVGUnitLength * y1;
@property ( nonatomic, retain ) IJSVGUnitLength * y2;
@property ( nonatomic, retain) IJSVGColorList * colorList;
+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element
colors:(NSArray **)someColors;
- (CGGradientRef)CGGradient;
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect;
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox;
- (void)_debugStart:(CGPoint)startPoint
end:(CGPoint)endPoint
context:(CGContextRef)ctx;
- (IJSVGColorList *)computedColorList;
@end
+78 -38
View File
@@ -11,8 +11,8 @@
@implementation IJSVGGradient
@synthesize gradient, CGGradient;
@synthesize angle, startPoint, endPoint;
@synthesize x1, x2, y1, y2;
@synthesize colorList = _colorList;
- (void)dealloc
{
@@ -21,7 +21,8 @@
[y1 release], y1 = nil;
[y2 release], y2 = nil;
[gradient release], gradient = nil;
if( CGGradient != nil ) {
[_colorList release], _colorList = nil;
if(CGGradient != nil) {
CGGradientRelease(CGGradient);
}
[super dealloc];
@@ -31,25 +32,29 @@
{
IJSVGGradient * clone = [super copyWithZone:zone];
clone.gradient = [[self.gradient copy] autorelease];
clone.startPoint = self.startPoint;
clone.endPoint = self.endPoint;
return clone;
}
- (void)setColorList:(IJSVGColorList *)list
{
[_colorList release], _colorList = nil;
_colorList = list.retain;
if(CGGradient != nil) {
CGGradientRelease(CGGradient);
}
}
+ (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element
colors:(NSArray **)someColors
{
// find each stop element
NSArray * stops = [element nodesForXPath:@"stop"
error:nil];
NSMutableArray * colors = [[[NSMutableArray alloc] init] autorelease];
NSArray * stops = [element children];
NSMutableArray * colors = [[[NSMutableArray alloc] initWithCapacity:stops.count] autorelease];
CGFloat * stopsParams = (CGFloat *)malloc(stops.count*sizeof(CGFloat));
NSInteger i = 0;
for( NSXMLElement * stop in stops )
{
for( NSXMLElement * stop in stops ) {
// find the offset
CGFloat offset = [[[stop attributeForName:@"offset"] stringValue] floatValue];
CGFloat offset = [stop attributeForName:@"offset"].stringValue.floatValue;
if( offset > 1.f ) {
offset /= 100.f;
}
@@ -60,53 +65,69 @@
CGFloat stopOpacity = 1.f;
NSXMLNode * stopOpacityAttribute = [stop attributeForName:@"stop-opacity"];
if( stopOpacityAttribute != nil ) {
stopOpacity = [[stopOpacityAttribute stringValue] floatValue];
stopOpacity = stopOpacityAttribute.stringValue.floatValue;
}
// find the stop color
NSColor * stopColor = [IJSVGColor colorFromHEXString:[[stop attributeForName:@"stop-color"] stringValue]
alpha:stopOpacity];
// no hex, grab it from predefined
if( stopColor == nil )
{
stopColor = [IJSVGColor colorFromPredefinedColorName:[[stop attributeForName:@"stop-color"] stringValue]];
if( stopColor != nil && stopOpacity != 1.f ) {
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
to:stopOpacity];
}
}
// add it into the array
if( stopColor != nil ) {
[(NSMutableArray *)colors addObject:stopColor];
NSString * scs = [stop attributeForName:@"stop-color"].stringValue;
NSColor * stopColor = [IJSVGColor colorFromString:scs];
if(stopColor != nil && stopOpacity != 1.f) {
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
to:stopOpacity];
}
// compute any style that there was...
NSXMLNode * styleAttribute = [stop attributeForName:@"style"];
if( styleAttribute != nil )
{
IJSVGStyle * style = [IJSVGStyle parseStyleString:[styleAttribute stringValue]];
if( styleAttribute != nil ) {
IJSVGStyle * style = [IJSVGStyle parseStyleString:styleAttribute.stringValue];
NSColor * color = [IJSVGColor colorFromString:[style property:@"stop-color"]];
// we have a color!
if( color != nil ) {
// is there a stop opacity?
NSNumber * number = nil;
if( (number = [style property:@"stop-opacity"] ) != nil ) {
NSString * numberString = nil;
if( (numberString = [style property:@"stop-opacity"] ) != nil ) {
color = [IJSVGColor changeAlphaOnColor:color
to:[number floatValue]];
to:numberString.floatValue];
} else {
color = [IJSVGColor changeAlphaOnColor:color
to:stopOpacity];
}
[(NSMutableArray *)colors addObject:color];
stopColor = color;
}
}
// default is black
if(stopColor == nil) {
stopColor = [IJSVGColor colorFromString:@"black"];
if(stopOpacity != 1.f) {
stopColor = [IJSVGColor changeAlphaOnColor:stopColor
to:stopOpacity];
}
}
// add the stop color
[(NSMutableArray *)colors addObject:stopColor];
}
*someColors = colors;
return stopsParams;
}
- (IJSVGColorList *)computedColorList
{
IJSVGColorList * sheet = [[[IJSVGColorList alloc] init] autorelease];
NSInteger num = self.gradient.numberOfColorStops;
for(NSInteger i = 0; i < num; i++) {
NSColor * color;
[self.gradient getColor:&color
location:nil
atIndex:i];
[sheet addColor:color];
}
return sheet;
}
- (CGGradientRef)CGGradient
{
// store it in the cache
@@ -117,23 +138,42 @@
// actually create the gradient
NSInteger num = self.gradient.numberOfColorStops;
CGFloat * locations = malloc(sizeof(CGFloat)*num);
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num, &kCFTypeArrayCallBacks);
CFMutableArrayRef colors = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)num,
&kCFTypeArrayCallBacks);
for( NSInteger i = 0; i < num; i++ ) {
NSColor * color;
[self.gradient getColor:&color
location:&locations[i]
atIndex:i];
if(_colorList != nil) {
color = [_colorList proposedColorForColor:color];
}
CFArrayAppendValue(colors, color.CGColor);
}
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace, colors, locations);
CGGradientRef result = CGGradientCreateWithColors(self.gradient.colorSpace.CGColorSpace,
colors, locations);
CFRelease(colors);
free(locations);
return CGGradient = result;
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
}
- (void)_debugStart:(CGPoint)startPoint
end:(CGPoint)endPoint
context:(CGContextRef)ctx
{
CGContextSaveGState(ctx);
CGContextSetStrokeColorWithColor(ctx, NSColor.blackColor.CGColor);
CGContextSetLineWidth(ctx, 1.f);
CGContextMoveToPoint(ctx, startPoint.x, startPoint.y);
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
CGContextStrokePath(ctx);
}
@end
+4
View File
@@ -15,6 +15,10 @@
}
@property (nonatomic, assign) CGRect viewBox;
@property (nonatomic, retain) IJSVGGradient * gradient;
@property (nonatomic, assign) CGAffineTransform absoluteTransform;
@property (nonatomic, assign) CGRect objectRect;
@end
+62 -1
View File
@@ -10,7 +10,10 @@
@implementation IJSVGGradientLayer
@synthesize viewBox;
@synthesize gradient;
@synthesize absoluteTransform;
@synthesize objectRect;
- (void)dealloc
{
@@ -22,10 +25,60 @@
{
if((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
}
- (void)setGradient:(IJSVGGradient *)newGradient
{
if(gradient != nil) {
[gradient release], gradient = nil;
}
gradient = [newGradient retain];
// lets check its alpha properties on the colors
BOOL hasAlphaChannel = NO;
NSInteger stops = gradient.gradient.numberOfColorStops;
for(NSInteger i = 0; i < stops; i++) {
NSColor * color = nil;
[gradient.gradient getColor:&color
location:NULL
atIndex:i];
if(color.alphaComponent != 1.f) {
hasAlphaChannel = YES;
break;
}
}
self.opaque = hasAlphaChannel == NO;
}
- (void)setOpacity:(float)opacity
{
if(opacity != 1.f) {
self.opaque = NO;
}
[super setOpacity:opacity];
}
- (void)setBackingScaleFactor:(CGFloat)backingScaleFactor
{
switch (self.renderQuality) {
case IJSVGRenderQualityOptimized: {
backingScaleFactor = (backingScaleFactor * .35f);
break;
}
case IJSVGRenderQualityLow: {
backingScaleFactor = (backingScaleFactor * .05f);
break;
}
default: {
break;
}
}
[super setBackingScaleFactor:backingScaleFactor];
}
- (void)drawInContext:(CGContextRef)ctx
{
[super drawInContext:ctx];
@@ -36,7 +89,15 @@
}
// draw the gradient
[self.gradient drawInContextRef:ctx rect:self.bounds];
CGAffineTransform trans = CGAffineTransformMakeTranslation(-CGRectGetMinX(objectRect),
-CGRectGetMinY(objectRect));
CGAffineTransform transform = CGAffineTransformConcat(absoluteTransform,trans);
CGContextSaveGState(ctx);
[self.gradient drawInContextRef:ctx
objectRect:objectRect
absoluteTransform:transform
viewPort:self.viewBox];
CGContextRestoreGState(ctx);
}
@end
+13
View File
@@ -0,0 +1,13 @@
//
// IJSVGGradientUnitLength.h
// IconJar
//
// Created by Curtis Hard on 29/03/2017.
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGUnitLength.h"
@interface IJSVGGradientUnitLength : IJSVGUnitLength
@end
+21
View File
@@ -0,0 +1,21 @@
//
// IJSVGGradientUnitLength.m
// IconJar
//
// Created by Curtis Hard on 29/03/2017.
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGGradientUnitLength.h"
@implementation IJSVGGradientUnitLength
- (NSString *)stringValue
{
if(self.type == IJSVGUnitLengthTypePercentage) {
return [NSString stringWithFormat:@"%g",self.value];
}
return [super stringValue];
}
@end
+1 -1
View File
@@ -62,7 +62,7 @@
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ - %ld",[super description],self.children.count];
return [NSString stringWithFormat:@"%@ - %@",[super description],self.children];
}
@end
+7 -1
View File
@@ -22,10 +22,16 @@
- (void)loadFromBase64EncodedString:(NSString *)encodedString
{
if([encodedString hasPrefix:@"data:"]) {
encodedString = [encodedString stringByReplacingOccurrencesOfString:@"\\s+"
withString:@""
options:NSRegularExpressionSearch
range:NSMakeRange(0, encodedString.length)];
}
NSURL * URL = [NSURL URLWithString:encodedString];
NSData * data = [NSData dataWithContentsOfURL:URL];
// no data, jsut ignore...invalid probably
// no data, just ignore...invalid probably
if(data == nil) {
return;
}
+16 -2
View File
@@ -28,14 +28,28 @@
// set the contents
self.contents = (id)imageRef;
// make sure we say we need help
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
// set the frame, simple stuff
self.frame = (CGRect){
.origin = CGPointZero,
.size = CGSizeMake( CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef))
.size = CGSizeMake(CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef))
};
}
return self;
}
- (void)setNeedsDisplay
{
// swap the content around on call
// because set needs display discards previous
// content - yolo!
id oldContent = self.contents;
[super setNeedsDisplay];
self.contents = oldContent;
}
@end
+22
View File
@@ -0,0 +1,22 @@
//
// IJSVGImageRep.h
// IJSVGExample
//
// Created by Curtis Hard on 15/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "IJSVGParser.h"
@class IJSVG;
@interface IJSVGImageRep : NSImageRep {
@private
IJSVG * _svg;
}
@property (nonatomic, readonly) CGRect viewBox;
@end
+104
View File
@@ -0,0 +1,104 @@
//
// IJSVGImageRep.m
// IJSVGExample
//
// Created by Curtis Hard on 15/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGImageRep.h"
#import "IJSVG.h"
@implementation IJSVGImageRep
@synthesize viewBox = _viewBox;
+ (void)load
{
[NSBitmapImageRep registerImageRepClass:self];
}
+ (BOOL)canInitWithData:(NSData *)data
{
return [IJSVGParser isDataSVG:data];
}
+ (NSArray<NSString *> *)imageTypes
{
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
}
+ (NSArray<NSString *> *)imageUnfilteredTypes
{
return @[(NSString *)kUTTypeScalableVectorGraphics, @"svg"];
}
+ (NSArray<NSImageRep *> *)imageRepsWithData:(NSData *)data
{
IJSVGImageRep * instance = [self imageRepWithData:data];
if(instance == nil) {
return @[];
}
return @[instance];
}
+ (instancetype)imageRepWithData:(NSData *)data
{
return [[[self alloc] initWithData:data] autorelease];
}
- (void)dealloc
{
[_svg release], _svg = nil;
[super dealloc];
}
- (instancetype)initWithData:(NSData *)data
{
if((self = [super init]) != nil) {
// grab the string from the data
// its more then likely UTF-8...
NSString * string = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
_svg = [[IJSVG alloc] initWithSVGString:string];
// no valid SVG, just return nil;
if(_svg == nil) {
[self release];
return nil;
}
// set default properties
self.pixelsWide = _svg.viewBox.size.width;
self.pixelsHigh = _svg.viewBox.size.height;
self.size = _svg.viewBox.size;
}
return self;
}
- (BOOL)draw
{
[_svg drawInRect:self.viewBox];
return YES;
}
- (BOOL)drawAtPoint:(NSPoint)point
{
[_svg drawAtPoint:point
size:_svg.viewBox.size];
return YES;
}
- (BOOL)drawInRect:(NSRect)rect
{
[_svg drawInRect:rect];
return YES;
}
- (CGRect)viewBox
{
return _svg.viewBox;
}
@end
+23 -45
View File
@@ -8,60 +8,38 @@
#import <QuartzCore/QuartzCore.h>
#import "IJSVGTransaction.h"
#import "IJSVGRendering.h"
@class IJSVGShapeLayer;
@class IJSVGGradientLayer;
@class IJSVGPatternLayer;
@class IJSVGStrokeLayer;
#define IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION \
- (void)addSublayer:(CALayer *)layer { \
if([layer isKindOfClass:[IJSVGLayer class]] == NO && \
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) { \
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.", \
[layer class]]; \
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"\
reason:r \
userInfo:nil];\
@throw exception; \
}\
[super addSublayer:layer];\
} \
\
- (void)setBackingScaleFactor:(CGFloat)newFactor \
{ \
if(self.backingScaleFactor == newFactor) { \
return; \
} \
backingScaleFactor = newFactor; \
self.contentsScale = newFactor; \
self.rasterizationScale = newFactor; \
[self setNeedsDisplay]; \
};
#define IJSVG_LAYER_DEFAULT_PROPERTIES \
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer; \
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer; \
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer; \
@property (nonatomic, assign) BOOL requiresBackingScaleHelp; \
@property (nonatomic, assign) CGFloat backingScaleFactor;
#define IJSVG_LAYER_DEFAULT_SYNTHESIZE \
@synthesize gradientFillLayer; \
@synthesize patternFillLayer; \
@synthesize strokeLayer; \
@synthesize requiresBackingScaleHelp; \
@synthesize backingScaleFactor;
#define IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS \
IJSVGBeginTransactionLock(); \
[super dealloc]; \
IJSVGEndTransactionLock();
@class IJSVGGroupLayer;
@interface IJSVGLayer : CALayer {
@private
IJSVGLayer * _maskingLayer;
}
IJSVG_LAYER_DEFAULT_PROPERTIES
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer;
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer;
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer;
@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer;
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer;
+ (void)recursivelyWalkLayer:(CALayer *)layer
withBlock:(void (^)(CALayer * layer, BOOL isMask))block;
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer *)sublayer
withOffset:(CGPoint)offset;
@end
+163 -5
View File
@@ -8,19 +8,177 @@
#import "IJSVGLayer.h"
#import "IJSVGShapeLayer.h"
#import "IJSVGGroupLayer.h"
#import "IJSVG.h"
@implementation IJSVGLayer
IJSVG_LAYER_DEFAULT_SYNTHESIZE
@synthesize gradientFillLayer;
@synthesize patternFillLayer;
@synthesize gradientStrokeLayer;
@synthesize patternStrokeLayer;
@synthesize strokeLayer;
@synthesize requiresBackingScaleHelp;
@synthesize backingScaleFactor;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
#ifndef __clang_analyzer__
- (void)dealloc
{
IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS
[_maskingLayer release], _maskingLayer = nil;
[super dealloc];
}
#endif
IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer
{
NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease];
for(CALayer * subLayer in layer.sublayers) {
if(subLayer.sublayers.count != 0) {
NSArray * moreLayers = [self deepestSublayersOfLayer:(IJSVGLayer *)subLayer];
[arr addObjectsFromArray:moreLayers];
} else {
[arr addObject:subLayer];
}
}
return arr;
}
+ (void)recursivelyWalkLayer:(CALayer *)layer
withBlock:(void (^)(CALayer * layer, BOOL isMask))block
{
// call for layer and mask if there is one
block(layer, NO);
// do the mask too!
if(layer.mask != nil) {
block(layer.mask, YES);
}
// sublayers!!
for(CALayer * aLayer in layer.sublayers) {
[self recursivelyWalkLayer:aLayer
withBlock:block];
}
}
- (void)addSublayer:(CALayer *)layer
{
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
[layer class]];
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"
reason:r
userInfo:nil];
@throw exception;
}
[super addSublayer:layer];
}
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if(self.backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
[self setNeedsDisplay];
}
- (void)_customRenderInContext:(CGContextRef)ctx
{
if(self.convertMasksToPaths == YES && _maskingLayer != nil) {
CGContextSaveGState(ctx);
[self applySublayerMaskToContext:ctx
forSublayer:(IJSVGLayer *)self
withOffset:CGPointZero];
[super renderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[super renderInContext:ctx];
}
- (void)setConvertMasksToPaths:(BOOL)flag
{
if(convertMasksToPaths == flag) {
return;
}
convertMasksToPaths = flag;
if(flag == YES) {
if(_maskingLayer != nil){
[_maskingLayer release], _maskingLayer = nil;
}
_maskingLayer = [(IJSVGLayer *)self.mask retain];
self.mask = nil;
} else {
self.mask = _maskingLayer;
[_maskingLayer release], _maskingLayer = nil;
}
}
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer *)sublayer
withOffset:(CGPoint)offset
{
// apply any transforms needed
CGPoint layerOffset = offset;
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform);
CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) );
// walk up the superlayer chain
CALayer * superlayer = self.superlayer;
if (IJSVGIsSVGLayer(superlayer) == YES) {
[(IJSVGLayer *)superlayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer *)self
withOffset:layerOffset];
}
// grab the masking layer
IJSVGShapeLayer * maskingLayer = [self maskingLayer];
// if its a group we need to get the lowest level children
// and walk up the chain again
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
NSArray * subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
for(IJSVGLayer * subLayer in subs) {
[subLayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer *)self
withOffset:layerOffset];
}
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
// is a shape, go for it!
CGPathRef maskPath = maskingLayer.path;
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
CGContextAddPath(context, maskPath);
CGContextClip(context);
CGContextTranslateCTM(context, layerOffset.x, layerOffset.y);
}
CGContextConcatCTM(context, sublayerTransform);
}
- (IJSVGShapeLayer *)maskingLayer
{
return (IJSVGShapeLayer *)_maskingLayer ?: nil;
}
- (void)renderInContext:(CGContextRef)ctx
{
if(self.blendingMode != kCGBlendModeNormal) {
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, self.blendingMode);
[self _customRenderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[self _customRenderInContext:ctx];
}
- (id<CAAction>)actionForKey:(NSString *)event
{
return nil;
}
@end
+4 -2
View File
@@ -8,6 +8,7 @@
#import <QuartzCore/QuartzCore.h>
#import "IJSVGNode.h"
#import "IJSVGRenderingStyle.h"
@class IJSVGLayer;
@@ -15,8 +16,9 @@
}
@property (nonatomic, retain) NSColor * fillColor;
@property (nonatomic, retain) NSColor * strokeColor;
@property (nonatomic, assign) CGRect viewBox;
@property (nonatomic, retain) IJSVGRenderingStyle * style;
- (IJSVGLayer *)layerForNode:(IJSVGNode *)node;
+447 -137
View File
@@ -26,18 +26,22 @@
@implementation IJSVGLayerTree
#define DEFAULT_SHAPE_FILL_COLOR [NSColor blackColor].CGColor
@synthesize fillColor;
@synthesize strokeColor;
@synthesize viewBox;
@synthesize style = _style;
- (void)dealloc
{
[fillColor release], fillColor = nil;
[strokeColor release], strokeColor = nil;
[_style release], _style = nil;
[super dealloc];
}
- (id)init
{
if((self = [super init]) != nil) {
}
return self;
}
- (IJSVGLayer *)layerForNode:(IJSVGNode *)node
{
IJSVGLayer * layer = nil;
@@ -54,44 +58,67 @@
layer = [self layerForImage:(IJSVGImage *)node];
}
// apply any basic defaults
[self applyDefaultsToLayer:layer
fromNode:node];
[self applyDefaultsToLayer:layer fromNode:node];
return [self proposedLayerAfterApplyingTransforms:layer
transforms:node.transforms];
// create the new layer
layer = [self applyTransforms:node.transforms
toLayer:layer
fromNode:node];
return layer;
}
- (IJSVGLayer *)proposedLayerAfterApplyingTransforms:(IJSVGLayer *)layer
transforms:(NSArray<IJSVGTransform *> *)transforms
- (IJSVGLayer *)applyTransforms:(NSArray<IJSVGTransform *> *)transforms
toLayer:(IJSVGLayer *)layer
fromNode:(IJSVGNode *)node
{
// any x and y?
CGFloat x = [node.x computeValue:layer.frame.size.width];
CGFloat y = [node.y computeValue:layer.frame.size.height];
// do some magic transform
if(transforms.count == 0 && x == 0.f && y == 0.f) {
return layer;
}
if(x != 0.f || y != 0.f) {
// we must add translate to the stack
NSMutableArray * trans = nil;
if(transforms != nil) {
trans = [[transforms mutableCopy] autorelease];
} else {
trans = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
}
[trans addObject:[IJSVGTransform transformByTranslatingX:x y:y]];
transforms = trans;
}
// add any transforms
if(transforms.count != 0) {
IJSVGLayer * topLayer = nil;
IJSVGLayer * parentLayer = nil;
IJSVGLayer * topLayer = nil;
IJSVGLayer * parentLayer = nil;
for(IJSVGTransform * transform in transforms) {
// make sure we apply the transform to the parent
// so they stack
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
childLayer.affineTransform = transform.CGAffineTransform;
for(IJSVGTransform * transform in transforms) {
// make sure we apply the transform to the parent
// so they stack
IJSVGGroupLayer * childLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
childLayer.affineTransform = transform.CGAffineTransform;
// add it to the parent layer
if(parentLayer != nil) {
[parentLayer addSublayer:childLayer];
} else {
// make sure we keep track of the top most layer
topLayer = childLayer;
}
// reset parent layer to the new child
parentLayer = childLayer;
// add it to the parent layer
if(parentLayer != nil) {
[parentLayer addSublayer:childLayer];
} else {
// make sure we keep track of the top most layer
topLayer = childLayer;
}
// swap the layer around
[parentLayer addSublayer:layer];
layer = topLayer;
// reset parent layer to the new child
parentLayer = childLayer;
}
// swap the layer around
[parentLayer addSublayer:layer];
layer = topLayer;
return layer;
}
@@ -99,37 +126,59 @@
fromNode:(IJSVGNode *)node
{
CGFloat opacity = node.opacity.value;
if(opacity == 0.f) {
opacity = 1.f;
}
layer.opacity = opacity;
// setup the blending mode
if(node.blendMode != IJSVGBlendModeNormal) {
layer.blendingMode = (CGBlendMode)node.blendMode;
}
// display?
if(node.shouldRender == NO) {
layer.hidden = YES;
}
}
- (IJSVGLayer *)layerForImage:(IJSVGImage *)image
{
IJSVGImageLayer * layer = [[[IJSVGImageLayer alloc] initWithCGImage:image.CGImage] autorelease];
layer.frame = CGRectMake(image.x.value, image.y.value, image.width.value, image.height.value);
layer.affineTransform = CGAffineTransformConcat(layer.affineTransform,
CGAffineTransformMakeScale( 1.f, -1.f));
// make sure we set the width and height correctly,
// as this may not be exactly the same as the size of the
// given image
CGRect frame = layer.frame;
frame.size.width = image.width.value;
frame.size.height = image.height.value;
layer.frame = frame;
return layer;
}
- (IJSVGLayer *)layerForGroup:(IJSVGGroup *)group
{
// grab the sub layer tree from the SVG
if(group.svg != nil) {
return [self layerForGroup:group.svg.rootNode];
}
IJSVGGroupLayer * groupLayer = [[[IJSVGGroupLayer alloc] init] autorelease];
for(IJSVGNode * node in group.children) {
[groupLayer addSublayer:[self layerForNode:node]];
}
groupLayer.frame = (CGRect){
.origin = (CGPoint){
.x = group.x.value,
.y = group.y.value
},
.origin = CGPointZero,
.size = (CGSize){
.width = group.width.value,
.height = group.height.value
}
};
// mask it - forgot groups can have masks too, doh! simple
// enough to apply though, recursion ftw!
[self maskLayer:groupLayer
fromNode:group];
return groupLayer;
}
@@ -151,16 +200,21 @@
}
- (IJSVGShapeLayer *)basicLayerForPath:(IJSVGPath *)path
originalBoundingBox:(CGRect *)originalBoundingBox
{
// setup path and layer
IJSVGShapeLayer * layer = [[[IJSVGShapeLayer alloc] init] autorelease];
CGPathRef introPath = [path newPathRefByAutoClosingPath:NO];
CGRect bounds = [self correctedBounds:CGPathGetBoundingBox(introPath)];
*originalBoundingBox = CGRectIntegral(CGPathGetBoundingBox(introPath));
layer.originalPathOrigin = (*originalBoundingBox).origin;
CGRect bounds = [self correctedBounds:*originalBoundingBox];
// zero back the path
CGAffineTransform trans = CGAffineTransformMakeTranslation(-bounds.origin.x,
-bounds.origin.y);
CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(introPath, &trans);
layer.path = transformedPath;
@@ -169,7 +223,7 @@
CGPathRelease(introPath);
// set the bounds
layer.frame = bounds;
layer.frame = CGRectIntegral(bounds);
// basic fill color and rule
layer.fillColor = nil;
@@ -178,7 +232,7 @@
}
- (IJSVGShapeLayer *)layerMaskFromLayer:(CAShapeLayer *)layer
fromNode:(IJSVGNode *)node
fromNode:(IJSVGNode *)node
{
IJSVGShapeLayer * mask = [[[IJSVGShapeLayer alloc] init] autorelease];
mask.fillColor = [NSColor blackColor].CGColor;
@@ -186,73 +240,59 @@
return mask;
}
- (CGAffineTransform)absoluteTransform:(IJSVGNode *)node
{
CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity;
IJSVGNode * intermediateNode = node.intermediateParentNode;
IJSVGNode * parentSVGNode = node;
while((parentSVGNode = parentSVGNode.parentNode) != nil) {
if(node == intermediateNode) {
continue;
}
parentAbsoluteTransform = [self absoluteTransform:parentSVGNode];
}
return CGAffineTransformConcat(IJSVGConcatTransforms(node.transforms),
parentAbsoluteTransform);
}
- (IJSVGLayer *)layerForPath:(IJSVGPath *)path
{
// is there a sub SVG?
if(path.svg != nil) {
// grab the sub layer tree from the SVG
return [path.svg layerWithTree:self];
}
// grab the basic shape layer
CGRect originalShapeBounds;
IJSVGShapeLayer * layer = [self basicLayerForPath:path
originalBoundingBox:&originalShapeBounds];
// garb the basic shape layer
IJSVGShapeLayer * layer = [self basicLayerForPath:path];
CGRect pathBoundingBox = CGPathGetBoundingBox(layer.path);
BOOL hasStroke = (path.strokeColor != nil ||
path.strokePattern != nil ||
path.strokeGradient != nil);
// any gradient?
if(self.fillColor == nil && path.fillGradient != nil) {
if(_style.fillColor == nil && path.fillGradient != nil) {
// add the mask
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
fromNode:path];
// create the gradient
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
gradient:path.fillGradient
fromNode:path
objectRect:originalShapeBounds
shouldMask:YES];
// the gradient drawing layer
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
gradLayer.frame = pathBoundingBox;
gradLayer.gradient = path.fillGradient;
gradLayer.mask = mask;
// is there a fill opacity?
if(path.fillOpacity.value != 0.f) {
gradLayer.opacity = path.fillOpacity.value;
}
// display it
[gradLayer setNeedsDisplay];
// add the gradient
// add the gradient and set it against the layer
[layer addSublayer:gradLayer];
// assign it
layer.gradientFillLayer = gradLayer;
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
// move back if needed
gradLayer.frame = (CGRect){
.size = gradLayer.frame.size,
.origin = CGPointMake(-(gradLayer.frame.origin.x),
-(gradLayer.frame.origin.y))
};
}
} else if(self.fillColor == nil && path.fillPattern != nil) {
} else if(_style.fillColor == nil && path.fillPattern != nil) {
// create the pattern, this is actually not as easy as it may seem
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
patternLayer.patternNode = path.fillPattern;
patternLayer.pattern = [self layerForNode:path.fillPattern];
patternLayer.frame = pathBoundingBox;
// add the mask
patternLayer.mask = [self layerMaskFromLayer:layer
fromNode:path];
// display it
[patternLayer setNeedsDisplay];
IJSVGPatternLayer * patternLayer = [self patternLayerForLayer:layer
pattern:path.fillPattern
fromNode:path];
// add it
[layer addSublayer:patternLayer];
// assign it
// apply offsets
[self applyOffsetsToLayer:patternLayer
fromNode:path.fillPattern];
layer.patternFillLayer = patternLayer;
} else {
@@ -262,63 +302,320 @@
NSColor * fColor = path.fillColor;
BOOL hasColor = (fColor.alphaComponent == 0.f || fColor == nil) == NO;
BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil;
if(self.fillColor && (hasFill || hasColor || fColor == nil)) {
fColor = self.fillColor;
if(_style.fillColor && (hasFill || hasColor || fColor == nil)) {
fColor = _style.fillColor;
} else if(fColor != nil && path.fillOpacity.value != 1.f) {
fColor = [IJSVGColor changeAlphaOnColor:fColor
to:path.fillOpacity.value];
}
// anything changed by user?
fColor = [_style.colorList proposedColorForColor:fColor];
// just set the color
layer.fillColor = fColor.CGColor ?: DEFAULT_SHAPE_FILL_COLOR;
if(fColor != nil) {
layer.fillColor = fColor.CGColor;
} else {
// use default color
NSColor * defColor = [IJSVGColor computeColorSpace:NSColor.blackColor];
if(path.fillOpacity.value != 1.f) {
defColor = [IJSVGColor changeAlphaOnColor:defColor
to:path.fillOpacity.value];
}
// work out if anything was changed by user
NSColor * proposedColor = [_style.colorList proposedColorForColor:defColor];
layer.fillColor = proposedColor.CGColor;
}
}
// stroke it
if(path.strokeColor != nil) {
if(hasStroke == YES) {
// same as fill, dont use global if the alpha is 0.f
NSColor * sColor = path.strokeColor;
if(self.strokeColor != nil && (sColor != nil && sColor.alphaComponent != 0.f)) {
sColor = self.strokeColor;
// load the stroke layer
IJSVGStrokeLayer * strokeLayer = [self strokeLayer:layer
fromNode:path];
// reset the node
BOOL moveStrokeLayer = NO;
if(_style.strokeColor == nil && path.strokeGradient != nil) {
// force reset of the mask colour as we need to use the stroke layer
// as the mask for the stroke gradient
strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor;
// create the gradient
IJSVGGradientLayer * gradLayer = [self gradientStrokeLayerForLayer:layer
gradient:path.strokeGradient
fromNode:path
objectRect:originalShapeBounds];
moveStrokeLayer = YES;
gradLayer.mask = strokeLayer;
gradLayer.opacity = strokeLayer.opacity;
// add it
[layer addSublayer:gradLayer];
layer.strokeLayer = strokeLayer;
layer.gradientStrokeLayer = gradLayer;
} else if(_style.strokeColor == nil && path.strokePattern != nil) {
// force reset of the mask
strokeLayer.strokeColor = [IJSVGColor computeColorSpace:NSColor.blackColor].CGColor;
// create the pattern
IJSVGPatternLayer * patternLayer = [self patternStrokeLayerForLayer:layer
pattern:path.strokePattern
fromNode:path];
// set the mask for it
moveStrokeLayer = YES;
patternLayer.mask = strokeLayer;
patternLayer.opacity = strokeLayer.opacity;
// add it
[layer addSublayer:patternLayer];
layer.strokeLayer = strokeLayer;
layer.patternStrokeLayer = (IJSVGPatternLayer *)patternLayer;
} else {
// just add the coloured layer
[layer addSublayer:strokeLayer];
layer.strokeLayer = strokeLayer;
}
// stroke layer
IJSVGStrokeLayer * strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease];
strokeLayer.path = layer.path;
strokeLayer.fillColor = nil;
strokeLayer.strokeColor = sColor.CGColor;
CGFloat lineWidth = 1.f;
if(path.strokeWidth.value > 0.f) {
lineWidth = path.strokeWidth.value;
// if we required to move the stroke layer
// then move it in based on half of what the stroke
// width is, as strokes are draw on the center
if(moveStrokeLayer) {
CGFloat layerStrokeWidth = strokeLayer.lineWidth;
CGRect rect = strokeLayer.frame;
rect.origin.x += (layerStrokeWidth*.5f);
rect.origin.y += (layerStrokeWidth*.5f);
strokeLayer.frame = rect;
}
// line styles
strokeLayer.lineWidth = lineWidth;
strokeLayer.lineCap = [self lineCap:path.lineCapStyle];
strokeLayer.lineJoin = [self lineJoin:path.lineJoinStyle];
strokeLayer.miterLimit = lineWidth;
CGFloat strokeOpacity = 1.f;
if(path.strokeOpacity.value != 0.f) {
strokeOpacity = path.strokeOpacity.value;
}
strokeLayer.opacity = strokeOpacity;
// dashing
strokeLayer.lineDashPhase = path.strokeDashOffset.value;
strokeLayer.lineDashPattern = [self lineDashPattern:path];
// add the stroke layer
[layer addSublayer:strokeLayer];
// add it
layer.strokeLayer = strokeLayer;
}
// apply masking
[self maskLayer:(IJSVGLayer *)layer
fromNode:path];
return (IJSVGLayer *)layer;
}
- (CGRect)correctBounds:(CGRect)bounds
forStrokedPath:(IJSVGNode *)path
{
// minus half the stroke width from x and y
// plus the stroke width to width and height
CGFloat val = path.strokeWidth.value;
bounds.origin.x -= (val*.5f);
bounds.origin.y -= (val*.5f);
bounds.size.width += val;
bounds.size.height += val;
return bounds;
}
- (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer
gradient:(IJSVGGradient *)gradient
fromNode:(IJSVGNode *)path
objectRect:(CGRect)objectRect
{
// the gradient drawing layer
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
gradient:gradient
fromNode:path
objectRect:objectRect
shouldMask:NO];
// set the bounds
CGRect bounds = CGPathGetBoundingBox(layer.path);
bounds = [self correctBounds:bounds forStrokedPath:path];
gradLayer.frame = bounds;
return gradLayer;
}
- (IJSVGGradientLayer *)gradientLayerForLayer:(IJSVGShapeLayer *)layer
gradient:(IJSVGGradient *)gradient
fromNode:(IJSVGNode *)path
objectRect:(CGRect)objectRect
shouldMask:(BOOL)shouldMask
{
// the gradient drawing layer
gradient.colorList = _style.colorList;
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
gradLayer.viewBox = self.viewBox;
gradLayer.frame = layer.bounds;
gradLayer.gradient = gradient;
gradLayer.absoluteTransform = [self absoluteTransform:path];
gradLayer.objectRect = CGRectApplyAffineTransform(objectRect,
gradLayer.absoluteTransform);
if(shouldMask == YES) {
// add the mask
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
fromNode:path];
gradLayer.mask = mask;
}
// is there a fill opacity?
if(path.fillOpacity.value != 0.f) {
gradLayer.opacity = path.fillOpacity.value;
}
gradLayer.masksToBounds = YES;
return gradLayer;
}
- (IJSVGPatternLayer *)patternStrokeLayerForLayer:(IJSVGShapeLayer *)layer
pattern:(IJSVGPattern *)pattern
fromNode:(IJSVGNode *)path
{
// create the pattern, this is actually not as easy as it may seem
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
patternLayer.patternNode = pattern;
patternLayer.pattern = [self layerForNode:pattern];
// is there a fill opacity?
if(path.fillOpacity.value != 0.f) {
patternLayer.opacity = path.fillOpacity.value;
}
// set the bounds
CGRect bounds = CGPathGetBoundingBox(layer.path);
bounds = [self correctBounds:bounds forStrokedPath:path];
patternLayer.frame = bounds;
patternLayer.masksToBounds = YES;
// display
[patternLayer setNeedsDisplay];
return patternLayer;
}
- (IJSVGPatternLayer *)patternLayerForLayer:(IJSVGShapeLayer *)layer
pattern:(IJSVGPattern *)pattern
fromNode:(IJSVGNode *)path
{
// create the pattern, this is actually not as easy as it may seem
IJSVGPatternLayer * patternLayer = [[[IJSVGPatternLayer alloc] init] autorelease];
patternLayer.patternNode = pattern;
patternLayer.pattern = [self layerForNode:pattern];
patternLayer.frame = CGPathGetBoundingBox(layer.path);
// is there a fill opacity?
if(path.fillOpacity.value != 0.f) {
patternLayer.opacity = path.fillOpacity.value;
}
// add the mask
patternLayer.mask = [self layerMaskFromLayer:layer
fromNode:path];
// display
[patternLayer setNeedsDisplay];
patternLayer.masksToBounds = YES;
return patternLayer;
}
- (void)applyOffsetsToLayer:(IJSVGLayer *)layer
fromNode:(IJSVGNode *)node
{
// make sure it has a superlayer
if(layer.superlayer == nil) {
return;
}
// grab the x and y
IJSVGUnitLength * x = nil;
IJSVGUnitLength * y = nil;
// sort out the rect
CGRect rect = layer.superlayer.frame;
CGRect frame = layer.frame;
// x
if((x = node.x) != nil) {
frame.origin.x = [x computeValue:rect.size.width];
}
// y
if((y = node.y) != nil) {
frame.origin.y = [y computeValue:rect.size.height];
}
// update the frame
if(CGRectEqualToRect(frame, layer.frame) == NO) {
layer.frame = frame;
}
}
- (IJSVGStrokeLayer *)strokeLayer:(IJSVGShapeLayer *)layer
fromNode:(IJSVGPath *)path
{
// same as fill, dont use global if the alpha is 0.f, but do use it
// if there is a pattern or gradient
NSColor * sColor = path.strokeColor;
if(_style.strokeColor != nil &&
((sColor != nil && sColor.alphaComponent != 0.f) ||
path.strokePattern != nil || path.strokeGradient != nil )) {
sColor = _style.strokeColor;
}
sColor = [_style.colorList proposedColorForColor:sColor];
// stroke layer
IJSVGStrokeLayer * strokeLayer = [[[IJSVGStrokeLayer alloc] init] autorelease];
strokeLayer.path = layer.path;
strokeLayer.fillColor = nil;
strokeLayer.strokeColor = sColor.CGColor;
CGFloat lineWidth = 1.f;
if(_style.lineWidth != IJSVGInheritedFloatValue) {
lineWidth = _style.lineWidth;
} else {
lineWidth = path.strokeWidth.value;
}
// work out line styles
IJSVGLineCapStyle lCapStyle;
IJSVGLineJoinStyle lJoinStyle;
// forced cap style
if(_style.lineCapStyle != IJSVGLineCapStyleNone) {
lCapStyle = _style.lineCapStyle;
} else {
lCapStyle = path.lineCapStyle;
}
// forced join style
if(_style.lineJoinStyle != IJSVGLineJoinStyleNone) {
lJoinStyle = _style.lineJoinStyle;
} else {
lJoinStyle = path.lineJoinStyle;
}
// line styles
strokeLayer.lineWidth = lineWidth;
strokeLayer.lineCap = [self lineCap:lCapStyle];
strokeLayer.lineJoin = [self lineJoin:lJoinStyle];
CGFloat strokeOpacity = 1.f;
if(path.strokeOpacity.value != 0.f) {
strokeOpacity = path.strokeOpacity.value;
}
strokeLayer.opacity = strokeOpacity;
// dashing
strokeLayer.lineDashPhase = path.strokeDashOffset.value;
strokeLayer.lineDashPattern = [self lineDashPattern:path];
return strokeLayer;
}
- (void)maskLayer:(IJSVGLayer *)layer
fromNode:(IJSVGNode *)node
{
@@ -354,7 +651,7 @@
// recursive colourize for each item
[self _recursiveColorLayersFromLayer:maskLayer
withColor:[NSColor whiteColor].CGColor];
withColor:[IJSVGColor computeColorSpace:NSColor.whiteColor].CGColor];
// add the mask
layer.mask = maskLayer;
@@ -448,4 +745,17 @@
}
}
+ (void)log:(IJSVGLayer *)layer
depth:(NSInteger)depth {
NSLog(@"%@%@: %@, Transforms: %@",[@"" stringByPaddingToLength:depth
withString:@"\t"
startingAtIndex:0],layer,
NSStringFromRect(layer.frame),
[IJSVGTransform affineTransformToSVGTransformAttributeString:layer.affineTransform]);
for(IJSVGLayer * sublayer in layer.sublayers) {
[self log:(IJSVGLayer *)sublayer
depth:depth++];
}
}
@end
+1 -3
View File
@@ -12,8 +12,6 @@
@interface IJSVGLinearGradient : IJSVGGradient
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGLinearGradient *)aGradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint;
gradient:(IJSVGLinearGradient *)aGradient;
@end
+48 -55
View File
@@ -13,81 +13,74 @@
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGLinearGradient *)aGradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint
{
CGFloat px1 = [[element attributeForName:@"x1"] stringValue].floatValue;
CGFloat px2 = [[element attributeForName:@"x2"] stringValue].floatValue;
CGFloat py1 = [[element attributeForName:@"y1"] stringValue].floatValue;
CGFloat py2 = [[element attributeForName:@"y2"] stringValue].floatValue;
// work out each coord, and work out if its a % or not
// annoyingly we need to check them all against each other -_-
BOOL isPercent = NO;
if(px1 <= 1.f && px2 <= 1.f && py1 <= 1.f && py2 <= 1.f) {
isPercent = YES;
} else if((px1 >= 0.f && px1 <= 1.f) && (px2 >= 0.f && px2 <= 1.f) &&
(py1 >= 0.f && py1 <= 1.f) && (py2 >= 0.f && py2 <= 1.f)) {
isPercent = YES;
}
// assume its a vertical / horizonal
if(isPercent == NO) {
// just ask unit for the value
aGradient.x1 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"x1"] stringValue] ?: @"0"];
aGradient.x2 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"x2"] stringValue] ?: @"100"];
aGradient.y1 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"y1"] stringValue] ?: @"0"];
aGradient.y2 = [IJSVGUnitLength unitWithString:[[element attributeForName:@"y2"] stringValue] ?: @"0"];
} else {
// make sure its a percent!
aGradient.x1 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"x1"] stringValue] ?: @"0"];
aGradient.x2 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"x2"] stringValue] ?: @"100"];
aGradient.y1 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"y1"] stringValue] ?: @"0"];
aGradient.y2 = [IJSVGUnitLength unitWithPercentageString:[[element attributeForName:@"y2"] stringValue] ?: @"0"];
}
// just ask unit for the value
NSString * x1 = ([element attributeForName:@"x1"].stringValue ?: @"0");
NSString * x2 = ([element attributeForName:@"x2"].stringValue ?: @"100%");
NSString * y1 = ([element attributeForName:@"y1"].stringValue ?: @"0");
NSString * y2 = ([element attributeForName:@"y2"].stringValue ?: @"0");
aGradient.x1 = [IJSVGGradientUnitLength unitWithString:x1 fromUnitType:aGradient.units];
aGradient.x2 = [IJSVGGradientUnitLength unitWithString:x2 fromUnitType:aGradient.units];
aGradient.y1 = [IJSVGGradientUnitLength unitWithString:y1 fromUnitType:aGradient.units];
aGradient.y2 = [IJSVGGradientUnitLength unitWithString:y2 fromUnitType:aGradient.units];
// compute the color stops and colours
NSArray * colors = nil;
CGFloat * stopsParams = [[self class] computeColorStopsFromString:element
CGFloat * stopsParams = [self.class computeColorStopsFromString:element
colors:&colors];
// create the gradient with the colours
NSGradient * grad = [[[NSGradient alloc] initWithColors:colors
NSGradient * grad = [[NSGradient alloc] initWithColors:colors
atLocations:stopsParams
colorSpace:[NSColorSpace genericRGBColorSpace]] autorelease];
colorSpace:IJSVGColor.defaultColorSpace];
free(stopsParams);
return grad;
return [grad autorelease];
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
// grab the start and end point
CGPoint aStartPoint = (CGPoint){
.x = [self.x1 computeValue:rect.size.width],
.y = [self.y1 computeValue:rect.size.height]
};
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGPoint aEndPoint = (CGPoint){
.x = [self.x2 computeValue:rect.size.width],
.y = [self.y2 computeValue:rect.size.height]
};
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
// convert the nsgradient to a CGGradient
CGGradientRef gRef = [self CGGradient];
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
// apply transform for each point
for( IJSVGTransform * transform in self.transforms ) {
CGAffineTransform trans = transform.CGAffineTransform;
aStartPoint = CGPointApplyAffineTransform(aStartPoint, trans);
aEndPoint = CGPointApplyAffineTransform(aEndPoint, trans);
// make sure we apply the absolute position to
// transform us back into the correct space
if(inUserSpace == YES) {
CGContextConcatCTM(ctx, absoluteTransform);
}
CGFloat width = CGRectGetWidth(boundingBox);
CGFloat height = CGRectGetHeight(boundingBox);
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
[self.y1 computeValue:height]);
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
[self.y2 computeValue:height]);
// transform the context
CGContextConcatCTM(ctx, selfTransform);
// draw the gradient
CGGradientDrawingOptions opt = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, gRef, aStartPoint, aEndPoint, opt);
CGGradientDrawingOptions options =
kCGGradientDrawsBeforeStartLocation|
kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(ctx, self.CGGradient, gradientStartPoint,
gradientEndPoint, options);
#ifdef IJSVG_DEBUG
[self _debugStart:gradientStartPoint
end:gradientEndPoint
context:ctx];
#endif
}
@end
+27 -5
View File
@@ -16,6 +16,7 @@
@class IJSVGGradient;
@class IJSVGGroup;
@class IJSVGPattern;
@class IJSVGTransform;
typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
IJSVGNodeTypeGroup,
@@ -39,6 +40,8 @@ typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
IJSVGNodeTypeSVG,
IJSVGNodeTypeText,
IJSVGNodeTypeTextSpan,
IJSVGNodeTypeStyle,
IJSVGNodeTypeSwitch,
IJSVGNodeTypeNotFound,
};
@@ -49,6 +52,7 @@ typedef NS_ENUM( NSInteger, IJSVGWindingRule ) {
};
typedef NS_ENUM( NSInteger, IJSVGLineCapStyle ) {
IJSVGLineCapStyleNone,
IJSVGLineCapStyleButt,
IJSVGLineCapStyleRound,
IJSVGLineCapStyleSquare,
@@ -56,6 +60,7 @@ typedef NS_ENUM( NSInteger, IJSVGLineCapStyle ) {
};
typedef NS_ENUM( NSInteger, IJSVGLineJoinStyle ) {
IJSVGLineJoinStyleNone,
IJSVGLineJoinStyleMiter,
IJSVGLineJoinStyleRound,
IJSVGLineJoinStyleBevel,
@@ -68,10 +73,23 @@ typedef NS_OPTIONS( NSInteger, IJSVGFontTraits ) {
IJSVGFontTraitItalic = 1 << 2
};
typedef NS_ENUM( NSInteger, IJSVGUnitType) {
IJSVGUnitUserSpaceOnUse,
IJSVGUnitObjectBoundingBox,
IJSVGUnitInherit
typedef NS_ENUM( NSInteger, IJSVGBlendMode) {
IJSVGBlendModeNormal = kCGBlendModeNormal,
IJSVGBlendModeMultiply = kCGBlendModeMultiply,
IJSVGBlendModeScreen = kCGBlendModeScreen,
IJSVGBlendModeOverlay = kCGBlendModeOverlay,
IJSVGBlendModeDarken = kCGBlendModeDarken,
IJSVGBlendModeLighten = kCGBlendModeLighten,
IJSVGBlendModeColorDodge = kCGBlendModeColorDodge,
IJSVGBlendModeColorBurn = kCGBlendModeColorBurn,
IJSVGBlendModeHardLight = kCGBlendModeHardLight,
IJSVGBlendModeSoftLight = kCGBlendModeSoftLight,
IJSVGBlendModeDifference = kCGBlendModeDifference,
IJSVGBlendModeExclusion = kCGBlendModeExclusion,
IJSVGBlendModeHue = kCGBlendModeHue,
IJSVGBlendModeSaturation = kCGBlendModeSaturation,
IJSVGBlendModeColor = kCGBlendModeColor,
IJSVGBlendModeLuminosity = kCGBlendModeLuminosity
};
static CGFloat IJSVGInheritedFloatValue = -99.9999991;
@@ -97,21 +115,25 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991;
@property ( nonatomic, retain ) NSColor * strokeColor;
@property ( nonatomic, copy ) NSString * identifier;
@property ( nonatomic, assign ) IJSVGNode * parentNode;
@property ( nonatomic, assign ) IJSVGNode * intermediateParentNode;
@property ( nonatomic, retain ) IJSVGGroup * clipPath;
@property ( nonatomic, retain ) IJSVGGroup * mask;
@property ( nonatomic, assign ) IJSVGWindingRule windingRule;
@property ( nonatomic, assign ) IJSVGLineCapStyle lineCapStyle;
@property ( nonatomic, assign ) IJSVGLineJoinStyle lineJoinStyle;
@property ( nonatomic, retain ) NSArray * transforms;
@property ( nonatomic, retain ) NSArray<IJSVGTransform *> * transforms;
@property ( nonatomic, retain ) IJSVGDef * def;
@property ( nonatomic, retain ) IJSVGGradient * fillGradient;
@property ( nonatomic, retain ) IJSVGPattern * fillPattern;
@property ( nonatomic, retain ) IJSVGGradient * strokeGradient;
@property ( nonatomic, retain ) IJSVGPattern * strokePattern;
@property ( nonatomic, assign ) CGFloat * strokeDashArray;
@property ( nonatomic, assign ) NSInteger strokeDashArrayCount;
@property ( nonatomic, retain ) IJSVGUnitLength * strokeDashOffset;
@property ( nonatomic, retain ) IJSVG * svg;
@property ( nonatomic, assign ) IJSVGUnitType contentUnits;
@property ( nonatomic, assign ) IJSVGUnitType units;
@property ( nonatomic, assign ) IJSVGBlendMode blendMode;
+ (IJSVGNodeType)typeForString:(NSString *)string
kind:(NSXMLNodeKind)kind;
+66 -13
View File
@@ -8,6 +8,7 @@
#import "IJSVGNode.h"
#import "IJSVGDef.h"
#import "IJSVGUtils.h"
@implementation IJSVGNode
@@ -29,11 +30,14 @@
@synthesize opacity;
@synthesize identifier;
@synthesize parentNode;
@synthesize intermediateParentNode;
@synthesize transforms;
@synthesize windingRule;
@synthesize def;
@synthesize fillGradient;
@synthesize fillPattern;
@synthesize strokeGradient;
@synthesize strokePattern;
@synthesize clipPath;
@synthesize lineCapStyle;
@synthesize lineJoinStyle;
@@ -45,6 +49,7 @@
@synthesize mask;
@synthesize units;
@synthesize contentUnits;
@synthesize blendMode;
- (void)dealloc
{
@@ -60,6 +65,8 @@
[strokeDashOffset release], strokeDashOffset = nil;
[unicode release], unicode = nil;
[fillGradient release], fillGradient = nil;
[strokeGradient release], strokeGradient = nil;
[strokePattern release], strokePattern = nil;
[transforms release], transforms = nil;
[fillColor release], fillColor = nil;
[strokeColor release], strokeColor = nil;
@@ -79,6 +86,10 @@
kind:(NSXMLNodeKind)kind
{
string = [string lowercaseString];
if([string isEqualToString:@"style"])
return IJSVGNodeTypeStyle;
if([string isEqualToString:@"switch"])
return IJSVGNodeTypeSwitch;
if( [string isEqualToString:@"defs"] )
return IJSVGNodeTypeDef;
if( [string isEqualToString:@"g"] )
@@ -122,6 +133,12 @@
if([string isEqualToString:@"tspan"] || kind == NSXMLTextKind) {
return IJSVGNodeTypeTextSpan;
}
// are we commong HTML? - if so just treat as a group
if(IJSVGIsCommonHTMLElementName(string) == YES) {
return IJSVGNodeTypeGroup;
}
return IJSVGNodeTypeNotFound;
}
@@ -129,6 +146,7 @@
{
if( ( self = [self initWithDef:YES] ) != nil )
{
self.opacity = [IJSVGUnitLength unitWithFloat:1];
}
return self;
}
@@ -148,6 +166,8 @@
self.fillGradient = node.fillGradient;
self.fillPattern = node.fillPattern;
self.strokeGradient = node.strokeGradient;
self.strokePattern = node.strokePattern;
self.fillColor = node.fillColor;
self.strokeColor = node.strokeColor;
@@ -172,6 +192,7 @@
self.parentNode = node.parentNode;
self.shouldRender = node.shouldRender;
self.blendMode = node.blendMode;
// dash array needs physical memory copied
CGFloat * nStrokeDashArray = (CGFloat *)malloc(node.strokeDashArrayCount*sizeof(CGFloat));
@@ -183,7 +204,7 @@
- (id)copyWithZone:(NSZone *)zone
{
IJSVGNode * node = [[self class] allocWithZone:zone];
IJSVGNode * node = [self.class allocWithZone:zone];
[node applyPropertiesFromNode:self];
return node;
}
@@ -194,15 +215,24 @@
{
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
self.strokeOpacity = [IJSVGUnitLength unitWithFloat:1.f];
self.fillOpacity.inherit = YES;
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
self.shouldRender = YES;
self.strokeWidth = [IJSVGUnitLength unitWithFloat:0.f];
self.strokeOpacity = [IJSVGUnitLength unitWithFloat:1.f];
self.strokeOpacity.inherit = YES;
self.strokeWidth = [IJSVGUnitLength unitWithFloat:1.f];
self.strokeWidth.inherit = YES;
self.windingRule = IJSVGWindingRuleInherit;
self.lineCapStyle = IJSVGLineCapStyleInherit;
self.lineJoinStyle = IJSVGLineJoinStyleInherit;
self.units = IJSVGUnitInherit;
self.blendMode = IJSVGBlendModeNormal;
if( flag ) {
def = [[IJSVGDef alloc] init];
}
@@ -213,10 +243,12 @@
- (IJSVGDef *)defForID:(NSString *)anID
{
IJSVGDef * aDef = nil;
if( (aDef = [def defForID:anID]) != nil )
if( (aDef = [def defForID:anID]) != nil ) {
return aDef;
if( parentNode != nil )
}
if( parentNode != nil ) {
return [parentNode defForID:anID];
}
return nil;
}
@@ -228,7 +260,7 @@
// winding rule can inherit..
- (IJSVGWindingRule)windingRule
{
if( windingRule == IJSVGWindingRuleInherit && parentNode != nil ) {
if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
return parentNode.windingRule;
}
return windingRule;
@@ -236,20 +268,20 @@
- (IJSVGLineCapStyle)lineCapStyle
{
if( lineCapStyle == IJSVGLineCapStyleInherit )
{
if( parentNode != nil )
if( lineCapStyle == IJSVGLineCapStyleInherit ) {
if( parentNode != nil ) {
return parentNode.lineCapStyle;
}
}
return lineCapStyle;
}
- (IJSVGLineJoinStyle)lineJoinStyle
{
if( lineJoinStyle == IJSVGLineJoinStyleInherit )
{
if( parentNode != nil )
if( lineJoinStyle == IJSVGLineJoinStyleInherit ) {
if( parentNode != nil ) {
return parentNode.lineJoinStyle;
}
}
return lineJoinStyle;
}
@@ -307,8 +339,9 @@
// must be on the path, it can also be on the
- (NSColor *)fillColor
{
if( fillColor == nil && parentNode != nil )
if( fillColor == nil && parentNode != nil ) {
return parentNode.fillColor;
}
return fillColor;
}
@@ -332,4 +365,24 @@
return fillPattern;
}
// these are all recursive, so go up the chain
// if they dont exist on this specific node
- (IJSVGGradient *)strokeGradient
{
if(strokeGradient == nil && parentNode != nil) {
return parentNode.strokeGradient;
}
return strokeGradient;
}
// these are all recursive, so go up the chain
// if they dont exist on this specific node
- (IJSVGPattern *)strokePattern
{
if(strokePattern == nil && parentNode != nil) {
return parentNode.strokePattern;
}
return strokePattern;
}
@end
+5
View File
@@ -49,6 +49,7 @@ static NSString const * IJSVGAttributeStroke = @"stroke";
static NSString const * IJSVGAttributeStrokeDashArray = @"stroke-dasharray";
static NSString const * IJSVGAttributeFill = @"fill";
static NSString const * IJSVGAttributeFillRule = @"fill-rule";
static NSString const * IJSVGAttributeBlendMode = @"mix-blend-mode";
static NSString const * IJSVGAttributeDisplay = @"display";
static NSString const * IJSVGAttributeStyle = @"style";
static NSString const * IJSVGAttributeD = @"d";
@@ -92,7 +93,9 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
IJSVGStyleSheet * _styleSheet;
NSMutableArray * _parsedNodes;
NSMutableDictionary * _defNodes;
NSMutableDictionary * _baseDefNodes;
NSMutableArray<IJSVG *> * _svgs;
NSMutableArray * _definedGroups;
struct {
unsigned int shouldHandleForeignObject: 1;
@@ -104,6 +107,8 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
@property ( nonatomic, readonly ) NSRect viewBox;
@property ( nonatomic, readonly ) NSSize proposedViewSize;
+ (BOOL)isDataSVG:(NSData *)data;
- (id)initWithSVGString:(NSString *)string
error:(NSError **)error
delegate:(id<IJSVGParserDelegate>)delegate;
+317 -304
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -24,6 +24,7 @@
{
if((self = [super init]) != nil) {
self.requiresBackingScaleHelp = YES;
self.shouldRasterize = YES;
}
return self;
}
+1 -3
View File
@@ -18,8 +18,6 @@
@property ( nonatomic, retain ) IJSVGUnitLength * radius;
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGRadialGradient *)gradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint;
gradient:(IJSVGRadialGradient *)gradient;
@end
+85 -78
View File
@@ -34,123 +34,130 @@
grad.cx = self.cx;
grad.cy = self.cy;
grad.radius = self.radius;
grad.startPoint = self.startPoint;
grad.endPoint = self.endPoint;
return grad;
}
+ (NSGradient *)parseGradient:(NSXMLElement *)element
gradient:(IJSVGRadialGradient *)gradient
startPoint:(CGPoint *)startPoint
endPoint:(CGPoint *)endPoint
{
// cx defaults to 50% if not specified
NSDictionary * kv = @{@"cx":@"cx",
@"cy":@"cy",
@"r":@"radius",
@"fx":@"fx"};
@"r":@"radius"};
for(NSString * key in kv.allKeys) {
NSString * str = [element attributeForName:key].stringValue;
IJSVGUnitLength * unit = nil;
if(str != nil) {
unit = [IJSVGUnitLength unitWithPercentageString:str];
unit = [IJSVGUnitLength unitWithString:str
fromUnitType:gradient.units];
} else {
unit = [IJSVGUnitLength unitWithPercentageFloat:50];
// spec says to say 50% for missing property default
unit = [IJSVGUnitLength unitWithPercentageFloat:.5f];
}
[gradient setValue:unit
forKey:kv[key]];
}
// fy defaults to cy if not specified
NSString * fy = [element attributeForName:@"fy"].stringValue;
if(fy != nil) {
gradient.fy = [IJSVGUnitLength unitWithPercentageString:fy];
} else {
gradient.fy = gradient.cy;
// fx and fy are the same unless specified otherwise
gradient.fx = gradient.cx;
gradient.fy = gradient.cy;
// needs fixing
NSString * fx = [element attributeForName:@"fx"].stringValue;
if(fx != nil) {
gradient.fx = [IJSVGUnitLength unitWithString:fx
fromUnitType:gradient.units];
}
if( gradient.gradient != nil )
NSString * fy = [element attributeForName:@"fy"].stringValue;
if(fx != nil) {
gradient.fy = [IJSVGUnitLength unitWithString:fy
fromUnitType:gradient.units];
}
if( gradient.gradient != nil ) {
return nil;
*startPoint = CGPointMake(gradient.cx.valueAsPercentage, gradient.cy.valueAsPercentage);
*endPoint = CGPointMake(gradient.fx.valueAsPercentage, gradient.fy.valueAsPercentage);
}
NSArray * colors = nil;
CGFloat * colorStops = [[self class] computeColorStopsFromString:element colors:&colors];
CGFloat * colorStops = [self.class computeColorStopsFromString:element colors:&colors];
NSGradient * ret = [[[NSGradient alloc] initWithColors:colors
atLocations:colorStops
colorSpace:[NSColorSpace genericRGBColorSpace]] autorelease];
colorSpace:IJSVGColor.defaultColorSpace] autorelease];
free(colorStops);
return ret;
}
- (CGFloat)_handleTransform:(IJSVGTransform *)transform
bounds:(CGRect)bounds
index:(NSInteger)index
value:(CGFloat)value
{
// rotate transform, assume its based on percentages
// if lower then 0 is specified for 1 or 2
CGFloat max = bounds.size.width>bounds.size.height?bounds.size.width:bounds.size.height;
if( transform.command == IJSVGTransformCommandRotate ) {
switch(index) {
case 1:
case 2: {
if(value<1.f) {
return (max*value);
}
break;
}
}
}
return value;
}
- (void)drawInContextRef:(CGContextRef)ctx
rect:(NSRect)rect
objectRect:(NSRect)objectRect
absoluteTransform:(CGAffineTransform)absoluteTransform
viewPort:(CGRect)viewBox
{
CGRect bounds = rect;
for( IJSVGTransform * transform in self.transforms ) {
IJSVGTransformParameterModifier modifier = ^CGFloat(NSInteger index, CGFloat value) {
return [self _handleTransform:transform
bounds:bounds
index:index
value:value];
};
CGContextConcatCTM(ctx, [transform CGAffineTransformWithModifier:modifier]);
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
CGFloat radius = 0.f;
CGPoint startPoint = CGPointZero;
CGPoint gradientStartPoint = CGPointZero;
CGPoint gradientEndPoint = CGPointZero;
// transforms
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
CGRect boundingBox = inUserSpace ? viewBox : objectRect;
// make sure we apply the absolute position to
// transform us back into the correct space
if(inUserSpace == YES) {
CGContextConcatCTM(ctx, absoluteTransform);
}
CGPoint sp = self.startPoint;
CGPoint ep = self.endPoint;
if( self.startPoint.x == .5f ) {
sp.x = bounds.size.width*self.startPoint.x;
// compute size based on percentages
CGFloat x = [self.cx computeValue:CGRectGetWidth(boundingBox)];
CGFloat y = [self.cy computeValue:CGRectGetHeight(boundingBox)];
startPoint = CGPointMake(x, y);
CGFloat val = MIN(CGRectGetWidth(boundingBox),
CGRectGetHeight(boundingBox));
radius = [self.radius computeValue:val];
CGFloat ex = [self.fx computeValue:CGRectGetWidth(boundingBox)];
CGFloat ey = [self.fy computeValue:CGRectGetHeight(boundingBox)];
gradientEndPoint = CGPointMake(ex, ey);
gradientStartPoint = startPoint;
// transform if width or height is not equal - this can only
// be done if we are using objectBoundingBox
if(inUserSpace == NO && CGRectGetWidth(boundingBox) != CGRectGetHeight(boundingBox)) {
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
gradientStartPoint.y);
if(CGRectGetWidth(boundingBox) > CGRectGetHeight(boundingBox)) {
tr = CGAffineTransformScale(tr, CGRectGetWidth(boundingBox)/CGRectGetHeight(boundingBox), 1);
} else {
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(boundingBox)/CGRectGetWidth(boundingBox));
}
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
selfTransform = CGAffineTransformConcat(tr, selfTransform);
}
// transform the context
CGContextConcatCTM(ctx, selfTransform);
// draw the gradient
CGGradientDrawingOptions options =
kCGGradientDrawsBeforeStartLocation|
kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient(ctx, self.CGGradient,
gradientEndPoint, 0,
gradientStartPoint,
radius, options);
if(self.startPoint.y == .5f) {
sp.y = bounds.size.height*self.startPoint.y;
}
if(self.endPoint.x == .5f) {
ep.x = bounds.size.width*self.endPoint.x;
}
if(self.endPoint.y == .5f) {
ep.y = bounds.size.height*self.endPoint.y;
}
CGFloat r = self.radius.value;
if(r == .5f) {
r = (sp.x>sp.y?sp.x:sp.y);
}
// actually perform the draw
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation;
CGGradientRef grad = self.CGGradient;
CGContextDrawRadialGradient(ctx, grad, sp, 0.f, ep, r, options);
#ifdef IJSVG_DEBUG_GRADIENTS
[self _debugStart:gradientStartPoint
end:gradientEndPoint
context:ctx];
#endif
}
@end
+21
View File
@@ -0,0 +1,21 @@
//
// IJSVGRendering.h
// IJSVGExample
//
// Created by Curtis Hard on 14/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
typedef NS_ENUM(NSInteger, IJSVGRenderQuality) {
IJSVGRenderQualityFullResolution, // slowest to render
IJSVGRenderQualityOptimized, // best of both worlds
IJSVGRenderQualityLow // fast rendering
};
@interface IJSVGRendering : NSObject
@end
+13
View File
@@ -0,0 +1,13 @@
//
// IJSVGRendering.m
// IJSVGExample
//
// Created by Curtis Hard on 14/03/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGRendering.h"
@implementation IJSVGRendering
@end
+24
View File
@@ -0,0 +1,24 @@
//
// IJSVGStyleList.h
// IconJar
//
// Created by Curtis Hard on 09/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IJSVGNode.h"
#import "IJSVGColorList.h"
@interface IJSVGRenderingStyle : NSObject
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
@property (nonatomic, assign) CGFloat lineWidth;
@property (nonatomic, retain) IJSVGColorList * colorList;
@property (nonatomic, retain) NSColor * fillColor;
@property (nonatomic, retain) NSColor * strokeColor;
+ (NSArray<NSString *> *)observableProperties;
@end
+56
View File
@@ -0,0 +1,56 @@
//
// IJSVGStyleList.m
// IconJar
//
// Created by Curtis Hard on 09/07/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGRenderingStyle.h"
@implementation IJSVGRenderingStyle
@synthesize colorList = _colorList;
@synthesize lineCapStyle = _lineCapStyle;
@synthesize lineJoinStyle = _lineJoinStyle;
@synthesize lineWidth = _lineWidth;
@synthesize fillColor = _fillColor;
@synthesize strokeColor = _strokeColor;
- (void)dealloc
{
[_fillColor release], _fillColor = nil;
[_strokeColor release], _strokeColor = nil;
[_colorList release], _colorList = nil;
[super dealloc];
}
- (id)init
{
if((self = [super init]) != nil) {
_lineCapStyle = IJSVGLineCapStyleNone;
_lineJoinStyle = IJSVGLineJoinStyleNone;
_lineWidth = IJSVGInheritedFloatValue;
_colorList = [[IJSVGColorList alloc] init];
}
return self;
}
+ (NSArray<NSString *> *)observableProperties
{
unsigned int count;
objc_property_t * properties = class_copyPropertyList(IJSVGRenderingStyle.class,
&count);
NSMutableArray * names = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
for(int i = 0; i < count; i++) {
objc_property_t property = properties[i];
const char * name = property_getName(property);
NSString * stringName = [NSString stringWithCString:name
encoding:NSUTF8StringEncoding];
[names addObject:stringName];
}
free(properties);
return names;
}
@end
+22 -2
View File
@@ -8,9 +8,29 @@
#import <QuartzCore/QuartzCore.h>
#import "IJSVGLayer.h"
#import "IJSVGUtils.h"
@interface IJSVGShapeLayer : CAShapeLayer
@interface IJSVGShapeLayer : CAShapeLayer {
@private
IJSVGLayer * _maskingLayer;
}
IJSVG_LAYER_DEFAULT_PROPERTIES
@property (nonatomic, assign) IJSVGGradientLayer * gradientFillLayer;
@property (nonatomic, assign) IJSVGPatternLayer * patternFillLayer;
@property (nonatomic, assign) IJSVGStrokeLayer * strokeLayer;
@property (nonatomic, assign) IJSVGGradientLayer * gradientStrokeLayer;
@property (nonatomic, assign) IJSVGPatternLayer * patternStrokeLayer;
@property (nonatomic, assign) BOOL requiresBackingScaleHelp;
@property (nonatomic, assign) CGFloat backingScaleFactor;
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
@property (nonatomic, assign) CGBlendMode blendingMode;
@property (nonatomic, assign) CGPoint absoluteOrigin;
@property (nonatomic, assign) CGPoint originalPathOrigin;
@property (nonatomic, assign) BOOL convertMasksToPaths;
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer *)sublayer
withOffset:(CGPoint)offset;
@end
+143 -3
View File
@@ -7,16 +7,156 @@
//
#import "IJSVGShapeLayer.h"
#import "IJSVGGroupLayer.h"
@implementation IJSVGShapeLayer
IJSVG_LAYER_DEFAULT_SYNTHESIZE
@synthesize gradientFillLayer;
@synthesize patternFillLayer;
@synthesize gradientStrokeLayer;
@synthesize patternStrokeLayer;
@synthesize strokeLayer;
@synthesize requiresBackingScaleHelp;
@synthesize backingScaleFactor;
@synthesize blendingMode;
@synthesize convertMasksToPaths;
@synthesize originalPathOrigin;
@synthesize renderQuality;
- (void)dealloc
{
IJSVG_LAYER_DEFAULT_DEALLOC_INSTRUCTIONS
[_maskingLayer release], _maskingLayer = nil;
[super dealloc];
}
IJSVG_LAYER_ADD_SUBVIEW_DEFAULT_IMPLEMENTATION
- (void)addSublayer:(CALayer *)layer {
if([layer isKindOfClass:[IJSVGLayer class]] == NO &&
[layer isKindOfClass:[IJSVGShapeLayer class]] == NO) {
NSString * r = [NSString stringWithFormat:@"The layer must be an instance of IJSVGLayer, %@ given.",
[layer class]];
NSException * exception = [NSException exceptionWithName:@"IJSVGInvalidSublayerException"
reason:r
userInfo:nil];
@throw exception;
}
[super addSublayer:layer];
}
- (void)setBackingScaleFactor:(CGFloat)newFactor
{
if(self.backingScaleFactor == newFactor) {
return;
}
backingScaleFactor = newFactor;
self.contentsScale = newFactor;
self.rasterizationScale = newFactor;
[self setNeedsDisplay];
}
- (void)_customRenderInContext:(CGContextRef)ctx
{
if(self.convertMasksToPaths == YES && _maskingLayer != nil) {
CGContextSaveGState(ctx);
[self applySublayerMaskToContext:ctx
forSublayer:(IJSVGLayer *)self
withOffset:CGPointZero];
[super renderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[super renderInContext:ctx];
}
- (void)setConvertMasksToPaths:(BOOL)flag
{
if(convertMasksToPaths == flag) {
return;
}
convertMasksToPaths = flag;
if(flag == YES) {
if(_maskingLayer != nil) {
[_maskingLayer release], _maskingLayer = nil;
}
_maskingLayer = [(IJSVGLayer *)self.mask retain];
self.mask = nil;
} else {
self.mask = _maskingLayer;
[_maskingLayer release], _maskingLayer = nil;
}
}
- (void)applySublayerMaskToContext:(CGContextRef)context
forSublayer:(IJSVGLayer *)sublayer
withOffset:(CGPoint)offset
{
// apply any transforms needed
CGPoint layerOffset = offset;
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(sublayer.transform);
CGContextConcatCTM( context, CGAffineTransformInvert(sublayerTransform) );
// walk up the superlayer chain
CALayer * superlayer = self.superlayer;
if (IJSVGIsSVGLayer(superlayer) == YES) {
[(IJSVGLayer *)superlayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer *)self
withOffset:layerOffset];
}
// grab the masking layer
IJSVGShapeLayer * maskingLayer = [self maskingLayer];
// if its a group we need to get the lowest level children
// and walk up the chain again
if([maskingLayer isKindOfClass:[IJSVGGroupLayer class]]) {
NSArray * subs = [IJSVGLayer deepestSublayersOfLayer:maskingLayer];
for(IJSVGLayer * subLayer in subs) {
[subLayer applySublayerMaskToContext:context
forSublayer:(IJSVGLayer *)self
withOffset:layerOffset];
}
} else if ([maskingLayer isKindOfClass:[IJSVGShapeLayer class]]) {
// is a shape, go for it!
CGPathRef maskPath = maskingLayer.path;
CGContextTranslateCTM(context, -layerOffset.x, -layerOffset.y);
CGContextAddPath(context, maskPath);
CGContextClip(context);
CGContextTranslateCTM(context, layerOffset.x, layerOffset.y);
}
CGContextConcatCTM(context, sublayerTransform);
}
- (IJSVGShapeLayer *)maskingLayer
{
return (IJSVGShapeLayer *)_maskingLayer ?: nil;
}
- (void)renderInContext:(CGContextRef)ctx
{
if(self.blendingMode != kCGBlendModeNormal) {
CGContextSaveGState(ctx);
CGContextSetBlendMode(ctx, self.blendingMode);
[self _customRenderInContext:ctx];
CGContextRestoreGState(ctx);
return;
}
[self _customRenderInContext:ctx];
}
- (CGPoint)absoluteOrigin
{
CGPoint point = CGPointZero;
CALayer * pLayer = self;
while(pLayer != nil) {
point.x += pLayer.frame.origin.x;
point.y += pLayer.frame.origin.y;
pLayer = pLayer.superlayer;
}
return point;
}
- (id<CAAction>)actionForKey:(NSString *)event
{
return nil;
}
@end
+18
View File
@@ -0,0 +1,18 @@
//
// IJSVGStringAdditions.h
// IconJar
//
// Created by Curtis Hard on 07/06/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (IJSVGAdditions)
- (NSArray<NSString *> *)componentsSeparatedByChars:(char *)aChar;
- (BOOL)isNumeric;
- (BOOL)containsAlpha;
- (NSArray *)componentsSplitByWhiteSpace;
@end
+92
View File
@@ -0,0 +1,92 @@
//
// IJSVGStringAdditions.m
// IconJar
//
// Created by Curtis Hard on 07/06/2019.
// Copyright © 2019 Curtis Hard. All rights reserved.
//
#import "IJSVGStringAdditions.h"
@implementation NSString (IJSVGAdditions)
- (NSArray<NSString *> *)componentsSeparatedByChars:(char *)aChar
{
NSMutableArray * comp = [[[NSMutableArray alloc] init] autorelease];
NSInteger length = self.length;
unichar * chars = (unichar *)calloc(sizeof(unichar),self.length);
NSInteger ind = 0;
BOOL startedString = NO;
// block for easy comparison
NSUInteger aLength = strlen(aChar);
BOOL (^charsContainsChar)(char anotherChar) = ^(char anotherChar) {
for(NSInteger i = 0; i < aLength; i++) {
if(aChar[i] == anotherChar) {
return YES;
}
}
return NO;
};
for(NSInteger i = 0; i < length; i++) {
// the char
unichar theChar = [self characterAtIndex:i];
// start the buffer
BOOL isEqualToChar = charsContainsChar(theChar);
if(isEqualToChar == NO) {
startedString = YES;
chars[ind++] = theChar;
}
// has started and char is the search char, or its at end
if((startedString == YES && isEqualToChar) ||
(i == (length-1) && startedString == YES)) {
startedString = NO;
// append the comp
[comp addObject:[NSString stringWithCharacters:chars length:ind]];
free(chars);
// restart and realloc the memory
ind = 0;
chars = (unichar *)calloc(sizeof(unichar), self.length);
}
}
free(chars);
return comp;
}
- (BOOL)containsAlpha
{
const char * buffer = self.UTF8String;
unsigned long length = strlen(buffer);
for( int i = 0; i < length; i++ ) {
if( isalpha(buffer[i]) ) {
return YES;
}
}
return NO;
}
- (BOOL)isNumeric
{
const char * buffer = self.UTF8String;
unsigned long length = strlen(buffer);
for(int i = 0; i < length; i++) {
if(!isnumber(buffer[i])) {
return NO;
}
}
return YES;
}
- (NSArray *)componentsSplitByWhiteSpace
{
return [self componentsSeparatedByChars:"\t\n\r "];
}
@end
+38 -30
View File
@@ -44,25 +44,44 @@
+ (IJSVGStyle *)parseStyleString:(NSString *)string
{
static NSRegularExpression * _reg = nil;
static dispatch_once_t onceToken;
IJSVGStyle * style = [[[self class] alloc] init];
dispatch_once(&onceToken, ^{
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z\\-]+)\\:([^;]+)\\;?"
options:0
error:nil];
});
[_reg enumerateMatchesInString:string
options:0
range:NSMakeRange( 0, string.length )
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSString * key = [string substringWithRange:[result rangeAtIndex:1]];
NSString * value = [string substringWithRange:[result rangeAtIndex:2]];
[[self class] computeStyleProperty:key
value:value
style:style];
}];
return [style autorelease];
IJSVGStyle * style = [[[self.class alloc] init] autorelease];
NSInteger length = string.length;
NSInteger index = 0;
NSString * key = nil;
NSString * value = nil;
// iterate over the string - its actually really simple what we need
// to do
for(NSInteger i = 0; i < length; i++) {
unichar c = [string characterAtIndex:i];
// find the key
if(c == ':') {
key = [string substringWithRange:NSMakeRange(index, (i-index))];
index = i+1;
}
// find the value
else if(c == ';' || i == (length-1)) {
NSInteger chomp;
if(i == (length-1) && c != ';') {
chomp = (i-(index-1));
} else {
chomp = (i-index);
}
value = [string substringWithRange:NSMakeRange(index, chomp)];
index = i+1;
}
// set the propery if it actually exists
if(key != nil && value != nil) {
[style setPropertyValue:[self.class trimString:value]
forProperty:[self.class trimString:key]];
key = nil;
value = nil;
}
}
return style;
}
+ (NSString *)trimString:(NSString *)string
@@ -75,17 +94,6 @@
return @[@"fill",@"stroke-colour",@"stop-color",@"stroke"];
}
+ (void)computeStyleProperty:(NSString *)key
value:(NSString *)value
style:(IJSVGStyle *)style
{
key = [[self class] trimString:key];
value = [[self class] trimString:value];
[style setPropertyValue:value
forProperty:key];
}
+ (BOOL)isNumeric:(NSString *)string
{
return [[NSScanner scannerWithString:string] scanFloat:NULL];
+7 -3
View File
@@ -71,12 +71,16 @@
// create a new selector if not found
if((selector = [_selectors objectForKey:selectorName]) == nil) {
selector = [[[IJSVGStyleSheetSelector alloc] initWithSelectorString:selectorName] autorelease];
[_selectors setObject:selector
forKey:selectorName];
if(selector != nil) {
[_selectors setObject:selector
forKey:selectorName];
}
}
// add it to our list
[array addObject:selector];
if(selector != nil) {
[array addObject:selector];
}
}
return array;
}
+47 -9
View File
@@ -257,7 +257,12 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
{
selector = [string copy];
_rawSelectors = [[NSMutableArray alloc] init];
[self _compile];
// failed to compile
if([self _compile] == NO) {
[self release], self = nil;
return nil;
}
[self _calculate];
}
return self;
@@ -283,23 +288,55 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
}
}
- (void)_compile
- (BOOL)validateSelector:(NSString *)string
{
char * invalidChars = "@:;*()[]";
NSUInteger length = strlen(invalidChars);
NSUInteger sLength = string.length;
for(NSUInteger i = 0; i < length; i++) {
for(NSUInteger s = 0; s < sLength; s++) {
// if found invalid char, just return NO instantly
if(invalidChars[i] == [string characterAtIndex:s]) {
return NO;
}
}
}
return YES;
}
- (BOOL)_compile
{
// completely unsupported
if([self validateSelector:selector] == NO) {
return NO;
}
// keychar lookup
char * keychars = "#+.>~ ";
NSUInteger aLength = strlen(keychars);
BOOL (^isKeyChar)(char anotherChar) = ^(char anotherChar) {
for(NSInteger i = 0; i < aLength; i++) {
if(keychars[i] == anotherChar) {
return YES;
}
}
return NO;
};
NSUInteger length = selector.length;
NSMutableArray * sels = [[[NSMutableArray alloc] init] autorelease];
NSCharacterSet * alphaNumeric = [NSCharacterSet characterSetWithCharactersInString:@"_-abcdefghijklmnopqrstuvwxyz0123456789"];
IJSVGStyleSheetSelectorRaw * rawSelector = [[[IJSVGStyleSheetSelectorRaw alloc] init] autorelease];
for(NSUInteger i = 0; i < length; i++)
{
for(NSUInteger i = 0; i < length; i++) {
unichar c = [selector characterAtIndex:i];
// beginning of class
if( c == '.' ) {
i++;
for(NSUInteger a = i; a < length; a++ ) {
unichar ca = [selector characterAtIndex:a];
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
if(isKeyChar(ca) == YES || a == length-1) {
// if at end, add 1 to a so it gets the last character
if( a == length-1 ) {
a++;
@@ -316,7 +353,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
i++;
for(NSUInteger a = i; a < length; a++ ) {
unichar ca = [selector characterAtIndex:a];
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
if(isKeyChar(ca) == YES || a == length-1) {
// if at end, add 1 to a so it gets the last character
if( a == length-1 ) {
a++;
@@ -375,7 +412,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
else {
for( NSUInteger a = i; a < length; a++ ) {
unichar ca = [selector characterAtIndex:a];
if([alphaNumeric characterIsMember:ca] == NO || a == length-1) {
if(isKeyChar(ca) == YES || a == length-1) {
if( a == length-1 ) {
a++;
}
@@ -397,6 +434,7 @@ BOOL IJSVGStyleSheetMatchSelector(IJSVGNode * node, IJSVGStyleSheetSelectorRaw *
}
// now its compiled, we need to reverse the selectors
[_rawSelectors addObjectsFromArray:[sels reverseObjectEnumerator].allObjects];
return YES;
}
+13 -2
View File
@@ -9,13 +9,24 @@
#import "IJSVGTransaction.h"
void IJSVGBeginTransactionLock() {
if(NSThread.isMainThread == YES) {
return;
}
[CATransaction begin];
[CATransaction lock];
if(@available(macOS 10.14, *)) {} else {
[CATransaction lock];
}
[CATransaction setDisableActions:YES];
};
void IJSVGEndTransactionLock() {
[CATransaction unlock];
if(NSThread.isMainThread == YES) {
return;
}
if(@available(macOS 10.14, *)) {} else {
[CATransaction unlock];
}
[CATransaction commit];
};
+14
View File
@@ -9,11 +9,16 @@
#import <Foundation/Foundation.h>
#import "IJSVGUtils.h"
@class IJSVGTransform;
typedef CGFloat (^IJSVGTransformParameterModifier)(NSInteger index, CGFloat value);
typedef void (^IJSVGTransformApplyBlock)(IJSVGTransform * transform);
typedef NS_OPTIONS( NSInteger, IJSVGTransformCommand ) {
IJSVGTransformCommandMatrix,
IJSVGTransformCommandTranslate,
IJSVGTransformCommandTranslateX,
IJSVGTransformCommandTranslateY,
IJSVGTransformCommandScale,
IJSVGTransformCommandRotate,
IJSVGTransformCommandSkewX,
@@ -35,12 +40,21 @@ typedef NS_OPTIONS( NSInteger, IJSVGTransformCommand ) {
@property ( nonatomic, assign ) NSInteger parameterCount;
@property ( nonatomic, assign ) NSInteger sort;
NSString * IJSVGDebugAffineTransform(CGAffineTransform transform);
NSString * IJSVGDebugTransforms(NSArray<IJSVGTransform *> * transforms);
void IJSVGApplyTransform(NSArray<IJSVGTransform *> * transforms, IJSVGTransformApplyBlock block);
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform *> * transforms);
+ (NSArray<IJSVGTransform *> *)transformsFromAffineTransform:(CGAffineTransform)affineTransform;
+ (NSArray *)transformsForString:(NSString *)string;
+ (NSBezierPath *)transformedPath:(IJSVGPath *)path;
+ (NSArray<NSString *> *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform;
+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)affineTransform;
- (CGAffineTransform)CGAffineTransform;
- (CGAffineTransform)CGAffineTransformWithModifier:(IJSVGTransformParameterModifier)modifier;
- (CGAffineTransform)stackIdentity:(CGAffineTransform)identity;
- (void)recalculateWithBounds:(CGRect)bounds;
+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x
y:(CGFloat)y;
@end
+125 -13
View File
@@ -24,7 +24,7 @@
- (id)copyWithZone:(NSZone *)zone
{
IJSVGTransform * trans = [[[self class] alloc] init];
IJSVGTransform * trans = [[self.class alloc] init];
trans.command = self.command;
trans.parameters = (CGFloat*)malloc(sizeof(CGFloat)*self.parameterCount);
trans.sort = sort;
@@ -33,6 +33,51 @@
return trans;
}
NSString * IJSVGDebugAffineTransform(CGAffineTransform transform)
{
NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease];
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform]];
return [strings componentsJoinedByString:@" "];
}
NSString * IJSVGDebugTransforms(NSArray<IJSVGTransform *> * transforms)
{
NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease];
IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) {
[strings addObjectsFromArray:[IJSVGTransform affineTransformToSVGTransformAttributeString:transform.CGAffineTransform]];
});
return [strings componentsJoinedByString:@" "];
}
CGAffineTransform IJSVGConcatTransforms(NSArray<IJSVGTransform *> * transforms)
{
__block CGAffineTransform trans = CGAffineTransformIdentity;
IJSVGApplyTransform(transforms, ^(IJSVGTransform *transform) {
trans = CGAffineTransformConcat(trans, transform.CGAffineTransform);
});
return trans;
}
void IJSVGApplyTransform(NSArray<IJSVGTransform *> * transforms, IJSVGTransformApplyBlock block)
{
for(IJSVGTransform * transform in transforms) {
block(transform);
}
};
+ (IJSVGTransform *)transformByTranslatingX:(CGFloat)x
y:(CGFloat)y
{
IJSVGTransform * transform = [[[self alloc] init] autorelease];
transform.command = IJSVGTransformCommandTranslate;
transform.parameterCount = 2;
CGFloat * params = (CGFloat *)malloc(sizeof(CGFloat)*2);
params[0] = x;
params[1] = y;
transform.parameters = params;
return transform;
}
- (void)recalculateWithBounds:(CGRect)bounds
{
CGFloat max = bounds.size.width>bounds.size.height?bounds.size.width:bounds.size.height;
@@ -55,6 +100,10 @@
return IJSVGTransformCommandMatrix;
if( [str isEqualToString:@"translate"] )
return IJSVGTransformCommandTranslate;
if([str isEqualToString:@"translatex"])
return IJSVGTransformCommandTranslateX;
if([str isEqualToString:@"translatey"])
return IJSVGTransformCommandTranslateY;
if( [str isEqualToString:@"scale"] )
return IJSVGTransformCommandScale;
if( [str isEqualToString:@"skewx"])
@@ -75,6 +124,8 @@
return 1;
case IJSVGTransformCommandMatrix:
return 2;
case IJSVGTransformCommandTranslateX:
case IJSVGTransformCommandTranslateY:
case IJSVGTransformCommandTranslate:
return -1;
default:
@@ -88,7 +139,7 @@
static NSRegularExpression * _reg = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\((.*?)\\)"
_reg = [[NSRegularExpression alloc] initWithPattern:@"([a-zA-Z]+)\\(([^\\)]+)\\)"
options:0
error:nil];
});
@@ -97,22 +148,23 @@
[_reg enumerateMatchesInString:string
options:0
range:NSMakeRange( 0, string.length )
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
{
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSString * command = [string substringWithRange:[result rangeAtIndex:1]];
IJSVGTransformCommand commandType = [[self class] commandForCommandString:command];
if( commandType == IJSVGTransformCommandNotImplemented )
IJSVGTransformCommand commandType = [self.class commandForCommandString:command];
if( commandType == IJSVGTransformCommandNotImplemented ) {
return;
}
// create the transform
NSString * params = [string substringWithRange:[result rangeAtIndex:2]];
IJSVGTransform * transform = [[[[self class] alloc] init] autorelease];
IJSVGTransform * transform = [[[self.class alloc] init] autorelease];
NSInteger count = 0;
transform.command = commandType;
transform.parameters = [IJSVGUtils commandParameters:params
count:&count];
transform.parameterCount = count;
transform.sort = [[self class] sortForTransformCommand:commandType];
transform.sort = [self.class sortForTransformCommand:commandType];
[transforms addObject:transform];
}];
}
@@ -182,6 +234,18 @@
yBy:transform.parameters[1]];
break;
}
// translateX
case IJSVGTransformCommandTranslateX: {
[at translateXBy:transform.parameters[0] yBy:0.f];
break;
}
// translateY
case IJSVGTransformCommandTranslateY: {
[at translateXBy:0.f yBy:transform.parameters[0]];
break;
}
// scale
case IJSVGTransformCommandScale: {
@@ -237,6 +301,16 @@
}
return CGAffineTransformTranslate(identity, self.parameters[0], self.parameters[1]);
}
// translateX
case IJSVGTransformCommandTranslateX: {
return CGAffineTransformTranslate(identity, self.parameters[0], 0.f);
}
// translateY
case IJSVGTransformCommandTranslateY: {
return CGAffineTransformTranslate(identity, 0.f, self.parameters[0]);
}
// rotate
case IJSVGTransformCommandRotate: {
@@ -313,9 +387,9 @@
p0 = modifier(0,p0);
p1 = modifier(1,p1);
p2 = modifier(2,p2);
p3 = modifier(2,p3);
p4 = modifier(2,p4);
p5 = modifier(2,p5);
p3 = modifier(3,p3);
p4 = modifier(4,p4);
p5 = modifier(5,p5);
}
return CGAffineTransformMake(p0, p1, p2, p3, p4, p5);
}
@@ -334,6 +408,24 @@
return CGAffineTransformMakeTranslation(p0, p1);
}
// translateX
case IJSVGTransformCommandTranslateX: {
CGFloat p0 = self.parameters[0];
if(modifier != nil) {
p0 = modifier(0, p0);
}
return CGAffineTransformMakeTranslation(p0, 0.f);
}
// translateY
case IJSVGTransformCommandTranslateY: {
CGFloat p0 = self.parameters[0];
if(modifier != nil) {
p0 = modifier(0, p0);
}
return CGAffineTransformMakeTranslation(0.f, p0);
}
// scale
case IJSVGTransformCommandScale: {
CGFloat p0 = self.parameters[0];
@@ -400,6 +492,19 @@
return CGAffineTransformIdentity;
}
+ (NSArray<IJSVGTransform *> *)transformsFromAffineTransform:(CGAffineTransform)affineTransform
{
NSArray * strings = [self affineTransformToSVGTransformAttributeString:affineTransform];
return [self transformsForString:[strings componentsJoinedByString:@" "]];
}
+ (NSString *)affineTransformToSVGMatrixString:(CGAffineTransform)transform
{
return [NSString stringWithFormat:@"matrix(%g,%g,%g,%g,%g,%g)",
transform.a, transform.b, transform.c, transform.d,
transform.tx, transform.ty];
}
// this is an Object-C version of the matrixToTransform method from SVGO
+ (NSArray<NSString *> *)affineTransformToSVGTransformAttributeString:(CGAffineTransform)affineTransform
{
@@ -414,6 +519,7 @@
CGFloat sx = sqrtf(data[0]*data[0] + data[1] * data[1]);
CGFloat sy = (data[0]*data[3] - data[1]*data[2])/sx;
CGFloat colSum = data[0]*data[2] + data[1]*data[3];
CGFloat rowSum = data[0]*data[1] + data[2]*data[3];
BOOL scaleBefore = rowSum != 0.f || (sx == sy);
@@ -439,8 +545,8 @@
sy = data[3];
} else if(colSum == 0.f || (sx == 1.f && sy == 1.f) || scaleBefore == NO) {
if(scaleBefore == NO) {
sx = (data[0] < 0.f ? -1.f : 1.f * sqrtf(data[0] * data[0] + data[2] * data[2]));
sy = (data[3] < 0.f ? -1.f : 1.f * sqrtf(data[1] * data[1] + data[3] * data[3]));
sx = (data[0] < 0.f ? -1.f : 1.f) * sqrtf(data[0] * data[0] + data[2] * data[2]);
sy = (data[3] < 0.f ? -1.f : 1.f) * sqrtf(data[1] * data[1] + data[3] * data[3]);
NSString * str = nil;
if(sx == sy) {
str = [NSString stringWithFormat:@"scale(%g)",sx];
@@ -499,5 +605,11 @@
return trans;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ %@",[super description],
[self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]];
}
@end
+9
View File
@@ -13,6 +13,12 @@ typedef NS_ENUM(NSInteger, IJSVGUnitLengthType) {
IJSVGUnitLengthTypePercentage
};
typedef NS_ENUM( NSInteger, IJSVGUnitType) {
IJSVGUnitUserSpaceOnUse,
IJSVGUnitObjectBoundingBox,
IJSVGUnitInherit
};
@interface IJSVGUnitLength : NSObject
@property (nonatomic, assign) IJSVGUnitLengthType type;
@@ -26,6 +32,9 @@ typedef NS_ENUM(NSInteger, IJSVGUnitLengthType) {
+ (IJSVGUnitLength *)unitWithString:(NSString *)string;
+ (IJSVGUnitLength *)unitWithPercentageString:(NSString *)string;
+ (IJSVGUnitLength *)unitWithString:(NSString *)string
fromUnitType:(IJSVGUnitType)units;
- (CGFloat)valueAsPercentage;
- (CGFloat)computeValue:(CGFloat)anotherValue;
- (NSString *)stringValue;
+28 -3
View File
@@ -7,6 +7,7 @@
//
#import "IJSVGUnitLength.h"
#import "IJSVGNode.h"
@implementation IJSVGUnitLength
@@ -22,6 +23,15 @@
return unit;
}
+ (IJSVGUnitLength *)unitWithString:(NSString *)string
fromUnitType:(IJSVGUnitType)units
{
if(units == IJSVGUnitObjectBoundingBox) {
return [self unitWithPercentageString:string];
}
return [self unitWithString:string];
}
+ (IJSVGUnitLength *)unitWithFloat:(CGFloat)number
type:(IJSVGUnitLengthType)type
{
@@ -46,10 +56,20 @@
+ (IJSVGUnitLength *)unitWithString:(NSString *)string
{
// just return noting for inherit, node will deal
// with the rest...hopefully
NSCharacterSet * cSet = NSCharacterSet.whitespaceCharacterSet;
string = [string stringByTrimmingCharactersInSet:cSet];
if([string isEqualToString:@"inherit"]) {
return nil;
}
IJSVGUnitLength * unit = [[[self alloc] init] autorelease];
unit.value = [string floatValue];
unit.value = string.floatValue;
unit.type = IJSVGUnitLengthTypeNumber;
if([string hasSuffix:@"%"] == YES) {
unit.value /= 100.f;
unit.type = IJSVGUnitLengthTypePercentage;
}
return unit;
@@ -58,7 +78,7 @@
- (CGFloat)computeValue:(CGFloat)anotherValue
{
if(self.type == IJSVGUnitLengthTypePercentage) {
return ((anotherValue/100)*self.value);
return ((anotherValue/100.f)*(self.value*100.f));
}
return self.value;
}
@@ -71,9 +91,14 @@
- (NSString *)stringValue
{
if(self.type == IJSVGUnitLengthTypePercentage) {
return [NSString stringWithFormat:@"%g%%",self.value];
return [NSString stringWithFormat:@"%g%%",(self.value*100.f)];
}
return [NSString stringWithFormat:@"%g",self.value];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%f%@",self.value,(self.type == IJSVGUnitLengthTypePercentage ? @"%" : @"")];
}
@end
+17
View File
@@ -7,7 +7,10 @@
//
#import <Foundation/Foundation.h>
#include <xlocale.h>
#import "IJSVGCommand.h"
#import "IJSVGGradientUnitLength.h"
#import "IJSVGStringAdditions.h"
@interface IJSVGUtils : NSObject
@@ -17,6 +20,14 @@ CGFloat angle( CGPoint a, CGPoint b );
CGFloat radians_to_degrees( CGFloat radians);
CGFloat degrees_to_radians( CGFloat degrees );
BOOL IJSVGIsCommonHTMLElementName(NSString * str);
NSArray * IJSVGCommonHTMLElementNames();
NSString * IJSVGShortFloatString(CGFloat f);
NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision);
BOOL IJSVGIsLegalCommandCharacter(unichar aChar);
BOOL IJSVGIsSVGLayer(CALayer * layer);
+ (IJSVGCommandType)typeForCommandString:(NSString *)string;
+ (CGFloat *)commandParameters:(NSString *)command
count:(NSInteger *)count;
@@ -25,6 +36,10 @@ CGFloat degrees_to_radians( CGFloat degrees );
+ (IJSVGLineJoinStyle)lineJoinStyleForString:(NSString *)string;
+ (IJSVGLineCapStyle)lineCapStyleForString:(NSString *)string;
+ (IJSVGUnitType)unitTypeForString:(NSString *)string;
+ (IJSVGBlendMode)blendModeForString:(NSString *)string;
+ (NSString *)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode;
+ (NSRange)rangeOfParentheses:(NSString *)string;
+ (void)logParameters:(CGFloat *)param
count:(NSInteger)count;
+ (CGFloat)floatValue:(NSString *)string;
@@ -39,4 +54,6 @@ CGFloat degrees_to_radians( CGFloat degrees );
+ (IJSVGFontTraits)fontWeightTraitForString:(NSString *)string
weight:(CGFloat *)weight;
+ (CGPathRef)newFlippedCGPath:(CGPathRef)path;
+ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath *)bezPath;
@end
+380 -20
View File
@@ -7,9 +7,187 @@
//
#import "IJSVGUtils.h"
#import "IJSVGLayer.h"
#import "IJSVGShapeLayer.h"
@implementation IJSVGUtils
BOOL IJSVGIsCommonHTMLElementName(NSString * str)
{
str = str.lowercaseString;
return [IJSVGCommonHTMLElementNames() containsObject:str];
};
NSArray * IJSVGCommonHTMLElementNames()
{
static NSArray * names = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
names = [@[@"a",
@"abbr",
@"acronym",
@"abbr",
@"address",
@"applet",
@"embed",
@"object",
@"area",
@"article",
@"aside",
@"audio",
@"b",
@"base",
@"basefont",
@"bdi",
@"bdo",
@"big",
@"blockquote",
@"body",
@"br",
@"button",
@"canvas",
@"caption",
@"center",
@"cite",
@"code",
@"col",
@"colgroup",
@"colgroup",
@"datalist",
@"dd",
@"del",
@"details",
@"dfn",
@"dialog",
@"dir",
@"ul",
@"div",
@"dl",
@"dt",
@"em",
@"embed",
@"fieldset",
@"figcaption",
@"figure",
@"figure",
@"font",
@"footer",
@"form",
@"frame",
@"frameset",
@"h1",
@"h6",
@"head",
@"header",
@"hr",
@"html",
@"i",
@"iframe",
@"img",
@"input",
@"ins",
@"kbd",
@"label",
@"input",
@"legend",
@"fieldset",
@"li",
@"link",
@"main",
@"map",
@"mark",
@"menu",
@"menuitem",
@"meta",
@"meter",
@"nav",
@"noframes",
@"noscript",
@"object",
@"ol",
@"optgroup",
@"option",
@"output",
@"p",
@"param",
@"picture",
@"pre",
@"progress",
@"q",
@"rp",
@"rt",
@"ruby",
@"s",
@"samp",
@"script",
@"section",
@"select",
@"small",
@"source",
@"video",
@"audio",
@"span",
@"strike",
@"del",
@"s",
@"strong",
@"style",
@"sub",
@"summary",
@"details",
@"sup",
@"table",
@"tbody",
@"td",
@"template",
@"textarea",
@"tfoot",
@"th",
@"thead",
@"time",
@"title",
@"tr",
@"track",
@"video",
@"audio",
@"tt",
@"u",
@"ul",
@"var",
@"video",
@"wbr"] retain];
});
return names;
};
NSString * IJSVGShortFloatString(CGFloat f)
{
return [NSString stringWithFormat:@"%g",f];
};
NSString * IJSVGShortFloatStringWithPrecision(CGFloat f, NSInteger precision)
{
NSString * format = [NSString stringWithFormat:@"%@.%ld%@",@"%",precision,@"f"];
NSString * ret = [NSString stringWithFormat:format,f];
// can it be reduced even more?
if(ret.floatValue == (float)ret.integerValue) {
ret = [NSString stringWithFormat:@"%ld",ret.integerValue];
}
return ret;
};
BOOL IJSVGIsLegalCommandCharacter(unichar aChar)
{
const char * validChars = "MmZzLlHhVvCcSsQqTtAa";
return strchr(validChars, aChar) != NULL;
}
BOOL IJSVGIsSVGLayer(CALayer * layer)
{
return [layer isKindOfClass:IJSVGLayer.class] ||
[layer isKindOfClass:IJSVGShapeLayer.class];
}
CGFloat angle( CGPoint a, CGPoint b ) {
return [IJSVGUtils angleBetweenPointA:a
pointb:b];
@@ -36,15 +214,39 @@ CGFloat degrees_to_radians( CGFloat degrees )
+ (IJSVGCommandType)typeForCommandString:(NSString *)string
{
return [string isEqualToString:[string uppercaseString]] ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
return isupper([string characterAtIndex:0]) ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
}
+ (NSRange)rangeOfParentheses:(NSString *)string
{
NSRange range = NSMakeRange(NSNotFound, 0);
const char * characters = string.UTF8String;
unsigned long length = strlen(characters);
for(NSInteger i = 0; i < length; i++) {
char c = characters[i];
if(c == '(') {
range.location = i + 1;
} else if(c == ')') {
range.length = i - range.location;
}
}
return range;
}
+ (NSString *)defURL:(NSString *)string
{
// insta check for URL
NSCharacterSet * set = NSCharacterSet.whitespaceCharacterSet;
string = [string stringByTrimmingCharactersInSet:set];
NSString * check = [string substringToIndex:3].lowercaseString;
if([check isEqualToString:@"url"] == NO) {
return nil;
}
static NSRegularExpression * _reg = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_reg = [[NSRegularExpression alloc] initWithPattern:@"url\\s?\\(\\s?#(.*?)\\)\\;?"
_reg = [[NSRegularExpression alloc] initWithPattern:@"url\\(['\"]?([^)]+?)['\"]?\\)"
options:0
error:nil];
});
@@ -52,11 +254,15 @@ CGFloat degrees_to_radians( CGFloat degrees )
[_reg enumerateMatchesInString:string
options:0
range:NSMakeRange( 0, string.length )
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
{
if( ( foundID = [string substringWithRange:[result rangeAtIndex:1]] ) != nil )
usingBlock:^(NSTextCheckingResult *result,
NSMatchingFlags flags, BOOL *stop) {
if((foundID = [string substringWithRange:[result rangeAtIndex:1]]) != nil) {
*stop = YES;
}
}];
if([foundID hasPrefix:@"#"] == YES) {
foundID = [foundID substringFromIndex:1];
}
return foundID;
}
@@ -119,17 +325,109 @@ CGFloat degrees_to_radians( CGFloat degrees )
return IJSVGUnitObjectBoundingBox;
}
+ (IJSVGBlendMode)blendModeForString:(NSString *)string
{
string = string.lowercaseString;
if([string isEqualToString:@"normal"])
return IJSVGBlendModeNormal;
if([string isEqualToString:@"multiply"])
return IJSVGBlendModeMultiply;
if([string isEqualToString:@"screen"])
return IJSVGBlendModeScreen;
if([string isEqualToString:@"overlay"])
return IJSVGBlendModeOverlay;
if([string isEqualToString:@"darken"])
return IJSVGBlendModeDarken;
if([string isEqualToString:@"lighten"])
return IJSVGBlendModeLighten;
if([string isEqualToString:@"color-dodge"])
return IJSVGBlendModeColorDodge;
if([string isEqualToString:@"color-burn"])
return IJSVGBlendModeColorBurn;
if([string isEqualToString:@"hard-light"])
return IJSVGBlendModeHardLight;
if([string isEqualToString:@"soft-light"])
return IJSVGBlendModeSoftLight;
if([string isEqualToString:@"difference"])
return IJSVGBlendModeDifference;
if([string isEqualToString:@"exclusion"])
return IJSVGBlendModeExclusion;
if([string isEqualToString:@"hue"])
return IJSVGBlendModeHue;
if([string isEqualToString:@"saturation"])
return IJSVGBlendModeSaturation;
if([string isEqualToString:@"color"])
return IJSVGBlendModeColor;
if([string isEqualToString:@"luminosity"])
return IJSVGBlendModeLuminosity;
return IJSVGBlendModeNormal;
}
+ (NSString *)mixBlendingModeForBlendMode:(IJSVGBlendMode)blendMode
{
switch (blendMode) {
case IJSVGBlendModeMultiply: {
return @"multiple";
}
case IJSVGBlendModeScreen: {
return @"screen";
}
case IJSVGBlendModeOverlay: {
return @"overlay";
}
case IJSVGBlendModeDarken: {
return @"darken";
}
case IJSVGBlendModeLighten: {
return @"lighten";
}
case IJSVGBlendModeColorDodge: {
return @"color-dodge";
}
case IJSVGBlendModeColorBurn: {
return @"color-burn";
}
case IJSVGBlendModeHardLight: {
return @"hard-light";
}
case IJSVGBlendModeSoftLight: {
return @"soft-light";
}
case IJSVGBlendModeDifference: {
return @"difference";
}
case IJSVGBlendModeExclusion: {
return @"exclusion";
}
case IJSVGBlendModeHue: {
return @"hue";
}
case IJSVGBlendModeSaturation: {
return @"saturation";
}
case IJSVGBlendModeColor: {
return @"color";
}
case IJSVGBlendModeLuminosity: {
return @"luminosity";
}
case IJSVGBlendModeNormal:
default: {
return nil;
}
}
}
+ (CGFloat *)commandParameters:(NSString *)command
count:(NSInteger *)count
{
if( [command isKindOfClass:[NSNumber class]] )
{
if( [command isKindOfClass:[NSNumber class]] ) {
CGFloat * ret = (CGFloat *)malloc(1*sizeof(CGFloat));
ret[0] = [(NSNumber *)command floatValue];
*count = 1;
return ret;
}
return [[self class] scanFloatsFromString:command
return [self.class scanFloatsFromString:command
size:count];
}
@@ -138,12 +436,11 @@ CGFloat degrees_to_radians( CGFloat degrees )
{
// default sizes and memory
// sizes for the string buffer
NSInteger defSize = 50;
NSInteger size = defSize;
NSInteger sLength = string.length;
const NSInteger defFloatSize = 30;
const NSInteger defSize = 15;
// default memory size for the floats
NSInteger defFloatSize = 100;
// default memory size for the float
NSInteger size = defSize;
NSInteger floatSize = defFloatSize;
NSInteger i = 0;
@@ -152,6 +449,8 @@ CGFloat degrees_to_radians( CGFloat degrees )
const char * cString = [string cStringUsingEncoding:NSUTF8StringEncoding];
const char * validChars = "0123456789eE+-.";
NSInteger sLength = strlen(cString);
// buffer for the returned floats
CGFloat * floats = (CGFloat *)malloc(sizeof(CGFloat)*defFloatSize);
@@ -168,7 +467,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
nextChar = cString[i+1];
}
bool isValid = strchr(validChars, currentChar);
bool isValid = strchr(validChars, currentChar) != NULL;
// in order to work out the split, its either because the next char is
// a hyphen or a plus, or next char is a decimal and the current number is a decimal
@@ -205,7 +504,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
// is at end of string, or wants to be stopped
// buffer has to actually exist or its completly
// useless and will cause a crash
if(buffer != NULL && (wantsEnd || i == sLength-1)) {
if((buffer != NULL && bufferCount != 0) && (wantsEnd || i == sLength-1)) {
// make sure there is enough room in the float pool
if((counter+1) == floatSize) {
floatSize += defFloatSize;
@@ -213,17 +512,18 @@ CGFloat degrees_to_radians( CGFloat degrees )
}
// add the float
floats[counter++] = atof(buffer);
floats[counter++] = strtod_l(buffer, NULL, NULL);
// memory clean and counter resets
free(buffer);
size = defSize;
memset(buffer, '\0', sizeof(*buffer)*size);
isDecimal = false;
bufferCount = 0;
buffer = NULL;
}
i++;
}
if(buffer != NULL) {
free(buffer);
}
*length = counter;
return floats;
}
@@ -231,7 +531,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
+ (CGFloat *)parseViewBox:(NSString *)string
{
NSInteger size = 0;
return [[self class] scanFloatsFromString:string
return [self.class scanFloatsFromString:string
size:&size];
}
@@ -268,4 +568,64 @@ CGFloat degrees_to_radians( CGFloat degrees )
return (point1.x * point2.y < point1.y * point2.x ? -1 : 1) * acosf(ratio(point1, point2));
}
+ (CGPathRef)newFlippedCGPath:(CGPathRef)path
{
CGRect boundingBox = CGPathGetPathBoundingBox(path);
CGAffineTransform scale = CGAffineTransformMakeScale(1.f, -1.f);
CGAffineTransform translate = CGAffineTransformTranslate(scale, 0.f, boundingBox.size.height);
CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &translate);
return transformPath;
}
+ (CGPathRef)newCGPathFromBezierPath:(NSBezierPath *)bezPath
{
CGPathRef immutablePath = NULL;
// Then draw the path elements.
NSInteger numElements = bezPath.elementCount;
if (numElements > 0) {
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (NSInteger i = 0; i < numElements; i++) {
switch ([bezPath elementAtIndex:i associatedPoints:points]) {
case NSMoveToBezierPathElement: {
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
}
case NSLineToBezierPathElement: {
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
}
case NSCurveToBezierPathElement: {
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
}
case NSClosePathBezierPathElement: {
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
}
// Be sure the path is closed or Quartz may not do valid hit detection.
if (didClosePath == NO) {
CGPathCloseSubpath(path);
}
// memory clean
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
@end
+25
View File
@@ -0,0 +1,25 @@
//
// IJSVGView.h
// IconJar
//
// Created by Curtis Hard on 04/04/2017.
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "IJSVG.h"
IB_DESIGNABLE
@interface IJSVGView : NSView {
IBInspectable NSString * imageName;
IBInspectable NSColor * tintColor;
IJSVG * SVG;
}
@property (nonatomic, retain) IJSVG * SVG;
+ (IJSVGView *)viewWithSVGNamed:(NSString *)name;
- (id)initWithSVG:(IJSVG *)anSvg;
@end
+80
View File
@@ -0,0 +1,80 @@
//
// IJSVGView.m
// IconJar
//
// Created by Curtis Hard on 04/04/2017.
// Copyright © 2017 Curtis Hard. All rights reserved.
//
#import "IJSVGView.h"
@implementation IJSVGView
@synthesize SVG;
- (void)dealloc
{
// make sure we call this, or block may get called for a view
// that doesnt exist
[SVG prepForDrawingInView:nil];
[imageName release], imageName = nil;
[SVG release], SVG = nil;
[super dealloc];
}
+ (IJSVGView *)viewWithSVGNamed:(NSString *)name
{
IJSVG * anSVG = [IJSVG svgNamed:name];
return [[[self alloc] initWithSVG:anSVG] autorelease];
}
- (id)initWithSVG:(IJSVG *)anSvg
{
if((self = [super init]) != nil) {
self.SVG = anSvg;
}
return self;
}
- (void)awakeFromNib
{
// image was set via IB
if(imageName != nil) {
IJSVG * anSVG = [IJSVG svgNamed:imageName];
if(tintColor != nil) {
anSVG.style.fillColor = tintColor;
}
self.SVG = anSVG;
}
}
- (void)setSVG:(IJSVG *)anSVG
{
// memory clean
if(SVG != nil) {
[SVG release], SVG = nil;
}
SVG = [anSVG retain];
// redisplay ourself!
[SVG prepForDrawingInView:self];
[self setNeedsDisplay:YES];
}
- (BOOL)isFlipped
{
return YES;
}
- (void)drawRect:(NSRect)dirtyRect
{
// only draw if there is actually an SVG
if(self.SVG == nil) {
return;
}
// draw the svg
[self.SVG drawInRect:self.bounds];
}
@end
+4 -4
View File
@@ -18,17 +18,17 @@
[trans scaleXBy:1.f yBy:-1.f];
[trans translateXBy:0.f yBy:path.controlPointBounds.size.height];
path = [trans transformBezierPath:path];
return [[self class] SVGDocumentStringForBezierPath:path];
return [self.class SVGDocumentStringForBezierPath:path];
}
+ (NSString *)SVGDocumentStringForBezierPath:(NSBezierPath *)path
{
return [[self class] SVGDocumentForBezierPath:path].XMLString;
return [self.class SVGDocumentForBezierPath:path].XMLString;
}
+ (NSXMLDocument *)SVGDocumentForBezierPath:(NSBezierPath *)path
{
NSXMLElement * root = [[self class] rootElementForPath:path];
NSXMLElement * root = [self.class rootElementForPath:path];
// create the path data
NSXMLElement * p = [[[NSXMLElement alloc] initWithName:@"path"] autorelease];
@@ -36,7 +36,7 @@
// add the drawing command
NSXMLNode * n = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
[n setName:@"d"];
[n setStringValue:[[self class] SVGPathStringForBezierPath:path]];
[n setStringValue:[self.class SVGPathStringForBezierPath:path]];
[p addAttribute:n];
// add the drawing path to the root