123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- import sys
- from io import BytesIO
- from . import Image
- from ._util import isPath
- qt_versions = [
- ["6", "PyQt6"],
- ["side6", "PySide6"],
- ["5", "PyQt5"],
- ["side2", "PySide2"],
- ]
- qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
- for qt_version, qt_module in qt_versions:
- try:
- if qt_module == "PyQt6":
- from PyQt6.QtCore import QBuffer, QIODevice
- from PyQt6.QtGui import QImage, QPixmap, qRgba
- elif qt_module == "PySide6":
- from PySide6.QtCore import QBuffer, QIODevice
- from PySide6.QtGui import QImage, QPixmap, qRgba
- elif qt_module == "PyQt5":
- from PyQt5.QtCore import QBuffer, QIODevice
- from PyQt5.QtGui import QImage, QPixmap, qRgba
- elif qt_module == "PySide2":
- from PySide2.QtCore import QBuffer, QIODevice
- from PySide2.QtGui import QImage, QPixmap, qRgba
- except (ImportError, RuntimeError):
- continue
- qt_is_installed = True
- break
- else:
- qt_is_installed = False
- qt_version = None
- def rgb(r, g, b, a=255):
- """(Internal) Turns an RGB color into a Qt compatible color integer."""
-
-
- return qRgba(r, g, b, a) & 0xFFFFFFFF
- def fromqimage(im):
- """
- :param im: QImage or PIL ImageQt object
- """
- buffer = QBuffer()
- qt_openmode = QIODevice.OpenMode if qt_version == "6" else QIODevice
- buffer.open(qt_openmode.ReadWrite)
-
-
- if im.hasAlphaChannel():
- im.save(buffer, "png")
- else:
- im.save(buffer, "ppm")
- b = BytesIO()
- b.write(buffer.data())
- buffer.close()
- b.seek(0)
- return Image.open(b)
- def fromqpixmap(im):
- return fromqimage(im)
-
-
-
-
-
-
-
-
-
-
- def align8to32(bytes, width, mode):
- """
- converts each scanline of data from 8 bit to 32 bit aligned
- """
- bits_per_pixel = {"1": 1, "L": 8, "P": 8}[mode]
-
- bits_per_line = bits_per_pixel * width
- full_bytes_per_line, remaining_bits_per_line = divmod(bits_per_line, 8)
- bytes_per_line = full_bytes_per_line + (1 if remaining_bits_per_line else 0)
- extra_padding = -bytes_per_line % 4
-
- if not extra_padding:
- return bytes
- new_data = []
- for i in range(len(bytes) // bytes_per_line):
- new_data.append(
- bytes[i * bytes_per_line : (i + 1) * bytes_per_line]
- + b"\x00" * extra_padding
- )
- return b"".join(new_data)
- def _toqclass_helper(im):
- data = None
- colortable = None
- exclusive_fp = False
-
- if hasattr(im, "toUtf8"):
-
- im = str(im.toUtf8(), "utf-8")
- if isPath(im):
- im = Image.open(im)
- exclusive_fp = True
- qt_format = QImage.Format if qt_version == "6" else QImage
- if im.mode == "1":
- format = qt_format.Format_Mono
- elif im.mode == "L":
- format = qt_format.Format_Indexed8
- colortable = []
- for i in range(256):
- colortable.append(rgb(i, i, i))
- elif im.mode == "P":
- format = qt_format.Format_Indexed8
- colortable = []
- palette = im.getpalette()
- for i in range(0, len(palette), 3):
- colortable.append(rgb(*palette[i : i + 3]))
- elif im.mode == "RGB":
-
- im = im.convert("RGBA")
- data = im.tobytes("raw", "BGRA")
- format = qt_format.Format_RGB32
- elif im.mode == "RGBA":
- data = im.tobytes("raw", "BGRA")
- format = qt_format.Format_ARGB32
- else:
- if exclusive_fp:
- im.close()
- raise ValueError(f"unsupported image mode {repr(im.mode)}")
- size = im.size
- __data = data or align8to32(im.tobytes(), size[0], im.mode)
- if exclusive_fp:
- im.close()
- return {"data": __data, "size": size, "format": format, "colortable": colortable}
- if qt_is_installed:
- class ImageQt(QImage):
- def __init__(self, im):
- """
- An PIL image wrapper for Qt. This is a subclass of PyQt's QImage
- class.
- :param im: A PIL Image object, or a file name (given either as
- Python string or a PyQt string object).
- """
- im_data = _toqclass_helper(im)
-
-
-
-
- self.__data = im_data["data"]
- super().__init__(
- self.__data,
- im_data["size"][0],
- im_data["size"][1],
- im_data["format"],
- )
- if im_data["colortable"]:
- self.setColorTable(im_data["colortable"])
- def toqimage(im):
- return ImageQt(im)
- def toqpixmap(im):
-
-
-
-
- qimage = toqimage(im)
- return QPixmap.fromImage(qimage)
|