Krita/KisPainter

From KDE Community Wiki

KisPainter/KisPaintEngine

OBSOLETE FOR NOW: Implementing a full rasterizer is too much work for now

Introduction

KisPainter was created in the Qt 1.x days and modeled closely on QPainter. Since then, fashions have changed and KisPainter no longer looks as familiar as it once did to hackers. Besides, it doesn't supply us with everything we need to mangle pixels in a high-level way. (The low-level way is using iterators, writeBytes or setPixel, in order of desirability.)

Requirements

  • Familiar to Qt programmers, simple api
  • Can paint using Krita's brushes, paintops, compositeops and Pigment
  • Can paint using QBrush, QPen and QGradient
  • Flood fill, gradient fill, pattern fill
  • Can cope with read-only, read/write, write-only masks and selections
  • offer a transparent way to make generic KOffice vector shapes paint themselves with Krita brushes.

Overview

Qt has split its painting system in three parts:

  • QPaintDevice -- that which can be painted on
  • QPaintEngine -- that which knows how to paint primitives on a QPaintDevice
  • QPainter -- offers a high-level api and can be used to paint on anything.

A QPaintDevice has a method that presents a QPaintEngine to a QPainter which then uses the QPaintEngine to change the pixels on the QPaintDevice.

Qt has various paint devices: raster, opengl, postscript, pdf. The raster paint engine paints on frame buffers: basically a 1d array of pixels.

The Krita equivalents are:

  • KisPaintDevice::QPaintDevice -- a tile-based raster paint device
  • KisPaintEngine::QPaintEngine -- knows how to paint primitives on a KisPaintDevice
  • QPainter -- uses the KisPaintEngine to paint using QPen, QBrush, QGradient, QPainterPath etc. on a KisPaintDevice. We can use this inside paintops that do more than draw a dab on a paint device and shapes can use this to paint themselves on a KisPaintDevice
  • KisPainter -- knows how to paint using KisBrush, KisPaintOp, Pigment on a KisPaintDevice.

There clearly is duplication with the QPainter/KisPainter combo, but it is not apparent how to resolve that. Should we extend KisPaintEngine with everything necessary to paint with KisBrushes, KisPaintOps etc? Or Should we have two engines? Or should we keep the implementation inside KisPainter?

Problems

A Rasterizer for KisPaintEngine

There are two possibilities for implementing KisPaintEngine: either write a native KisPaintDevice rasterizer for lines, painter paths and text (Qt uses Freetype here) or have KisPaintEngine first draw everything on a QImage and then use KisPainter to composite the QImage (after colorspace conversion!) on the target paint device.

The first is a lot of work and quite a maintenance burden, but can be much, much faster than the second option. We can also mix & match the approach: do the simple things directly, and the more complex things through QImage.

QPaintEngineState

QPaintEngineState passes along the state of the QPainter to the paint engine. If we use an underlying QImage, we need to pass along the state to the QPainter we create on the QImage. This appears to be slightly complex and is definitely not what TT was thinking about when they created it.

Mapping Qt's composite ops to Krita's composite ops

Qt uses the basic porter-duff composite ops, while krita has a larger set of photoshop-inspired composite ops. The two sets overlap, but either set has options that are not present in the other set.

Selections

Selections and masks need to be honoured.

Transactions

KisPaintEngine + QPainter should still create transactions for the Krita undo system.

Design guidelines for the reworked KisPainter

A state machine

In line with the design of Arthur and OpenGL, we should make KisPainter a state engine. That means: setters for things like paint ops, composite ops, colors etc, instead of parameters to all functions.

Saving and restoring of state

Needs to be possible, too! Maybe have a KisPainterState analogous to the QPaintEngineState?