This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-12
Channels
- # aleph (61)
- # announcements (2)
- # babashka (65)
- # beginners (64)
- # calva (2)
- # clerk (1)
- # cljsrn (1)
- # clojure (60)
- # clojure-austin (7)
- # clojure-europe (13)
- # clojure-italy (2)
- # clojure-losangeles (4)
- # clojure-nl (2)
- # clojure-norway (94)
- # clojure-romania (2)
- # clojure-uk (7)
- # clojuredesign-podcast (5)
- # clojurescript (3)
- # core-typed (2)
- # datomic (42)
- # docker (24)
- # emacs (10)
- # exercism (50)
- # graphql (83)
- # honeysql (25)
- # hyperfiddle (12)
- # malli (13)
- # membrane (49)
- # off-topic (50)
- # podcasts-discuss (1)
- # re-frame (3)
- # reagent (12)
- # reitit (5)
- # releases (2)
- # remote-jobs (8)
Hi! I am running into problems trying to style som text with skia.membrane.paragraph
, or if it is saving/drawing it to an image. All I get is a white rectangle. Correctly sized, afaict. Here’s what I am trying with:
(defn- create-text [text-width title author description]
(let [style #:text-style {;:color [1 1 1]
:font-families ["NimbusSans" "Menlo"]
:font-size 32}]
(para/paragraph [{:text (str title "\n")
:style (merge style #:text-style {:weight :bold})}
{:text (str author "\n")
:style (merge style #:text-style {:slant :italic})}
{:text description
:style style}]
text-width)))
(comment
(def text (create-text 1160 "ImageMagick + Pango + Babashka = ♥️"
"Peter Strömberg"
"Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."))
(java2d/save-image "sometext.png" text (ui/bounds text))
:rcf)
What am I doing wrong? Note that I’ve commented out the :color
style. Because I thought that if the rectangle is white, then drawing white text might be one of the problems. But It is all a white filled, empty, rectangle anyway,What I really want is white text on a transparent background as an image. Because I am later placing the text image on another image.
Hey! The styled text from membrane.skia.paragraph
only works with the skia backend.
If you're on the jvm you can get the skia deps with:
com.phronemophobic.membrane/skialib-macosx-aarch64 {:mvn/version "0.14-beta"}
com.phronemophobic.membrane/skialib-linux-x86-64 {:mvn/version "0.14-beta"}
com.phronemophobic.membrane/skialib-macosx-x86-64 {:mvn/version "0.14-beta"}
You only need the dep that matches your system, but including extra doesn't hurt.You should then be able to run things using the membrane.skia
namespace instead of the membrane.java2d
namespace.
membrane.skia
also has save-image
I just tried your code and got
If you're switching from the java2d backend to the skia backend, you may need to restart your repl 😕
java.awt doesn't always play well with other libs
Here's the version that gets the bold and italic to work:
(defn- create-text [text-width title author description]
(let [style #:text-style {;:color [1 1 1]
:font-families ["NimbusSans" "Menlo"]
:font-size 32}]
(para/paragraph [{:text (str title "\n")
:style (merge style #:text-style {:font-style
#:font-style {:weight :bold}})}
{:text (str author "\n")
:style (merge style #:text-style {:font-style
#:font-style {:slant :italic}})}
{:text description
:style style}]
text-width)))
Here's the code for white text on a transparent background:
(defn- create-text [text-width title author description]
(let [style #:text-style {:color [1 1 1]
:font-families ["NimbusSans" "Menlo"]
:font-size 32}]
(para/paragraph [{:text (str title "\n")
:style (merge style #:text-style {:font-style
#:font-style {:weight :bold}})}
{:text (str author "\n")
:style (merge style #:text-style {:font-style
#:font-style {:slant :italic}})}
{:text description
:style style}]
text-width)))
(comment
(def text (create-text 1160 "ImageMagick + Pango + Babashka = ♥️"
"Peter Strömberg"
"Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."))
(skia/save-image "sometext.png" text nil
nil 0 false
)
(skia/run (fn []
(ui/fill-bordered
[0 0 0]
0
(create-text 1160 "ImageMagick + Pango + Babashka = ♥️"
"Peter Strömberg"
"Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."))
))
:rcf)
By default, skia/save-image
will fill a white background since that's what folks usually want, but you can skip the clear step by passing false
as the last parameter.
Now things work. Thanks! Is there a way I can draw-to-image
like with java2d
, or shall I just use temp files?
there’s no need to. if you have an element, you can just compose it directly
i’m away from keyboard, but you can get the image by calling ui/image with the path and overlay by putting them both in a vector
@U0ETXRFEW , If you get a chance, I would love to hear how this experiment turned out for you including the good, bad, or ugly.
I never figured out how to compose the image using membrane. Neither how to avoid creating a temporary image using skia. So right now I have this:
(defn- create-text
[{:keys [width title author description]}]
(let [style #:text-style {:color [1 1 1]
:font-families ["Nimbus Sans" "Arial"]
:font-size 32}]
(para/paragraph [{:text (str title "\n")
:style (merge style #:text-style {:font-style #:font-style {:weight :bold}})}
{:text (str author "\n")
:style (merge style #:text-style {:font-style #:font-style {:slant :italic}})}
{:text description
:style style}]
width)))
(comment
(def text (create-text {:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}))
(skia/save-image (str (doto (fs/tmp-path! "rcf" "sometext.png") println)) text nil nil 0 false)
:rcf)
(defn add-texts! [image slug texts]
(let [g (.createGraphics image)
text-padding-w 30
text-padding-h 20
margin-bottom 80
image-height (.getHeight image)
rect-width (.getWidth image)
text-width (- rect-width (* text-padding-w 2))
text (create-text (assoc texts :width text-width))
text-x text-padding-w
text-image-path (str (fs/tmp-path! slug "texts.png"))
_text-image? (skia/save-image text-image-path text nil nil 0 false) ;; TODO: Handle error?
text-image-file (io/as-file text-image-path)
text-image (ImageIO/read text-image-file)
rect-height (+ (.getHeight text-image) (* text-padding-h 2))
rect-y (- image-height rect-height margin-bottom)
text-y (+ rect-y text-padding-h)]
(doto g
(.setComposite (AlphaComposite/getInstance AlphaComposite/SRC_OVER 0.5))
(.setColor Color/BLACK)
(.fillRect 0 rect-y rect-width rect-height)
(.setComposite (AlphaComposite/getInstance AlphaComposite/SRC_OVER 1))
(.drawImage text-image text-x text-y nil)
.dispose)
image))
Which works, but anyway. 😃Thanks for reporting back. Glad you got it working. I'll write an example with membrane, but tbh, java2d image API isn't so bad.
Here's one other way to write it:
(defn add-texts2 [[image-width image-height] texts]
(let [text-padding-w 30
text-padding-h 20
margin-bottom 80
image-height image-height
rect-width image-width
text-width (- rect-width (* text-padding-w 2))
text (create-text (assoc texts :width text-width))
text-x text-padding-w
rect-height (+ (ui/height text) (* text-padding-h 2))
rect-y (- image-height rect-height margin-bottom)
text-y (+ rect-y text-padding-h)]
[(ui/translate
0 rect-y
(ui/filled-rectangle [0 0 0 0.5]
rect-width
rect-height))
(ui/translate text-x text-y
text)]))
(defn compose [background text]
[background
(add-texts2 (ui/bounds background)
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."})])
(comment
(skia/save-image "overlay.png"
(add-texts2 [800 400]
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)
nil nil 0 false)
;; compose with another image
(skia/save-image "composite.png"
(compose (ui/image "mybackground.png")
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)
nil nil 0 false)
,)
Not totally sure that's what you're looking for. Anyway, I'm happy to answer any other questions or do a virtual pair session sometime if you're interested!
Looks pretty close to what I’m looking for. 😃 I’m composing an image, so if there is a way to make compose return an image?
The second save-image
in the rcf will save that to disk:
(skia/save-image "composite.png"
(compose (ui/image "mybackground.png")
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)
nil nil 0 false)
Or what do you mean by an image?
For the most part, an image is just a rasterized array of pixels, but that's usually not that useful.
It's possible to get the rasterized pixels, but I'm guessing you're looking for something else
I want something that I can crop, rescale, save as jpg or png. Stuff like that. java.awt.image
has had what I need there so far.
There are descriptions for most of those operations and I can add any that are missing:
• crop -> (ui/scissor-view offset bounds view)
• rescale -> (ui/scale sx sy view)
• save as png (skia/save-image ...)
I’m adding metadata from some blog posts as overlays on the images. Because Twitter/X has stopped showing metadata for links. It only shows an image.
Most everything works on views which are just data descriptions of the graphical elements and transformations. Views can be displayed, measured, inspected, and composed with other views. There are also several drawing implementations based on various different graphics libraries.
My suggestions would be to compose and manipulate views and then write the final result to disk with skia/save-image
.
I think I can make do with writing a temporary png, and then do a last step reading that png file and converting it to jpg.
Yea, that also works, but I think it's easier to work with views programmatically unless I'm missing something. I would be happy to hop on a call for a bit now or later if you're interested and think that would be helpful.
Ok, here's the code I was running locally:
(defn add-texts2 [[image-width image-height] texts]
(let [text-padding-w 30
text-padding-h 20
margin-bottom 80
image-height image-height
rect-width image-width
text-width (- rect-width (* text-padding-w 2))
text (create-text (assoc texts :width text-width))
text-x text-padding-w
rect-height (+ (ui/height text) (* text-padding-h 2))
rect-y (- image-height rect-height margin-bottom)
text-y (+ rect-y text-padding-h)]
[(ui/translate
0 rect-y
(ui/filled-rectangle [0 0 0 0.5]
rect-width
rect-height))
(ui/translate text-x text-y
text)]))
(defn compose [background text]
[background
(add-texts2 (ui/bounds background)
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."})])
(comment
(skia/save-image "overlay.png"
(add-texts2 [800 400]
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)
nil nil 0 false)
;; compose with another image
(skia/save-image "composite.jpeg"
(compose (ui/image "mybackground.png")
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)
nil nil 85 false)
,)
(defn crop [img]
(let [[w h] ( ui/bounds img)]
[(ui/translate
0
(- (* h (/ 1 3)))
(ui/scissor-view
[0
(* h (/ 1 3))]
[w
(* h (/ 1 3))]
img))]))
(defmacro wrap-errors [body]
`(try
(ui/try-draw
~body
(fn [draw# e#]
(draw# (ui/label e#))))
(catch Exception e#
(ui/label e#))))
(def mpos (atom nil))
(defn debug []
(wrap-errors
(let [size [400 600]]
(ui/on
:mouse-move
(fn [pos]
(reset! mpos pos)
nil)
(ui/vertical-layout
(ui/label @mpos)
(crop
(compose (ui/image "mybackground.png")
{:width 1160
:title "ImageMagick + Pango + Babashka = ♥️"
:author "Peter Strömberg"
:description "Where there's a will there's a way. I can now hack on my ImageMagick + Pango script in my Babashka REPL on my Mac."}
)) []
(ui/filled-rectangle [1 0 0]
10 10))))))
(comment
(skia/run
#'debug)
(skia/run (constantly
(ui/label "hello world")))
,)
fyi, just released version 0.14.2-beta
which fixes the layout issue with scissor-view.