badgemaker.nim 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # author: Ethosa
  2. import streams
  3. import xmltree
  4. import strutils
  5. import strtabs
  6. import base64
  7. type
  8. BadgeRef* = ref object
  9. style: string ## egg "flat", "square", "plastic" etc.
  10. label: string ## left text.
  11. value: string ## right text.
  12. label_text_color: string ## left text color
  13. value_text_color: string ## right text color
  14. label_color: string ## left color.
  15. value_color: string ## right color.
  16. font: string ## label and value font.
  17. font_size: int
  18. width, height: int
  19. image_path: string ## image path for icon.
  20. image_color: string ## image fill color.
  21. label_shadow, value_shadow: bool
  22. dx, dy: int
  23. proc newBadge*(label="", value="", style="flat", label_color="#212121",
  24. value_color="#e0e0e0", label_text_color="white",
  25. value_text_color="black", width=120, height=20): BadgeRef =
  26. ## Creates a new Badge object.
  27. BadgeRef(label: label, value: value, style: style,
  28. label_text_color: label_text_color, value_text_color: value_text_color,
  29. label_color: label_color, value_color: value_color,
  30. font: "DejaVu Sans,Verdana,Geneva,sans-serif",
  31. width: width, height: height, image_path: "", image_color: "",
  32. font_size: 12, label_shadow: false, value_shadow: false, dx: 0, dy: 0)
  33. proc setFont*(badge: BadgeRef, font: string) {.inline.} =
  34. ## Sets badge font.
  35. badge.font = font
  36. proc setFontSize*(badge: BadgeRef, size: int) {.inline.} =
  37. ## Sets badge font size.
  38. badge.font_size = size
  39. proc setIcon*(badge: BadgeRef, image_path: string) {.inline.} =
  40. ## Sets icon for badge.
  41. badge.image_path = image_path
  42. proc setIcon*(badge: BadgeRef, image_path, color: string) {.inline.} =
  43. ## Sets icon with fill color.
  44. badge.image_path = image_path
  45. badge.image_color = color
  46. proc setShadow*(badge: BadgeRef, label=false, value=false) {.inline.} =
  47. ## Change text drop shadow.
  48. badge.label_shadow = label
  49. badge.value_shadow = value
  50. proc offsetShadow*(badge: BadgeRef, dx, dy: int) {.inline.} =
  51. ## Change drop shadow offset.
  52. badge.dx = dx
  53. badge.dy = dy
  54. proc `$`*(badge: BadgeRef): string =
  55. let
  56. # start variables
  57. image_width = if badge.image_path != "": badge.height else: 0
  58. labell = len(badge.label)
  59. valuel = len(badge.value)
  60. bfsize = (badge.font_size - 3).int
  61. bfsize1 = (badge.font_size/2).int
  62. labelw = labell*bfsize + labell + image_width
  63. valuew = valuel*bfsize + valuel + image_width
  64. radius = if "square" in badge.style: "0" else: "4"
  65. dif =
  66. if labelw > valuew:
  67. labelw - valuew + radius.parseInt
  68. else:
  69. labelw - badge.font_size + radius.parseInt
  70. stop_opacity = if "plastic" notin badge.style: "0" else: ".1"
  71. # Drop shadow effect.
  72. var shadow = newXMLTree("defs", [], newStringTable(modeCaseSensitive))
  73. shadow.add newXMLTree(
  74. "filter", [], {
  75. "id": "drop_shadow", "x": "0", "y": "0", "width": "200%", "height": "200%"
  76. }.toXMLAttributes)
  77. shadow[0].add newXMLTree(
  78. "feOffset", [], {
  79. "result": "offOut", "in": "SourceAlpha", "dx": $badge.dx, "dy": $badge.dy
  80. }.toXMLAttributes)
  81. shadow[0].add newXMLTree(
  82. "feGaussianBlur", [], {
  83. "result": "blurOut", "in": "offOut", "stdDeviation": "1"
  84. }.toXMLAttributes)
  85. shadow[0].add newXMLTree(
  86. "feBlend", [], {
  87. "in": "SourceGraphic", "in2": "blurOut", "mode": "normal"
  88. }.toXMLAttributes)
  89. var
  90. # trees
  91. tree = newXMLTree(
  92. "svg", [], {
  93. "xmlns": "http://www.w3.org/2000/svg",
  94. "xmlns:xlink": "http://www.w3.org/1999/xlink",
  95. "width": $badge.width, "height": $badge.height
  96. }.toXMLAttributes)
  97. main = newXMLTree("g", [], {"mask": "url(#gradient)"}.toXMLAttributes)
  98. text = newXMLTree("g", [], {
  99. "font-family": badge.font, "font-size": $badge.font_size, "fill": badge.label_color
  100. }.toXMLAttributes)
  101. gradient = newXMLTree(
  102. "linearGradient", [],
  103. {"id": "gradient", "x2": "0", "y2": "100%"}.toXMLAttributes)
  104. gradient.add newXMLTree("stop", [], {
  105. "offset": "0", "stop-color": "#bbb", "stop-opacity": stop_opacity
  106. }.toXMLAttributes)
  107. gradient.add newXMLTree("stop", [], {
  108. "offset": "1", "stop-opacity": stop_opacity
  109. }.toXMLAttributes)
  110. main.add newXMLTree(
  111. "rect", [], {
  112. "x": "0", "y": "0", "width": $(labelw),
  113. "height": $badge.height, "rx": radius, "ry": radius,
  114. "style": "fill:" & badge.label_color
  115. }.toXMLAttributes)
  116. main.add newXMLTree(
  117. "rect", [], {
  118. "x": $dif, "y": "0",
  119. "width": $((badge.width - bfsize1) - dif),
  120. "height": $badge.height,
  121. "rx": "0", "ry": "0", "style": "fill:" & badge.value_color
  122. }.toXMLAttributes)
  123. main.add newXMLTree(
  124. "rect", [], {
  125. "x": $(badge.width - badge.font_size), "y": "0",
  126. "width": $badge.font_size, "height": $badge.height,
  127. "rx": radius, "ry": radius,
  128. "style": "fill:" & badge.value_color
  129. }.toXMLAttributes)
  130. main.add newXMLTree(
  131. "path", [], {
  132. "fill": "url(#gradient)",
  133. "d": "M0 0h" & $badge.width & "v" & $badge.height & "H0z"
  134. }.toXMLAttributes)
  135. text.add newXMLTree(
  136. "text", [], {
  137. "x": $(image_width + 2 + parseInt(radius)),
  138. "y": $(badge.height/2 + (badge.font_size/2) - 1.0), "fill": badge.label_text_color,
  139. "filter": if badge.label_shadow: "url(#drop_shadow)" else: ""
  140. }.toXMLAttributes)
  141. text.add newXMLTree(
  142. "text", [], {
  143. "x": $(dif + 2),
  144. "y": $(badge.height/2 + (badge.font_size/2) - 1.0), "fill": badge.value_text_color,
  145. "filter": if badge.value_shadow: "url(#drop_shadow)" else: ""
  146. }.toXMLAttributes)
  147. text[0].add newText badge.label
  148. text[1].add newText badge.value
  149. tree.add gradient
  150. tree.add shadow
  151. tree.add main
  152. tree.add text
  153. if badge.image_path != "":
  154. var
  155. img = newFileStream(badge.image_path, fmRead)
  156. image = img.readAll
  157. img.close
  158. tree.add newXMLTree(
  159. "image", [], {
  160. "xlink:href": "data:image/png;base64," & encode image,
  161. "width": $badge.height, "height": $badge.height,
  162. "x": radius, "y": "0", "fill": badge.image_color
  163. }.toXMLAttributes)
  164. return $tree
  165. proc write*(badge: BadgeRef, filename: string) =
  166. ## Writes SVG image in file.
  167. var strm = newFileStream(filename, fmWrite)
  168. strm.write $badge
  169. strm.close