Let's have some fun with python coding

Not exactly usefull but fun.
loading bytes of 8 images takes some seconds. (Krita freezes)

import re
from urllib import request
from krita import Krita
from PyQt5.QtGui import QImage


def get_qimage_from_url(image_url):
    app = Krita.instance()
    name = image_url.rsplit("/", 1)[-1]  # strip path
    name = name.split(".", 1)[0]  # strip ext
    r = request.urlopen(image_url)
    if r.getcode() == 200:
        image = QImage()
        image.loadFromData(r.read())
        return qimage_to_document(image, name)

def qimage_to_document(qimage, name=""):
    app = Krita.instance()
    if not qimage.isNull():
        qimage.convertToFormat(QImage.Format_RGBA8888)
        w = qimage.width()
        h = qimage.height()
        
        document = app.createDocument(w, h, name, "RGBA", "U8", "", 72.0)
        app.activeWindow().addView(document)
        
        node = document.topLevelNodes()[0]

        ptr = qimage.constBits()
        ptr.setsize(qimage.byteCount())
        node.setPixelData(bytes(ptr.asarray()), 0, 0, w, h)
        
        node.setOpacity(255)
        document.refreshProjection()
        return document

def get_images_from_gallery():
    image_element_re = re.compile(r"<meta itemprop='image' content='https://krita-artists\.org/uploads/default/optimized/2X/[a-zA-Z0-9_/]+\.jpeg'>")
    url = "https://krita-artists.org/tag/featured"
    r = request.urlopen(url)
    text = r.read().decode('utf-8')
    for index, meta_str in enumerate(image_element_re.findall(text)):
        get_qimage_from_url(meta_str[32:-2])  # crop url from string
        if index > 8:
            return  # limit to 8 first images

get_images_from_gallery()

/AkiR

2 Likes

Lets continue having fun :slight_smile:

"""
Let’s have some fun with python coding 02
Select paint layer in Krita, and run the script. (pixels in layer will be replaced)
"""
from krita import Krita
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import QPlainTextEdit
from PyQt5.QtMultimedia import QCameraInfo, QCamera, QCameraImageCapture


def walk_nodes(nodes, depth_first=True):
    stack = list((n, 0) for n in nodes)
    while stack:
        node, depth = stack.pop(0 if depth_first else -1)
        yield node, depth
        stack[0:0] = ((n, depth +1) for n in node.childNodes())

def find_document_for(node):
    app = Krita.instance()
    for document in app.documents():
        for n, _ in walk_nodes([document.rootNode()]):
            if n == node:
                return document

def get_enum_str(owner_cls, enum_cls, enum_value):
    for attr_name in dir(owner_cls):
        attr = getattr(owner_cls, attr_name)
        if isinstance(attr, enum_cls) and (attr == enum_value):
            return attr_name

class CameraLayer(QPlainTextEdit):
    """ serves as debug console. """
    _instance = None

    def __init__(self, node):
        super(CameraLayer, self).__init__()
        old = type(self)._instance
        if old:
            old._camera.stop()
        type(self)._instance = self  # hack, to keep self alive.
        self._node = node
        self._document = find_document_for(self._node)

        cam_info = QCameraInfo.availableCameras()[0]
        cam_info_desc = cam_info.description()
        self.appendPlainText("First camera device connected to computer: {cam_info_desc}".format(**locals()))

        self._camera = QCamera(cam_info)
        self._camera.setCaptureMode(QCamera.CaptureStillImage)
        self._cap = QCameraImageCapture(self._camera)
        self._cap.setCaptureDestination(QCameraImageCapture.CaptureToBuffer)  # CaptureToFile
                
        self._cap.readyForCaptureChanged.connect(self.on_ready_changed)
        self._cap.error.connect(self.on_error)
        self._cap.imageCaptured.connect(self.on_image_captured)
        self._camera.statusChanged.connect(self.on_status_changed)
        self._camera.error.connect(self.on_camera_error)

        self.appendPlainText("Warming up, the camera!")
        self._camera.start()
        self.startTimer(int(1000 / 15))  # 15 fps

    def on_ready_changed(self, is_ready):
        self.appendPlainText("on_ready_changed({is_ready!r})".format(**locals()))
            
    def on_status_changed(self, status):
        status_name = get_enum_str(QCamera, QCamera.Status, status)
        self.appendPlainText("on_status_changed({status_name!r})".format(**locals()))

    def on_image_captured(self, id, preview):
        self.appendPlainText("on_image_captured(...)")
        if not preview.isNull():
            preview.convertToFormat(QImage.Format_RGBA8888)
            ptr = preview.constBits()
            ptr.setsize(preview.byteCount())
            self._node.setPixelData(bytes(ptr.asarray()), 0, 0, preview.width(), preview.height())
            self._document.refreshProjection()

    def on_camera_error(self, error):
        error_name = get_enum_str(QCamera, QCamera.Error, error)
        self.appendPlainText("on_camera_error({error_name!r})".format(**locals()))
        self._camera.stop()

    def on_error(self, id, error, errorString):
        self.appendPlainText("on_error({errorString!r})".format(**locals()))
        self._camera.stop()

    def timerEvent(self, event):
        if self._cap.isReadyForCapture():
            self.appendPlainText("\n*** Say cheese! ***\n".format(**locals()))
            self._cap.capture()  # "C:/tmp/cam_test.jpg"

    def closeEvent(self, event):
        self._camera.stop()
        return super(CameraLayer, self).closeEvent(event)

app = Krita.instance()
node = app.activeDocument().activeNode()
cam_layer = CameraLayer(node)
cam_layer.show()
2 Likes

Now code is morphed to better form.

Ps. Feel free to pinch code, I dont have any plans where this geos in future…

Now this should also work on Linux.
Auto install using python is disabled. (manual file copy needed)

Have fun.

1 Like

Can you post some information about what the plugin does.

There is three experimantal plugins for krita.

  • Arc Welding plugin is going to be experiment with canvas transforms. How to read / write / connect Canvas QTransform to from plugin, also how to capture & fake QMouse / QTabletEvents.

  • Camera Layer plugin adds a new layer type to Krita, uses QCamera. Use your webcam as source for layer. (Up coming bonus: Paint layer properties dialog with JSON metadata)

  • Fetch gallery plugin simply transfers image data from URL to document / layer (data is newer saved to file)

All the plugins are still under construction. (plugins DON’T work correctly now) (I try to polish them in up coming weekend, work kinda eats free time …)

/Aki R.

2 Likes

These sound really exciting. thanks for sharing.