treeform / pixie

Full-featured 2d graphics library for Nim.
MIT License
743 stars 28 forks source link

Create the same image with different dpis #373

Closed AmjadHD closed 2 years ago

AmjadHD commented 2 years ago

I want to export 3 versions of the following image: @1x, @2x and @3x the dpi, How do I do that ?

import pixie

let image = newImage(62, 62)

let path = newPath()
path.roundedRect(rect(11, 5, 40, 40), 6, 6, 6, 6)

image.fillPath(path, rgba(255, 255, 255, 255))

image.writeFile("overlay_bg.png")

Figma export scale: image

treeform commented 2 years ago

That just makes double and triple resolution image:

# let imagex2 = image.resize(image.width * 2, image.height * 2)
let imagex2 = image.magnifyBy2() # faster
imagex2 .writeFile("overlay_bg@2x.png")
let imagex3 = image.resize(image.width * 3, image.height * 3)
imagex3.writeFile("overlay_bg@3x.png")
AmjadHD commented 2 years ago

That doesn't give the wanted result: Figma: overlay_bg_figma@2x Pixie: overlay_bg_pixie@2x

treeform commented 2 years ago

You right you not only want to scale the image up but draw everything at higher resolution at the start. I think this does what you want:

import pixie

block:
  let image = newImage(62, 62)

  let path = newPath()
  path.roundedRect(rect(11, 5, 40, 40), 6, 6, 6, 6)

  image.fillPath(path, rgba(255, 255, 255, 255))

  image.writeFile("overlay_bg.png")

block:
  let image = newImage(62*2, 62*2)

  let path = newPath()
  path.roundedRect(rect(11*2, 5*2, 40*2, 40*2), 6*2, 6*2, 6*2, 6*2)

  image.fillPath(path, rgba(255, 255, 255, 255))

  image.writeFile("overlay_bg@2x.png")

block:
  let image = newImage(62*3, 62*3)

  let path = newPath()
  path.roundedRect(rect(11*3, 5*3, 40*3, 40*3), 6*3, 6*3, 6*3, 6*3)

  image.fillPath(path, rgba(255, 255, 255, 255))

  image.writeFile("overlay_bg@3.png")
treeform commented 2 years ago

Or like this:

import pixie, strformat

proc draw(scale: int, suffix: string) =
  let image = newImage(62 * scale, 62 * scale)

  let path = newPath()
  path.roundedRect(rect(11, 5, 40, 40), 6, 6, 6, 6)

  image.fillPath(
    path,
    rgba(255, 255, 255, 255),
    scale(vec2(scale.float32, scale.float32))
  )

  image.writeFile(&"overlay_bg{suffix}.png")

draw(1, "")
draw(2, "@2x")
draw(3, "@3x")
AmjadHD commented 2 years ago

Yes, that does it, what if I have a shadow, how do I scale it ?

proc drawOverlayShadow() = 
  let image = newImage(62, 62)

  let path = newPath()
  path.roundedRect(rect(13, 7, 36, 36), 4, 4, 4, 4)

  let rndRect = newImage(62, 62)
  rndRect.fillPath(path, rgba(255, 255, 255, 255))

  let shadow = rndRect.shadow(
    offset = vec2(0, 6),
    spread = 0,
    blur = 12,
    color = color(0, 0, 0, 0.4)
  )

  image.draw(shadow)

  image.writeFile("overlay_shadow.png")
treeform commented 2 years ago

you would need the scale the blur, spread and the offset.

AmjadHD commented 2 years ago

Can't there just be a parameter passed somewhere, to scale the whole image ?

treeform commented 2 years ago

If you use context you can have apply scaling right at the start, but in your case context does not support shadows.

AmjadHD commented 2 years ago

Ok, this works:

import pkg/pixie
import std/strformat

proc drawOverlayShadow(scale: int, suffix: string) =
  let image = newImage(62 * scale, 62 * scale)
  let scalef = scale.float32

  let r = 4.0'f32
  let path = newPath()
  path.roundedRect(rect(13, 7, 36, 36), r, r, r, r)

  let rndRect = newImage(62 * scale, 62 * scale)
  rndRect.fillPath(path, white, scale(vec2(scalef, scalef)))

  let shadow = rndRect.shadow(
    offset = vec2(0, 6 * scalef),
    spread = 0.0f32,
    blur = 12 * scalef,
    color = color(0, 0, 0, 0.4)
  )

  image.draw(shadow)

  image.writeFile(&"{assetsPath}/overlay_shadow{suffix}.png")

drawOverlayShadow(1, "")
drawOverlayShadow(2, "@2x")
drawOverlayShadow(3, "@3x")

Are you aware of how can I do the same with skia-python ? thanks !