Brush API

잉크 Brush API는 캔버스에 그릴 브러시를 만들고 맞춤설정하는 방법을 제공합니다.

브러시 만들기

브러시를 만들려면 Brush.createWithColorLong()와 같은 이름이 지정된 인수를 사용하여 Brush 팩토리 메서드를 사용합니다. 이 클래스를 사용하면 다음 속성을 설정할 수 있습니다.

  • family: 브러시의 스타일입니다. 텍스트의 서체 또는 글꼴과 유사합니다. 사용 가능한 BrushFamily 값은 StockBrushes을 참고하세요.
  • color: 브러시의 색상입니다. ColorLong를 사용하여 색상을 설정할 수 있습니다.
  • size: 브러시로 만든 획의 기본 두께입니다.
  • epsilon: 획의 두 점이 서로 다른 것으로 간주되어야 하는 최소 거리로, 획의 지오메트리의 세부사항 또는 충실도 수준을 제어합니다.
    • 값이 높을수록 획이 더 단순화되어 메모리 사용량이 줄고 렌더링 속도가 빨라지지만, 확대하면 들쭉날쭉한 모서리와 같은 눈에 띄는 아티팩트가 발생할 수 있습니다.
    • 값이 낮을수록 고품질 확대/축소를 위한 세부정보가 더 많이 보존되지만 메모리 사용량이 증가합니다.
    • 1px 단위 스케일로 프로토타입을 제작하는 경우 0.1이 적절한 시작점입니다. 다양한 화면 밀도를 지원하는 프로덕션 앱의 경우 밀도 독립형 단위 (예: dp)를 사용하고 그에 따라 입실론을 조정하세요.
val redBrush = Brush.createWithColorLong(
  family = StockBrushes.pressurePen(),
  colorLong = Color.RED.pack(),
  size = 5F,
  epsilon = 0.1F
)

브러시 속성 수정

copy() 메서드를 사용하여 기존 브러시의 사본을 만들 수 있습니다. 이 메서드를 사용하면 브러시의 속성을 변경할 수 있습니다.

val blueBrush = redBrush.copy(colorLong = Color.BLUE.pack())

맞춤 브러시

StockBrushes은 다용도로 사용할 수 있는 일반 브러시를 제공하지만, Ink API는 고유한 예술적 효과를 위해 완전히 새로운 브러시 동작을 만들거나 이전 버전과의 호환성을 위해 특정 기존 브러시를 복제하는 고급 경로도 제공합니다.

맞춤 BrushFamily는 직렬화된 형식에서 로드됩니다. 필수 형식은 BrushFamily 프로토콜 버퍼의 gzip 압축된 바이너리 인코딩입니다. 이를 통해 지금 맞춤 브러시 파일을 로드하고 사용할 수 있습니다. 역직렬화되면 맞춤 BrushFamily를 사용하여 StockBrushes 계열과 마찬가지로 특정 색상과 크기의 새 Brush를 만들 수 있습니다.

class CustomBrushes(val context: Context) {

  private const val TAG = "CustomBrushes"

  val brushes by lazy { loadCustomBrushes(context) }

  @OptIn(ExperimentalInkCustomBrushApi::class)
  private fun loadCustomBrushes(): List<CustomBrush> {
    val brushFiles = mapOf(
        "Calligraphy" to (R.raw.calligraphy to R.drawable.draw_24px),
        "Flag Banner" to (R.raw.flag_banner to R.drawable.flag_24px),
        "Graffiti" to (R.raw.graffiti to R.drawable.format_paint_24px),
    // ...
    )

    val loadedBrushes = brushFiles.mapNotNull { (name, pair) ->
      val (resourceId, icon) = pair
      val brushFamily = context.resources.openRawResource(resourceId).use
      { inputStream ->
          BrushFamily.decode(inputStream)
      }
      CustomBrush(name, icon, brushFamily.copy(clientBrushFamilyId = name))     
    }
    return loadedBrushes
  }
}

data class CustomBrush(
  val name: String,
  val icon: Int,
  val brushFamily: BrushFamily
)