Advertisement
Guest User

Untitled

a guest
Dec 20th, 2014
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.37 KB | None | 0 0
  1. open System.Drawing
  2.  
  3. let brightness (c:Color) = c.GetBrightness ()
  4.  
  5. let pixels (bmp:Bitmap) =
  6. seq { for x in 0 .. bmp.Width - 1 do
  7. for y in 0 .. bmp.Height - 1 ->
  8. (x,y) |> bmp.GetPixel }
  9.  
  10. let breakpoint (bmp:Bitmap) =
  11. let pixelsCount = bmp.Width * bmp.Height
  12. let oneThird = pixelsCount / 3
  13. let pixs = pixels bmp
  14. let threshold =
  15. pixs
  16. |> Seq.map brightness
  17. |> Seq.sort
  18. |> Seq.pairwise
  19. |> Seq.skip oneThird
  20. |> Seq.take oneThird
  21. |> Seq.maxBy (fun (b0,b1) -> b1 - b0)
  22. |> snd
  23. let darkPixels =
  24. pixs
  25. |> Seq.map brightness
  26. |> Seq.filter ((>) threshold)
  27. |> Seq.length
  28. (threshold,darkPixels)
  29.  
  30. let sizeFor (bmp:Bitmap) (text:string) darkPixels =
  31. let width,height = bmp.Width, bmp.Height
  32. let pixels = width * height
  33. let textLength = text.Length
  34. let chars = textLength * pixels / darkPixels
  35. let w = (chars * width / height) |> float |> sqrt |> int
  36. let h = (w * height) / width
  37. (w,h)
  38.  
  39. let mappedPixels (bmp:Bitmap) (width,height) (x,y) =
  40.  
  41. // find bounds of intersected pixels
  42. let wScale = float bmp.Width / float width
  43. let hScale = float bmp.Height / float height
  44.  
  45. let loCol = int (wScale * float x)
  46. let hiCol =
  47. int (wScale * float (x + 1)) - 1
  48. |> min (bmp.Width - 1)
  49. let loRow = int (hScale * float y)
  50. let hiRow =
  51. int (hScale * float (y + 1)) - 1
  52. |> min (bmp.Width - 1)
  53.  
  54. // covered pixels
  55. seq { for col in loCol .. hiCol do
  56. for row in loRow .. hiRow -> (col,row) }
  57.  
  58. let reducer (img:Bitmap) pixs =
  59. pixs
  60. |> Seq.map img.GetPixel
  61. |> Seq.averageBy brightness
  62.  
  63. let simplified (bmp:Bitmap) (width,height) threshold =
  64.  
  65. let map = mappedPixels bmp (width,height)
  66. let reduce = reducer bmp
  67. let isDark value = value < threshold
  68.  
  69. let hasLetter = map >> reduce >> isDark
  70.  
  71. Array2D.init width height (fun col row ->
  72. (col,row) |> hasLetter)
  73.  
  74. let applyTo (bmp:Bitmap) (width,height) threshold (text:string) =
  75.  
  76. let chars = text |> Seq.toList
  77. let image = simplified bmp (width,height) threshold
  78.  
  79. let nextPosition (col,row) =
  80. match (col < width - 1) with
  81. | true -> (col+1,row)
  82. | false -> (0,row+1)
  83.  
  84. (chars,(0,0))
  85. |> Seq.unfold (fun (cs,(col,row)) ->
  86. let next = nextPosition (col,row)
  87. match cs with
  88. | [] -> Some(' ',(cs,next))
  89. | c::tail ->
  90. if image.[col,row]
  91. then
  92. Some(c,(tail,next))
  93. else Some(' ',(cs,next)))
  94.  
  95. let rebuild (width,height) (data:char seq) =
  96. seq { for row in 0 .. height - 1 ->
  97. data
  98. |> Seq.map string
  99. |> Seq.skip (row * width)
  100. |> Seq.take width
  101. |> Seq.toArray
  102. |> (String.concat "") }
  103. |> (String.concat "\n")
  104.  
  105.  
  106. (* DEMO *)
  107.  
  108. let path = @"c:/users/mathias/pictures/fsharp-logo.jpg" //fsharp-logo.jpg" //santa-claus-01.jpg" //fsharp-logo.jpg" //beer.jpg" //santa-claus-01.jpg"
  109. let bmp = new Bitmap(path)
  110.  
  111. let text = """F# is a mature, open source, cross-platform, functional-first programming language. It empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code."""
  112.  
  113. let threshold,darkPixels = breakpoint bmp
  114. let width,height = sizeFor bmp text darkPixels
  115.  
  116. text
  117. |> applyTo bmp (width,height) threshold
  118. |> rebuild (width,height)
  119.  
  120.  
  121. // Solver version
  122.  
  123. let countDark (bmp:Bitmap) threshold (w,h) =
  124.  
  125. let map = mappedPixels bmp (w,h)
  126. let reduce = reducer bmp
  127. let hasLetter value = value < threshold
  128.  
  129. let isDark = map >> reduce >> hasLetter
  130.  
  131. seq { for col in 0 .. w - 1 do
  132. for row in 0 .. h - 1 -> (col,row) }
  133. |> Seq.filter isDark
  134. |> Seq.length
  135.  
  136. let solver (bmp:Bitmap) (text:string) =
  137.  
  138. let targetLength = text.Length
  139. let targetRatio = float bmp.Width / float bmp.Height
  140. let threshold,dark = breakpoint bmp
  141. let darkCount = countDark bmp threshold
  142. let ratioError (w,h) =
  143. abs((float w / float h) - targetRatio)
  144.  
  145. let candidate (w,h) d =
  146. if d > targetLength then [ (w-1,h);(w,h-1) ]
  147. elif d < targetLength then [ (w+1,h);(w,h+1) ]
  148. else []
  149. |> List.minBy ratioError
  150. |> fun x -> x, darkCount x
  151.  
  152. let rec search (w,h) d =
  153. match (d=targetLength) with
  154. | true -> (w,h)
  155. | false ->
  156. let (w',h'), d' = candidate (w,h) d
  157. if (abs (d'-targetLength) >= abs (d-targetLength))
  158. then (w,h)
  159. else search (w',h') d'
  160.  
  161. let w0,h0 = sizeFor bmp text dark
  162. let d0 = darkCount (w0,h0)
  163.  
  164. search (w0,h0) d0
  165.  
  166.  
  167. let text' =
  168. """F# is a mature, open source, cross-platform, functional-first programming language. It empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code. F# runs on Linux, Mac OS X, Android, iOS, Windows, GPUs, and browsers. It is free to use and is open source under an OSI-approved license. F# is used in a wide range of application areas and is supported by both an active open community and industry-leading companies providing professional tools."""
  169. |> fun text -> text.Replace(" ","").Replace(",","").Replace(".","")
  170.  
  171. let width',height' = solver bmp text'
  172. let threshold',_ = breakpoint bmp
  173.  
  174. text'
  175. |> applyTo bmp (width',height') threshold'
  176. |> rebuild (width',height')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement