optimizing svg paths for generating themes

For discussions about programming, programming questions/advice, and projects that don't really have anything to do with Puppy.
Message
Author
User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#61 Post by technosaurus »

Yeah, we need to keep Zigbert's GPL stuff separate. We don't want to have to include the entire GPL virus with everything that uses even 1 icon (screenshots, simple web pages, etc...) A license should never be longer than the code that it licenses.

I'm also trying to convert everything into strictly relative paths, so that they can be combined or used in a layout simply by adding an offset to the first move operation (mX X) or even in a game using a really simple/crappy svg game framework. If you have any absolute paths, other than the first M, then adding an offset will really screw up the image. Repeated/similar shapes compress much better as relative paths and are easier to cut and paste for hand editing.

As an example, I put together the first 16 of the 64 I-Ching symbols using relative paths. Note that 90% of the code is repeated (== better compression)

Code: Select all

<path id="hex1"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8z"/>
<path id="hex2"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16z"/>
<path id="hex3"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-32h16v8h-16z"/>
<path id="hex4"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-32h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16z"/>
<path id="hex5"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 -48h16v8h-16zm0-32h16v8h-16z"/>
<path id="hex6"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-32h16v8h-16z"/>
<path id="hex7"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-32h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16z"/>
<path id="hex8"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-32h16v8h-16z"/>
<path id="hex9"  d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 -48h16v8h-16z"/>
<path id="hex10" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 -32h16v8h-16z"/>
<path id="hex11" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 -48h16v8h-16zm0 -16h16v8h-16zm0 -16h16v8h-16z"/>
<path id="hex12" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0 -16h16v8h-16zm0 -16h16v8h-16z"/>
<path id="hex13" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40-16h16v8h-16z"/>
<path id="hex14" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40-64h16v8h-16z"/>
<path id="hex15" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-16h16v8h-16zm0-32h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16z"/>
<path id="hex16" d="m0 2v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm0 16v8h96v-8zm40 0h16v8h-16zm0-16h16v8h-16zm0-16h16v8h-16zm0-32h16v8h-16zm0-16h16v8h-16z"/>
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
01micko
Posts: 8741
Joined: Sat 11 Oct 2008, 13:39
Location: qld
Contact:

#62 Post by 01micko »

technosaurus wrote:Yeah, we need to keep Zigbert's GPL stuff separate. We don't want to have to include the entire GPL virus with everything that uses even 1 icon (screenshots, simple web pages, etc...) A license should never be longer than the code that it licenses.
No reason we can't change the licence on the icons even though they are part of woof-ce. I'll see what ziggy thinks.
Puppy Linux Blog - contact me for access

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#63 Post by technosaurus »

I've got enough template code to start pulling out the paths

* minimizing using this: https://jakearchibald.github.io/svgomg/
* convert to relative paths using this: http://jsfiddle.net/MC53K/
* Next convert commas to spaces
* Finally convert " -" (space+minus-sign) to "-" (minus-sign)

Here is the work in progress:

Code: Select all

#!/bin/sh
#normally these would be sourced from external file(s)
icon_AtoZ="M25 32l3 24h-6l3-24zm-11-13l-8 57h15l1-10h6l1 10h15l-9-57h-21zm46 39h-12v-10h12zm30-27l-11 33h11v12h-27v-10l11-35h-11v-12h27z"
icon_AtoZ="M12 72h12l2-12h12l2 12h12l-12-48h-18zm22-24h-6l3-12zm16 0h6v3h-6zm22-12h-16v-12h30v12l-16 24h16v12h-30v-12z"
icon_calculator="M24 6v84h48v-84h-48zm6 6h36v24h-36v-24zm3 30h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6z"
icon_e2dots="M48 23c-46.5 0-40.5 88 25.5 61v-10c-20 8-43 8-43-15h46v-6c0-19-14.3-30-28.5-30zm18.5 27h-36c0-24 36-24 36 0zm5.5-37.5c0 8.5-14 8.5-14 0s14-8.5 14 0zm-34 0c0 8.5-14 8.5-14 0s14-8.5 14 0z"
icon_notepad="M66 6l18 72-48 6-18-72zm-40 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4z"
icon_pencil="M48 72l12-12 12-48-12-6-12 48z"
icon_at="M57,47c0,16,-21,16,-21,0s21,-16,21,0zm7.97,17.263c-16.97,14.737,-40.97,3.737,-40.97,-16.263c0,-30,46,-30,46,-3c0,10,-6.105,14,-13,14v-24"
icon_puppy_outline="M90 54c-2 56-82 56-84 0 0-2.9 1-6 1-9v-19c0-6 13-11 23-8 10-6 20-6 29-4h20c8 0 10 16 4 20 3 3 7 12 7 20"
icon_puppy="M90 54c-2 56-82 56-84 0 0-2.9 1-6 1-9v-19c0-6 13-11 23-8 10-6 20-6 29-4h20c8 0 10 16 4 20 3 3 7 12 7 20m-12-12a6 6 0 1 0 1 1zm-36 6a12 12 0 1 0 1 1zm-1 0a6 6 0 1 0 1 1zm18 24l12-12-24 6zq6 6 18 -6q-12 12 -18 6 q-6 12-18 6q12 6 18-6m24-38q-6 6 -8 -6t-6-12m-40 2q6 12 -18 16"
#add more paths above here: ...

#normally this would be sourced from an external config file... for themes
num_colors=2
color0="#777"
color1="#bbb"

genicon(){
local out="$1"
local color_count=0
echo '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">' >"$out.svg" 
shift
while [ "$1" ]; do
	local color=`eval echo \\${color$((color_count%num_colors))}`
	local icon=`eval echo \\${icon_$1}`
#todo add more attributes: stroke, stroke-width, opacity, etc...
	echo "	<path fill=\"${color}\" d=\"${icon}\"/>" >>"$out.svg"
	color_count=$((1+color_count))
	shift
done
echo "</svg>" >>"$out.svg"
}

#usage
genicon pencil_icon_output notepad pencil
Edit:

svgomg doesn't convert rounded rectangles to paths, so I came up with this javascript snippet

Code: Select all

<script>
	var x=10, y=10, width=80, height=70, rx=10, ry=15;
	console.log(
		'<path d="M' +x+' '+((y+ry)|0)+
		'q0-'+ry+' ' +rx+'-'+ry+'h'+((width-2*rx)|0)+
		'q'+rx+' 0 ' +rx+' '+ry+'v'+((height-2*ry)|0)+
		'q0 '+ry+'-' +rx+' '+ry+'h-'+((width-2*rx)|0)+
		'q-'+rx+' 0-'+rx+'-'+ry+'z"/>'
	);
</script>
It shouldn't be hard to convert to shell if anyone is interested
Edit2:

Code: Select all

rounded_rect(){ #example with hardcode variables
	x=10 y=10 width=80 height=70 rx=10 ry=15
	echo "<path d=\"M${x} $((y+ry))
q0-${ry} ${rx}-${ry}h$((width-2*rx))
q${rx} 0 ${rx} ${ry}v$((height-2*ry))
q0 ${ry}-${rx} ${ry}h-$((width-2*rx))
q-${rx} 0-${rx}-${ry}z\"/>"
}
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#64 Post by technosaurus »

update:

I simplified the icon generator while making it more functional "'cuz datz wut I do"

Now you can overlay multiple paths with different fill colors to combine into a single icon (I haven't dealt with strokes and gradients yet - TODO)

Since I have been converting the paths to relative (sometimes with full manual redraw) it is now possible to change the overlay position like this:

Code: Select all

#generates a rounded button with a laptop with a small warning offset 24 px to the right
genicon  "$background_rounded_rect8" "$icon_laptop" "${icon_warn/M48 48/M64 48}"  >laptop-warning.svg
Here is the progress thus far:

Code: Select all

#!/bin/ash
#normally these would be sourced from external file(s)
icon_keyboard="M6 36v24q0 6 6 6h72q6 0 6-6v-24q0-6-6-6h-72q-6 0-6 6m6 0v3h3v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m-71 6v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h9v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m-71 4v3h5v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h7v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m-71 4v3h7v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h9v-3m-57 4v3h9v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h11v-3m7 0v3h3v-3m-67 4v3h5v-3m1 0v3h4v-3m1 0v3h4v-3m1 0v3h24v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m1 0v3h4v-3m3 0v3h3v-3m1 0v3h3v-3m1 0v3h3v-3m-34-58v30"
icon_menu="M24 18a6 6 0 1 0 0 12h48a6 6 0 1 0 0 -12z
m0 24a6 6 0 1 0 0 12h48a6 6 0 1 0 0 -12zm0 24a6 6 0 1 0 0 12h48a6 6 0 1 0 0 -12z"
icon_flag_blank="M12 18q24 8 36 0t36 0v48q0-8-36 0t-36 0z"
icon_AtoZ="M12 72h12l2-12h12l2 12h12l-12-48h-18zm22-24h-6l3-12zm16-6h8v6h-8zm22-6h-16v-12h30v12l-16 24h16v12h-30v-12z"
icon_calculator="M24 6v84h48v-84h-48zm6 6h36v24h-36v-24zm3 30h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6zm-24 12h6v6h-6zm12 0h6v6h-6zm12 0h6v6h-6z"
icon_e="M32 60h48a30 36 0 1 0-6 18l-6-12a9 8 0 1 1-36-6zm2-12a12 12 0 1 1 32 0z"
icon_e2dots="M48 23c-46.5 0-40.5 88 25.5 61v-10c-20 8-43 8-43-15h46v-6c0-19-14.3-30-28.5-30zm18.5 27h-36c0-24 36-24 36 0zm5.5-37.5c0 8.5-14 8.5-14 0s14-8.5 14 0zm-34 0c0 8.5-14 8.5-14 0s14-8.5 14 0z"
icon_paper="M66 6l18 72-48 6-18-72zm-40 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4m-30 12l32-4z"
icon_pencil="M48 72l12-12 12-48-12-6-12 48z"
icon_at="M57 47c0 16 -21 16 -21 0s21-16 21 0zm8 17c-17 15 -41 4 -41-16c0 -30 46 -30 46-3c0 10-6 14-13 14v-24"
icon_puppy_outline="M90 54c-2 56-82 56-84 0 0-2.9 1-6 1-9v-19c0-6 13-11 23-8 10-6 20-6 29-4h20c8 0 10 16 4 20 3 3 7 12 7 20"
icon_puppy="M90 54c-2 56-82 56-84 0 0-2.9 1-6 1-9v-19c0-6 13-11 23-8 10-6 20-6 29-4h20c8 0 10 16 4 20 3 3 7 12 7 20m-12-12a6 6 0 1 0 1 1zm-36 6a12 12 0 1 0 1 1zm-1 0a6 6 0 1 0 1 1zm18 24l12-12-24 6zq6 6 18 -6q-12 12 -18 6 q-6 12-18 6q12 6 18-6m24-38q-6 6 -8 -6t-6-12m-40 2q6 12 -18 16"
icon_magazin="M12 24q24-8 36 0q24-8 36 0v48q0-8-36 0q0-8-36 0z"
icon_cd=d="M4 48a44 44 0 1 1 0 1zm39 1a5 5 0 1 0 0-1z"
icon_bluetooth="M48 48l-24 24 6 6 18-18 0 36 30-30-18-18 18-18-30-30 0 36-18-18-6 6zm8-8l0-19 9 9zm0 36l0-19 9 9z"
icon_umlaut="M32 6a6 6 0 1 0 1 0zm30 0a6 6 0 1 0 1 0z"
icon_X="M12 24l12-12 24 24 24-24 12 12-24 24 24 24-12 12-24-24-24 24-12-12 24-24z"
icon_triangle="M12 18v60h48zm28 50h-18v-24z"
icon_wrench="M84 72q6 0 6-6l-42-42q6 -24-18-18l8 8q0 6-6 6l-8-8q0 24 18 18z"
icon_LT_left="M28 6v12l-18 30 18 30v12l-26-42z"
icon_LT_right="M68 6v12l-18 30 18 30v12l-26-42z"
icon_GT_left="M28 6v12l18 30-18 30v12l26-42z"
icon_GT_right="M68 6v12l18 30-18 30v12l26-42z"
icon_slash="M48 6h12l-12 84h-12z"
icon_bulb="M36 68a32 32 0 1 1 24 0zv6h24v-6zh24v12h-24zv18h24v-18zm12-28q3 6 0 24z"
icon_joypad="M80 12l-24 24 24 24a12 12 0 0 1 -24 24l-42-42a12 12 0 0 1 24-24l18 18m-24-12l-4-4-4 4-4-4-4 4 4 4-4 4 4 4 4-4 4 4 4-4-4-4zm32 28a4 4 0 1 0 1 1zm8 8a4 4 0 1 0 1 1zm-8 8a4 4 0 1 0 1 1zm-8-8a4 4 0 1 0 1 1z"
icon_globe="M48 1a47 47 0 1 0 0.1 0a18 47 0 1 0 0.1 0zm-41 24h82m-88 22h94m-88 24h82"
icon_film="M14 14v68h68v-68zm6 6h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6zm50 -48h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6zm0 12h6v6h-6z"
icon_music_note="M68 29v25c0 10-16 10-17 8-1-3 3-8 11-8v-14l-18 3v17c0 10-16 11-17 8s3-8 11-8l0-26z"
icon_paperclip="M13 48l5 4l36-36c14-14 35 7 21 21l-41 41c-9 9-21-4-13-12l41-41c3-2 6 1 4 4l-36 36l5 4l36-36c8-8-5-21-13-13l-40 40c-18 18 6 37 21 22l40-40c20-20-10-50-30-30z"
icon_ribbon="M15 15q12 32 32 32t34 34l-12 8q-12-32-34-34t-28-28z"
icon_articulated_spline="M15 15q12 32 32 32t34 34l-12 8q-24-24-24-48t-24-32m-5 9l8-8m0 24l16-12m8 36l9-9m0 26l16-9"
icon_camera="M84 48c0 28-42 28-42 0s42-28 42 0zm-21-15c-7.5 0-15 5-15 15c0 20 30 20 30 0c0-10-7.5-15-15-15zm0 6c4.5 0 9 3 9 9c0 12-18 12-18 0c0-6 4.5-9 9-9zm-54-18v54h78v-54zm6 6h15v12h-15v-12z"
icon_cylinder="M24 8q24-6 48 0v80q-24 8-48 0z"
icon_reverse_cylinder_small="M30 12v12q18 6 36 0v-12q-18 -4 -36 0z"
icon_reverse_cylinder_med="M30 12v30q18 6 36 0v-30q-18 -4 -36 0z"
icon_reverse_cylinder_large="M30 12v54q18 6 36 0v-54q-18 -4 -36 0z"
icon_reverse_cylinder_max="M30 12v72q18 6 36 0v-72q-18 -4 -36 0z"
icon_laptop="M16 14h64v36h-64zm6 6v24h52v-24zm-6 32h64l6 16v4h-76v-4zm24 10l-2 5h18l-2-5z"
icon_notepad="M8 24v48h2v-48l24-6h2l-24 6v48h2v-48l24-6h2l-24 6v48h2v-48l24-6h2l-24 6q0 24 36 36l24-6q-24 0-36-36h-12l-24 6v48h12l24-6v-10q-23-9-24-32"
icon_mic="M42 12a12 12 0 0 0-24 24l12 6 48 42 10-12-42-48zl-24 24z"
icon_warn="M48 48l24 30h-48zm3 6h-6v12h6zm0 15h-6v6h6z"
icon_phone="M48 2h-12a22 46 0 1 0 0 92h6v-24a18 24 0 1 1 0-48z"
icon_key="M36 48a18 18 0 1 0 12 12l12-12 0-6 6 0 3-3 0 -4 2 0 0-2 4 0 0-4 4-4 0-12-6 0zm6 0l30-30m-36 48a6 6 0 1 1 -6 -6z"
icon_flag="M12 80v-64h6v2h-2v2h70v48h-70v16"
icon_video_cam="M36 30c0 8-12 8-12 0s12-8 12 0zm-18-12v12c0-16 24-16 24 0v-12c0-16-24-16-24 0zm24 12c0 16-24 16-24 0v48c0 16.12 24 16.406 24 0zm0-6h6v-12h24c7 0 12 5 12 12v24h-36v-12h-6"
icon_bar_top="M18 12h60v6h-60z"
icon_bar_bottom="M18 78h60v6h-60z"
icon_bar_left="M12 18h6v60h-6z"
icon_bar_right="M78 18h6v60h-6z"
icon_arrow_right="M48 30v12h-12v12h12v12l24-18z"
icon_arrow_left="M48 30v12h12v12h-12v12l-24-18z"
icon_arrow_up="M48 30l18 24h-12v12h-12v-12h-12z"
icon_arrow_down="M30 48h12v-12h12v12h12l-18 24z"
#TODO for better arrow names see https://en.wikipedia.org/wiki/Arrow_(symbol)

icon_battery_empty="$icon_cylinder$icon_reverse_cylinder_max$icon_warn"
icon_battery_low="$icon_cylinder$icon_reverse_cylinder_large"
icon_battery_med="$icon_cylinder$icon_reverse_cylinder_med"
icon_battery_high="$icon_cylinder$icon_reverse_cylinder_small"
icon_battery="$icon_cylinder"


background_touch_right="M48 96a48 48 0 0 1 0-96h48v96z"
background_touch_left="M0 0h48a48 48 0 1 1 0 96h-48z"
background_touch_top="M0 0h96v48a48 48 0 0 1-96 0z"
background_touch_bottom="M0 96h96v-48a48 48 0 0 0-96 0z"
background_circle="M0 47v1a48 48 0 1 0 0-1z"
background_rect="M0 0h96v96h-96z"
background_rounded_rect="M0 6q0-6 6-6h84q6 0 6 6v84q0 6-6 6h-84q-6 0-6-6z"
background_rounded_rect2="M0 12q0-12 12-12h72q12 0 12 12v72q0 12-12 12h-72q-12 0-12-12z"
background_rounded_rect3="M0 18q0-18 18-18h60q18 0 18 18v60q0 18-18 18h-60q-18 0-18-18z"
background_rounded_rect4="M0 24q0-24 24-24h48q24 0 24 24v48q0 24-24 24h-48q-24 0-24-24z"
background_rounded_rect5="M0 30q0-30 30-30h36q30 0 30 30v36q0 30-30 30h-36q-30 0-30-30z"
background_rounded_rect6="M0 36q0-36 36-36h24q36 0 36 36v24q0 36-36 36h-24q-36 0-36-36z"
background_rounded_rect7="M0 42q0-42 42-42h12q42 0 42 42v12q0 42-42 42h-12q-42 0-42-42z"
background_rounded_rect8="M0 45q0-45 45-45h6q45 0 45 45v6q0 45-45 45h-6q-45 0-45-45z"
background_clear_button="M0 42q0-42 42-42h12q42 0 42 42v12q0 42-42 42h-12q-42 0-42-42zM0 48a48 48 0 1 0 0-0.1z"
#add more paths above here: ...

#normally this would be sourced from an external config file... for themes
num_colors=2
color0="#777"
color1="#bbb"

genicon(){
local color_count=0
echo '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">'
while [ "$1" ]; do
	local color=`eval echo \\${color$((color_count%num_colors))}`
#todo add more attributes: stroke, stroke-width, opacity, etc...
	echo "	<path fill=\"${color}\" d=\"${1}\"/>"
	color_count=$((1+color_count))
	shift
done
echo "</svg>"
}

rounded_rect(){
	x=0 y=0 width=96 height=96 rx=45 ry=45
	echo "<path d=\"M${x} $((y+ry))
q0-${ry} ${rx}-${ry}h$((width-2*rx))
q${rx} 0 ${rx} ${ry}v$((height-2*ry))
q0 ${ry}-${rx} ${ry}h-$((width-2*rx))
q-${rx} 0-${rx}-${ry}z\"/>"
}

#usage
genicon  "$background_rounded_rect8" "$icon_laptop"  >laptop.svg
#genicon "$icon_paper" "$icon_pencil" >notes2.svg
#rounded_rect
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#65 Post by technosaurus »

I started doing some 16x8 fonts to add to the icons... so far I am up to Q/q. They all use relative paths and use a move at the end to put it into the upper right corner so that if subsequent letters get pasted to the path, they render as actual text (on our 96px icons that would be up to 4 high by 8 wide)

Just to test them out I made this SVG text generator code
usage:
text2svg "The quick brown fox jumped over the lazy dog
Hello World" > my.svg

Code: Select all

#!/bin/sh
maxlength=0
length=0
height=16
text="$1"
while [ "$text" ]; do
	length=$((length+8))
	case "$text" in
		"	"*)S="${S}m16 0";length=$((length+8));;
		" "*)S="${S}m8 0";;
		!*)S="${S}m4 2v10m0 1v1m4-14";;
		\"*)S="${S}m3 3v3m2-3v3m3-6";;
		\#*)S="${S}m2 4v8m4-8v8m-5-2h6m-6-4h6m1-6";;
		\$*)S="${S}m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m-2-3v14m2-4";;
		%*)S="${S}m2 2v1m4-1l-4 12m4-1v1m2-14";;
		\&*)S="${S}m6 4a2 2 0 1 0-3 3a3 3 0 1 0 4 4m0 2l-4-6m5-7";;
		\'*)S="${S}m4 3v3m4-6";;
		\(*)S="${S}m4 14q-3-6 0-12m4-2";;
		\)*)S="${S}m4 14q3-6 0-12m4-2";;

		0*)S="${S}m2 7a2 4 0 1 1 4 0v2a2 4 0 1 1 -4 0zm2 0v2m2-8.1";;
		1*)S="${S}m3 4l1-1v11m4-14";;
		2*)S="${S}m2 4a2 3 0 1 1 3 5l-3 4h4m2-13";;
		3*)S="${S}m2 4a2 2 0 1 1 1 3m0 0a2 3 0 1 1-1 4m6-11";;
		4*)S="${S}m2 2v6h4v6-12l2-2";;
		5*)S="${S}m2 14h2a2 2 0 1 0 -2-6v-5h4m2-3";;
		6*)S="${S}m3 8a2 3 0 1 1 -1 1l4-7m2-2";;
		7*)S="${S}m2 3h4l-4 11m6-14";;
		8*)S="${S}m3.5 7a2 2 0 1 1 1 0a2 3 0 1 1 -1 0zm4.5-7";;
		9*)S="${S}m2 14l4-6a2 3 0 1 0 -1 1m3-9";;
		A*)S="${S}m1 14l3-12l3 12m-1-4h-4m6-10";;
		B*)S="${S}m2 2a3 2 0 1 1 0 5a2.5 2 0 1 1 0 7zm6-2";;
		C*)S="${S}m6 4a2.5 6 0 1 0 0 8m2-12";;
		D*)S="${S}m2 2a4 6 0 1 1 0 12zm6-2";;
		E*)S="${S}m6 14h-4v-12h4m-4 6h3m3-8";;
		F*)S="${S}m2 14v-12h4m-4 6h3m3-8";;
		G*)S="${S}m6 4a2.5 6 0 1 0 0 8v-2h-1m3-10";;
		H*)S="${S}m2 2v12-6h4v6-12m2-2";;
		I*)S="${S}m2 2h4-2v12h2-4m6-14";;
		J*)S="${S}m4 2h2v8q0 4-4 4m6-14";;
		K*)S="${S}m2 2v12-7l4 7-4-7 4-5m2-2";;
		L*)S="${S}m2 2v12h4m2-14";;
		M*)S="${S}m2 14v-12l2 6 2-6v12m2-14";;
		N*)S="${S}m2 14v-12l4 12v-12m2-2";;
		O*)S="${S}m6 8a2 6 0 1 0 0 .1zm2-8.1";;
		P*)S="${S}m2 2a3 2 0 1 1 0 5v7zm6-2";;
		Q*)S="${S}m6 8a2 6 0 1 0 0 .1zm-2-1.1l3 7m1-14";;
		R*)S="${S}m2 14v-12a3 2 0 1 1 0 5l4 7m2-14";;
		S*)S="${S}m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m2-4";;
		T*)S="${S}m1 2h6-3v12m4-14";;
		U*)S="${S}m2 2v10q2 4 4 0v-10m2-2";;
		V*)S="${S}m2 2l2 12 2-12m2-2";;
		W*)S="${S}m2 2l1 12 1-6 1 6 1-12m2-2";;
		X*)S="${S}m2 2l4 12m-4 0l4-12m2-2";;
		Y*)S="${S}m2 2l2 6v6-6l2-6m2-2";;
		Z*)S="${S}m6 14h-4l4-12h-4m6-2";;
		
		_*)S="${S}m1 15h6m1-15";;
		a*)S="${S}m6 9a2 3 0 1 0 0 3v2-7m2-7";;
		b*)S="${S}m2 9a2 3 0 1 1 0 3v2-12m6-2";;
		c*)S="${S}m6 9a2 3 0 1 0 0 3m2-12";;
		d*)S="${S}m6 9a2 3 0 1 0 0 3v2-12m2-2";;
		e*)S="${S}m6 12a2 3 0 1 1 0-2h-4m6-10";;
		f*)S="${S}m6 2q-4-0-4 4v1h2-2v7m6-14";;
		g*)S="${S}m6 9a2 3 0 1 0 0 3v-5 7q-2 2-4 0m6-14";;
		h*)S="${S}m2 2v12-4a2 2 0 1 1 4 0v4m2-14";;
		i*)S="${S}m4 6v1m0 1v6m4-13";;
		j*)S="${S}m4 7v1m0 1v5q0 2-2 2m4-14";;
		k*)S="${S}m2 2v12-4l4 4-4-4 4-2m2-8";;
		l*)S="${S}m4 2v12m4-14";;
		m*)S="${S}m2 8v6-4a1 2 0 1 1 2 0v4-4a1 2 0 1 1 2 0v4m2-14";;
		n*)S="${S}m2 8v6-4a2 2 0 1 1 4 0v4m2-14";;
		o*)S="${S}m6 10a2 3 0 1 0 0 .1zm2-10.1";;
		p*)S="${S}m2 9a2 3 0 1 1 0 3v4-8m6-8";;
		q*)S="${S}m6 9a2 3 0 1 0 0 3v4-8m2-8";;
		r*)S="${S}m2 8v6-4a2 2 0 1 1 4 0m2-10";;
		s*)S="${S}m2 13q4 0 2-2t2-2m2-9";;
		t*)S="${S}m4 6v8-6h2-4m6-8";;
		u*)S="${S}m2 8v4a2 2 0 1 0 4 0v2-6m2-8";;
		v*)S="${S}m2 8l2 6 2-6m2-8";;
		w*)S="${S}m2 8l1 6 1-4 1 4 1-6m2-8";;
		x*)S="${S}m2 8l4 6m-4 0l4-6m2-8";;
		y*)S="${S}m2 8l2 4l2-4-4 8m6-16";;
		z*)S="${S}m2 8h4l-4 6h4m2-12";;
		"
"*)S="${S}M0 $((height))"
		height=$((height+16))
		[ $length -gt $maxlength ] && maxlength=$((length-8))
		length=0
		;;
	esac
	text="${text#?}"
done
[ $length -gt $maxlength ] && maxlength=$length
echo "<svg viewBox=\"0 0 ${maxlength} ${height}\">
	<path stroke=\"#fff\" fill=\"none\" d=\"$S\"/>
</svg>"
Note: puppy's forum adds spaces at the ends of code block lines when you cut and paste it ... you'll have to remove them for some parts to work

If you just strip out the length and height bits and the svg xml, the path "$S" can be use to overlay another SVG. It can replace a text box with x and y offsets by prepending it with "M${x_offset} ${y_offset}"
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
solo
Posts: 389
Joined: Thu 14 Nov 2013, 20:33

#66 Post by solo »

Great work technosaurus!

Something strange though, the text doesn't seem to come out entirely horizontal. If you type in a long sentence, you'll notice it will slightly slope downward.
Attachments
slopetext.jpg
(3.33 KiB) Downloaded 412 times

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#67 Post by technosaurus »

Try this one, I had to make some tweaks to finish the paths in the right spots (the last "m" command has to move it back to y=0 and x=8 so that the origin of the next on is in the right spot) I finished of the printable ascii characters while I was at it... also has newline support (unlike the svg text tag) BTW the offsets are like path offsets, not the bass-ackward <text> tag ...you don't need to account for the font height (IIRC with y=0 on a text tag the font will be above the top of the image).

Its really more of a prototype - I'm already porting it to C so I can eventually use it to make a FUSE based mountable virtual filesystem (I think I'll call it IconFS) One of the things this will be good for is to provide icons to unknown MIME-Types such as "application/x-<some_extension>" They can just get a generic "application" icon with a text overlay of the extension or minor type. That's more of a long term project though.

Code: Select all

#!/bin/sh

text2svg(){
SVG_text_style=' stroke="#fff" fill="none" '
maxlength=0
local text="$1"
shift
local x=${x_offset:-0}
local y=${y_offset:-0}
local S
[ "$x_offset" ] && [ "$y_offset" ] && S="$M${x} $((y))"
length=0
height=16
while [ "$text" ]; do
	length=$((length+8))
	case "$text" in
		"	"*)S="${S}m16 0";length=$((length+8));;
		"
"*)		S="${S}M${x} $((y+height))"
		height=$((height+16))
		[ $length -gt $maxlength ] && maxlength=$((length-8))
		length=0
		;;

		" "*)S="${S}m8 0";;
		!*)S="${S}m4 2v10m0 1v1m4-14";;
		\"*)S="${S}m3 3v3m2-3v3m3-6";;
		\#*)S="${S}m2 4v8m4-8v8m-5-2h6m-6-4h6m1-6";;
		\$*)S="${S}m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m-2-3v14m4-15";;
		%*)S="${S}m2 2v1m4-1l-4 12m4-1v1m2-14";;
		\&*)S="${S}m6 4a2 2 0 1 0-3 3a3 3 0 1 0 4 4m0 2l-4-6m5-7";;
		\'*)S="${S}m4 3v3m4-6";;
		\(*)S="${S}m4 14q-3-6 0-12m4-2";;
		\)*)S="${S}m4 14q3-6 0-12m4-2";;
		\**)S="${S}m1 8h6m-1 4l-4-8m2 0v8m-2 0l4-8m2-4";;
		+*)S="${S}m1 8h6m-3-4v8m4-12";;
		,*)S="${S}m5 11v1l-2 2m5-14";;
		.*)S="${S}m4 11v1m4-12";;
		-*)S="${S}m2 8h4m2-8";;
		/*)S="${S}m2 14l4-12m2-2";;

		0*)S="${S}m2 7a2 4 0 1 1 4 0v2a2 4 0 1 1-4 0zm2 0v2m4-9.1";;
		1*)S="${S}m3 4l1-1v11m4-14";;
		2*)S="${S}m2 4a2 3 0 1 1 3 5l-3 4h4m2-13";;
		3*)S="${S}m2 4a2 2 0 1 1 1 3m0 0a2 3 0 1 1-1 4m6-11";;
		4*)S="${S}m2 2v6h4v6-12l2-2";;
		5*)S="${S}m2 14h2a2 2 0 1 0 -2-6v-5h4m2-3";;
		6*)S="${S}m3 8a2 3 0 1 1 -1 1l4-7m2-2";;
		7*)S="${S}m2 3h4l-4 11m6-14";;
		8*)S="${S}m3.5 7a2 2 0 1 1 1 0a2 3 0 1 1 -1 0zm4.5-7";;
		9*)S="${S}m2 14l4-6a2 3 0 1 0 -1 1m3-9";;

		:*)S="${S}m4 4v1m0 4v1m4-10";;
		\;*)S="${S}m4 4v1m0 4q0 1-1 1m5-10";;
		\<*)S="${S}m6 12l-4-4 4-4m2-4";;
		=*)S="${S}m2 6h4m-4 3h4m2-9";;
		\>*)S="${S}m2 12l4-4-4-4m6-4";;
		\?*)S="${S}m2 6a2 2 0 1 1 2 2v2m0 1v1m4-12";;
		@*)S="${S}m5 8a1 1 0 1 1 0 -1a1 2 0 1 0 2-0a3 4 0 1 0 -2 4m3-11";;

		A*)S="${S}m1 14l3-12l3 12m-1-4h-4m6-10";;
		B*)S="${S}m2 2a3 2 0 1 1 0 5a2.5 2 0 1 1 0 7zm6-2";;
		C*)S="${S}m6 4a2.5 6 0 1 0 0 8m2-12";;
		D*)S="${S}m2 2a4 6 0 1 1 0 12zm6-2";;
		E*)S="${S}m6 14h-4v-12h4m-4 6h3m3-8";;
		F*)S="${S}m2 14v-12h4m-4 6h3m3-8";;
		G*)S="${S}m6 4a2.5 6 0 1 0 0 8v-2h-1m3-10";;
		H*)S="${S}m2 2v12-6h4v6-12m2-2";;
		I*)S="${S}m2 2h4-2v12h2-4m6-14";;
		J*)S="${S}m4 2h2v8q0 4-4 4m6-14";;
		K*)S="${S}m2 2v12-7l4 7-4-7 4-5m2-2";;
		L*)S="${S}m2 2v12h4m2-14";;
		M*)S="${S}m2 14v-12l2 6 2-6v12m2-14";;
		N*)S="${S}m2 14v-12l4 12v-12m2-2";;
		O*)S="${S}m6 8a2 6 0 1 0 0 .1zm2-8.1";;
		P*)S="${S}m2 2a3 2 0 1 1 0 5v7zm6-2";;
		Q*)S="${S}m6 8a2 6 0 1 0 0 .1zm-2-1.1l3 7m1-14";;
		R*)S="${S}m2 14v-12a3 2 0 1 1 0 5l4 7m2-14";;
		S*)S="${S}m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m2-4";;
		T*)S="${S}m1 2h6-3v12m4-14";;
		U*)S="${S}m2 2v10q2 4 4 0v-10m2-2";;
		V*)S="${S}m2 2l2 12 2-12m2-2";;
		W*)S="${S}m2 2l1 12 1-6 1 6 1-12m2-2";;
		X*)S="${S}m2 2l4 12m-4 0l4-12m2-2";;
		Y*)S="${S}m2 2l2 6v6-6l2-6m2-2";;
		Z*)S="${S}m6 14h-4l4-12h-4m6-2";;
		
		\[*)S="${S}m5 14h-2v-12h2m3-2";;
		\\*)S="${S}m2 2l4 12m2-14";;
		]*)S="${S}m3 14h2v-12h-2m5-2";;
		^*)S="${S}m2 5l2-2 2 2m2-5";;
		_*)S="${S}m1 15h6m1-15";;
		\`*)S="${S}m3 4l2 1m3-5";;
		
		a*)S="${S}m6 9a2 3 0 1 0 0 3v2-7m2-7";;
		b*)S="${S}m2 9a2 3 0 1 1 0 3v2-12m6-2";;
		c*)S="${S}m6 9a2 3 0 1 0 0 3m2-12";;
		d*)S="${S}m6 9a2 3 0 1 0 0 3v2-12m2-2";;
		e*)S="${S}m6 12a2 3 0 1 1 0-2h-4m6-10";;
		f*)S="${S}m2 14v-6h2-2q0-4 4-4m2-4";;
		g*)S="${S}m6 11a2 3 0 1 1 0-3a2 4 0 1 1-4 6m6-14";;
		h*)S="${S}m2 2v12-4a2 2 0 1 1 4 0v4m2-14";;
		i*)S="${S}m4 6v1m0 1v6m4-13";;
		j*)S="${S}m4 6v1m0 1v5q0 2-2 2m6-15";;
		k*)S="${S}m2 2v12-4l4 4-4-4 4-2m2-8";;
		l*)S="${S}m4 2v12m4-14";;
		m*)S="${S}m2 8v6-4a1 2 0 1 1 2 0v4-4a1 2 0 1 1 2 0v4m2-14";;
		n*)S="${S}m2 8v6-4a2 2 0 1 1 4 0v4m2-14";;
		o*)S="${S}m6 10a2 3 0 1 0 0 .1zm2-10.1";;
		p*)S="${S}m2 9a2 3 0 1 1 0 3v4-8m6-8";;
		q*)S="${S}m6 9a2 3 0 1 0 0 3v5-9m2-8";;
		r*)S="${S}m2 8v6-4a2 2 0 1 1 4 0m2-10";;
		s*)S="${S}m2 13a2 1 0 0 0 2-3a2 1 0 0 1 2-2m2-8";;
		t*)S="${S}m4 6v8-6h2-4m6-8";;
		u*)S="${S}m2 8v4a2 2 0 1 0 4 0v2-6m2-8";;
		v*)S="${S}m2 8l2 6 2-6m2-8";;
		w*)S="${S}m2 8l1 6 1-4 1 4 1-6m2-8";;
		x*)S="${S}m2 8l4 6m-4 0l4-6m2-8";;
		y*)S="${S}m2 8l2 4l2-4-4 8m6-16";;
		z*)S="${S}m2 8h4l-4 6h4m2-14";;
		{*)S="${S}m5 14a1 6 0 0 1-1-5l-1-1 1-1a1 6 0 0 1 1-5m3-2";;
		\|*)S="${S}m4 14v-12m4-2";;
		}*)S="${S}m3 14a1 6 0 0 0 1-5l1-1-1-1a1 6 0 0 0 -1-5m5-2";;
		~*)S="${S}m2 4q1-1 2 0t2 0m2-4";;
		*)S="${S}m1 1h6v14h-6zm7-1";;
	esac
	text="${text#?}"
done
[ $length -gt $maxlength ] && maxlength=$length
echo "<svg viewBox=\"0 0 ${maxlength} ${height}\">
	$@
	<path ${SVG_text_style} d=\"$S\"/>
</svg>"

}

text2svg '~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?
`1234567890-=qwertyuiop[]\asdfghjkl;'\''zxcvbnm,./'
Edit: I added my C version with some extra options - don't use in production environments, but it seems to be working passably.
Attachments
text2svg.tar.gz
C version source and 64bit compiled binary
Not for production (uses unchecked sprintf)
(5.95 KiB) Downloaded 130 times
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
solo
Posts: 389
Joined: Thu 14 Nov 2013, 20:33

#68 Post by solo »

I tried the new script, but there must be something wrong with the syntax of your last line.

Code: Select all

text2svg '~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?
`1234567890-=qwertyuiop[]\asdfghjkl;'\''zxcvbnm,./'
Because when I run the script, I get an svg that has the proper length for the string of characters I entered, but the only characters that actually show up in the svg image itself, are

Code: Select all

~!@#$%^

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#69 Post by technosaurus »

I can't duplicate the error. I assume it has to do with our outdated forum. I'll try to rename the svg to png for upload and a tarball with both the c and shell versions
Attachments
text2svg.tar.gz
(7 KiB) Downloaded 138 times
hw.png
actually an svg - just rename the extension
(2.36 KiB) Downloaded 164 times
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#70 Post by technosaurus »

I added support for icons using the icons that have been converted to strictly relative paths.... running out of steam though, so I'll probably wait till after Memorial Day weekend to look at it again (with fresh eyes).

If anyone wants to play with it, I added the C version to github

Compile with
gcc -Os -std=c99 svg_generator.c -o svg_generator -s
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

step
Posts: 1349
Joined: Fri 04 May 2012, 11:20

#71 Post by step »

Very nice. My meager suggestion: alternative example for the usage line, with blue strokes, so it's immediately visible in mtpaint and inkscape, for instance:

Code: Select all

svg_generator -x 96 -y 0 -s 'stroke="#0000ff" fill="none"' -d '<path d="m0 0h96v96h-96z"/>' -i puppy -t 'hello world'
Attachments
xscreenshot00000.png
(9.76 KiB) Downloaded 392 times
[url=http://murga-linux.com/puppy/viewtopic.php?t=117546]Fatdog64-810[/url]|[url=http://goo.gl/hqZtiB]+Packages[/url]|[url=http://goo.gl/6dbEzT]Kodi[/url]|[url=http://goo.gl/JQC4Vz]gtkmenuplus[/url]

User avatar
vovchik
Posts: 1507
Joined: Tue 24 Oct 2006, 00:02
Location: Ukraine

#72 Post by vovchik »

Dear technosaurus,

Great work you have done with SVGs. I have already somewhat cannibalized the font stuff for my skinned OPEN_GL widgets.

http://basic-converter.proboards.com/th ... ollTo=8960

Thanks a million. :)

With kind regards,
vovchik

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#73 Post by technosaurus »

@vovchic thanks, I checked out that thread. I'm not really satisfied with the font either - this was just a proof of concept for a fixed width font. I could make the font variable width next time I get a chance to clean it up. I didn't do bold or italics since they can be implemented with stroke-width and transforms.

I should have used something like this:
Image

Is anyone interested in me posting a version of my svg path editor designed for font path editing?
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
vovchik
Posts: 1507
Joined: Tue 24 Oct 2006, 00:02
Location: Ukraine

#74 Post by vovchik »

Dear technosaurus,

I'm interested! And your "proof of concept" certainly convinced me. Impressive, indeed.

Here is a little c header with the unisans free ASCII chars. The array could ultimately be a structure or a two-dimensional char* array, with the char width as a separate element, but that is easy enough to do. :)

The xpos for each char_path can done easily by <path transform='translate(char_width, 0) where char_width is the cumulative string width based on preceding char_widths. For this particular set of outlines the svg needs a viewBox(0 0 cumulative char_width, 100) which can be scaled using <svg height='HHH' width='WWW'. And preserveAspectRatio='none' in the svg header will ensure that the bounding box will be filled. Also, I use transform='translate(0,75) scale(1,-1)' in the svg header.

An example:

<svg width='100' height='100' viewBox='0 0 170.996 100'
opacity='1' preserveAspectRatio='none'
transform='translate(0,75) scale(1,-1)'>

<!-- Text to display: 'A' -->
<linearGradient id='lg1' x1='50%'
x2='50%' y1='0%' y2='100%'>
<stop offset='0%' stop-color='pink' />
<stop offset='46.447%' stop-color='red' />
<stop offset='100%' stop-color='pink' />
</linearGradient>
<g stroke='none' stroke-width='1' fill='url(#lg1)' transform='rotate(0, 0, 0)' >

<path transform='translate(0,0)' ch_name='A' ch_width='70.996' d='m70.020 0.000 ... z' />

</g>
</svg>


With kind regards,
vovchik
Attachments
unisans_svg.h.tar.gz
(6.33 KiB) Downloaded 121 times

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#75 Post by technosaurus »

You can embed the width in the path as long as they are all under 256 bytes using something like (I used this to embed string length):

Code: Select all

for(int i=0; i<last_path ; i++)
    printf("\t\"\\x%02X\" \"%s\",\n",strlen(paths[i]), paths[i]);
Which should produce something like:

Code: Select all

    "\x1F" "some random string of len 0x1f.",
    "\x1C" "another string of length 27."
Then you just do something like:

Code: Select all

char *path = paths[i]
size_t length = *path++;
memcpy(dest,path,length)l
if your length exceeds 255 bytes you'd need to modify the printf to match something like:

Code: Select all

char *path = paths[i]
size_t length = 256 * *path++;
length += *path++;
memcpy(dest,path,length)l
You can add as many byte "fields" like this as you want, but I am beginning to get a bit too far off topic. I can post further on this topic in my C snippets thread if anyone is interested. I am still modifying my font editor - will post it soon.
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
vovchik
Posts: 1507
Joined: Tue 24 Oct 2006, 00:02
Location: Ukraine

#76 Post by vovchik »

Dear technosaurus,

Thanks. Please post any snippets you have related to generating SVGs that we might find useful....and the editor, whenever it is ready. :)

With kind regards,
vovchik

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#77 Post by technosaurus »

Ok, It looks like crap but here is a font path editor

Code: Select all

<html>
<head>
<style>
	#layout{height:100%;width:100%}
	td{height:100%;}
	td div{float:left}
	textarea{height:50%;width:100%;}
	path:hover{stroke-width:1px;stroke:#eee}
	path{fill:none}
</style>
</head>
<body>
<table id="layout">
<tr>
<td width="200">
	<div onclick="addPoint(this,event)" onmousemove="showPos(this,event)">
		<svg title="tooltip" id="svg" width="200" height="400" viewBox="0 0 8 16" />
	</div>
</td>
<td>
	<div>
		<div onclick="addPath()">
		<svg id="thumb" title="click to append" width="24px" height="24px" viewBox="0 0 8 16" />
		</div>
		<div><select id="select" onchange="setThumb('template')" ></select></div>
		<div><input id="color" onchange="setThumb()" type="color" ></input></div>
		<div><button id="bold_but" onclick="toggleBold();"> <b>B</b> </button></div>
		<div><button id="ital_but" onclick="toggleItalic();"> <i>I</i> </button></div>
	</div>
	<div>
		<div>Saved: <select id="select_saved" onchange="setThumb('saved')" ></select></div>
		<div><button id="save" onclick="save();"> <b> Save </b> </button></div>
		<div><button id="show" onclick="showSaved();"> <b> Show </b> </button></div>
	</div>
		<br>
	<div>
		<div>width: <input id="width" value="8" onchange="setFont(this,'w')" type="number" min="1" max="8"></input></div>
		<div>height: <input id="height" value="16" onchange="setFont(this,'h')" type="number" min="1" max="16"></input></div>
		<div>cap: <input id="cap" value="1" onchange="setFont(this,'cap')" type="number" min="0" max="15"></input></div>
		<div>mean: <input id="mean" value="6" onchange="setFont(this,'mean')" type="number" min="1" max="15"></input></div>
		<div>base: <input id="base" value="12" onchange="setFont(this,'base')" type="number" min="1" max="16"></input></div>
		<div>descent: <input id="descent" value="15" onchange="setFont(this,'descent')" type="number" min="1" max="16"></input></div>
	</div>
	<textarea name="raw" oninput="setSVG()" id="raw">
	</textarea>
</td>
</tr>
</table>

<script>
	var last,raw=document.getElementById("raw"),
		font = {"h":16,"w":8,"cap":1,"mean":6,"base":12,"descent":15,"cur":"","editing":"template"},
		isbold=false, isitalic=false,
		svg=document.getElementById("svg"),
		select=document.getElementById("select"),
		select_saved=document.getElementById("select_saved"),
		thumb=document.getElementById("thumb"),
		color=document.getElementById("color"),
		viewbox = svg.getAttribute("viewBox").split(" "),
		vbstyle=getComputedStyle(svg,null),
		vbw=parseInt(vbstyle.getPropertyValue("width"),10)/viewbox[2],
		vbh=parseInt(vbstyle.getPropertyValue("height"),10)/viewbox[3],
	paths = {
		"template" : {
			"!"	:	"m4 2v10m0 1v1m4-14",
			"\"":	"m3 3v3m2-3v3m3-6",
			"#"	:	"m2 4v8m4-8v8m-5-2h6m-6-4h6m1-6",
			"$"	:	"m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m-2-3v14m4-15",
			"%"	:	"m2 2v1m4-1l-4 12m4-1v1m2-14",
			"&"	:	"m6 4a2 2 0 1 0-3 3a3 3 0 1 0 4 4m0 2l-4-6m5-7",
			"'"	:	"m4 3v3m4-6",
			"("	:	"m4 14q-3-6 0-12m4-2",
			")"	:	"m4 14q3-6 0-12m4-2",
			"*"	:	"m1 8h6m-1 4l-4-8m2 0v8m-2 0l4-8m2-4",
			"+"	:	"m1 8h6m-3-4v8m4-12",
			","	:	"m5 11v1l-2 2m5-14",
			"-"	:	"m2 8h4m2-8",
			"."	:	"m4 11v1m4-12",
			"/"	:	"m2 14l4-12m2-2",
			"0"	:	"m2 7a2 4 0 1 1 4 0v2a2 4 0 1 1-4 0zm2 0v2m4-9.1",
			"1"	:	"m3 4l1-1v11m4-14",
			"2"	:	"m2 4a2 3 0 1 1 3 5l-3 4h4m2-13",
			"3"	:	"m2 4a2 2 0 1 1 1 3m0 0a2 3 0 1 1-1 4m6-11",
			"4"	:	"m2 2v6h4v6-12l2-2",
			"5"	:	"m2 14h2a2 2 0 1 0 -2-6v-5h4m2-3",
			"6"	:	"m3 8a2 3 0 1 1 -1 1l4-7m2-2",
			"7"	:	"m2 3h4l-4 11m6-14",
			"8"	:	"m3.5 7a2 2 0 1 1 1 0a2 3 0 1 1 -1 0zm4.5-7",
			"9"	:	"m2 14l4-6a2 3 0 1 0 -1 1m3-9",
			":"	:	"m4 4v1m0 4v1m4-10",
			";"	:	"m4 4v1m0 4q0 1-1 1m5-10",
			"<"	:	"m6 12l-4-4 4-4m2-4",
			"="	:	"m2 6h4m-4 3h4m2-9",
			">"	:	"m2 12l4-4-4-4m6-4",
			"?"	:	"m2 6a2 2 0 1 1 2 2v2m0 1v1m4-12",
			"@"	:	"m5 8a1 1 0 1 1 0 -1a1 2 0 1 0 2-0a3 4 0 1 0 -2 4m3-11",
			"A"	:	"m1 14l3-12l3 12m-1-4h-4m6-10",
			"B"	:	"m2 2a3 2 0 1 1 0 5a2.5 2 0 1 1 0 7zm6-2",
			"C"	:	"m6 4a2.5 6 0 1 0 0 8m2-12",
			"D"	:	"m2 2a4 6 0 1 1 0 12zm6-2",
			"E"	:	"m6 14h-4v-12h4m-4 6h3m3-8",
			"F"	:	"m2 14v-12h4m-4 6h3m3-8",
			"G"	:	"m6 4a2.5 6 0 1 0 0 8v-2h-1m3-10",
			"H"	:	"m2 2v12-6h4v6-12m2-2",
			"I"	:	"m2 2h4-2v12h2-4m6-14",
			"J"	:	"m4 2h2v8q0 4-4 4m6-14",
			"K"	:	"m2 2v12-7l4 7-4-7 4-5m2-2",
			"L"	:	"m2 2v12h4m2-14",
			"M"	:	"m2 14v-12l2 6 2-6v12m2-14",
			"N"	:	"m2 14v-12l4 12v-12m2-2",
			"O"	:	"m6 8a2 6 0 1 0 0 .1zm2-8.1",
			"P"	:	"m2 2a3 2 0 1 1 0 5v7zm6-2",
			"Q"	:	"m6 8a2 6 0 1 0 0 .1zm-2-1.1l3 7m1-14",
			"R"	:	"m2 14v-12a3 2 0 1 1 0 5l4 7m2-14",
			"S"	:	"m2 12a2 3 0 1 0 2-4a2 3 0 1 1 2-4m2-4",
			"T"	:	"m1 2h6-3v12m4-14",
			"U"	:	"m2 2v10q2 4 4 0v-10m2-2",
			"V"	:	"m2 2l2 12 2-12m2-2",
			"W"	:	"m2 2l1 12 1-6 1 6 1-12m2-2",
			"X"	:	"m2 2l4 12m-4 0l4-12m2-2",
			"Y"	:	"m2 2l2 6v6-6l2-6m2-2",
			"Z"	:	"m6 14h-4l4-12h-4m6-2",
			"["	:	"m5 14h-2v-12h2m3-2",
			"\\"	:	"m2 2l4 12m2-14",
			"]"	:	"m3 14h2v-12h-2m5-2",
			"^"	:	"m2 5l2-2 2 2m2-5",
			"_"	:	"m1 15h6m1-15",
			"`"	:	"m3 4l2 1m3-5",
			"a"	:	"m6 9a2 3 0 1 0 0 3v2-7m2-7",
			"b"	:	"m2 9a2 3 0 1 1 0 3v2-12m6-2",
			"c"	:	"m6 9a2 3 0 1 0 0 3m2-12",
			"d"	:	"m6 9a2 3 0 1 0 0 3v2-12m2-2",
			"e"	:	"m6 12a2 3 0 1 1 0-2h-4m6-10",
			"f"	:	"m2 14v-6h2-2q0-4 4-4m2-4",
			"g"	:	"m6 11a2 3 0 1 1 0-3a2 4 0 1 1-4 6m6-14",
			"h"	:	"m2 2v12-4a2 2 0 1 1 4 0v4m2-14",
			"i"	:	"m4 6v1m0 1v6m4-13",
			"j"	:	"m4 6v1m0 1v5q0 2-2 2m6-15",
			"k"	:	"m2 2v12-4l4 4-4-4 4-2m2-8",
			"l"	:	"m4 2v12m4-14",
			"m"	:	"m2 8v6-4a1 2 0 1 1 2 0v4-4a1 2 0 1 1 2 0v4m2-14",
			"n"	:	"m2 8v6-4a2 2 0 1 1 4 0v4m2-14",
			"o"	:	"m6 10a2 3 0 1 0 0 .1zm2-10.1",
			"p"	:	"m2 9a2 3 0 1 1 0 3v4-8m6-8",
			"q"	:	"m6 9a2 3 0 1 0 0 3v5-9m2-8",
			"r"	:	"m2 8v6-4a2 2 0 1 1 4 0m2-10",
			"s"	:	"m2 13a2 1 0 0 0 2-3a2 1 0 0 1 2-2m2-8",
			"t"	:	"m4 6v8-6h2-4m6-8",
			"u"	:	"m2 8v4a2 2 0 1 0 4 0v2-6m2-8",
			"v"	:	"m2 8l2 6 2-6m2-8",
			"w"	:	"m2 8l1 6 1-4 1 4 1-6m2-8",
			"x"	:	"m2 8l4 6m-4 0l4-6m2-8",
			"y"	:	"m2 8l2 4l2-4-4 8m6-16",
			"z"	:	"m2 8h4l-4 6h4m2-14",
			"{"	:	"m5 14a1 6 0 0 1-1-5l-1-1 1-1a1 6 0 0 1 1-5m3-2",
			"|"	:	"m4 14v-12m4-2",
			"}"	:	"m3 14a1 6 0 0 0 1-5l1-1-1-1a1 6 0 0 0 -1-5m5-2",
			"~"	:	"m2 4q1-1 2 0t2 0m2-4",
			"~NA":	"m1 1h6v14h-6zm7-1"
		},
		"saved" : {}
	};

function setFont(o,d){
	font[d]=o.value;
	setSVG();
}

function setThumb(o){
	var p="";
	if (o=="saved")	p = paths[o][select_saved.value];
	else p = paths[o][select.value]
	font.editing=o;
	thumb.innerHTML = "\\"+createPath(p);
}

function createPath(p){
	var b = (isbold)? '2' : '1', c = color.value,
		i = (isitalic)? ' transform="skewX(-8)" ' : ' ';
	return '\n<path id="path"'+i+'stroke="'+c+'" stroke-width="'+b+'" d="'+p+'"/>';
}

function addPath(){
	font.cur = (font.editing=="saved") ? select2.value : select.value;
	raw.value = paths[font.editing][font.cur];
	setSVG();
}

for (i in paths["template"]){
	var option = document.createElement("option");
	option.text=i;
	select.add(option);
}

function save(){
	select_saved.innerHTML=""
	paths.saved[font.cur]=raw.value;
	for (i in paths.saved){
		var option = document.createElement("option");
		option.text=i;
		select_saved.add(option);
	}
}

function showSaved(){
	var s="";
	for (i in paths["saved"]){
		s+='"'+i+'" : "' + paths["saved"][i]+ '"\r\n'
	}
	raw.value=s;
}

function getVBpos(n,ev){
	var style=getComputedStyle(svg,null),
		w=parseInt(style.getPropertyValue("width"),10),
		h=parseInt(style.getPropertyValue("height"),10);
		//FIXME
	return [((ev.pageX - n.offsetLeft)/vbw).toFixed(1) , ((ev.pageY - n.offsetTop)/vbw).toFixed(1)];
}

function toggleBold(){
	isbold=!isbold;
	var bold_but=document.getElementById("bold_but");
	bold_but.innerHTML=(isbold)? "B" : "<b>B</b>";
	setThumb(font.editing);
	setSVG();
}

function toggleItalic(){
	isitalic=!isitalic;
	var ital_but=document.getElementById("ital_but");
	ital_but.innerHTML=(isitalic)? "I" : "<i>I</i>";
	setThumb(font.editing);
	setSVG();
}

function showPos(n,ev){
	var title=getVBpos(n,ev);
	svg.setAttribute("title",title);
	svg.parentNode.setAttribute("title",title); //chrome doesn't do tooltip on svg
}

function addPoint(n,ev){
	var abspoint = getVBpos(n,ev), path = document.getElementById("path"),
		point = path.getPointAtLength(path.getTotalLength());
	raw.value+="" + (abspoint[0]-point.x).toFixed(1) + " " + (abspoint[1]-point.y).toFixed(1);
	setSVG();
}


function guide(){
	return '<path stroke="#f77" stroke-width=".1" d="m0 '+font.cap+'h'+font.w+'"/>'+
		'<path stroke="#7f7" stroke-width=".1" d="m0 '+font.mean+'h'+font.w+'"/>'+
		'<path stroke="#77f" stroke-width=".1" d="m0 '+font.base+'h'+font.w+'"/>'+
		'<path stroke="#f77" stroke-width=".1" d="m0 '+font.descent+'h'+font.w+'"/>'+
		'<path stroke="#777" stroke-width=".5" fill="none" d="m0 0h'+font.w+'v'+font.h+'h-'+font.w+'z"/>';
}

function setSVG(){
	var cur = guide()+createPath(raw.value);
	if (last != cur){
		last=cur;
		svg.innerHTML=last;
	}
};
setThumb(font.editing);
setSVG();

</script>
</body>
</html>
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
vovchik
Posts: 1507
Joined: Tue 24 Oct 2006, 00:02
Location: Ukraine

#78 Post by vovchik »

Dear technosaurus,

Thanks. I am now looking at it and it looks useful; however, there is a learning curve, as with everything. :)

With kind regards,
vovchik

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#79 Post by technosaurus »

vovchik wrote:there is a learning curve, as with everything
Thanks for testing it out - I realize its not _user-friendly_ yet. I spent too much time getting the little nuances to work. I futzed for a long time with clicking on the preview to automatically add a relative point - turns out chromium/chrome/opera has a bug computing the current location if there is a "z" in the path (firefox/seamonkey is fine)... I had no more patience for BS after that, so formatting the html with css will have to wait.

Here are the basics though:
Left hand side is the preview area with a gray box surrounding the desired font size. The lines represent the cap, mean, base and descent as illustrated in my previous post

Right hand side is the control area. The first thing is a thumbnail view of the currently selected template (or saved) glyph, followed by a dropdown of my (now much more obviously crappy - with guides in place) glyphs. The B and I buttons just give you a preview of what they _could_ look like bold or italic - I haven't added a parameter for the stroke-width (normal or bold) or the skew (italic)
After that is the dropdown for saved glyphs which get saved when you click the save button (next) You can get a copy of all of your saved paths by clicking the show button. The rest of the parameters change what they say in the preview area - I would recommend setting these once at the beginning of your session though, so fonts look like they belong together.

TODO
I would like to add a grid checkbox too, so that its easier to guess at relative points

I'd like to add a way to introduce other unicode characters - any thoughts on the best way to do that?

I added the click method - so you can just put your "l" and click where you want it to go, It works for the points associated with "c" "q", "s" "t" and "m" as well, but "h" and "v" get extra unwanted parameters. I'd like to make it smarter by checking the last letter in the path

Some of the SVG path commands are not intuitive to learn, I'd like to set up a clickable/configurable graphical interface to automatically add the appropriate letter (and other parameters as applicable, such as in arcs)

Side note for vovchik: Are you using nanosvg in BACON for your SVG? - If so, do you think we could'should use (something like) this to add <text> support ... I already patched nanosvgrast.h to do independent x-y scaling for use in jwm, but AFAIK the parser just throws out text. I almost started to hack this directly into the parser until I realized nanosvgrast.h is already based on stb_truetype code, so I'm not sure.
Attachments
svg-font-oath-editor.png
(4.5 KiB) Downloaded 449 times
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
vovchik
Posts: 1507
Joined: Tue 24 Oct 2006, 00:02
Location: Ukraine

#80 Post by vovchik »

Dear technosaurus,

Thanks for all the details on the path editor. I will study it. And I have been using both stb_truetype - for display of truetype in BACON on an OPEN_GL canvas - and nanosvg for the SVG bits and had to do the workaround with paths because of the missing <text> implementation. Although, as you rightly say, it would be preferable to hack nano to display <text>, perhaps by getting the glyphs via stb_truetype, and modding nanosvg to accept <def font><glyph> and <text>. Just thinking out loud. :)

With kind regards,
vovchik

Post Reply