Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 399e9271b4 | |||
| f9107094a4 | |||
| 7a64c122cf | |||
| 8ee96c4a5b | |||
| 7cace854bd | |||
| 91cf59bd32 | |||
| b5e15445a5 | |||
| e7577a3e76 | |||
| 25b38fa128 | |||
| 8ef14224dd | |||
| ebfc31cdb1 | |||
| ccfcfbf228 | |||
| 4fe1d594b0 | |||
| 61d5bb99d5 | |||
| faccec3e01 | |||
| 66e9c9000e | |||
| 2006e68c2a | |||
| 01aea1129d | |||
| 388982d37b | |||
| 941130d1f2 | |||
| b9e964dc50 | |||
| 8532819b6a | |||
| e576803bb7 | |||
| a6a802a36b | |||
| b50963292c | |||
| c40c63c48d | |||
| 6d21b56416 | |||
| dbdd8a6971 | |||
| b7ba91aa82 | |||
| 98efacf93c | |||
| 1b3cf5a1a0 | |||
| 35f8663631 | |||
| 6d4eb76803 | |||
| 36dae3ad1b | |||
| 8149293b7b |
@@ -8,6 +8,12 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
343A19181FB2212C000652A2 /* IJSVGGradientUnitLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A19171FB2212C000652A2 /* IJSVGGradientUnitLength.m */; };
|
||||
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 */; };
|
||||
@@ -33,6 +39,8 @@
|
||||
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 */; };
|
||||
@@ -43,6 +51,11 @@
|
||||
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 */; };
|
||||
59D1E39E2022577500C54672 /* IJSVGQuartzRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */; };
|
||||
59D1E3A0202279CA00C54672 /* Group.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D1E39F202279CA00C54672 /* Group.svg */; };
|
||||
59D6C4142049939800F16F13 /* move.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4132049939800F16F13 /* move.svg */; };
|
||||
59D6C4162049947E00F16F13 /* sprite-1.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4152049947E00F16F13 /* sprite-1.svg */; };
|
||||
59D6C4182049977E00F16F13 /* fa-brands.svg in Resources */ = {isa = PBXBuildFile; fileRef = 59D6C4172049977E00F16F13 /* fa-brands.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 */; };
|
||||
@@ -93,6 +106,12 @@
|
||||
/* 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>"; };
|
||||
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>"; };
|
||||
@@ -139,6 +158,8 @@
|
||||
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>"; };
|
||||
@@ -157,6 +178,12 @@
|
||||
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>"; };
|
||||
59D1E39C2022577500C54672 /* IJSVGQuartzRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSVGQuartzRenderer.h; sourceTree = "<group>"; };
|
||||
59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSVGQuartzRenderer.m; sourceTree = "<group>"; };
|
||||
59D1E39F202279CA00C54672 /* Group.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Group.svg; sourceTree = "<group>"; };
|
||||
59D6C4132049939800F16F13 /* move.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = move.svg; sourceTree = "<group>"; };
|
||||
59D6C4152049947E00F16F13 /* sprite-1.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "sprite-1.svg"; sourceTree = "<group>"; };
|
||||
59D6C4172049977E00F16F13 /* fa-brands.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "fa-brands.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>"; };
|
||||
@@ -294,6 +321,17 @@
|
||||
5956657A19B62F4600D805FF /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
59D6C4172049977E00F16F13 /* fa-brands.svg */,
|
||||
59D1E39F202279CA00C54672 /* Group.svg */,
|
||||
590C87F5201FD0D4004A1554 /* car.svg */,
|
||||
590C87F3201FC9E3004A1554 /* radialgradient2.svg */,
|
||||
590C87F0201FBF27004A1554 /* AJ_Digital_Camera.svg */,
|
||||
590C87EC201FA08C004A1554 /* intertwingly.svg */,
|
||||
59D6C4152049947E00F16F13 /* sprite-1.svg */,
|
||||
590C87EE201FA092004A1554 /* NewTux.svg */,
|
||||
590C87EA201F9888004A1554 /* json.svg */,
|
||||
5991A2AA201E310200913E3B /* heart.svg */,
|
||||
5991A2A8201E30E600913E3B /* gradients.svg */,
|
||||
59265CE71C4F840400F333F0 /* css.svg */,
|
||||
59459CEB19B906FE00CE493B /* clipped.svg */,
|
||||
59F799E119B880CE00096CB7 /* htc_one.svg */,
|
||||
@@ -302,6 +340,7 @@
|
||||
595665DD19B6309C00D805FF /* test.svg */,
|
||||
5986308619BA104800CF15EA /* linecap.svg */,
|
||||
5986308B19BA180E00CF15EA /* dashed.svg */,
|
||||
59D6C4132049939800F16F13 /* move.svg */,
|
||||
5956657B19B62F4600D805FF /* Info.plist */,
|
||||
5956657C19B62F4600D805FF /* main.m */,
|
||||
5956659A19B62F9500D805FF /* IJSVGExample-Prefix.pch */,
|
||||
@@ -439,6 +478,8 @@
|
||||
597046A11E24352700A60138 /* IJSVGStrokeLayer.m */,
|
||||
59E0F5EB1E29964700F757F7 /* IJSVGUnitLength.h */,
|
||||
59E0F5EC1E29964700F757F7 /* IJSVGUnitLength.m */,
|
||||
59D1E39C2022577500C54672 /* IJSVGQuartzRenderer.h */,
|
||||
59D1E39D2022577500C54672 /* IJSVGQuartzRenderer.m */,
|
||||
);
|
||||
name = source;
|
||||
path = ../../source;
|
||||
@@ -488,7 +529,7 @@
|
||||
5956656F19B62F4600D805FF /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0600;
|
||||
LastUpgradeCheck = 0920;
|
||||
ORGANIZATIONNAME = "Curtis Hard";
|
||||
TargetAttributes = {
|
||||
5956657619B62F4600D805FF = {
|
||||
@@ -526,13 +567,25 @@
|
||||
files = (
|
||||
59B93C6D19B7D1840063E823 /* paperplane.svg in Resources */,
|
||||
5956658219B62F4600D805FF /* Images.xcassets in Resources */,
|
||||
590C87ED201FA08C004A1554 /* intertwingly.svg in Resources */,
|
||||
59D6C4182049977E00F16F13 /* fa-brands.svg in Resources */,
|
||||
590C87F1201FBF27004A1554 /* AJ_Digital_Camera.svg in Resources */,
|
||||
590C87EF201FA093004A1554 /* NewTux.svg in Resources */,
|
||||
59D6C4162049947E00F16F13 /* sprite-1.svg in Resources */,
|
||||
59265CE81C4F840400F333F0 /* css.svg in Resources */,
|
||||
595665DE19B6309C00D805FF /* test.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 */,
|
||||
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 */,
|
||||
59D6C4142049939800F16F13 /* move.svg in Resources */,
|
||||
5991A2AB201E310200913E3B /* heart.svg in Resources */,
|
||||
5986308C19BA180E00CF15EA /* dashed.svg in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -555,6 +608,7 @@
|
||||
59E2646919BA240D008A6FDB /* IJSVGStyle.m in Sources */,
|
||||
59E2646419BA240D008A6FDB /* IJSVGLinearGradient.m in Sources */,
|
||||
595665DC19B6302600D805FF /* README.md in Sources */,
|
||||
59D1E39E2022577500C54672 /* IJSVGQuartzRenderer.m in Sources */,
|
||||
5941DAFD1CF9BC9B00B3A911 /* IJSVGImage.m in Sources */,
|
||||
599465DE1C4AA87200A2EEF3 /* IJSVGStyleSheetSelector.m in Sources */,
|
||||
5948DED61BB2BFE5004156FF /* IJSVGWriter.m in Sources */,
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
After Width: | Height: | Size: 515 KiB |
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -671,19 +671,19 @@
|
||||
<window title="IJSVGExample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" 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="contentRect" x="335" y="390" width="600" height="479"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<view key="contentView" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="556" height="679"/>
|
||||
<view key="contentView" misplaced="YES" id="EiT-Mj-1SZ">
|
||||
<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"/>
|
||||
<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="184" y="628"/>
|
||||
<point key="canvasLocation" x="98" y="496.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -12,7 +12,7 @@
|
||||
|
||||
- (IJSVG *)svg
|
||||
{
|
||||
return [[IJSVG svgNamed:@"paperplane"] retain];
|
||||
return [[IJSVG svgNamed:@"heart"] retain];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
|
||||
@interface SVGView : NSView {
|
||||
|
||||
@private
|
||||
IJSVG * svg;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
if( ( self = [super initWithFrame:frameRect] ) != nil )
|
||||
{
|
||||
svg = [self svg];
|
||||
svg.renderQuality = IJSVGRenderQualityLow;
|
||||
svg.renderingBackingScaleHelper = ^{
|
||||
return [svg computeBackingScale:self.window.backingScaleFactor];
|
||||
return self.window.backingScaleFactor;
|
||||
};
|
||||
}
|
||||
return self;
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
- (IJSVG *)svg
|
||||
{
|
||||
return [IJSVG svgNamed:@"test"];
|
||||
return [IJSVG svgNamed:@"car"];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
|
||||
|
After Width: | Height: | Size: 515 KiB |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 522 KiB |
@@ -13,8 +13,10 @@
|
||||
#import "IJSVGGroupLayer.h"
|
||||
#import "IJSVGImageLayer.h"
|
||||
#import "IJSVGExporter.h"
|
||||
#import "IJSVGRendering.h"
|
||||
|
||||
@class IJSVG;
|
||||
@class IJSVGQuartzRenderer;
|
||||
|
||||
void IJSVGBeginTransactionLock();
|
||||
void IJSVGEndTransactionLock();
|
||||
@@ -34,8 +36,6 @@ withSVGString:(NSString *)subSVGString;
|
||||
|
||||
@end
|
||||
|
||||
typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
|
||||
@interface IJSVG : NSObject <NSPasteboardWriting, IJSVGParserDelegate> {
|
||||
|
||||
@private
|
||||
@@ -47,7 +47,10 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
CGRect _viewBox;
|
||||
CGSize _proposedViewSize;
|
||||
CGFloat _lastProposedBackingScale;
|
||||
IJSVGRenderQuality _lastProposedRenderQuality;
|
||||
CGFloat _backingScale;
|
||||
NSMutableDictionary * _replacementColors;
|
||||
IJSVGQuartzRenderer * _quartzRenderer;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject: 1;
|
||||
@@ -70,9 +73,12 @@ typedef CGFloat (^IJSVGRenderingBackingScaleFactorHelper)();
|
||||
@property (nonatomic, assign) CGFloat strokeWidth;
|
||||
@property (nonatomic, assign) IJSVGLineCapStyle lineCapStyle;
|
||||
@property (nonatomic, assign) IJSVGLineJoinStyle lineJoinStyle;
|
||||
@property (nonatomic, assign) IJSVGRenderQuality renderQuality;
|
||||
@property (nonatomic, assign) BOOL clipToViewport;
|
||||
|
||||
- (void)prepForDrawingInView:(NSView *)view;
|
||||
- (BOOL)isFont;
|
||||
- (IJSVGGroup *)rootNode;
|
||||
- (NSRect)viewBox;
|
||||
- (NSArray<IJSVGPath *> *)glyphs;
|
||||
- (NSString *)identifier;
|
||||
|
||||
@@ -19,16 +19,21 @@
|
||||
@synthesize lineCapStyle;
|
||||
@synthesize lineJoinStyle;
|
||||
@synthesize renderingBackingScaleHelper;
|
||||
@synthesize clipToViewport;
|
||||
@synthesize renderQuality;
|
||||
|
||||
- (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;
|
||||
[super dealloc];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
|
||||
+ (id)svgNamed:(NSString *)string
|
||||
@@ -333,7 +338,14 @@
|
||||
|
||||
- (void)_setupBasicsFromAnyInitializer
|
||||
{
|
||||
_lastProposedBackingScale = 1.f;
|
||||
self.clipToViewport = YES;
|
||||
self.renderQuality = IJSVGRenderQualityOptimized;
|
||||
|
||||
// setup low level backing scale
|
||||
_lastProposedBackingScale = 0.f;
|
||||
self.renderingBackingScaleHelper = ^CGFloat{
|
||||
return 1.f;
|
||||
};
|
||||
}
|
||||
|
||||
- (NSString *)identifier
|
||||
@@ -353,6 +365,11 @@
|
||||
return _viewBox;
|
||||
}
|
||||
|
||||
- (IJSVGGroup *)rootNode
|
||||
{
|
||||
return _group;
|
||||
}
|
||||
|
||||
- (BOOL)isFont
|
||||
{
|
||||
return [_group isFont];
|
||||
@@ -405,7 +422,7 @@
|
||||
{
|
||||
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);
|
||||
@@ -551,12 +568,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);
|
||||
}
|
||||
|
||||
@@ -566,8 +584,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;
|
||||
|
||||
@@ -605,62 +623,71 @@
|
||||
@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 -= round((_viewBox.origin.x)*_scale);
|
||||
viewPort.origin.y -= round((_viewBox.origin.y)*_scale);
|
||||
viewPort = CGRectIntegral(viewPort);
|
||||
|
||||
// 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
|
||||
IJSVGBeginTransactionLock();
|
||||
// do we need to update the backing scales on the
|
||||
// layers?
|
||||
if(self.renderingBackingScaleHelper != nil) {
|
||||
[self _askHelperForBackingScale];
|
||||
}
|
||||
|
||||
// render the layers
|
||||
[self.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);
|
||||
}
|
||||
@@ -674,15 +701,20 @@
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
IJSVGRenderQuality quality = self.renderQuality;
|
||||
_lastProposedBackingScale = scale;
|
||||
_lastProposedRenderQuality = quality;
|
||||
|
||||
// walk the tree
|
||||
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
|
||||
if(((IJSVGLayer *)layer).requiresBackingScaleHelp == YES) {
|
||||
((IJSVGLayer *)layer).backingScaleFactor = scale;
|
||||
IJSVGLayer * propLayer = ((IJSVGLayer *)layer);
|
||||
propLayer.renderQuality = quality;
|
||||
if(propLayer.requiresBackingScaleHelp == YES) {
|
||||
propLayer.backingScaleFactor = scale;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -770,17 +802,19 @@
|
||||
|
||||
// block to find colors in stroke and fill
|
||||
void (^block)(CALayer * layer, BOOL isMask) = ^void (CALayer * layer, BOOL isMask) {
|
||||
if([layer isKindOfClass:[IJSVGShapeLayer class]] && isMask == NO) {
|
||||
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];
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if(color.alphaComponent != 0.f) {
|
||||
[colors addObject:color];
|
||||
}
|
||||
}
|
||||
if(sLayer.strokeColor != nil) {
|
||||
color = [NSColor colorWithCGColor:sLayer.strokeColor];
|
||||
color = [IJSVGColor computeColorSpace:color];
|
||||
if(color.alphaComponent != 0.f) {
|
||||
[colors addObject:color];
|
||||
}
|
||||
|
||||
@@ -160,12 +160,16 @@ 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
|
||||
|
||||
@@ -11,12 +11,31 @@
|
||||
|
||||
@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
|
||||
@@ -37,157 +56,153 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
{
|
||||
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:@"000000" forKey:@"currentcolor"];
|
||||
[_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];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,10 +222,13 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSColor * color = nil;
|
||||
string = [string lowercaseString];
|
||||
NSColor * color = [[self class] colorFromPredefinedColorName:string];
|
||||
if( color != nil ) {
|
||||
return color;
|
||||
if([self.class isHex:string] == NO) {
|
||||
color = [self.class colorFromPredefinedColorName:string];
|
||||
if( color != nil ) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
if( [[string lowercaseString] isEqualToString:@"none"] ) {
|
||||
@@ -226,37 +244,61 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
if( count == 4 ) {
|
||||
alpha = params[3];
|
||||
}
|
||||
color = [NSColor colorWithDeviceRed:params[0]/255
|
||||
green:params[1]/255
|
||||
blue:params[2]/255
|
||||
color = [NSColor colorWithDeviceRed:params[0]/255.f
|
||||
green:params[1]/255.f
|
||||
blue:params[2]/255.f
|
||||
alpha:alpha];
|
||||
free(params);
|
||||
return color;
|
||||
}
|
||||
|
||||
color = [[self class] colorFromHEXString:string
|
||||
alpha:1.f];
|
||||
// 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) {
|
||||
alpha = params[3];
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
// memory clean!
|
||||
free(hsb);
|
||||
free(params);
|
||||
return color;
|
||||
}
|
||||
|
||||
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 = [self computeColorSpace:color];
|
||||
@@ -275,12 +317,22 @@ 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];
|
||||
}
|
||||
|
||||
// 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,
|
||||
return [NSString stringWithFormat:@"rgba(%d,%d,%d,%g)",red, green, blue,
|
||||
((float)alpha/100.f)];
|
||||
}
|
||||
|
||||
@@ -598,20 +650,35 @@ static NSMutableDictionary * _colorTree = nil;
|
||||
|
||||
+ (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 [NSColor colorWithDeviceRed:((hex >> 16) & 0xFF) / 255.f
|
||||
green:((hex >> 6) & 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:@"#"] )
|
||||
@@ -629,19 +696,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 [NSColor colorWithDeviceRed:((hex>>16) & 0xFF)/255.f
|
||||
green:((hex>>8) & 0xFF)/255.f
|
||||
blue:(hex & 0xFF)/255.f
|
||||
alpha:alpha];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:¶meterCount];
|
||||
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
|
||||
@@ -71,8 +82,9 @@ static NSMutableDictionary * _classes = nil;
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -82,13 +73,19 @@
|
||||
}
|
||||
|
||||
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
|
||||
@@ -98,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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])];
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandHorizontalLine
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"h"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
|
||||
@implementation IJSVGCommandQuadraticCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"q"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 4;
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
@implementation IJSVGCommandSmoothCurve
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"s"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 4;
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
|
||||
@implementation IJSVGCommandVerticalLine
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[IJSVGCommand registerClass:[self class]
|
||||
forCommand:@"v"];
|
||||
}
|
||||
|
||||
+ (NSInteger)requiredParameterCount
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -26,6 +26,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
|
||||
IJSVGExporterOptionRemoveHiddenElements = 1 << 8,
|
||||
IJSVGExporterOptionScaleToSizeIfNecessary = 1 << 9,
|
||||
IJSVGExporterOptionCompressOutput = 1 << 10,
|
||||
IJSVGExporterOptionCollapseGradients = 1 << 11,
|
||||
IJSVGExporterOptionCreateClasses = 1 << 12,
|
||||
IJSVGExporterOptionRemoveWidthHeightAttributes = 1 << 13,
|
||||
IJSVGExporterOptionAll = IJSVGExporterOptionRemoveUselessDef|
|
||||
IJSVGExporterOptionRemoveUselessGroups|
|
||||
IJSVGExporterOptionCreateUseForPaths|
|
||||
@@ -35,7 +38,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
|
||||
IJSVGExporterOptionCleanupPaths|
|
||||
IJSVGExporterOptionRemoveHiddenElements|
|
||||
IJSVGExporterOptionScaleToSizeIfNecessary|
|
||||
IJSVGExporterOptionCompressOutput
|
||||
IJSVGExporterOptionCompressOutput|
|
||||
IJSVGExporterOptionCollapseGradients|
|
||||
IJSVGExporterOptionRemoveWidthHeightAttributes
|
||||
};
|
||||
|
||||
@interface IJSVGExporter : NSObject {
|
||||
@@ -46,13 +51,9 @@ typedef NS_OPTIONS( NSInteger, IJSVGExporterOptions) {
|
||||
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;
|
||||
|
||||
@@ -26,61 +26,74 @@
|
||||
#define XML_DOC_NSXLINK @"http://www.w3.org/1999/xlink"
|
||||
#define XML_DOCTYPE_VERSION @"1.0"
|
||||
#define XML_DOC_CHARSET @"UTF-8"
|
||||
#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/curthard89/IJSVG)"
|
||||
#define XML_DOC_GENERATOR @"Generated by IJSVG (https://github.com/iconjar/IJSVG)"
|
||||
|
||||
@synthesize title;
|
||||
@synthesize description;
|
||||
|
||||
const NSArray * IJSVGShortCharacterArray()
|
||||
{
|
||||
static NSArray * _array;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_array = [@[@"a",@"b",@"c",@"d",@"e",@"f",@"g",@"h",@"i",@"j",@"k",@"l",
|
||||
@"m",@"n",@"o",@"p",@"q",@"r",@"s",@"t",@"u",@"v",@"w",@"x",@"y",@"z",
|
||||
@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",
|
||||
@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z"] retain];
|
||||
});
|
||||
return _array;
|
||||
}
|
||||
|
||||
const NSArray * IJSVGInheritableAttributes()
|
||||
{
|
||||
static NSArray * _attributes;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_attributes = [@[
|
||||
@"clip-rule",
|
||||
@"color",
|
||||
@"color-interpolation",
|
||||
@"color-interpolation-filters",
|
||||
@"color-profile",
|
||||
@"color-rendering",
|
||||
@"cursor",
|
||||
@"direction",
|
||||
@"fill",
|
||||
@"fill-opacity",
|
||||
@"fill-rule",
|
||||
@"font",
|
||||
@"font-family",
|
||||
@"font-size",
|
||||
@"font-size-adjust",
|
||||
@"font-stretch",
|
||||
@"font-style",
|
||||
@"font-variant",
|
||||
@"font-weight",
|
||||
@"glyph-orientation-horizontal",
|
||||
@"glyph-orientation-vertical",
|
||||
@"image-rendering",
|
||||
@"kerning",
|
||||
@"letter-spacing",
|
||||
@"marker",
|
||||
@"marker-end",
|
||||
@"marker-mid",
|
||||
@"marker-start",
|
||||
@"pointer-events",
|
||||
@"shape-rendering",
|
||||
@"stroke",
|
||||
@"stroke-dasharray",
|
||||
@"stroke-dashoffset",
|
||||
@"stroke-linecap",
|
||||
@"stroke-linejoin",
|
||||
@"stroke-miterlimit",
|
||||
@"stroke-opacity",
|
||||
@"stroke-width",
|
||||
@"text-anchor",
|
||||
@"text-rendering",
|
||||
@"visibility",
|
||||
@"white-space",
|
||||
@"word-spacing",
|
||||
@"writing-mode"] retain];
|
||||
@"clip-rule",
|
||||
@"color",
|
||||
@"color-interpolation",
|
||||
@"color-interpolation-filters",
|
||||
@"color-profile",
|
||||
@"color-rendering",
|
||||
@"cursor",
|
||||
@"direction",
|
||||
@"fill",
|
||||
@"fill-opacity",
|
||||
@"fill-rule",
|
||||
@"font",
|
||||
@"font-family",
|
||||
@"font-size",
|
||||
@"font-size-adjust",
|
||||
@"font-stretch",
|
||||
@"font-style",
|
||||
@"font-variant",
|
||||
@"font-weight",
|
||||
@"glyph-orientation-horizontal",
|
||||
@"glyph-orientation-vertical",
|
||||
@"image-rendering",
|
||||
@"kerning",
|
||||
@"letter-spacing",
|
||||
@"marker",
|
||||
@"marker-end",
|
||||
@"marker-mid",
|
||||
@"marker-start",
|
||||
@"pointer-events",
|
||||
@"shape-rendering",
|
||||
@"stroke",
|
||||
@"stroke-dasharray",
|
||||
@"stroke-dashoffset",
|
||||
@"stroke-linecap",
|
||||
@"stroke-linejoin",
|
||||
@"stroke-miterlimit",
|
||||
@"stroke-opacity",
|
||||
@"stroke-width",
|
||||
@"text-anchor",
|
||||
@"text-rendering",
|
||||
@"visibility",
|
||||
@"white-space",
|
||||
@"word-spacing",
|
||||
@"writing-mode"] retain];
|
||||
});
|
||||
return _attributes;
|
||||
}
|
||||
@@ -97,11 +110,6 @@ NSDictionary * IJSVGElementAttributeDictionary(NSXMLElement * element) {
|
||||
return dict;
|
||||
};
|
||||
|
||||
NSString * IJSVGShortFloatString(CGFloat f)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%g",f];
|
||||
};
|
||||
|
||||
NSString * IJSVGHashURL(NSString * key) {
|
||||
return [NSString stringWithFormat:@"url(#%@)",key];
|
||||
};
|
||||
@@ -165,11 +173,19 @@ NSString * IJSVGHash(NSString * key) {
|
||||
// sort out viewbox
|
||||
NSRect viewBox = _svg.viewBox;
|
||||
NSDictionary * attributes = @{
|
||||
@"viewBox":[self viewBoxWithRect:viewBox],
|
||||
@"version": [NSString stringWithFormat:@"%g",XML_DOC_VERSION],
|
||||
@"xmlns": XML_DOC_NS,
|
||||
@"xmlns:xlink": XML_DOC_NSXLINK
|
||||
};
|
||||
@"viewBox":[self viewBoxWithRect:viewBox],
|
||||
@"version": [NSString stringWithFormat:@"%g",XML_DOC_VERSION],
|
||||
@"xmlns": XML_DOC_NS,
|
||||
@"xmlns:xlink": XML_DOC_NSXLINK
|
||||
};
|
||||
|
||||
// add on width and height unless specified otherwise
|
||||
if((_options & IJSVGExporterOptionRemoveWidthHeightAttributes) == 0) {
|
||||
NSMutableDictionary * attDict = [[attributes mutableCopy] autorelease];
|
||||
attDict[@"width"] = IJSVGShortFloatString(_size.width);
|
||||
attDict[@"height"] = IJSVGShortFloatString(_size.height);
|
||||
attributes = [[attDict copy] autorelease];
|
||||
}
|
||||
|
||||
// was there a size set?
|
||||
if(CGSizeEqualToSize(CGSizeZero, _size) == NO &&
|
||||
@@ -219,6 +235,19 @@ NSString * IJSVGHash(NSString * key) {
|
||||
return root;
|
||||
}
|
||||
|
||||
- (NSString *)generateID
|
||||
{
|
||||
const NSArray * chars = IJSVGShortCharacterArray();
|
||||
if(_idCount < chars.count) {
|
||||
return chars[_idCount++];
|
||||
}
|
||||
|
||||
if((_idCount % chars.count) == 0) {
|
||||
_shortIdCount++;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@%ld",chars[(_idCount++ % chars.count)],_shortIdCount];
|
||||
}
|
||||
|
||||
- (void)_prepare
|
||||
{
|
||||
// create the stand alone DOM
|
||||
@@ -226,18 +255,28 @@ NSString * IJSVGHash(NSString * key) {
|
||||
_dom.version = XML_DOCTYPE_VERSION;
|
||||
_dom.characterEncoding = XML_DOC_CHARSET;
|
||||
|
||||
// add defs in
|
||||
[_dom.rootElement addChild:[self defElement]];
|
||||
|
||||
// sort out header
|
||||
|
||||
// sort out stuff, so here we go...
|
||||
[self _recursiveParseFromLayer:_svg.layer
|
||||
intoElement:(_scaledRootNode?:_dom.rootElement)];
|
||||
|
||||
// this needs to be added incase it needs to be cleaned
|
||||
NSXMLElement * defNode = [self defElement];
|
||||
if(defNode.childCount != 0) {
|
||||
[_dom.rootElement insertChild:[self defElement]
|
||||
atIndex:0];
|
||||
}
|
||||
|
||||
// cleanup
|
||||
[self _cleanup];
|
||||
|
||||
// could had been removed during cleaning process needs to be added back in!
|
||||
if(defNode.childCount != 0 && defNode.parent == nil) {
|
||||
[_dom.rootElement insertChild:[self defElement]
|
||||
atIndex:0];
|
||||
}
|
||||
|
||||
// add generator
|
||||
NSXMLNode * generatorNode = [[[NSXMLNode alloc] initWithKind:NSXMLCommentKind] autorelease];
|
||||
generatorNode.stringValue = XML_DOC_GENERATOR;
|
||||
@@ -262,11 +301,6 @@ NSString * IJSVGHash(NSString * key) {
|
||||
[self _cleanDef];
|
||||
}
|
||||
|
||||
// move any possible attributes to its parent group
|
||||
if((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) {
|
||||
[self _moveAttributesToGroup];
|
||||
}
|
||||
|
||||
// collapse groups
|
||||
if((_options & IJSVGExporterOptionCollapseGroups) != 0) {
|
||||
[self _collapseGroups];
|
||||
@@ -286,6 +320,65 @@ NSString * IJSVGHash(NSString * key) {
|
||||
if((_options & IJSVGExporterOptionCollapseGroups) != 0) {
|
||||
[self _compressGroups];
|
||||
}
|
||||
|
||||
// collapse gradients?
|
||||
if((_options & IJSVGExporterOptionCollapseGradients) != 0) {
|
||||
[self _collapseGradients];
|
||||
}
|
||||
|
||||
// create classes?
|
||||
if((_options & IJSVGExporterOptionCreateClasses) != 0) {
|
||||
[self _createClasses];
|
||||
}
|
||||
|
||||
// move attributes to group
|
||||
if((_options & IJSVGExporterOptionMoveAttributesToGroup) != 0) {
|
||||
[self _moveAttributesToGroupWithElement:_dom.rootElement];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_createClasses
|
||||
{
|
||||
const NSArray * inhert = IJSVGInheritableAttributes();
|
||||
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*"
|
||||
error:nil];
|
||||
NSMutableDictionary * rules = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
for(NSXMLElement * element in elements) {
|
||||
NSDictionary * inhertEl = [self intersectableAttributes:IJSVGElementAttributeDictionary(element)
|
||||
inheritableAttributes:inhert];
|
||||
NSString * styles = [self styleSheetRulesFromDictionary:inhertEl];
|
||||
NSString * className = nil;
|
||||
if((className = [rules objectForKey:styles]) == nil) {
|
||||
className = [NSString stringWithFormat:@"%@",[self generateID]];
|
||||
rules[styles] = className;
|
||||
}
|
||||
|
||||
for(NSString * attributeName in inhertEl) {
|
||||
[element removeAttributeForName:attributeName];
|
||||
}
|
||||
IJSVGApplyAttributesToElement(@{@"class":className},element);
|
||||
}
|
||||
|
||||
// add styles to dom
|
||||
NSXMLElement * styles = [[[NSXMLElement alloc] initWithName:@"style"] autorelease];
|
||||
NSXMLNode * node = [[[NSXMLNode alloc] initWithKind:NSXMLTextKind] autorelease];
|
||||
|
||||
NSMutableArray * classes = [[[NSMutableArray alloc] initWithCapacity:rules.count] autorelease];
|
||||
for(NSString * r in rules) {
|
||||
[classes addObject:[NSString stringWithFormat:@".%@%@",rules[r],r]];
|
||||
}
|
||||
node.stringValue = [classes componentsJoinedByString:@""];
|
||||
[styles addChild:node];
|
||||
[_dom.rootElement insertChild:styles atIndex:0];
|
||||
}
|
||||
|
||||
- (NSString *)styleSheetRulesFromDictionary:(NSDictionary *)dict
|
||||
{
|
||||
NSMutableArray * array = [[[NSMutableArray alloc] initWithCapacity:dict.count] autorelease];
|
||||
for(NSString * key in dict.allKeys) {
|
||||
[array addObject:[NSString stringWithFormat:@"%@: %@;",key,dict[key]]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"{%@}",[array componentsJoinedByString:@" "]];
|
||||
}
|
||||
|
||||
- (void)_sortAttributesOnElement:(NSXMLElement *)element
|
||||
@@ -304,85 +397,116 @@ NSString * IJSVGHash(NSString * key) {
|
||||
{
|
||||
// find any elements where they have a style, but the element itself
|
||||
// must not be in the defs
|
||||
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*[@style][not(ancestor::defs)]"
|
||||
NSArray<NSXMLElement *> * elements = [_dom nodesForXPath:@"//*[@display='none']"
|
||||
error:nil];
|
||||
|
||||
for(NSXMLElement * element in elements) {
|
||||
// parse the style
|
||||
NSString * styleString = [element attributeForName:@"style"].stringValue;
|
||||
IJSVGStyle * style = [IJSVGStyle parseStyleString:styleString];
|
||||
if([[style property:@"display"] isEqualToString:@"none"]) {
|
||||
// this can be removed!
|
||||
NSXMLElement * parent = (NSXMLElement *)element.parent;
|
||||
[parent removeChildAtIndex:element.index];
|
||||
NSXMLElement * parent = (NSXMLElement *)element.parent;
|
||||
[parent removeChildAtIndex:element.index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_collapseGradients
|
||||
{
|
||||
NSString * xPath = @"//defs/*[self::linearGradient or self::radialGradient]";
|
||||
NSArray<NSXMLElement *> * gradients = [_dom nodesForXPath:xPath error:nil];
|
||||
for(NSInteger i = 0; i < gradients.count; i++) {
|
||||
if(i != 0) {
|
||||
NSXMLElement * gradientA = gradients[i];
|
||||
NSXMLElement * gradientB = nil;
|
||||
for(NSInteger s = (i - 1); s >= 0; s--) {
|
||||
gradientB = gradients[s];
|
||||
if([self compareElementChildren:gradientA toElement:gradientB] == YES) {
|
||||
NSString * idString = [gradientB attributeForName:@"id"].stringValue;
|
||||
if(idString == nil || idString.length == 0) {
|
||||
idString = [self generateID];
|
||||
IJSVGApplyAttributesToElement(@{@"id":idString}, gradientB);
|
||||
}
|
||||
NSDictionary * atts = @{@"xlink:href":IJSVGHash(idString)};
|
||||
IJSVGApplyAttributesToElement(atts, gradientA);
|
||||
[gradientA setChildren:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_moveAttributesToGroup
|
||||
- (BOOL)compareElementChildren:(NSXMLElement *)element
|
||||
toElement:(NSXMLElement *)toElement
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSArray * childrenA = element.children;
|
||||
NSArray * childrenB = toElement.children;
|
||||
if(childrenA.count != childrenB.count) {
|
||||
return NO;
|
||||
}
|
||||
for(NSInteger i = 0; i < childrenA.count; i++) {
|
||||
NSXMLElement * childA = childrenA[i];
|
||||
NSXMLElement * childB = childrenB[i];
|
||||
if([self compareElement:childA withElement:childB] == NO) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_moveAttributesToGroupWithElement:(NSXMLElement *)parentElement
|
||||
{
|
||||
|
||||
const NSArray * excludedNodes = @[@"script",@"style",@"defs"];
|
||||
if([excludedNodes containsObject:parentElement.name] == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
const NSArray * inheritableAttributes = IJSVGInheritableAttributes();
|
||||
|
||||
NSDictionary * intersection = @{};
|
||||
NSMutableArray * grouped = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
NSInteger counter = 0;
|
||||
NSInteger size = parentElement.childCount - 1;
|
||||
for(NSXMLElement * element in parentElement.children) {
|
||||
|
||||
NSArray<NSXMLElement *> * groups = [_dom nodesForXPath:@"//g"
|
||||
error:nil];
|
||||
NSDictionary * attributes = [self intersectableAttributes:IJSVGElementAttributeDictionary(element)
|
||||
inheritableAttributes:inheritableAttributes];
|
||||
|
||||
const NSArray * inheritableAttributes = IJSVGInheritableAttributes();
|
||||
if(intersection.count == 0) {
|
||||
intersection = attributes;
|
||||
}
|
||||
|
||||
for(NSXMLElement * group in groups) {
|
||||
@autoreleasepool {
|
||||
NSDictionary * intersection = @{};
|
||||
|
||||
// does it have a mask/clip?
|
||||
BOOL hasClip = [group attributeForName:@"clip-path"] != nil ||
|
||||
[group attributeForName:@"mask"] != nil;
|
||||
|
||||
NSMutableArray * intersected = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
// loop around each child
|
||||
for(NSXMLElement * child in group.children) {
|
||||
if(child.attributes.count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// straight add on
|
||||
NSDictionary * atts = [self intersectableAttributes:IJSVGElementAttributeDictionary(child)
|
||||
inheritableAttributes:inheritableAttributes];
|
||||
if(intersection.count == 0) {
|
||||
intersection = atts;
|
||||
} else {
|
||||
|
||||
// work out the intersection
|
||||
NSDictionary * dict = nil;
|
||||
dict = [self intersectionInheritableAttributes:intersection
|
||||
currentAttributes:atts
|
||||
inheritableAttributes:inheritableAttributes];
|
||||
|
||||
// break if nothing
|
||||
if(dict == nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add them
|
||||
intersection = dict;
|
||||
}
|
||||
// add the child to array
|
||||
[intersected addObject:child];
|
||||
NSDictionary * dict = [self intersectionInheritableAttributes:intersection
|
||||
currentAttributes:attributes
|
||||
inheritableAttributes:inheritableAttributes];
|
||||
|
||||
for(NSString * attributeToRemove in dict.allKeys) {
|
||||
[element removeAttributeForName:attributeToRemove];
|
||||
}
|
||||
if(dict != nil) {
|
||||
[grouped addObject:element];
|
||||
}
|
||||
|
||||
if(dict == nil || counter == size) {
|
||||
if(grouped.count > 1) {
|
||||
NSXMLElement * groupElement = [[[NSXMLElement alloc] initWithName:@"g"] autorelease];
|
||||
NSXMLElement * lastElement = (NSXMLElement *)grouped.lastObject;
|
||||
NSInteger index = lastElement.index;
|
||||
[parentElement replaceChildAtIndex:index withNode:groupElement];
|
||||
for(NSXMLElement * elementToGroup in grouped) {
|
||||
[elementToGroup detach];
|
||||
[groupElement addChild:elementToGroup];
|
||||
}
|
||||
|
||||
if(intersected.count != 0 && hasClip == NO) {
|
||||
for(NSXMLElement * child in intersected) {
|
||||
for(NSString * attributeName in intersection.allKeys) {
|
||||
// remove attribute
|
||||
[child removeAttributeForName:attributeName];
|
||||
// add the
|
||||
NSDictionary * atts = nil;
|
||||
atts = @{attributeName:intersection[attributeName]};
|
||||
IJSVGApplyAttributesToElement(atts, group);
|
||||
}
|
||||
}
|
||||
IJSVGApplyAttributesToElement(intersection, groupElement);
|
||||
} else {
|
||||
if(grouped.count == 1) {
|
||||
NSXMLElement * onlyElement = (NSXMLElement *)grouped.lastObject;
|
||||
IJSVGApplyAttributesToElement(intersection, onlyElement);
|
||||
}
|
||||
}
|
||||
intersection = @{};
|
||||
[grouped removeAllObjects];
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +530,10 @@ NSString * IJSVGHash(NSString * key) {
|
||||
for(NSString * key in newAttributes.allKeys) {
|
||||
// make sure they are the same and
|
||||
// they are inheritable
|
||||
if([currentAttributes objectForKey:key] == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if([currentAttributes objectForKey:key] != nil &&
|
||||
[inheritableAtts containsObject:key] &&
|
||||
[newAttributes[key] isEqualToString:currentAttributes[key]]) {
|
||||
@@ -478,7 +606,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
[(NSXMLElement *)n.parent removeChildAtIndex:n.index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)_collapseGroups
|
||||
@@ -486,11 +614,10 @@ NSString * IJSVGHash(NSString * key) {
|
||||
NSArray * groups = [_dom nodesForXPath:@"//g" error:nil];
|
||||
const NSArray * inheritable = IJSVGInheritableAttributes();
|
||||
for(NSXMLElement * group in groups) {
|
||||
|
||||
|
||||
// dont do anything due to it being referenced
|
||||
if([group attributeForName:@"id"] != nil ||
|
||||
[group attributeForName:@"transform"] != nil) {
|
||||
continue;
|
||||
if([group attributeForName:@"id"] != nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(group.attributes.count != 0 && group.children.count == 1) {
|
||||
@@ -501,31 +628,35 @@ NSString * IJSVGHash(NSString * key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(NSXMLNode * gAttribute in group.attributes) {
|
||||
|
||||
// if it just doesnt have the attriute, just add it
|
||||
if([child attributeForName:gAttribute.name] == NO) {
|
||||
// remove first, or throws a wobbly
|
||||
[group removeAttributeForName:gAttribute.name];
|
||||
[child addAttribute:gAttribute];
|
||||
|
||||
} else if([gAttribute.name isEqualToString:@"transform"]) {
|
||||
|
||||
// transform requires concatination
|
||||
NSXMLNode * childTransform = [child attributeForName:@"transform"];
|
||||
childTransform.stringValue = [NSString stringWithFormat:@"%@ %@",
|
||||
gAttribute.stringValue, childTransform.stringValue];
|
||||
|
||||
} else if([inheritable containsObject:gAttribute.name] == NO) {
|
||||
|
||||
// if its not inheritable, only remove it if its not equal
|
||||
NSXMLNode * aAtt = [child attributeForName:gAttribute.name];
|
||||
if(aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
[group removeAttributeForName:gAttribute.name];
|
||||
}
|
||||
for(NSXMLNode * gAttribute in group.attributes) {
|
||||
|
||||
// if it just doesnt have the attriute, just add it
|
||||
if([child attributeForName:gAttribute.name] == NO) {
|
||||
// remove first, or throws a wobbly
|
||||
[group removeAttributeForName:gAttribute.name];
|
||||
[child addAttribute:gAttribute];
|
||||
} else if([gAttribute.name isEqualToString:@"transform"]) {
|
||||
// transform requires concatination
|
||||
NSXMLNode * childTransform = [child attributeForName:@"transform"];
|
||||
childTransform.stringValue = [NSString stringWithFormat:@"%@ %@",
|
||||
gAttribute.stringValue, childTransform.stringValue];
|
||||
|
||||
} else if([inheritable containsObject:gAttribute.name] == NO) {
|
||||
// if its not inheritable, only remove it if its not equal
|
||||
NSXMLNode * aAtt = [child attributeForName:gAttribute.name];
|
||||
if(aAtt == nil || (aAtt != nil && [aAtt.stringValue isEqualToString:gAttribute.stringValue] == NO)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
[group removeAttributeForName:gAttribute.name];
|
||||
}
|
||||
|
||||
// remove the group as its useless!
|
||||
if(group.attributes.count == 0) {
|
||||
[child detach];
|
||||
[(NSXMLElement *)group.parent replaceChildAtIndex:group.index
|
||||
withNode:child];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,7 +708,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
element.name = @"path";
|
||||
|
||||
NSDictionary * atts = @{@"d":data,
|
||||
@"id":[NSString stringWithFormat:@"path-%ld",(++_pathCount)]};
|
||||
@"id":[self generateID]};
|
||||
IJSVGApplyAttributesToElement(atts, element);
|
||||
|
||||
// store it against the def
|
||||
@@ -648,39 +779,13 @@ NSString * IJSVGHash(NSString * key) {
|
||||
- (void)applyTransformToElement:(NSXMLElement *)element
|
||||
fromLayer:(IJSVGLayer *)layer
|
||||
{
|
||||
// dont do anything, they are the same
|
||||
CGFloat x = layer.frame.origin.x;
|
||||
CGFloat y = layer.frame.origin.y;
|
||||
|
||||
// check for x or y..they must be included
|
||||
if(CGAffineTransformEqualToTransform(layer.affineTransform, CGAffineTransformIdentity) &&
|
||||
x == 0.f && y == 0.f) {
|
||||
CGAffineTransform transform = layer.affineTransform;
|
||||
if(CGAffineTransformEqualToTransform(transform, CGAffineTransformIdentity) == YES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct the matrix
|
||||
CGAffineTransform transform = layer.affineTransform;
|
||||
|
||||
// was there already x and y transform?
|
||||
BOOL hasXTransform = transform.tx != 0.f;
|
||||
BOOL hasYTransform = transform.ty != 0.f;
|
||||
|
||||
// move the x and y position
|
||||
if(x != 0.f || y != 0.f) {
|
||||
transform = CGAffineTransformConcat( transform, CGAffineTransformMakeTranslation( x, y ));
|
||||
}
|
||||
|
||||
// x and y were not given so just transform
|
||||
if(hasXTransform) {
|
||||
transform.tx /= 2.f;
|
||||
}
|
||||
if(hasYTransform) {
|
||||
transform.ty /= 2.f;
|
||||
}
|
||||
|
||||
// append the string
|
||||
NSArray * transformArray = [IJSVGTransform affineTransformToSVGTransformAttributeString:transform];
|
||||
NSString * transformStr = [transformArray componentsJoinedByString:@" "];
|
||||
NSString * transformStr = [IJSVGTransform affineTransformToSVGMatrixString:transform];
|
||||
|
||||
// apply it to the node
|
||||
IJSVGApplyAttributesToElement(@{@"transform":transformStr},element);
|
||||
@@ -708,6 +813,9 @@ NSString * IJSVGHash(NSString * key) {
|
||||
|
||||
- (NSString *)base64EncodedStringFromCGImage:(CGImageRef)image
|
||||
{
|
||||
if(image == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// convert the CGImage into an NSImage
|
||||
NSBitmapImageRep * rep = [[[NSBitmapImageRep alloc] initWithCGImage:image] autorelease];
|
||||
@@ -733,7 +841,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
patternElement.name = @"pattern";
|
||||
|
||||
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = [NSString stringWithFormat:@"pattern-%ld",(++_patternCount)];
|
||||
dict[@"id"] = [self generateID];
|
||||
dict[@"width"] = IJSVGShortFloatString(layer.patternNode.width.value);
|
||||
dict[@"height"] = IJSVGShortFloatString(layer.patternNode.height.value);
|
||||
|
||||
@@ -780,12 +888,12 @@ NSString * IJSVGHash(NSString * key) {
|
||||
toElement:(NSXMLElement *)element
|
||||
{
|
||||
IJSVGGradient * gradient = layer.gradient;
|
||||
NSString * gradKey = [NSString stringWithFormat:@"gradient-%ld",(++_gradCount)];
|
||||
NSString * gradKey = [self generateID];
|
||||
NSXMLElement * gradientElement = [[[NSXMLElement alloc] init] autorelease];
|
||||
|
||||
// work out linear gradient
|
||||
if([gradient isKindOfClass:[IJSVGLinearGradient class]]) {
|
||||
|
||||
|
||||
IJSVGLinearGradient * lGradient = (IJSVGLinearGradient *)gradient;
|
||||
gradientElement.name = @"linearGradient";
|
||||
NSDictionary * dict = @{@"id":gradKey,
|
||||
@@ -838,12 +946,21 @@ NSString * IJSVGHash(NSString * key) {
|
||||
atts[@"offset"] = [NSString stringWithFormat:@"%g%%",(location*100)];
|
||||
|
||||
// add the color
|
||||
atts[@"stop-color"] = [IJSVGColor colorStringFromColor:aColor
|
||||
forceHex:YES];
|
||||
NSString * stopColor = [IJSVGColor colorStringFromColor:aColor
|
||||
forceHex:YES
|
||||
allowShorthand:YES];
|
||||
if([stopColor isEqualToString:@"#000000"] == NO) {
|
||||
atts[@"stop-color"] = stopColor;
|
||||
}
|
||||
|
||||
// we need to work out the color at this point, annoyingly...
|
||||
CGFloat opacity = aColor.alphaComponent;
|
||||
atts[@"stop-opacity"] = [NSString stringWithFormat:@"%g",opacity];
|
||||
|
||||
// is opacity is equal to 1, no need to add it as spec
|
||||
// defaults opacity to 1 anyway :)
|
||||
if(opacity != 1.f) {
|
||||
atts[@"stop-opacity"] = IJSVGShortFloatStringWithPrecision(opacity, 2);
|
||||
}
|
||||
|
||||
// att the attributes
|
||||
|
||||
@@ -859,24 +976,9 @@ NSString * IJSVGHash(NSString * key) {
|
||||
// work out the transform
|
||||
NSArray * transforms = layer.gradient.transforms;
|
||||
if(transforms.count != 0.f) {
|
||||
CGAffineTransform transform = [self affineTransformFromTransforms:transforms];
|
||||
|
||||
// work out if there is x and y translate
|
||||
BOOL hasXTransform = transform.tx != 0.f;
|
||||
BOOL hasYTransform = transform.ty != 0.f;
|
||||
|
||||
// x and y were not given so just transform
|
||||
if(hasXTransform) {
|
||||
transform.tx /= 2.f;
|
||||
}
|
||||
if(hasYTransform) {
|
||||
transform.ty /= 2.f;
|
||||
}
|
||||
|
||||
// apply the attributes
|
||||
NSArray * transforms = [IJSVGTransform affineTransformToSVGTransformAttributeString:transform];
|
||||
NSString * tString = [transforms componentsJoinedByString:@" "];
|
||||
IJSVGApplyAttributesToElement(@{@"gradientTransform":tString}, gradientElement);
|
||||
CGAffineTransform transform = IJSVGConcatTransforms(transforms);
|
||||
NSString * transformString = [IJSVGTransform affineTransformToSVGMatrixString:transform];
|
||||
IJSVGApplyAttributesToElement(@{@"gradientTransform":transformString}, gradientElement);
|
||||
}
|
||||
|
||||
// add it to the element passed in
|
||||
@@ -885,7 +987,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
|
||||
// fill opacity
|
||||
if(layer.opacity != 1.f) {
|
||||
IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatString(layer.opacity)}, element);
|
||||
IJSVGApplyAttributesToElement(@{@"fill-opacity":IJSVGShortFloatStringWithPrecision(layer.opacity,2)}, element);
|
||||
}
|
||||
} else {
|
||||
IJSVGApplyAttributesToElement(@{@"stroke":IJSVGHashURL(gradKey)}, element);
|
||||
@@ -905,13 +1007,16 @@ NSString * IJSVGHash(NSString * key) {
|
||||
fromParent:(NSXMLElement *)parent
|
||||
{
|
||||
NSString * base64String = [self base64EncodedStringFromCGImage:(CGImageRef)layer.contents];
|
||||
if(base64String == nil || layer.contents == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// image element for the SVG
|
||||
NSXMLElement * imageElement = [[[NSXMLElement alloc] init] autorelease];
|
||||
imageElement.name = @"image";
|
||||
|
||||
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = [NSString stringWithFormat:@"image-%ld",(++_imageCount)];
|
||||
dict[@"id"] = [self generateID];
|
||||
dict[@"width"] = IJSVGShortFloatString(layer.frame.size.width);
|
||||
dict[@"height"] = IJSVGShortFloatString(layer.frame.size.height);
|
||||
dict[@"xlink:href"] = base64String;
|
||||
@@ -936,10 +1041,17 @@ NSString * IJSVGHash(NSString * key) {
|
||||
e.name = @"path";
|
||||
CGPathRef path = layer.path;
|
||||
|
||||
// copy the path as we want to translate
|
||||
CGAffineTransform trans = CGAffineTransformMakeTranslation(layer.originalPathOrigin.x,
|
||||
layer.originalPathOrigin.y);
|
||||
CGPathRef transformPath = CGPathCreateCopyByTransformingPath(path, &trans);
|
||||
|
||||
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
|
||||
// path
|
||||
dict[@"d"] = [self pathFromCGPath:path];
|
||||
dict[@"d"] = [self pathFromCGPath:transformPath];
|
||||
|
||||
CGPathRelease(transformPath);
|
||||
|
||||
// work out even odd rule
|
||||
if([layer.fillRule isEqualToString:kCAFillRuleNonZero] == NO) {
|
||||
@@ -996,7 +1108,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
parentLayer:(IJSVGPatternLayer *)layer
|
||||
stroke:YES
|
||||
toElement:e];
|
||||
|
||||
|
||||
} else if(strokeLayer.strokeColor != nil) {
|
||||
NSColor * strokeColor = [NSColor colorWithCGColor:strokeLayer.strokeColor];
|
||||
NSString * strokeColorString = [IJSVGColor colorStringFromColor:strokeColor];
|
||||
@@ -1004,6 +1116,10 @@ NSString * IJSVGHash(NSString * key) {
|
||||
// could be none
|
||||
if(strokeColorString != nil) {
|
||||
dict[@"stroke"] = strokeColorString;
|
||||
if([strokeColorString isEqualToString:@"none"] == YES) {
|
||||
// remove the stroke width as its completely useless
|
||||
[dict removeObjectForKey:@"stroke-width"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,7 +1161,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// apply the attributes
|
||||
IJSVGApplyAttributesToElement(dict, e);
|
||||
|
||||
@@ -1062,7 +1178,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
|
||||
// opacity
|
||||
if(layer.opacity != 1.f) {
|
||||
dict[@"opacity"] = IJSVGShortFloatString(layer.opacity);
|
||||
dict[@"opacity"] = IJSVGShortFloatStringWithPrecision(layer.opacity,2);
|
||||
}
|
||||
|
||||
// blendmode - we only every apply a stylesheet blend mode
|
||||
@@ -1111,7 +1227,7 @@ NSString * IJSVGHash(NSString * key) {
|
||||
mask.name = @"mask";
|
||||
|
||||
// create the key
|
||||
NSString * maskKey = [NSString stringWithFormat:@"mask-%ld",(++_maskCount)];
|
||||
NSString * maskKey = [self generateID];
|
||||
NSMutableDictionary * dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
dict[@"id"] = maskKey;
|
||||
dict[@"maskContentUnits"] = @"userSpaceOnUse";
|
||||
@@ -1229,3 +1345,4 @@ void IJSVGExporterPathCaller(void * info, const CGPathElement * pathElement) {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
@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;
|
||||
@@ -26,6 +23,8 @@
|
||||
colors:(NSArray **)someColors;
|
||||
- (CGGradientRef)CGGradient;
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect;
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox;
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
@implementation IJSVGGradient
|
||||
|
||||
@synthesize gradient, CGGradient;
|
||||
@synthesize angle, startPoint, endPoint;
|
||||
@synthesize x1, x2, y1, y2;
|
||||
|
||||
- (void)dealloc
|
||||
@@ -31,8 +30,6 @@
|
||||
{
|
||||
IJSVGGradient * clone = [super copyWithZone:zone];
|
||||
clone.gradient = [[self.gradient copy] autorelease];
|
||||
clone.startPoint = self.startPoint;
|
||||
clone.endPoint = self.endPoint;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -40,14 +37,11 @@
|
||||
colors:(NSArray **)someColors
|
||||
{
|
||||
// find each stop element
|
||||
NSArray * stops = [element nodesForXPath:@"stop"
|
||||
error:nil];
|
||||
|
||||
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;
|
||||
if( offset > 1.f ) {
|
||||
@@ -134,7 +128,9 @@
|
||||
}
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = .35f;
|
||||
break;
|
||||
}
|
||||
case IJSVGRenderQualityLow: {
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -30,15 +30,26 @@
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
- (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
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "IJSVGTransaction.h"
|
||||
#import "IJSVGRendering.h"
|
||||
|
||||
@class IJSVGShapeLayer;
|
||||
@class IJSVGGradientLayer;
|
||||
@@ -28,6 +29,7 @@
|
||||
@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;
|
||||
|
||||
@@ -26,13 +26,10 @@
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVGBeginTransactionLock();
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
[super dealloc];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
|
||||
|
||||
+ (NSArray *)deepestSublayersOfLayer:(CALayer *)layer
|
||||
{
|
||||
NSMutableArray * arr = [[[NSMutableArray alloc] init] autorelease];
|
||||
@@ -65,7 +62,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addSublayer:(CALayer *)layer {
|
||||
- (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.",
|
||||
@@ -80,14 +78,14 @@
|
||||
|
||||
- (void)setBackingScaleFactor:(CGFloat)newFactor
|
||||
{
|
||||
if(self.backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
if(self.backingScaleFactor == newFactor) {
|
||||
return;
|
||||
}
|
||||
backingScaleFactor = newFactor;
|
||||
self.contentsScale = newFactor;
|
||||
self.rasterizationScale = newFactor;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)_customRenderInContext:(CGContextRef)ctx
|
||||
{
|
||||
@@ -176,18 +174,11 @@
|
||||
return;
|
||||
}
|
||||
[self _customRenderInContext:ctx];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPoint)absoluteOrigin
|
||||
- (id<CAAction>)actionForKey:(NSString *)event
|
||||
{
|
||||
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;
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -67,44 +67,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;
|
||||
}
|
||||
|
||||
@@ -112,9 +135,6 @@
|
||||
fromNode:(IJSVGNode *)node
|
||||
{
|
||||
CGFloat opacity = node.opacity.value;
|
||||
if(opacity == 0.f) {
|
||||
opacity = 1.f;
|
||||
}
|
||||
layer.opacity = opacity;
|
||||
|
||||
// setup the blending mode
|
||||
@@ -126,29 +146,38 @@
|
||||
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
|
||||
@@ -180,16 +209,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;
|
||||
|
||||
@@ -198,9 +232,7 @@
|
||||
CGPathRelease(introPath);
|
||||
|
||||
// set the bounds
|
||||
bounds.origin.x += path.x.value;
|
||||
bounds.origin.y += path.y.value;
|
||||
layer.frame = bounds;
|
||||
layer.frame = CGRectIntegral(bounds);
|
||||
|
||||
// basic fill color and rule
|
||||
layer.fillColor = nil;
|
||||
@@ -217,16 +249,36 @@
|
||||
return mask;
|
||||
}
|
||||
|
||||
- (CGAffineTransform)absoluteTransform:(IJSVGNode *)node
|
||||
{
|
||||
CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity;
|
||||
IJSVGNode * intermediateNode = node.intermediateParentNode;
|
||||
node = node.parentNode;
|
||||
while(node != nil) {
|
||||
// intermediateParent should be skipped as these are elements
|
||||
// created by use statements and are technically fake elements, but the
|
||||
// spec says use them for the transforms, yolo!
|
||||
if(node == intermediateNode) {
|
||||
node = node.parentNode;
|
||||
continue;
|
||||
}
|
||||
CGAffineTransform trans = IJSVGConcatTransforms(node.transforms);
|
||||
parentAbsoluteTransform = CGAffineTransformConcat(trans,parentAbsoluteTransform);
|
||||
node = node.parentNode;
|
||||
}
|
||||
return 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];
|
||||
BOOL hasStroke = (path.strokeColor != nil ||
|
||||
path.strokePattern != nil ||
|
||||
path.strokeGradient != nil);
|
||||
|
||||
// any gradient?
|
||||
if(self.fillColor == nil && path.fillGradient != nil) {
|
||||
@@ -234,15 +286,12 @@
|
||||
// create the gradient
|
||||
IJSVGGradientLayer * gradLayer = [self gradientLayerForLayer:layer
|
||||
gradient:path.fillGradient
|
||||
fromNode:path];
|
||||
fromNode:path
|
||||
objectRect:originalShapeBounds
|
||||
shouldMask:YES];
|
||||
|
||||
// add the gradient and set it against the layer
|
||||
[layer addSublayer:gradLayer];
|
||||
|
||||
// apply offsets
|
||||
[self applyOffsetsToLayer:gradLayer
|
||||
fromNode:path.fillGradient];
|
||||
|
||||
layer.gradientFillLayer = gradLayer;
|
||||
|
||||
} else if(self.fillColor == nil && path.fillPattern != nil) {
|
||||
@@ -269,6 +318,9 @@
|
||||
BOOL hasFill = path.fillPattern != nil || path.fillGradient != nil;
|
||||
if(self.fillColor && (hasFill || hasColor || fColor == nil)) {
|
||||
fColor = self.fillColor;
|
||||
} else if(fColor != nil && path.fillOpacity.value != 1.f) {
|
||||
fColor = [IJSVGColor changeAlphaOnColor:fColor
|
||||
to:path.fillOpacity.value];
|
||||
}
|
||||
|
||||
// anything changed by user?
|
||||
@@ -292,9 +344,7 @@
|
||||
}
|
||||
|
||||
// stroke it
|
||||
if(path.strokeColor != nil ||
|
||||
path.strokePattern != nil ||
|
||||
path.strokeGradient != nil) {
|
||||
if(hasStroke == YES) {
|
||||
|
||||
// load the stroke layer
|
||||
IJSVGStrokeLayer * strokeLayer = [self strokeLayer:layer
|
||||
@@ -311,7 +361,8 @@
|
||||
// create the gradient
|
||||
IJSVGGradientLayer * gradLayer = [self gradientStrokeLayerForLayer:layer
|
||||
gradient:path.strokeGradient
|
||||
fromNode:path];
|
||||
fromNode:path
|
||||
objectRect:originalShapeBounds];
|
||||
|
||||
moveStrokeLayer = YES;
|
||||
gradLayer.mask = strokeLayer;
|
||||
@@ -402,33 +453,19 @@
|
||||
- (IJSVGGradientLayer *)gradientStrokeLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
gradient:(IJSVGGradient *)gradient
|
||||
fromNode:(IJSVGNode *)path
|
||||
objectRect:(CGRect)objectRect
|
||||
{
|
||||
// the gradient drawing layer
|
||||
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
|
||||
gradLayer.gradient = gradient;
|
||||
|
||||
// is there a fill opacity?
|
||||
if(path.fillOpacity.value != 0.f) {
|
||||
gradLayer.opacity = path.fillOpacity.value;
|
||||
}
|
||||
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;
|
||||
|
||||
// display it
|
||||
[gradLayer setNeedsDisplay];
|
||||
|
||||
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
|
||||
// move back if needed
|
||||
gradLayer.frame = (CGRect){
|
||||
.size = gradLayer.frame.size,
|
||||
.origin = CGPointMake(-fabs(gradLayer.frame.origin.x),
|
||||
-fabs(gradLayer.frame.origin.y))
|
||||
};
|
||||
}
|
||||
|
||||
return gradLayer;
|
||||
}
|
||||
|
||||
@@ -436,34 +473,29 @@
|
||||
- (IJSVGGradientLayer *)gradientLayerForLayer:(IJSVGShapeLayer *)layer
|
||||
gradient:(IJSVGGradient *)gradient
|
||||
fromNode:(IJSVGNode *)path
|
||||
objectRect:(CGRect)objectRect
|
||||
shouldMask:(BOOL)shouldMask
|
||||
{
|
||||
// add the mask
|
||||
IJSVGShapeLayer * mask = [self layerMaskFromLayer:layer
|
||||
fromNode:path];
|
||||
|
||||
// the gradient drawing layer
|
||||
IJSVGGradientLayer * gradLayer = [[[IJSVGGradientLayer alloc] init] autorelease];
|
||||
gradLayer.frame = CGPathGetBoundingBox(((IJSVGShapeLayer *)layer).path);
|
||||
gradLayer.viewBox = self.viewBox;
|
||||
gradLayer.frame = layer.bounds;
|
||||
gradLayer.gradient = gradient;
|
||||
gradLayer.mask = mask;
|
||||
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;
|
||||
}
|
||||
|
||||
// display it
|
||||
[gradLayer setNeedsDisplay];
|
||||
|
||||
if(path.fillGradient.units == IJSVGUnitUserSpaceOnUse) {
|
||||
// move back if needed
|
||||
gradLayer.frame = (CGRect){
|
||||
.size = gradLayer.frame.size,
|
||||
.origin = CGPointMake(-fabs(gradLayer.frame.origin.x),
|
||||
-fabs(gradLayer.frame.origin.y))
|
||||
};
|
||||
}
|
||||
|
||||
gradLayer.masksToBounds = YES;
|
||||
return gradLayer;
|
||||
}
|
||||
|
||||
@@ -485,10 +517,10 @@
|
||||
CGRect bounds = CGPathGetBoundingBox(layer.path);
|
||||
bounds = [self correctBounds:bounds forStrokedPath:path];
|
||||
patternLayer.frame = bounds;
|
||||
patternLayer.masksToBounds = YES;
|
||||
|
||||
// display
|
||||
[patternLayer setNeedsDisplay];
|
||||
|
||||
return patternLayer;
|
||||
}
|
||||
|
||||
@@ -513,6 +545,7 @@
|
||||
|
||||
// display
|
||||
[patternLayer setNeedsDisplay];
|
||||
patternLayer.masksToBounds = YES;
|
||||
|
||||
return patternLayer;
|
||||
}
|
||||
@@ -551,7 +584,7 @@
|
||||
}
|
||||
|
||||
- (IJSVGStrokeLayer *)strokeLayer:(IJSVGShapeLayer *)layer
|
||||
fromNode:(IJSVGNode *)path
|
||||
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
|
||||
@@ -742,4 +775,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
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
@interface IJSVGLinearGradient : IJSVGGradient
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGLinearGradient *)aGradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint;
|
||||
gradient:(IJSVGLinearGradient *)aGradient;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
+ (NSGradient *)parseGradient:(NSXMLElement *)element
|
||||
gradient:(IJSVGLinearGradient *)aGradient
|
||||
startPoint:(CGPoint *)startPoint
|
||||
endPoint:(CGPoint *)endPoint
|
||||
{
|
||||
|
||||
CGFloat px1 = [[element attributeForName:@"x1"] stringValue].floatValue;
|
||||
@@ -25,10 +23,8 @@
|
||||
// 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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -55,39 +51,56 @@
|
||||
// create the gradient with the colours
|
||||
NSGradient * grad = [[NSGradient alloc] initWithColors:colors
|
||||
atLocations:stopsParams
|
||||
colorSpace:[NSColorSpace genericRGBColorSpace]];
|
||||
colorSpace:IJSVGColor.defaultColorSpace];
|
||||
|
||||
free(stopsParams);
|
||||
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 absTransform = absoluteTransform;
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
// convert the nsgradient to a CGGradient
|
||||
CGGradientRef gRef = [self CGGradient];
|
||||
|
||||
// apply transform for each point
|
||||
for( IJSVGTransform * transform in self.transforms ) {
|
||||
CGAffineTransform trans = transform.CGAffineTransform;
|
||||
aStartPoint = CGPointApplyAffineTransform(aStartPoint, trans);
|
||||
aEndPoint = CGPointApplyAffineTransform(aEndPoint, trans);
|
||||
#pragma mark User Space On Use
|
||||
if(inUserSpace == YES) {
|
||||
CGFloat width = CGRectGetWidth(viewBox);
|
||||
CGFloat height = CGRectGetHeight(viewBox);
|
||||
gradientStartPoint = CGPointMake([self.x1 computeValue:width],
|
||||
[self.y1 computeValue:height]);
|
||||
|
||||
gradientEndPoint = CGPointMake([self.x2 computeValue:width],
|
||||
[self.y2 computeValue:height]);
|
||||
|
||||
// transform absolute - due to user space
|
||||
CGContextConcatCTM(ctx, absTransform);
|
||||
} else {
|
||||
#pragma mark Object Bounding Box
|
||||
CGFloat width = CGRectGetWidth(objectRect);
|
||||
CGFloat height = CGRectGetHeight(objectRect);
|
||||
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);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@class IJSVGGradient;
|
||||
@class IJSVGGroup;
|
||||
@class IJSVGPattern;
|
||||
@class IJSVGTransform;
|
||||
|
||||
typedef NS_ENUM( NSInteger, IJSVGNodeType ) {
|
||||
IJSVGNodeTypeGroup,
|
||||
@@ -120,12 +121,13 @@ 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;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "IJSVGNode.h"
|
||||
#import "IJSVGDef.h"
|
||||
#import "IJSVGUtils.h"
|
||||
|
||||
@implementation IJSVGNode
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
@synthesize opacity;
|
||||
@synthesize identifier;
|
||||
@synthesize parentNode;
|
||||
@synthesize intermediateParentNode;
|
||||
@synthesize transforms;
|
||||
@synthesize windingRule;
|
||||
@synthesize def;
|
||||
@@ -131,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;
|
||||
}
|
||||
|
||||
@@ -138,6 +146,7 @@
|
||||
{
|
||||
if( ( self = [self initWithDef:YES] ) != nil )
|
||||
{
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:1];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -206,6 +215,7 @@
|
||||
{
|
||||
self.opacity = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
self.fillOpacity = [IJSVGUnitLength unitWithFloat:1.f];
|
||||
self.fillOpacity.inherit = YES;
|
||||
|
||||
self.strokeDashOffset = [IJSVGUnitLength unitWithFloat:0.f];
|
||||
self.shouldRender = YES;
|
||||
@@ -233,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;
|
||||
}
|
||||
|
||||
@@ -248,7 +260,7 @@
|
||||
// winding rule can inherit..
|
||||
- (IJSVGWindingRule)windingRule
|
||||
{
|
||||
if( windingRule == IJSVGWindingRuleInherit && parentNode != nil ) {
|
||||
if(windingRule == IJSVGWindingRuleInherit && parentNode != nil) {
|
||||
return parentNode.windingRule;
|
||||
}
|
||||
return windingRule;
|
||||
@@ -256,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;
|
||||
}
|
||||
@@ -327,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject
|
||||
NSMutableDictionary * _defNodes;
|
||||
NSMutableDictionary * _baseDefNodes;
|
||||
NSMutableArray<IJSVG *> * _svgs;
|
||||
NSMutableArray * _definedGroups;
|
||||
|
||||
struct {
|
||||
unsigned int shouldHandleForeignObject: 1;
|
||||
@@ -106,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;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
[_parsedNodes release], _parsedNodes = nil;
|
||||
[_defNodes release], _defNodes = nil;
|
||||
[_baseDefNodes release], _baseDefNodes = nil;
|
||||
[_definedGroups release], _definedGroups = nil;
|
||||
[_svgs release], _svgs = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -115,6 +116,18 @@
|
||||
|
||||
}
|
||||
|
||||
+ (BOOL)isDataSVG:(NSData *)data
|
||||
{
|
||||
@try {
|
||||
NSError * error;
|
||||
NSXMLDocument * doc = [[[NSXMLDocument alloc] initWithData:data
|
||||
options:0
|
||||
error:&error] autorelease];
|
||||
return doc != nil && error == nil;
|
||||
} @catch(NSException * exception) {}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id)initWithFileURL:(NSURL *)aURL
|
||||
error:(NSError **)error
|
||||
delegate:(id<IJSVGParserDelegate>)delegate
|
||||
@@ -139,10 +152,11 @@
|
||||
- (void *)_handleErrorWithCode:(NSUInteger)code
|
||||
error:(NSError **)error
|
||||
{
|
||||
if( error )
|
||||
if( error ) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:code
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
[_document release], _document = nil;
|
||||
[self release], self = nil;
|
||||
return nil;
|
||||
@@ -156,12 +170,12 @@
|
||||
|
||||
// check the viewbox
|
||||
if( NSEqualRects( self.viewBox, NSZeroRect ) ||
|
||||
self.size.width == 0 || self.size.height == 0 )
|
||||
{
|
||||
if( error != NULL )
|
||||
self.size.width == 0 || self.size.height == 0 ) {
|
||||
if( error != NULL ) {
|
||||
*error = [[[NSError alloc] initWithDomain:IJSVGErrorDomain
|
||||
code:IJSVGErrorInvalidViewBox
|
||||
userInfo:nil] autorelease];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
@@ -178,26 +192,25 @@
|
||||
|
||||
// parse common attributes on the SVG element
|
||||
[self _parseElementForCommonAttributes:svgElement
|
||||
node:self];
|
||||
node:self
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// find the sizebox!
|
||||
NSXMLNode * attribute = nil;
|
||||
if( ( attribute = [svgElement attributeForName:(NSString *)IJSVGAttributeViewBox] ) != nil ) {
|
||||
|
||||
// we have a viewbox...
|
||||
CGFloat * box = [IJSVGUtils parseViewBox:[attribute stringValue]];
|
||||
viewBox = NSMakeRect( box[0], box[1], box[2], box[3]);
|
||||
free(box);
|
||||
|
||||
} else {
|
||||
|
||||
// there is no view box so find the width and height
|
||||
CGFloat w = [[[svgElement attributeForName:(NSString *)IJSVGAttributeWidth] stringValue] floatValue];
|
||||
CGFloat h = [[[svgElement attributeForName:(NSString *)IJSVGAttributeHeight] stringValue] floatValue];
|
||||
if( h == 0.f && w != 0.f )
|
||||
if( h == 0.f && w != 0.f ) {
|
||||
h = w;
|
||||
else if( w == 0.f && h != 0.f )
|
||||
} else if( w == 0.f && h != 0.f ) {
|
||||
w = h;
|
||||
}
|
||||
viewBox = NSMakeRect( 0.f, 0.f, w, h );
|
||||
}
|
||||
|
||||
@@ -212,7 +225,7 @@
|
||||
} else if( h == 0 && w != 0.f ) {
|
||||
h = viewBox.size.height;
|
||||
}
|
||||
proposedViewSize = NSMakeSize( w, h );
|
||||
proposedViewSize = NSMakeSize(w, h);
|
||||
|
||||
// the root element is SVG, so iterate over its children
|
||||
// recursively
|
||||
@@ -224,7 +237,8 @@
|
||||
// now everything has been done we need to compute the style tree
|
||||
for(NSDictionary * dict in _parsedNodes) {
|
||||
[self _postParseElementForCommonAttributes:dict[@"element"]
|
||||
node:dict[@"node"]];
|
||||
node:dict[@"node"]
|
||||
ignoreAttributes:nil];
|
||||
}
|
||||
|
||||
// dont need the style sheet or the parsed nodes as this point
|
||||
@@ -235,6 +249,7 @@
|
||||
|
||||
- (void)_postParseElementForCommonAttributes:(NSXMLElement *)element
|
||||
node:(IJSVGNode *)node
|
||||
ignoreAttributes:(NSArray *)ignoredAttributes
|
||||
{
|
||||
|
||||
// first of all, compute a style sheet
|
||||
@@ -244,8 +259,11 @@
|
||||
// attribute helpers
|
||||
typedef void (^cp)(NSString *);
|
||||
void (^attr)(const NSString *, cp) = ^(NSString * key, cp block) {
|
||||
NSString * v = [element attributeForName:key].stringValue
|
||||
?: [style property:key];
|
||||
if([ignoredAttributes containsObject:key]) {
|
||||
return;
|
||||
}
|
||||
NSString * v = [style property:key] ?:
|
||||
[element attributeForName:key].stringValue;
|
||||
if(v != nil && v.length != 0) {
|
||||
block(v);
|
||||
}
|
||||
@@ -397,12 +415,15 @@
|
||||
node.fillPattern = (IJSVGPattern *)obj;
|
||||
}
|
||||
} else {
|
||||
// its a color
|
||||
node.fillColor = [IJSVGColor colorFromString:value];
|
||||
if(node.fillOpacity.value != 1.f) {
|
||||
node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor
|
||||
to:node.fillOpacity.value];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// fill opacity
|
||||
attr(IJSVGAttributeFillOpacity, ^(NSString * value) {
|
||||
if(node.fillOpacity.value != 1.f) {
|
||||
node.fillColor = [IJSVGColor changeAlphaOnColor:node.fillColor
|
||||
to:node.fillOpacity.value];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -425,22 +446,34 @@
|
||||
}
|
||||
|
||||
- (id)definedObjectForID:(NSString *)anID
|
||||
xmlElement:(NSXMLElement **)element
|
||||
{
|
||||
// check base def nodes first, then check rest of document
|
||||
NSXMLElement * parseElement = _baseDefNodes[anID] ?: _defNodes[anID];
|
||||
if(parseElement != nil) {
|
||||
// parse the element
|
||||
IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease];
|
||||
|
||||
// parse the block
|
||||
if(element != nil && element != NULL) {
|
||||
*element = parseElement;
|
||||
}
|
||||
IJSVGGroup * group = [[[IJSVGGroup alloc] init] autorelease];
|
||||
[self _parseBaseBlock:parseElement
|
||||
intoGroup:group
|
||||
def:NO];
|
||||
if(_definedGroups == nil) {
|
||||
_definedGroups = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[_definedGroups addObject:group];
|
||||
return [group defForID:anID];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)definedObjectForID:(NSString *)anID
|
||||
{
|
||||
return [self definedObjectForID:anID
|
||||
xmlElement:nil];
|
||||
}
|
||||
|
||||
- (BOOL)isFont
|
||||
{
|
||||
return [_glyphs count] != 0;
|
||||
@@ -476,9 +509,11 @@
|
||||
|
||||
- (void)_parseElementForCommonAttributes:(NSXMLElement *)element
|
||||
node:(IJSVGNode *)node
|
||||
ignoreAttributes:(NSArray *)ignoredAttributes
|
||||
{
|
||||
[self _postParseElementForCommonAttributes:element
|
||||
node:node];
|
||||
node:node
|
||||
ignoreAttributes:ignoredAttributes];
|
||||
}
|
||||
|
||||
- (void)_setupDefaultsForNode:(IJSVGNode *)node
|
||||
@@ -511,7 +546,7 @@
|
||||
|
||||
for(NSXMLElement * element in anElement.children) {
|
||||
// not a def
|
||||
if([IJSVGNode typeForString:element.name
|
||||
if([IJSVGNode typeForString:element.localName
|
||||
kind:element.kind] != IJSVGNodeTypeDef) {
|
||||
continue;
|
||||
}
|
||||
@@ -519,7 +554,7 @@
|
||||
// store each object
|
||||
for(NSXMLElement * childDef in element.children) {
|
||||
// is there any stylesheets within this?
|
||||
IJSVGNodeType childType = [IJSVGNode typeForString:childDef.name
|
||||
IJSVGNodeType childType = [IJSVGNode typeForString:childDef.localName
|
||||
kind:element.kind];
|
||||
|
||||
switch(childType) {
|
||||
@@ -552,7 +587,7 @@
|
||||
intoGroup:(IJSVGGroup *)parentGroup
|
||||
def:(BOOL)flag
|
||||
{
|
||||
NSString * subName = element.name;
|
||||
NSString * subName = element.localName;
|
||||
NSXMLNodeKind nodeKind = element.kind;
|
||||
IJSVGNodeType aType = [IJSVGNode typeForString:subName
|
||||
kind:nodeKind];
|
||||
@@ -579,15 +614,21 @@
|
||||
// sub SVG
|
||||
case IJSVGNodeTypeSVG: {
|
||||
|
||||
IJSVGPath * path = [[[IJSVGPath alloc] init] autorelease];
|
||||
IJSVGGroup * path = [[[IJSVGGroup alloc] init] autorelease];
|
||||
path.type = aType;
|
||||
path.name = subName;
|
||||
path.parentNode = parentGroup;
|
||||
|
||||
// grab common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// if its a sub svg, we can remove the attributes for x and y
|
||||
// this is required or it could go out of bounds before the exporter
|
||||
// hits the layers from the groups :)
|
||||
[element removeAttributeForName:@"x"];
|
||||
[element removeAttributeForName:@"y"];
|
||||
|
||||
// work out the SVG
|
||||
NSError * error = nil;
|
||||
@@ -632,7 +673,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// pass the commands for it
|
||||
[self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue]
|
||||
@@ -673,7 +715,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:group];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:group];
|
||||
node:group
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// recursively parse blocks
|
||||
[self _parseBlock:element
|
||||
@@ -699,7 +742,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parsePathCommandData:[[element attributeForName:(NSString *)IJSVGAttributeD] stringValue]
|
||||
intoPath:path];
|
||||
|
||||
@@ -721,7 +765,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parsePolygon:element
|
||||
intoPath:path];
|
||||
[parentGroup addDef:path];
|
||||
@@ -743,7 +788,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parsePolyline:element
|
||||
intoPath:path];
|
||||
[parentGroup addDef:path];
|
||||
@@ -767,7 +813,8 @@
|
||||
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:@[@"x",@"y"]];
|
||||
[parentGroup addDef:path];
|
||||
break;
|
||||
}
|
||||
@@ -785,7 +832,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parseLine:element
|
||||
intoPath:path];
|
||||
[parentGroup addDef:path];
|
||||
@@ -807,7 +855,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parseCircle:element
|
||||
intoPath:path];
|
||||
[parentGroup addDef:path];
|
||||
@@ -828,7 +877,8 @@
|
||||
// find common attributes
|
||||
[self _setupDefaultsForNode:path];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:path];
|
||||
node:path
|
||||
ignoreAttributes:nil];
|
||||
[self _parseEllipse:element
|
||||
intoPath:path];
|
||||
[parentGroup addDef:path];
|
||||
@@ -842,18 +892,41 @@
|
||||
NSString * xlinkID = [xlink substringFromIndex:1];
|
||||
IJSVGNode * node = [self definedObjectForID:xlinkID];
|
||||
|
||||
// there was no specified link ID, well, not that we could find,
|
||||
// so just break
|
||||
if(node == nil) {
|
||||
break;
|
||||
}
|
||||
|
||||
// due to this being a carbon clone, we need to clear the ID
|
||||
if([element attributeForName:(NSString *)IJSVGAttributeID] == nil) {
|
||||
node.identifier = nil;
|
||||
}
|
||||
|
||||
node.parentNode = parentGroup;
|
||||
// at this point, we need to create another group!
|
||||
IJSVGGroup * subGroup = [[[IJSVGGroup alloc] init] autorelease];
|
||||
subGroup.parentNode = parentGroup;
|
||||
[subGroup addChild:node];
|
||||
node.parentNode = subGroup;
|
||||
node.intermediateParentNode = subGroup;
|
||||
|
||||
// is there a width and height?
|
||||
CGFloat x = [element attributeForName:(NSString *)IJSVGAttributeX].stringValue.floatValue;
|
||||
CGFloat y = [element attributeForName:(NSString *)IJSVGAttributeY].stringValue.floatValue;
|
||||
|
||||
// we need to add a transform to the subgroup
|
||||
subGroup.transforms = @[[IJSVGTransform transformByTranslatingX:x y:y]];
|
||||
|
||||
if(!flag) {
|
||||
[parentGroup addChild:node];
|
||||
[parentGroup addChild:subGroup];
|
||||
}
|
||||
|
||||
// parse attributes from element onto group - but spec
|
||||
// says ignore x, y, width, height and xlink:href...
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:node];
|
||||
node:node
|
||||
ignoreAttributes:@[@"x",@"y",@"width",
|
||||
@"height",@"xlink:href"]];
|
||||
|
||||
[parentGroup addDef:node];
|
||||
break;
|
||||
@@ -864,43 +937,36 @@
|
||||
|
||||
NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue];
|
||||
NSString * xlinkID = [xlink substringFromIndex:1];
|
||||
IJSVGNode * node = [self definedObjectForID:xlinkID];
|
||||
NSXMLElement * referenceElement;
|
||||
IJSVGNode * node = [self definedObjectForID:xlinkID
|
||||
xmlElement:&referenceElement];
|
||||
if( node != nil ) {
|
||||
// we are a clone
|
||||
NSXMLElement * elementCopy = [self mergedElement:element
|
||||
withReferenceElement:referenceElement];
|
||||
|
||||
IJSVGLinearGradient * grad = [[[IJSVGLinearGradient alloc] init] autorelease];
|
||||
grad.type = aType;
|
||||
[grad applyPropertiesFromNode:node];
|
||||
|
||||
grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease];
|
||||
CGPoint startPoint, endPoint;
|
||||
[IJSVGLinearGradient parseGradient:element
|
||||
gradient:grad
|
||||
startPoint:&startPoint
|
||||
endPoint:&endPoint];
|
||||
grad.gradient = [IJSVGLinearGradient parseGradient:elementCopy
|
||||
gradient:grad];
|
||||
|
||||
[self _setupDefaultsForNode:grad];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:grad];
|
||||
grad.startPoint = startPoint;
|
||||
grad.endPoint = endPoint;
|
||||
[self _parseElementForCommonAttributes:elementCopy
|
||||
node:grad
|
||||
ignoreAttributes:nil];
|
||||
[parentGroup addDef:grad];
|
||||
break;
|
||||
}
|
||||
|
||||
IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease];
|
||||
gradient.type = aType;
|
||||
|
||||
CGPoint startPoint, endPoint;
|
||||
gradient.gradient = [IJSVGLinearGradient parseGradient:element
|
||||
gradient:gradient
|
||||
startPoint:&startPoint
|
||||
endPoint:&endPoint];
|
||||
gradient:gradient];
|
||||
|
||||
[self _setupDefaultsForNode:gradient];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:gradient];
|
||||
gradient.startPoint = startPoint;
|
||||
gradient.endPoint = endPoint;
|
||||
node:gradient
|
||||
ignoreAttributes:nil];
|
||||
[parentGroup addDef:gradient];
|
||||
break;
|
||||
}
|
||||
@@ -910,44 +976,37 @@
|
||||
|
||||
NSString * xlink = [[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue];
|
||||
NSString * xlinkID = [xlink substringFromIndex:1];
|
||||
IJSVGNode * node = [self definedObjectForID:xlinkID];
|
||||
if( node != nil )
|
||||
{
|
||||
NSXMLElement * referenceElement;
|
||||
IJSVGNode * node = [self definedObjectForID:xlinkID
|
||||
xmlElement:&referenceElement];
|
||||
if( node != nil ) {
|
||||
// we are a clone
|
||||
IJSVGRadialGradient * grad = [[[IJSVGRadialGradient alloc] init] autorelease];
|
||||
grad.type = aType;
|
||||
[grad applyPropertiesFromNode:node];
|
||||
grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease];
|
||||
|
||||
CGPoint startPoint, endPoint;
|
||||
[IJSVGRadialGradient parseGradient:element
|
||||
gradient:grad
|
||||
startPoint:&startPoint
|
||||
endPoint:&endPoint];
|
||||
NSXMLElement * elementCopy = [self mergedElement:element
|
||||
withReferenceElement:referenceElement];
|
||||
|
||||
grad.gradient = [IJSVGRadialGradient parseGradient:elementCopy
|
||||
gradient:grad];
|
||||
|
||||
[self _setupDefaultsForNode:grad];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:grad];
|
||||
grad.startPoint = startPoint;
|
||||
grad.endPoint = endPoint;
|
||||
[self _parseElementForCommonAttributes:elementCopy
|
||||
node:grad
|
||||
ignoreAttributes:nil];
|
||||
[parentGroup addDef:grad];
|
||||
break;
|
||||
}
|
||||
|
||||
IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease];
|
||||
gradient.type = aType;
|
||||
|
||||
CGPoint startPoint, endPoint;
|
||||
gradient.gradient = [IJSVGRadialGradient parseGradient:element
|
||||
gradient:gradient
|
||||
startPoint:&startPoint
|
||||
endPoint:&endPoint];
|
||||
gradient.startPoint = startPoint;
|
||||
gradient.endPoint = endPoint;
|
||||
gradient:gradient];
|
||||
|
||||
[self _setupDefaultsForNode:gradient];
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:gradient];
|
||||
node:gradient
|
||||
ignoreAttributes:nil];
|
||||
[parentGroup addDef:gradient];
|
||||
break;
|
||||
}
|
||||
@@ -964,7 +1023,8 @@
|
||||
|
||||
// find common attributes
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:group];
|
||||
node:group
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// recursively parse blocks
|
||||
[self _parseBlock:element
|
||||
@@ -982,7 +1042,8 @@
|
||||
|
||||
// find common attributes
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:pattern];
|
||||
node:pattern
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// pattern has children
|
||||
[self _parseBlock:element
|
||||
@@ -1001,7 +1062,8 @@
|
||||
|
||||
// find common attributes
|
||||
[self _parseElementForCommonAttributes:element
|
||||
node:image];
|
||||
node:image
|
||||
ignoreAttributes:nil];
|
||||
|
||||
// from base64
|
||||
[image loadFromBase64EncodedString:[[element attributeForName:(NSString *)IJSVGAttributeXLink] stringValue]];
|
||||
@@ -1015,6 +1077,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSXMLElement *)mergedElement:(NSXMLElement *)element
|
||||
withReferenceElement:(NSXMLElement *)reference
|
||||
{
|
||||
NSXMLElement * copy = [[reference copy] autorelease];
|
||||
for(NSXMLNode * attribute in element.attributes) {
|
||||
[copy removeAttributeForName:attribute.name];
|
||||
attribute = [[attribute copy] autorelease];
|
||||
[copy addAttribute:attribute];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (void)_parseBlock:(NSXMLElement *)anElement
|
||||
intoGroup:(IJSVGGroup*)parentGroup
|
||||
def:(BOOL)flag
|
||||
@@ -1044,16 +1118,14 @@
|
||||
NSUInteger len = [command length];
|
||||
|
||||
// allocate memory for the string buffer for reading
|
||||
unichar * buffer = (unichar *)calloc( len+1, sizeof(unichar));
|
||||
[command getCharacters:buffer
|
||||
range:NSMakeRange(0, len)];
|
||||
const char * buffer = [command cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
int defaultBufferSize = 200;
|
||||
int currentBufferSize = 0;
|
||||
int currentSize = defaultBufferSize;
|
||||
|
||||
unichar * commandBuffer = NULL;
|
||||
if( len != 0 ) {
|
||||
if(len != 0) {
|
||||
commandBuffer = (unichar *)calloc(defaultBufferSize,sizeof(unichar));
|
||||
}
|
||||
|
||||
@@ -1061,17 +1133,18 @@
|
||||
for( int i = 0; i < len; i++ ) {
|
||||
unichar currentChar = buffer[i];
|
||||
unichar nextChar = buffer[i+1];
|
||||
|
||||
BOOL atEnd = i == len-1;
|
||||
BOOL isStartCommand = IJSVGIsLegalCommandCharacter(nextChar);
|
||||
if( ( currentBufferSize + 1 ) == currentSize ) {
|
||||
currentSize += defaultBufferSize;
|
||||
commandBuffer = (unichar *)realloc( commandBuffer, sizeof(unichar)*currentSize);
|
||||
commandBuffer = (unichar *)realloc(commandBuffer, sizeof(unichar)*currentSize);
|
||||
}
|
||||
commandBuffer[currentBufferSize++] = currentChar;
|
||||
if( isStartCommand || atEnd ) {
|
||||
if(isStartCommand == YES || atEnd == YES) {
|
||||
NSString * commandString = [NSString stringWithCharacters:commandBuffer
|
||||
length:currentBufferSize];
|
||||
|
||||
|
||||
// previous command is actual subcommand
|
||||
IJSVGCommand * previousCommand = [_currentCommand subCommands].lastObject;
|
||||
IJSVGCommand * cCommand = [self _parseCommandString:commandString
|
||||
@@ -1083,19 +1156,15 @@
|
||||
_currentCommand = cCommand;
|
||||
}
|
||||
|
||||
free(commandBuffer);
|
||||
commandBuffer = NULL;
|
||||
|
||||
if( !atEnd ) {
|
||||
if(atEnd == NO) {
|
||||
currentBufferSize = 0;
|
||||
currentSize = defaultBufferSize;
|
||||
commandBuffer = (unichar *)calloc(defaultBufferSize,sizeof(unichar));
|
||||
memset(commandBuffer,'\0', sizeof(unichar)*currentSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free the buffer
|
||||
free(buffer);
|
||||
free(commandBuffer);
|
||||
}
|
||||
|
||||
- (IJSVGCommand *)_parseCommandString:(NSString *)string
|
||||
@@ -1188,8 +1257,7 @@
|
||||
NSInteger count = 0;
|
||||
CGFloat * params = [IJSVGUtils commandParameters:points
|
||||
count:&count];
|
||||
if( (count % 2) != 0 )
|
||||
{
|
||||
if( (count % 2) != 0 ) {
|
||||
// error occured, free the params
|
||||
free(params);
|
||||
return;
|
||||
@@ -1198,12 +1266,12 @@
|
||||
// construct a command
|
||||
NSMutableString * str = [[[NSMutableString alloc] init] autorelease];
|
||||
[str appendFormat:@"M%f,%f L",params[0],params[1]];
|
||||
for( NSInteger i = 2; i < count; i+=2 )
|
||||
{
|
||||
for( NSInteger i = 2; i < count; i+=2 ) {
|
||||
[str appendFormat:@"%f,%f ",params[i],params[i+1]];
|
||||
}
|
||||
if( closePath )
|
||||
if( closePath ) {
|
||||
[str appendString:@"z"];
|
||||
}
|
||||
[self _parsePathCommandData:str
|
||||
intoPath:path];
|
||||
free(params);
|
||||
@@ -1213,86 +1281,33 @@
|
||||
- (void)_parseRect:(NSXMLElement *)element
|
||||
intoPath:(IJSVGPath *)path
|
||||
{
|
||||
CGFloat aX, aY, aWidth, aHeight;
|
||||
if([self namespacedAttribute:(NSString *)IJSVGAttributeX
|
||||
element:element] != nil) {
|
||||
|
||||
// already namespaced, find them
|
||||
aX = [[self namespacedAttribute:(NSString *)IJSVGAttributeX
|
||||
element:element] floatValue];
|
||||
aY = [[self namespacedAttribute:(NSString *)IJSVGAttributeY
|
||||
element:element] floatValue];
|
||||
aWidth = [IJSVGUtils floatValue:[self namespacedAttribute:(NSString *)IJSVGAttributeWidth
|
||||
element:element]
|
||||
fallBackForPercent:self.viewBox.size.width];
|
||||
aHeight = [IJSVGUtils floatValue:[self namespacedAttribute:(NSString *)IJSVGAttributeHeight
|
||||
element:element]
|
||||
fallBackForPercent:self.viewBox.size.height];
|
||||
} else {
|
||||
|
||||
// reassign X
|
||||
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeX
|
||||
value:[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue]
|
||||
element:element];
|
||||
aX = [[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue] floatValue];
|
||||
|
||||
// reassign Y
|
||||
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeY
|
||||
value:[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue]
|
||||
element:element];
|
||||
aY = [[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue] floatValue];
|
||||
|
||||
// reassign width
|
||||
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeWidth
|
||||
value:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
|
||||
element:element];
|
||||
aWidth = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.width];
|
||||
|
||||
// reassign height
|
||||
[self applyNamespacedAttribute:(NSString *)IJSVGAttributeHeight
|
||||
value:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
|
||||
element:element];
|
||||
aHeight = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.height];
|
||||
|
||||
// set the namespaced versions as we need to remove the attributes
|
||||
[element removeAttributeForName:(NSString *)IJSVGAttributeX];
|
||||
[element removeAttributeForName:(NSString *)IJSVGAttributeY];
|
||||
[element removeAttributeForName:(NSString *)IJSVGAttributeWidth];
|
||||
[element removeAttributeForName:(NSString *)IJSVGAttributeHeight];
|
||||
}
|
||||
|
||||
CGFloat rX = [[[element attributeForName:(NSString *)IJSVGAttributeRX] stringValue] floatValue];
|
||||
CGFloat rY = [[[element attributeForName:(NSString *)IJSVGAttributeRY] stringValue] floatValue];
|
||||
if( [element attributeForName:(NSString *)IJSVGAttributeRY] == nil ) {
|
||||
// width and height
|
||||
CGFloat width = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeWidth] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.width];
|
||||
|
||||
|
||||
CGFloat height = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeHeight] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.height];
|
||||
|
||||
|
||||
// rect uses x and y as start of path, not move path object -_-
|
||||
CGFloat x = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeX] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.width];
|
||||
CGFloat y = [IJSVGUtils floatValue:[[element attributeForName:(NSString *)IJSVGAttributeY] stringValue]
|
||||
fallBackForPercent:self.viewBox.size.height];
|
||||
|
||||
// radius
|
||||
CGFloat rX = [element attributeForName:(NSString *)IJSVGAttributeRX].stringValue.floatValue;
|
||||
CGFloat rY = [element attributeForName:(NSString *)IJSVGAttributeRY].stringValue.floatValue;
|
||||
if([element attributeForName:(NSString *)IJSVGAttributeRY] == nil) {
|
||||
rY = rX;
|
||||
}
|
||||
|
||||
[path overwritePath:[NSBezierPath bezierPathWithRoundedRect:NSMakeRect( aX, aY, aWidth, aHeight)
|
||||
xRadius:rX
|
||||
yRadius:rY]];
|
||||
}
|
||||
|
||||
- (NSString *)namespacedAttribute:(NSString *)key
|
||||
element:(NSXMLElement *)element
|
||||
{
|
||||
key = [NSString stringWithFormat:@"ij-svg:%@",key];
|
||||
if([element attributeForName:key] != nil) {
|
||||
return [[element attributeForName:key] stringValue];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)applyNamespacedAttribute:(NSString *)key
|
||||
value:(NSString *)value
|
||||
element:(NSXMLElement *)element
|
||||
{
|
||||
key = [NSString stringWithFormat:@"ij-svg:%@",key];
|
||||
NSXMLNode * node = [[[NSXMLNode alloc] initWithKind:NSXMLAttributeKind] autorelease];
|
||||
node.name = key;
|
||||
node.stringValue= value;
|
||||
[element addAttribute:node];
|
||||
NSBezierPath * newPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect( x, y, width, height)
|
||||
xRadius:rX
|
||||
yRadius:rY];
|
||||
[path overwritePath:newPath];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
{
|
||||
if((self = [super init]) != nil) {
|
||||
self.requiresBackingScaleHelp = YES;
|
||||
self.shouldRasterize = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,123 +34,134 @@
|
||||
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];
|
||||
} else {
|
||||
unit = [IJSVGUnitLength unitWithPercentageFloat:50];
|
||||
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;
|
||||
gradient.fx = gradient.cx;
|
||||
gradient.fy = gradient.cy;
|
||||
|
||||
// needs fixing
|
||||
NSString * fx = [element attributeForName:@"fx"].stringValue;
|
||||
if(fx != nil) {
|
||||
if(fx.floatValue < 1.f) {
|
||||
gradient.fx = [IJSVGUnitLength unitWithPercentageString:fx];
|
||||
} else {
|
||||
gradient.fx = [IJSVGUnitLength unitWithString:fx];
|
||||
}
|
||||
}
|
||||
|
||||
if( gradient.gradient != nil )
|
||||
NSString * fy = [element attributeForName:@"fy"].stringValue;
|
||||
if(fx != nil) {
|
||||
if(fx.floatValue < 1.f) {
|
||||
gradient.fy = [IJSVGUnitLength unitWithPercentageString:fy];
|
||||
} else {
|
||||
gradient.fy = [IJSVGUnitLength unitWithString:fy];
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
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
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
objectRect:(NSRect)objectRect
|
||||
absoluteTransform:(CGAffineTransform)absoluteTransform
|
||||
viewPort:(CGRect)viewBox
|
||||
{
|
||||
// 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;
|
||||
BOOL inUserSpace = self.units == IJSVGUnitUserSpaceOnUse;
|
||||
CGFloat radius = self.radius.value;
|
||||
CGPoint startPoint = CGPointZero;
|
||||
CGPoint gradientStartPoint = CGPointZero;
|
||||
CGPoint gradientEndPoint = CGPointZero;
|
||||
|
||||
// transforms
|
||||
CGAffineTransform selfTransform = IJSVGConcatTransforms(self.transforms);
|
||||
|
||||
#pragma mark User Space On Use
|
||||
if(inUserSpace == YES) {
|
||||
CGFloat rad = radius*2.f;
|
||||
startPoint = CGPointMake(self.cx.value, self.cy.value);
|
||||
|
||||
// work out the new radius
|
||||
CGRect rect = CGRectMake(startPoint.x, startPoint.y, rad, rad);
|
||||
rect = CGRectApplyAffineTransform(rect, selfTransform);
|
||||
rect = CGRectApplyAffineTransform(rect, absoluteTransform);
|
||||
radius = CGRectGetHeight(rect)/2.f;
|
||||
|
||||
gradientStartPoint = startPoint;
|
||||
gradientEndPoint = CGPointMake(self.fx.value, self.fy.value);
|
||||
|
||||
// apply the absolute position
|
||||
CGContextConcatCTM(ctx, absoluteTransform);
|
||||
} else {
|
||||
#pragma mark Object Bounding Box
|
||||
// compute size based on percentages
|
||||
CGFloat x = [self.cx computeValue:CGRectGetWidth(objectRect)];
|
||||
CGFloat y = [self.cy computeValue:CGRectGetHeight(objectRect)];
|
||||
startPoint = CGPointMake(x, y);
|
||||
CGFloat val = MIN(CGRectGetWidth(objectRect), CGRectGetHeight(objectRect));
|
||||
radius = [self.radius computeValue:val];
|
||||
|
||||
CGFloat ex = [self.fx computeValue:CGRectGetWidth(objectRect)];
|
||||
CGFloat ey = [self.fy computeValue:CGRectGetHeight(objectRect)];
|
||||
|
||||
gradientEndPoint = CGPointMake(ex, ey);
|
||||
gradientStartPoint = startPoint;
|
||||
|
||||
// transform if width or height is not equal
|
||||
if(CGRectGetWidth(objectRect) != CGRectGetHeight(objectRect)) {
|
||||
CGAffineTransform tr = CGAffineTransformMakeTranslation(gradientStartPoint.x,
|
||||
gradientStartPoint.y);
|
||||
if(CGRectGetWidth(objectRect) > CGRectGetHeight(objectRect)) {
|
||||
tr = CGAffineTransformScale(tr, CGRectGetWidth(objectRect)/CGRectGetHeight(objectRect), 1);
|
||||
} else {
|
||||
tr = CGAffineTransformScale(tr, 1.f, CGRectGetHeight(objectRect)/CGRectGetWidth(objectRect));
|
||||
}
|
||||
tr = CGAffineTransformTranslate(tr, -gradientStartPoint.x, -gradientStartPoint.y);
|
||||
selfTransform = CGAffineTransformConcat(tr, selfTransform);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
#pragma mark Default drawing
|
||||
// transform the context
|
||||
CGContextConcatCTM(ctx, selfTransform);
|
||||
|
||||
- (void)drawInContextRef:(CGContextRef)ctx
|
||||
rect:(NSRect)rect
|
||||
{
|
||||
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]);
|
||||
}
|
||||
|
||||
CGPoint sp = self.startPoint;
|
||||
CGPoint ep = self.endPoint;
|
||||
|
||||
if( self.startPoint.x == .5f ) {
|
||||
sp.x = bounds.size.width*self.startPoint.x;
|
||||
}
|
||||
|
||||
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);
|
||||
// draw the gradient
|
||||
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation|
|
||||
kCGGradientDrawsAfterEndLocation;
|
||||
CGContextDrawRadialGradient(ctx, self.CGGradient,
|
||||
gradientEndPoint, 0, gradientStartPoint,
|
||||
radius, options);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -23,8 +23,10 @@
|
||||
@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
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
@synthesize backingScaleFactor;
|
||||
@synthesize blendingMode;
|
||||
@synthesize convertMasksToPaths;
|
||||
@synthesize originalPathOrigin;
|
||||
@synthesize renderQuality;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
IJSVGBeginTransactionLock();
|
||||
[_maskingLayer release], _maskingLayer = nil;
|
||||
[super dealloc];
|
||||
IJSVGEndTransactionLock();
|
||||
}
|
||||
|
||||
- (void)addSublayer:(CALayer *)layer {
|
||||
@@ -154,4 +154,9 @@
|
||||
return point;
|
||||
}
|
||||
|
||||
- (id<CAAction>)actionForKey:(NSString *)event
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#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,
|
||||
@@ -35,12 +38,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
|
||||
|
||||
@@ -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;
|
||||
@@ -101,8 +146,9 @@
|
||||
{
|
||||
NSString * command = [string substringWithRange:[result rangeAtIndex:1]];
|
||||
IJSVGTransformCommand commandType = [[self class] commandForCommandString:command];
|
||||
if( commandType == IJSVGTransformCommandNotImplemented )
|
||||
if( commandType == IJSVGTransformCommandNotImplemented ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create the transform
|
||||
NSString * params = [string substringWithRange:[result rangeAtIndex:2]];
|
||||
@@ -400,6 +446,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
|
||||
{
|
||||
@@ -500,5 +559,11 @@
|
||||
return trans;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ %@",[super description],
|
||||
[self.class affineTransformToSVGTransformAttributeString:self.CGAffineTransform]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <xlocale.h>
|
||||
#import "IJSVGCommand.h"
|
||||
#import "IJSVGGradientUnitLength.h"
|
||||
|
||||
@@ -18,6 +19,12 @@ 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;
|
||||
|
||||
@@ -12,16 +12,174 @@
|
||||
|
||||
@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)
|
||||
{
|
||||
char * validChars = "MmZzLlHhVvCcSsQqTtAa";
|
||||
NSUInteger length = strlen(validChars);
|
||||
for(NSUInteger i = 0; i < length; i++) {
|
||||
if(aChar == validChars[i]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
const char * validChars = "MmZzLlHhVvCcSsQqTtAa";
|
||||
return strchr(validChars, aChar) != NULL;
|
||||
}
|
||||
|
||||
BOOL IJSVGIsSVGLayer(CALayer * layer)
|
||||
@@ -56,7 +214,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
|
||||
|
||||
+ (IJSVGCommandType)typeForCommandString:(NSString *)string
|
||||
{
|
||||
return [string isEqualToString:[string uppercaseString]] ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
|
||||
return isupper([string characterAtIndex:0]) ? IJSVGCommandTypeAbsolute : IJSVGCommandTypeRelative;
|
||||
}
|
||||
|
||||
+ (NSString *)defURL:(NSString *)string
|
||||
@@ -235,8 +393,7 @@ CGFloat degrees_to_radians( CGFloat degrees )
|
||||
+ (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;
|
||||
@@ -251,12 +408,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;
|
||||
@@ -265,6 +421,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);
|
||||
|
||||
@@ -281,7 +439,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
|
||||
@@ -318,7 +476,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;
|
||||
@@ -326,17 +484,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;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
IB_DESIGNABLE
|
||||
@interface IJSVGView : NSView {
|
||||
|
||||
IBInspectable NSString * imageName;
|
||||
IJSVG * SVG;
|
||||
IBInspectable NSColor * tintColor;
|
||||
|
||||
IJSVG * SVG;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IJSVG * SVG;
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
// image was set via IB
|
||||
if(imageName != nil) {
|
||||
IJSVG * anSVG = [IJSVG svgNamed:imageName];
|
||||
// dont need the dom, so clean it
|
||||
[anSVG discardDOM];
|
||||
if(tintColor != nil) {
|
||||
anSVG.fillColor = tintColor;
|
||||
}
|
||||
self.SVG = anSVG;
|
||||
}
|
||||
}
|
||||
|
||||