1458 qWarning("QX11PixmapData::metric(): Invalid metric"); |
1456 qWarning("QX11PixmapData::metric(): Invalid metric"); |
1459 return 0; |
1457 return 0; |
1460 } |
1458 } |
1461 } |
1459 } |
1462 |
1460 |
|
1461 struct QXImageWrapper |
|
1462 { |
|
1463 XImage *xi; |
|
1464 }; |
|
1465 |
|
1466 bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const |
|
1467 { |
|
1468 XImage *xi = xiWrapper.xi; |
|
1469 |
|
1470 // ARGB32_Premultiplied |
|
1471 if (picture && depth() == 32) |
|
1472 return true; |
|
1473 |
|
1474 Visual *visual = (Visual *)xinfo.visual(); |
|
1475 |
|
1476 // RGB32 |
|
1477 if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000 |
|
1478 && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) |
|
1479 return true; |
|
1480 |
|
1481 // RGB16 |
|
1482 if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800 |
|
1483 && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f) |
|
1484 return true; |
|
1485 |
|
1486 return false; |
|
1487 } |
|
1488 |
|
1489 QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const |
|
1490 { |
|
1491 XImage *xi = xiWrapper.xi; |
|
1492 |
|
1493 QImage::Format format = QImage::Format_ARGB32_Premultiplied; |
|
1494 if (depth() == 24) |
|
1495 format = QImage::Format_RGB32; |
|
1496 else if (depth() == 16) |
|
1497 format = QImage::Format_RGB16; |
|
1498 |
|
1499 QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format); |
|
1500 // take ownership |
|
1501 image.data_ptr()->own_data = true; |
|
1502 xi->data = 0; |
|
1503 |
|
1504 // we may have to swap the byte order |
|
1505 if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst) |
|
1506 || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst)) |
|
1507 { |
|
1508 for (int i=0; i < image.height(); i++) { |
|
1509 if (depth() == 16) { |
|
1510 ushort *p = (ushort*)image.scanLine(i); |
|
1511 ushort *end = p + image.width(); |
|
1512 while (p < end) { |
|
1513 *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff); |
|
1514 p++; |
|
1515 } |
|
1516 } else { |
|
1517 uint *p = (uint*)image.scanLine(i); |
|
1518 uint *end = p + image.width(); |
|
1519 while (p < end) { |
|
1520 *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) |
|
1521 | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); |
|
1522 p++; |
|
1523 } |
|
1524 } |
|
1525 } |
|
1526 } |
|
1527 |
|
1528 // fix-up alpha channel |
|
1529 if (format == QImage::Format_RGB32) { |
|
1530 QRgb *p = (QRgb *)image.bits(); |
|
1531 for (int y = 0; y < xi->height; ++y) { |
|
1532 for (int x = 0; x < xi->width; ++x) |
|
1533 p[x] |= 0xff000000; |
|
1534 p += xi->bytes_per_line / 4; |
|
1535 } |
|
1536 } |
|
1537 |
|
1538 XDestroyImage(xi); |
|
1539 return image; |
|
1540 } |
|
1541 |
|
1542 QImage QX11PixmapData::toImage(const QRect &rect) const |
|
1543 { |
|
1544 QXImageWrapper xiWrapper; |
|
1545 xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(), |
|
1546 AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap); |
|
1547 |
|
1548 Q_CHECK_PTR(xiWrapper.xi); |
|
1549 if (!xiWrapper.xi) |
|
1550 return QImage(); |
|
1551 |
|
1552 if (canTakeQImageFromXImage(xiWrapper)) |
|
1553 return takeQImageFromXImage(xiWrapper); |
|
1554 |
|
1555 QImage image = toImage(xiWrapper, rect); |
|
1556 qSafeXDestroyImage(xiWrapper.xi); |
|
1557 return image; |
|
1558 } |
|
1559 |
1463 /*! |
1560 /*! |
1464 Converts the pixmap to a QImage. Returns a null image if the |
1561 Converts the pixmap to a QImage. Returns a null image if the |
1465 conversion fails. |
1562 conversion fails. |
1466 |
1563 |
1467 If the pixmap has 1-bit depth, the returned image will also be 1 |
1564 If the pixmap has 1-bit depth, the returned image will also be 1 |
1475 \sa fromImage(), {QImage#Image Formats}{Image Formats} |
1572 \sa fromImage(), {QImage#Image Formats}{Image Formats} |
1476 */ |
1573 */ |
1477 |
1574 |
1478 QImage QX11PixmapData::toImage() const |
1575 QImage QX11PixmapData::toImage() const |
1479 { |
1576 { |
|
1577 return toImage(QRect(0, 0, w, h)); |
|
1578 } |
|
1579 |
|
1580 QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const |
|
1581 { |
|
1582 XImage *xi = xiWrapper.xi; |
|
1583 |
1480 int d = depth(); |
1584 int d = depth(); |
1481 Visual *visual = (Visual *)xinfo.visual(); |
1585 Visual *visual = (Visual *)xinfo.visual(); |
1482 bool trucol = (visual->c_class >= TrueColor) && d > 1; |
1586 bool trucol = (visual->c_class >= TrueColor) && d > 1; |
1483 |
1587 |
1484 QImage::Format format = QImage::Format_Mono; |
1588 QImage::Format format = QImage::Format_Mono; |
1492 if (d > 8 || trucol) { |
1596 if (d > 8 || trucol) { |
1493 d = 32; |
1597 d = 32; |
1494 format = QImage::Format_RGB32; |
1598 format = QImage::Format_RGB32; |
1495 } |
1599 } |
1496 |
1600 |
1497 XImage *xi = XGetImage(X11->display, hd, 0, 0, w, h, AllPlanes, |
|
1498 (d == 1) ? XYPixmap : ZPixmap); |
|
1499 |
|
1500 Q_CHECK_PTR(xi); |
|
1501 if (!xi) |
|
1502 return QImage(); |
|
1503 |
|
1504 if (picture && depth() == 32) { |
|
1505 QImage image(w, h, QImage::Format_ARGB32_Premultiplied); |
|
1506 memcpy(image.bits(), xi->data, xi->bytes_per_line * xi->height); |
|
1507 |
|
1508 // we may have to swap the byte order |
|
1509 if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst) |
|
1510 || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst)) |
|
1511 { |
|
1512 for (int i=0; i < image.height(); i++) { |
|
1513 uint *p = (uint*)image.scanLine(i); |
|
1514 uint *end = p + image.width(); |
|
1515 if ((xi->byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) |
|
1516 || (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { |
|
1517 while (p < end) { |
|
1518 *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) |
|
1519 | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); |
|
1520 p++; |
|
1521 } |
|
1522 } else if (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
|
1523 while (p < end) { |
|
1524 *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff) |
|
1525 | ((*p ) & 0xff00ff00); |
|
1526 p++; |
|
1527 } |
|
1528 } |
|
1529 } |
|
1530 } |
|
1531 |
|
1532 // throw away image data |
|
1533 qSafeXDestroyImage(xi); |
|
1534 |
|
1535 return image; |
|
1536 } |
|
1537 |
|
1538 if (d == 1 && xi->bitmap_bit_order == LSBFirst) |
1601 if (d == 1 && xi->bitmap_bit_order == LSBFirst) |
1539 format = QImage::Format_MonoLSB; |
1602 format = QImage::Format_MonoLSB; |
1540 if (x11_mask && format == QImage::Format_RGB32) |
1603 if (x11_mask && format == QImage::Format_RGB32) |
1541 format = QImage::Format_ARGB32; |
1604 format = QImage::Format_ARGB32; |
1542 |
1605 |
1543 QImage image(w, h, format); |
1606 QImage image(xi->width, xi->height, format); |
1544 if (image.isNull()) // could not create image |
1607 if (image.isNull()) // could not create image |
1545 return image; |
1608 return image; |
1546 |
1609 |
1547 QImage alpha; |
1610 QImage alpha; |
1548 if (x11_mask) { |
1611 if (x11_mask) { |
1549 alpha = mask().toImage(); |
1612 if (rect.contains(QRect(0, 0, w, h))) |
|
1613 alpha = mask().toImage(); |
|
1614 else |
|
1615 alpha = mask().toImage().copy(rect); |
1550 } |
1616 } |
1551 bool ale = alpha.format() == QImage::Format_MonoLSB; |
1617 bool ale = alpha.format() == QImage::Format_MonoLSB; |
1552 |
1618 |
1553 if (trucol) { // truecolor |
1619 if (trucol) { // truecolor |
1554 const uint red_mask = (uint)visual->red_mask; |
1620 const uint red_mask = (uint)visual->red_mask; |
1587 int bppc = xi->bits_per_pixel; |
1653 int bppc = xi->bits_per_pixel; |
1588 |
1654 |
1589 if (bppc > 8 && xi->byte_order == LSBFirst) |
1655 if (bppc > 8 && xi->byte_order == LSBFirst) |
1590 bppc++; |
1656 bppc++; |
1591 |
1657 |
1592 for (int y = 0; y < h; ++y) { |
1658 for (int y = 0; y < xi->height; ++y) { |
1593 uchar* asrc = x11_mask ? alpha.scanLine(y) : 0; |
1659 uchar* asrc = x11_mask ? alpha.scanLine(y) : 0; |
1594 dst = (QRgb *)image.scanLine(y); |
1660 dst = (QRgb *)image.scanLine(y); |
1595 src = (uchar *)xi->data + xi->bytes_per_line*y; |
1661 src = (uchar *)xi->data + xi->bytes_per_line*y; |
1596 for (int x = 0; x < w; x++) { |
1662 for (int x = 0; x < xi->width; x++) { |
1597 switch (bppc) { |
1663 switch (bppc) { |
1598 case 8: |
1664 case 8: |
1599 pixel = *src++; |
1665 pixel = *src++; |
1600 break; |
1666 break; |
1601 case 16: // 16 bit MSB |
1667 case 16: // 16 bit MSB |
1621 case 33: // 32 bit LSB |
1687 case 33: // 32 bit LSB |
1622 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24; |
1688 pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24; |
1623 src += 4; |
1689 src += 4; |
1624 break; |
1690 break; |
1625 default: // should not really happen |
1691 default: // should not really happen |
1626 x = w; // leave loop |
1692 x = xi->width; // leave loop |
1627 y = h; |
1693 y = xi->height; |
1628 pixel = 0; // eliminate compiler warning |
1694 pixel = 0; // eliminate compiler warning |
1629 qWarning("QPixmap::convertToImage: Invalid depth %d", bppc); |
1695 qWarning("QPixmap::convertToImage: Invalid depth %d", bppc); |
1630 } |
1696 } |
1631 if (red_shift > 0) |
1697 if (red_shift > 0) |
1632 r = (pixel & red_mask) >> red_shift; |
1698 r = (pixel & red_mask) >> red_shift; |
1660 } |
1726 } |
1661 } |
1727 } |
1662 } else if (xi->bits_per_pixel == d) { // compatible depth |
1728 } else if (xi->bits_per_pixel == d) { // compatible depth |
1663 char *xidata = xi->data; // copy each scanline |
1729 char *xidata = xi->data; // copy each scanline |
1664 int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line); |
1730 int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line); |
1665 for (int y=0; y<h; y++) { |
1731 for (int y=0; y<xi->height; y++) { |
1666 memcpy(image.scanLine(y), xidata, bpl); |
1732 memcpy(image.scanLine(y), xidata, bpl); |
1667 xidata += xi->bytes_per_line; |
1733 xidata += xi->bytes_per_line; |
1668 } |
1734 } |
1669 } else { |
1735 } else { |
1670 /* Typically 2 or 4 bits display depth */ |
1736 /* Typically 2 or 4 bits display depth */ |
1686 memset(use, 0, 256); |
1752 memset(use, 0, 256); |
1687 memset(pix, 0, 256); |
1753 memset(pix, 0, 256); |
1688 bpl = image.bytesPerLine(); |
1754 bpl = image.bytesPerLine(); |
1689 |
1755 |
1690 if (x11_mask) { // which pixels are used? |
1756 if (x11_mask) { // which pixels are used? |
1691 for (int i = 0; i < h; i++) { |
1757 for (int i = 0; i < xi->height; i++) { |
1692 uchar* asrc = alpha.scanLine(i); |
1758 uchar* asrc = alpha.scanLine(i); |
1693 p = image.scanLine(i); |
1759 p = image.scanLine(i); |
1694 if (ale) { |
1760 if (ale) { |
1695 for (int x = 0; x < w; x++) { |
1761 for (int x = 0; x < xi->width; x++) { |
1696 if (asrc[x >> 3] & (1 << (x & 7))) |
1762 if (asrc[x >> 3] & (1 << (x & 7))) |
1697 use[*p] = 1; |
1763 use[*p] = 1; |
1698 ++p; |
1764 ++p; |
1699 } |
1765 } |
1700 } else { |
1766 } else { |
1701 for (int x = 0; x < w; x++) { |
1767 for (int x = 0; x < xi->width; x++) { |
1702 if (asrc[x >> 3] & (0x80 >> (x & 7))) |
1768 if (asrc[x >> 3] & (0x80 >> (x & 7))) |
1703 use[*p] = 1; |
1769 use[*p] = 1; |
1704 ++p; |
1770 ++p; |
1705 } |
1771 } |
1706 } |
1772 } |
1707 } |
1773 } |
1708 } else { |
1774 } else { |
1709 for (int i = 0; i < h; i++) { |
1775 for (int i = 0; i < xi->height; i++) { |
1710 p = image.scanLine(i); |
1776 p = image.scanLine(i); |
1711 end = p + bpl; |
1777 end = p + bpl; |
1712 while (p < end) |
1778 while (p < end) |
1713 use[*p++] = 1; |
1779 use[*p++] = 1; |
1714 } |
1780 } |
1736 image.setColorCount(ncols); // create color table |
1802 image.setColorCount(ncols); // create color table |
1737 // oh dear... no spare "transparent" pixel. |
1803 // oh dear... no spare "transparent" pixel. |
1738 // use first pixel in image (as good as any). |
1804 // use first pixel in image (as good as any). |
1739 trans = image.scanLine(0)[0]; |
1805 trans = image.scanLine(0)[0]; |
1740 } |
1806 } |
1741 for (int i = 0; i < h; i++) { |
1807 for (int i = 0; i < xi->height; i++) { |
1742 uchar* asrc = alpha.scanLine(i); |
1808 uchar* asrc = alpha.scanLine(i); |
1743 p = image.scanLine(i); |
1809 p = image.scanLine(i); |
1744 if (ale) { |
1810 if (ale) { |
1745 for (int x = 0; x < w; x++) { |
1811 for (int x = 0; x < xi->width; x++) { |
1746 if (!(asrc[x >> 3] & (1 << (x & 7)))) |
1812 if (!(asrc[x >> 3] & (1 << (x & 7)))) |
1747 *p = trans; |
1813 *p = trans; |
1748 ++p; |
1814 ++p; |
1749 } |
1815 } |
1750 } else { |
1816 } else { |
1751 for (int x = 0; x < w; x++) { |
1817 for (int x = 0; x < xi->width; x++) { |
1752 if (!(asrc[x >> 3] & (1 << (7 -(x & 7))))) |
1818 if (!(asrc[x >> 3] & (1 << (7 -(x & 7))))) |
1753 *p = trans; |
1819 *p = trans; |
1754 ++p; |
1820 ++p; |
1755 } |
1821 } |
1756 } |
1822 } |