예제 #1
0
 def render_html(self, ok):
     try:
         if not ok:
             return
         cwidth, cheight = self.page.mainFrame().contentsSize().width(), self.page.mainFrame().contentsSize().height()
         self.page.setViewportSize(QSize(cwidth, cheight))
         factor = float(self.width)/cwidth if cwidth > self.width else 1
         cutoff_height = int(self.height/factor)-3
         image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
         image.setDotsPerMeterX(self.dpi*(100/2.54))
         image.setDotsPerMeterY(self.dpi*(100/2.54))
         painter = QPainter(image)
         self.page.mainFrame().render(painter)
         painter.end()
         cheight = image.height()
         cwidth = image.width()
         pos = 0
         while pos < cheight:
             img = image.copy(0, pos, cwidth, min(cheight-pos, cutoff_height))
             pos += cutoff_height-20
             if cwidth > self.width:
                 img = img.scaledToWidth(self.width, Qt.SmoothTransform)
             f = os.path.join(self.tdir, '%d.png'%pos)
             img.save(f)
             self.images.append((f, img.width(), img.height()))
     finally:
         QApplication.quit()
예제 #2
0
 def render_html(self, ok):
     try:
         if not ok:
             return
         cwidth, cheight = self.page.mainFrame().contentsSize().width(
         ), self.page.mainFrame().contentsSize().height()
         self.page.setViewportSize(QSize(cwidth, cheight))
         factor = float(self.width) / cwidth if cwidth > self.width else 1
         cutoff_height = int(self.height / factor) - 3
         image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
         image.setDotsPerMeterX(self.dpi * (100 / 2.54))
         image.setDotsPerMeterY(self.dpi * (100 / 2.54))
         painter = QPainter(image)
         self.page.mainFrame().render(painter)
         painter.end()
         cheight = image.height()
         cwidth = image.width()
         pos = 0
         while pos < cheight:
             img = image.copy(0, pos, cwidth,
                              min(cheight - pos, cutoff_height))
             pos += cutoff_height - 20
             if cwidth > self.width:
                 img = img.scaledToWidth(self.width, Qt.SmoothTransform)
             f = os.path.join(self.tdir, '%d.png' % pos)
             img.save(f)
             self.images.append((f, img.width(), img.height()))
     finally:
         QApplication.quit()
예제 #3
0
    def add_image(self, img, cache_key):
        ref = self.get_image(cache_key)
        if ref is not None:
            return ref

        fmt = img.format()
        image = QImage(img)
        if (image.depth() == 1 and img.colorTable().size() == 2 and
            img.colorTable().at(0) == QColor(Qt.black).rgba() and
            img.colorTable().at(1) == QColor(Qt.white).rgba()):
            if fmt == QImage.Format_MonoLSB:
                image = image.convertToFormat(QImage.Format_Mono)
            fmt = QImage.Format_Mono
        else:
            if (fmt != QImage.Format_RGB32 and fmt != QImage.Format_ARGB32):
                image = image.convertToFormat(QImage.Format_ARGB32)
                fmt = QImage.Format_ARGB32

        w = image.width()
        h = image.height()
        d = image.depth()

        if fmt == QImage.Format_Mono:
            bytes_per_line = (w + 7) >> 3
            data = image.constBits().asstring(bytes_per_line * h)
            return self.write_image(data, w, h, d, cache_key=cache_key)

        has_alpha = False
        soft_mask = None

        if fmt == QImage.Format_ARGB32:
            tmask = image.constBits().asstring(4*w*h)[self.alpha_bit::4]
            sdata = bytearray(tmask)
            vals = set(sdata)
            vals.discard(255)  # discard opaque pixels
            has_alpha = bool(vals)
            if has_alpha:
                # Blend image onto a white background as otherwise Qt will render
                # transparent pixels as black
                background = QImage(image.size(), QImage.Format_ARGB32_Premultiplied)
                background.fill(Qt.white)
                painter = QPainter(background)
                painter.drawImage(0, 0, image)
                painter.end()
                image = background

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, 'jpeg', 94)
        data = bytes(ba.data())

        if has_alpha:
            soft_mask = self.write_image(tmask, w, h, 8)

        return self.write_image(data, w, h, 32, dct=True,
                                soft_mask=soft_mask, cache_key=cache_key)
예제 #4
0
    def add_image(self, img, cache_key):
        ref = self.get_image(cache_key)
        if ref is not None:
            return ref

        fmt = img.format()
        image = QImage(img)
        if (image.depth() == 1 and img.colorTable().size() == 2 and
            img.colorTable().at(0) == QColor(Qt.black).rgba() and
            img.colorTable().at(1) == QColor(Qt.white).rgba()):
            if fmt == QImage.Format_MonoLSB:
                image = image.convertToFormat(QImage.Format_Mono)
            fmt = QImage.Format_Mono
        else:
            if (fmt != QImage.Format_RGB32 and fmt != QImage.Format_ARGB32):
                image = image.convertToFormat(QImage.Format_ARGB32)
                fmt = QImage.Format_ARGB32

        w = image.width()
        h = image.height()
        d = image.depth()

        if fmt == QImage.Format_Mono:
            bytes_per_line = (w + 7) >> 3
            data = image.constBits().asstring(bytes_per_line * h)
            return self.write_image(data, w, h, d, cache_key=cache_key)

        has_alpha = False
        soft_mask = None

        if fmt == QImage.Format_ARGB32:
            tmask = image.constBits().asstring(4*w*h)[self.alpha_bit::4]
            sdata = bytearray(tmask)
            vals = set(sdata)
            vals.discard(255)  # discard opaque pixels
            has_alpha = bool(vals)
            if has_alpha:
                # Blend image onto a white background as otherwise Qt will render
                # transparent pixels as black
                background = QImage(image.size(), QImage.Format_ARGB32_Premultiplied)
                background.fill(Qt.white)
                painter = QPainter(background)
                painter.drawImage(0, 0, image)
                painter.end()
                image = background

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, 'jpeg', 94)
        data = bytes(ba.data())

        if has_alpha:
            soft_mask = self.write_image(tmask, w, h, 8)

        return self.write_image(data, w, h, 32, dct=True,
                                soft_mask=soft_mask, cache_key=cache_key)
예제 #5
0
    def render_cover(self, book_id):
        if self.ignore_render_requests.is_set():
            return
        tcdata, timestamp = self.thumbnail_cache[book_id]
        use_cache = False
        if timestamp is None:
            # Not in cache
            has_cover, cdata, timestamp = self.model(
            ).db.new_api.cover_or_cache(book_id, 0)
        else:
            has_cover, cdata, timestamp = self.model(
            ).db.new_api.cover_or_cache(book_id, timestamp)
            if has_cover and cdata is None:
                # The cached cover is fresh
                cdata = tcdata
                use_cache = True

        if has_cover:
            p = QImage()
            p.loadFromData(cdata, CACHE_FORMAT if cdata is tcdata else 'JPEG')
            if p.isNull() and cdata is tcdata:
                # Invalid image in cache
                self.thumbnail_cache.invalidate((book_id, ))
                self.update_item.emit(book_id)
                return
            cdata = None if p.isNull() else p
            if not use_cache:  # cache is stale
                if cdata is not None:
                    width, height = p.width(), p.height()
                    scaled, nwidth, nheight = fit_image(
                        width, height, self.delegate.cover_size.width(),
                        self.delegate.cover_size.height())
                    if scaled:
                        if self.ignore_render_requests.is_set():
                            return
                        p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio,
                                     Qt.SmoothTransformation)
                    cdata = p
                # update cache
                if cdata is None:
                    self.thumbnail_cache.invalidate((book_id, ))
                else:
                    try:
                        self.thumbnail_cache.insert(book_id, timestamp,
                                                    image_to_data(cdata))
                    except EncodeError as err:
                        self.thumbnail_cache.invalidate((book_id, ))
                        prints(err)
                    except Exception:
                        import traceback
                        traceback.print_exc()
        elif tcdata is not None:
            # Cover was removed, but it exists in cache, remove from cache
            self.thumbnail_cache.invalidate((book_id, ))
        self.delegate.cover_cache.set(book_id, cdata)
        self.update_item.emit(book_id)
예제 #6
0
    def render_cover(self, book_id):
        if self.ignore_render_requests.is_set():
            return
        tcdata, timestamp = self.thumbnail_cache[book_id]
        use_cache = False
        if timestamp is None:
            # Not in cache
            has_cover, cdata, timestamp = self.model().db.new_api.cover_or_cache(book_id, 0)
        else:
            has_cover, cdata, timestamp = self.model().db.new_api.cover_or_cache(book_id, timestamp)
            if has_cover and cdata is None:
                # The cached cover is fresh
                cdata = tcdata
                use_cache = True

        if has_cover:
            p = QImage()
            p.loadFromData(cdata, CACHE_FORMAT if cdata is tcdata else "JPEG")
            if p.isNull() and cdata is tcdata:
                # Invalid image in cache
                self.thumbnail_cache.invalidate((book_id,))
                self.update_item.emit(book_id)
                return
            cdata = None if p.isNull() else p
            if not use_cache:  # cache is stale
                if cdata is not None:
                    width, height = p.width(), p.height()
                    scaled, nwidth, nheight = fit_image(
                        width, height, self.delegate.cover_size.width(), self.delegate.cover_size.height()
                    )
                    if scaled:
                        if self.ignore_render_requests.is_set():
                            return
                        p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
                    cdata = p
                # update cache
                if cdata is None:
                    self.thumbnail_cache.invalidate((book_id,))
                else:
                    try:
                        self.thumbnail_cache.insert(book_id, timestamp, image_to_data(cdata))
                    except EncodeError as err:
                        self.thumbnail_cache.invalidate((book_id,))
                        prints(err)
                    except Exception:
                        import traceback

                        traceback.print_exc()
        elif tcdata is not None:
            # Cover was removed, but it exists in cache, remove from cache
            self.thumbnail_cache.invalidate((book_id,))
        self.delegate.cover_cache.set(book_id, cdata)
        self.update_item.emit(book_id)
예제 #7
0
def qimage_to_magick(img):
    ans = Image()
    fmt = get_pixel_map()
    if not img.hasAlphaChannel():
        if img.format() != img.Format_RGB32:
            img = QImage(img)
            img.setFormat(QImage.Format_RGB32)
        fmt = fmt.replace('A', 'P')
    else:
        if img.format() != img.Format_ARGB32:
            img = QImage(img)
            img.setFormat(img.Format_ARGB32)
    raw = img.constBits().ascapsule()
    ans.constitute(img.width(), img.height(), fmt, raw)
    return ans
예제 #8
0
 def render_cover(self, book_id):
     cdata = self.model().db.new_api.cover(book_id)
     if self.ignore_render_requests.is_set():
         return
     if cdata is not None:
         p = QImage()
         p.loadFromData(cdata)
         cdata = None
         if not p.isNull():
             width, height = p.width(), p.height()
             scaled, nwidth, nheight = fit_image(width, height, self.delegate.cover_size.width(), self.delegate.cover_size.height())
             if scaled:
                 if self.ignore_render_requests.is_set():
                     return
                 p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
             cdata = p
     self.delegate.cover_cache.set(book_id, cdata)
     self.update_item.emit(book_id)
예제 #9
0
def qimage_to_magick(img):
    ans = Image()
    if isosx:
        # For some reson, on OSX MagickConstituteImage fails, and I can't be
        # bothered figuring out why. Dumping to uncompressed PNG is reasonably
        # fast.
        raw = pixmap_to_data(img, 'PNG', quality=100)
        ans.load(raw)
        return ans
    fmt = get_pixel_map()
    if not img.hasAlphaChannel():
        if img.format() != img.Format_RGB32:
            img = QImage(img)
            img.setFormat(QImage.Format_RGB32)
        fmt = fmt.replace('A', 'P')
    else:
        if img.format() != img.Format_ARGB32:
            img = QImage(img)
            img.setFormat(img.Format_ARGB32)
    raw = img.constBits().ascapsule()
    ans.constitute(img.width(), img.height(), fmt, raw)
    return ans
예제 #10
0
파일: canvas.py 프로젝트: pwasiewi/calibre
def qimage_to_magick(img):
    ans = Image()
    if isosx:
        # For some reson, on OSX MagickConstituteImage fails, and I can't be
        # bothered figuring out why. Dumping to uncompressed PNG is reasonably
        # fast.
        raw = pixmap_to_data(img, 'PNG', quality=100)
        ans.load(raw)
        return ans
    fmt = get_pixel_map()
    if not img.hasAlphaChannel():
        if img.format() != img.Format_RGB32:
            img = QImage(img)
            img.setFormat(QImage.Format_RGB32)
        fmt = fmt.replace('A', 'P')
    else:
        if img.format() != img.Format_ARGB32:
            img = QImage(img)
            img.setFormat(img.Format_ARGB32)
    raw = img.constBits().ascapsule()
    ans.constitute(img.width(), img.height(), fmt, raw)
    return ans
    def _populate_covers(self):
        '''
        Display calibre cover for both unless mismatch
        '''
        def _fetch_marvin_cover(border_width=0):
            '''
            Retrieve LargeCoverJpg from cache
            '''
            #self._log_location('border_width: {0}'.format(border_width))
            con = sqlite3.connect(self.marvin_db_path)
            with con:
                con.row_factory = sqlite3.Row

                # Fetch Hash from mainDb
                cover_cur = con.cursor()
                cover_cur.execute('''SELECT
                                      Hash
                                     FROM Books
                                     WHERE ID = '{0}'
                                  '''.format(self.book_id))
                row = cover_cur.fetchone()

            book_hash = row[b'Hash']
            large_covers_subpath = self.connected_device._cover_subpath(size="large")
            cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash])
            stats = self.parent.ios.exists(cover_path)
            if stats:
                self._log("fetching large cover from cache")
                #self._log("cover size: {:,} bytes".format(int(stats['st_size'])))
                cover_bytes = self.parent.ios.read(cover_path, mode='rb')
                m_image = QImage()
                m_image.loadFromData(cover_bytes)

                if border_width:
                    # Construct a QPixmap with oversized yellow background
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE - border_width * 2,
                        Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width() + border_width * 2,
                              m_image.height() + border_width * 2))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.fillRect(self.m_pixmap.rect(), self.MISMATCH_COLOR)
                    m_painter.drawImage(border_width,
                                        border_width,
                                        m_image)
                else:
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE,
                        Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width(),
                              m_image.height()))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.drawImage(0, 0, m_image)

                self.marvin_cover.setPixmap(self.m_pixmap)
            else:
                # No cover available, use generic
                self._log("No cached cover, using generic")
                pixmap = QPixmap()
                pixmap.load(I('book.png'))
                pixmap = pixmap.scaled(self.COVER_ICON_SIZE,
                                       self.COVER_ICON_SIZE,
                                       aspectRatioMode=Qt.KeepAspectRatio,
                                       transformMode=Qt.SmoothTransformation)
                self.marvin_cover.setPixmap(pixmap)

        self.calibre_cover.setMaximumSize(QSize(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE))
        self.calibre_cover.setText('')
        self.calibre_cover.setScaledContents(False)

        self.marvin_cover.setMaximumSize(QSize(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE))
        self.marvin_cover.setText('')
        self.marvin_cover.setScaledContents(False)

        if self.cid:
            db = self.opts.gui.current_db
            if 'cover_hash' not in self.mismatches:
                mi = db.get_metadata(self.cid, index_is_id=True, get_cover=True, cover_as_data=True)

                c_image = QImage()
                if mi.has_cover:
                    c_image.loadFromData(mi.cover_data[1])
                    c_image = c_image.scaledToHeight(self.COVER_ICON_SIZE,
                                                     Qt.SmoothTransformation)
                    self.c_pixmap = QPixmap(QSize(c_image.width(),
                                                  c_image.height()))
                    c_painter = QPainter(self.c_pixmap)
                    c_painter.setRenderHints(c_painter.Antialiasing)
                    c_painter.drawImage(0, 0, c_image)
                else:
                    c_image.load(I('book.png'))
                    c_image = c_image.scaledToWidth(135,
                                                    Qt.SmoothTransformation)
                    # Construct a QPixmap with dialog background
                    self.c_pixmap = QPixmap(
                        QSize(c_image.width(),
                              c_image.height()))
                    c_painter = QPainter(self.c_pixmap)
                    c_painter.setRenderHints(c_painter.Antialiasing)
                    bgcolor = self.palette().color(QPalette.Background)
                    c_painter.fillRect(self.c_pixmap.rect(), bgcolor)
                    c_painter.drawImage(0, 0, c_image)

                # Set calibre cover
                self.calibre_cover.setPixmap(self.c_pixmap)

                if self.opts.prefs.get('development_mode', False):
                    # Show individual covers
                    _fetch_marvin_cover()
                else:
                    # Show calibre cover on both sides
                    self.marvin_cover.setPixmap(self.c_pixmap)

            else:
                # Covers don't match - render with border
                # Construct a QImage with the cover sized to fit inside border
                c_image = QImage()
                cdata = db.cover(self.cid, index_is_id=True)
                if cdata is None:
                    c_image.load(I('book.png'))
                    self.calibre_cover.setScaledContents(True)
                else:
                    c_image.loadFromData(cdata)

                c_image = c_image.scaledToHeight(
                    self.COVER_ICON_SIZE - self.BORDER_WIDTH * 2,
                    Qt.SmoothTransformation)

                # Construct a QPixmap with yellow background
                self.c_pixmap = QPixmap(
                    QSize(c_image.width() + self.BORDER_WIDTH * 2,
                          c_image.height() + self.BORDER_WIDTH * 2))
                c_painter = QPainter(self.c_pixmap)
                c_painter.setRenderHints(c_painter.Antialiasing)
                c_painter.fillRect(self.c_pixmap.rect(),self.MISMATCH_COLOR)
                c_painter.drawImage(self.BORDER_WIDTH, self.BORDER_WIDTH, c_image)
                self.calibre_cover.setPixmap(self.c_pixmap)

                # Render Marvin cover with small border if different covers,
                # large cover if no cover hash (loaded via OPDS)
                border_width = self.BORDER_WIDTH
                if self.mismatches['cover_hash']['Marvin'] is None:
                    border_width = self.BORDER_WIDTH * 3
                _fetch_marvin_cover(border_width=border_width)
        else:
            _fetch_marvin_cover()
예제 #12
0
        def _fetch_marvin_cover(with_border=False):
            '''
            Retrieve LargeCoverJpg from cache
            '''
            self._log_location()
            con = sqlite3.connect(self.marvin_db_path)
            with con:
                con.row_factory = sqlite3.Row

                # Fetch Hash from mainDb
                cover_cur = con.cursor()
                cover_cur.execute('''SELECT
                                      Hash
                                     FROM Books
                                     WHERE ID = '{0}'
                                  '''.format(self.book_id))
                row = cover_cur.fetchone()

            book_hash = row[b'Hash']
            large_covers_subpath = self.connected_device._cover_subpath(
                size="large")
            cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash])
            stats = self.parent.ios.exists(cover_path)
            if stats:
                self._log("fetching large cover from cache")
                #self._log("cover size: {:,} bytes".format(int(stats['st_size'])))
                cover_bytes = self.parent.ios.read(cover_path, mode='rb')
                m_image = QImage()
                m_image.loadFromData(cover_bytes)

                if with_border:
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE - self.BORDER_WIDTH * 2,
                        Qt.SmoothTransformation)

                    # Construct a QPixmap with yellow background
                    self.m_pixmap = QPixmap(
                        QSize(m_image.width() + self.BORDER_WIDTH * 2,
                              m_image.height() + self.BORDER_WIDTH * 2))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.fillRect(self.m_pixmap.rect(),
                                       QColor(0xFD, 0xFF, 0x99))
                    m_painter.drawImage(self.BORDER_WIDTH, self.BORDER_WIDTH,
                                        m_image)
                else:
                    m_image = m_image.scaledToHeight(self.COVER_ICON_SIZE,
                                                     Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width(), m_image.height()))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.drawImage(0, 0, m_image)

                self.marvin_cover.setPixmap(self.m_pixmap)
            else:
                # No cover available, use generic
                self._log("No cached cover, using generic")
                pixmap = QPixmap()
                pixmap.load(I('book.png'))
                pixmap = pixmap.scaled(self.COVER_ICON_SIZE,
                                       self.COVER_ICON_SIZE,
                                       aspectRatioMode=Qt.KeepAspectRatio,
                                       transformMode=Qt.SmoothTransformation)
                self.marvin_cover.setPixmap(pixmap)
예제 #13
0
class GLButton(Action, GLFrame):
    def __init__(self,
                 parent,
                 x=0,
                 y=0,
                 width=None,
                 height=None,
                 img=None,
                 text=None,
                 togglable=False,
                 imgoff=None,
                 action=None,
                 params=None):
        Action.__init__(self, action, params)
        GLFrame.__init__(self, parent, x, y, width, height)

        self.img = img
        self.setText(text)
        self.textColor = QColor(0, 0, 0)
        self.togglable = togglable
        self.toggled = False
        self.imgoff = imgoff

        self.focus = False
        self.enabled = True
        self.__initialized__ = False

    def setText(self, text):
        self.__text = text
        self.__computeTextPosition()

    def geometryChangedEvent(self):
        self.__computeTextPosition()

    def actionEvent(self):
        if self.togglable:
            self.toggled = not self.toggled

    def __computeTextPosition(self):
        if not self.__text is None:
            qf = QFontMetrics(self.parent.font())
            self.__textx = self.x + (self.width - qf.width(self.__text)) / 2
            self.__texty = self.y + qf.ascent() + (self.height -
                                                   qf.height()) / 2

    def __del__(self):
        self.parent.deleteTexture(self.textureId)
        if self.imgoff:
            self.parent.deleteTexture(self.textureOffId)

    def init(self):
        if not self.__initialized__:
            self.__initialized__ = True

            if self.img:
                self.imgV = QImage(self.img)
                assert not self.imgV.isNull()

                if self.width is None:
                    self.width = self.imgV.width()
                if self.height is None:
                    self.height = self.imgV.height()

                self.textureId = self.importTexture(self.imgV)

                if self.imgoff:
                    self.imgoffV = QImage(self.imgoff)
                    self.textureOffId = self.importTexture(self.imgoffV)

            self.__defaulttoggled = self.toggled
            self.__defaultenabled = self.enabled
        else:
            self.toggled = self.__defaulttoggled
            self.enabled = self.__defaultenabled

    def importTexture(self, img):
        return self.parent.bindTexture(img)

    def draw(self):
        if self.visible:
            glDisable(GL_LIGHTING)
            glEnable(GL_BLEND)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            self.parent.startScreenCoordinatesSystem()
            glLineWidth(2)
            glDisable(GL_LIGHTING)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
            if not self.enabled:
                glColor4f(0.5, 0.5, 0.5, 1.0)
            else:
                glColor4f(0, 0, 0, 1.0)
            self.drawBox()

            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
            if not self.enabled:
                glColor4f(1.0, 1.0, 1.0, 0.2)
            elif self.focus:
                glColor4f(1.0, 1.0, 1.0, 0.6)
            else:
                glColor4f(1.0, 1.0, 1.0, 0.4)
            self.drawBox()

            if self.img:
                glTranslatef(0, 0, -0.05)
                glEnable(GL_TEXTURE_2D)
                if not self.toggled and self.enabled:
                    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
                    glBindTexture(GL_TEXTURE_2D, self.textureId)
                else:
                    if self.imgoff:
                        glBindTexture(GL_TEXTURE_2D, self.textureOffId)
                    else:
                        if not self.toggled:
                            glColor4f(1, 1, 1, 0.7)
                        else:
                            if self.enabled:
                                glColor4f(0.2, 0.2, 0.2, 0.5)
                            else:
                                glColor4f(0.2, 0.2, 0.2, 0.3)
                        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
                                  GL_MODULATE)
                        glBindTexture(GL_TEXTURE_2D, self.textureId)
                glMatrixMode(GL_TEXTURE)
                glLoadIdentity()
                self.drawTexBox()
                glDisable(GL_TEXTURE_2D)
                glTranslatef(0, 0, 0.05)
            glLineWidth(1)
            if not self.__text is None:
                glColor4f(self.textColor.redF(), self.textColor.greenF(),
                          self.textColor.blueF(), self.textColor.alphaF())
                self.parent.drawText(self.__textx, self.__texty, self.__text)
            glEnable(GL_LIGHTING)
            self.parent.stopScreenCoordinatesSystem()

    def mousePressEvent(self, event):
        if self.enabled and self.visible and self.containspos(event.pos()):
            return True
        return False

    def mouseMoveEvent(self, event):
        if self.enabled and self.visible and self.containspos(event.pos()):
            self.parent.setFocusWidget(self)
            return True
        return False

    def mouseReleaseEvent(self, event):
        if self.enabled and self.visible and self.containspos(event.pos()):
            self.parent.selectedButton = None
            self.applyAction()
            return True
        return False
예제 #14
0
class MainWindow(QWidget):
    def __init__(self):
        QMainWindow.__init__(self)
        self.resize(500, 300)

        self.mainLayout = QHBoxLayout()
        self.chooseLayout = QHBoxLayout()
        self.layout = QVBoxLayout()
        self.pixLayout = QHBoxLayout()
        self.thresholdLayout = QHBoxLayout()
        self.timeLayout = QHBoxLayout()
        self.contoursLayout = QHBoxLayout()
        self.setLayout(self.mainLayout)
        self.setWindowTitle(
            "Image To Gcode V1.0 ----- build By yizheneng [email protected]")

        self.imageLabel = QLabel("image")

        self.mainLayout.addWidget(self.imageLabel)
        self.mainLayout.addLayout(self.layout)
        self.mainLayout.setStretchFactor(self.layout, 1)
        self.mainLayout.setStretchFactor(self.imageLabel, 3)

        self.pixLengthLabel = QLabel(u"像素大小(mm):")
        self.pixDoubleSpinBox = QDoubleSpinBox()
        self.pixDoubleSpinBox.setValue(1)
        self.pixDoubleSpinBox.setDecimals(6)
        self.pixLayout.addWidget(self.pixLengthLabel)
        self.pixLayout.addWidget(self.pixDoubleSpinBox)

        self.thresholdLabel = QLabel(u"阈值:")
        self.thresholdSpinBox = QSpinBox()
        self.thresholdSpinBox.valueChanged.connect(self.ThresholdValChange)
        self.thresholdSpinBox.setMaximum(255)
        self.thresholdSpinBox.setValue(120)
        self.thresholdLayout.addWidget(self.thresholdLabel)
        self.thresholdLayout.addWidget(self.thresholdSpinBox)

        self.timeLabel = QLabel(u"灼烧时间:")
        self.timeDoubleSpinBox = QDoubleSpinBox()
        self.timeDoubleSpinBox.setValue(0.3)
        self.timeLayout.addWidget(self.timeLabel)
        self.timeLayout.addWidget(self.timeDoubleSpinBox)

        self.chooseLabel = QLabel(u"只雕刻轮廓:")
        self.chooseBox = QCheckBox()
        self.chooseLayout.addWidget(self.chooseLabel)
        self.chooseLayout.addWidget(self.chooseBox)
        self.chooseBox.stateChanged.connect(self.ChooseValChanged)

        self.contoursWidthLabel = QLabel(u"边框宽度")
        self.ContoursWidthSpinBox = QSpinBox()
        self.ContoursWidthSpinBox.setEnabled(False)
        self.ContoursWidthSpinBox.setValue(1)
        self.contoursLayout.addWidget(self.contoursWidthLabel)
        self.contoursLayout.addWidget(self.ContoursWidthSpinBox)

        self.loadImageButton = QPushButton(u"加载图片")
        self.loadImageButton.clicked.connect(self.LoadImageButtonClicked)
        self.previewButton = QPushButton(u"预览")
        self.previewButton.clicked.connect(self.ThresholdValChange)
        self.makeCodeButton = QPushButton(u"生成G代码")
        self.makeCodeButton.clicked.connect(self.MakeGcode)

        self.layout.addLayout(self.pixLayout)
        self.layout.addLayout(self.thresholdLayout)
        self.layout.addLayout(self.timeLayout)
        self.layout.addLayout(self.chooseLayout)
        self.layout.addLayout(self.contoursLayout)
        self.layout.addWidget(self.loadImageButton)
        self.layout.addWidget(self.previewButton)
        self.layout.addWidget(self.makeCodeButton)

    def LoadImageButtonClicked(self):
        self.filePath = QFileDialog.getOpenFileName(self, u"选择图片文件", "",
                                                    "Images (*.bmp)")
        if self.filePath == "":
            QMessageBox.warning(self, u"发生错误", u"没有选择可以识别的文件!!")
            return

        self.srcImage = QImage(self.filePath)
        self.grayImage = QImage(self.srcImage.size(), QImage.Format_Indexed8)

        for i in range(256):
            self.grayImage.setColor(i, qRgb(i, i, i))

        for i in range(self.srcImage.width()):
            for j in range(self.srcImage.height()):
                temp = qGray(self.srcImage.pixel(i, j))
                self.grayImage.setPixel(i, j, temp)

        self.srcImage = QImage(self.grayImage)
        self.resultImage = QImage(self.grayImage)
        self.imageLabel.setPixmap(QPixmap(self.srcImage))

    def ChooseValChanged(self):
        self.ContoursWidthSpinBox.setEnabled(self.chooseBox.isChecked())

    def ThresholdValChange(self):
        for i in range(self.srcImage.width()):
            for j in range(self.srcImage.height()):
                temp = self.srcImage.pixelIndex(i, j)
                if (temp >= self.thresholdSpinBox.value()):
                    self.grayImage.setPixel(i, j, 255)
                else:
                    self.grayImage.setPixel(i, j, 0)
        self.resultImage = QImage(self.grayImage)
        #如果选中了只雕刻轮廓
        if self.chooseBox.isChecked():
            img = np.zeros(
                (self.grayImage.height(), self.grayImage.width(), 1), np.uint8)
            for i in range(self.grayImage.width()):
                for j in range(self.grayImage.height()):
                    img[j, i] = self.grayImage.pixelIndex(i, j)
            #提取轮廓
            contours = cv.findContours(img, cv.RETR_LIST,
                                       cv.CHAIN_APPROX_SIMPLE)
            img = np.zeros(
                (self.grayImage.height(), self.grayImage.width(), 1), np.uint8)
            cv.drawContours(img, contours[1][:-1], -1, (255, 255, 255),
                            self.ContoursWidthSpinBox.value())
            #转换轮廓到显示界面
            for i in range(self.resultImage.width()):
                for j in range(self.resultImage.height()):
                    if img[j, i] == 0:
                        self.resultImage.setPixel(i, j, 255)
                    else:
                        self.resultImage.setPixel(i, j, 0)

        self.imageLabel.setPixmap(QPixmap(self.resultImage))

    def MakeGcode(self):
        path = QFileDialog.getSaveFileName(self, u"选择保存路径", "", " (*.nc)")
        if path == "":
            QMessageBox.warning(self, u"发生错误", u"路径错误!!")
            return

        f = open(path, 'w')
        f.write("M5\n")

        for i in range(self.resultImage.width()):
            flag = False
            #检测这一行是否有点
            for j in range(self.resultImage.height()):
                if self.resultImage.pixelIndex(i, j) < 128:
                    flag = True
                    break
            #如果这一行都没有点则跳过这一行
            if flag:
                f.write("G0 Y%f\n" % (i * self.pixDoubleSpinBox.value()))
            else:
                continue

            if (i % 2) > 0:
                for j in range(self.resultImage.height()):
                    if self.resultImage.pixelIndex(i, j) < 128:
                        f.write("G0 X%f\n" %
                                (j * self.pixDoubleSpinBox.value()))
                        f.write("M3\n")
                        f.write("G4 P%f\n" % self.timeDoubleSpinBox.value())
                        f.write("M5\n")
            else:
                for j in range(self.resultImage.height())[::-1]:
                    if self.resultImage.pixelIndex(i, j) < 128:
                        f.write("G0 X%f\n" %
                                (j * self.pixDoubleSpinBox.value()))
                        f.write("M3\n")
                        f.write("G4 P%f\n" % self.timeDoubleSpinBox.value())
                        f.write("M5\n")

        f.write("M5\n")
        f.write("G0 X0 Y0\n")
        f.close()
        QMessageBox.information(self, u"成功", u"生成G代码文件成功!!")
예제 #15
0
    def drawOverlay(self, image, entry):
        
        #establish painter
        painter = QPainter()
        
        #set adjustment factor
        corner_fac = 0.037
        category_fac = 0.27
        text_fac = 0.03
        
        #load images
        category = QImage("res/" + str(entry[0]) + ".png")
        upperLeft = QImage("res/upperLeft.png")
        upperRight = QImage("res/upperRight.png")
        lowerLeft = QImage("res/lowerLeft.png")
        lowerRight = QImage("res/lowerRight.png")
        
        #adjust overlays to image size
        category = category.scaledToHeight(category_fac*image.height(), Qt.SmoothTransformation)
        upperLeft = upperLeft.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation)
        upperRight = upperRight.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation)
        lowerLeft = lowerLeft.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation)
        lowerRight = lowerRight.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation)
        self.voivoifont.setPixelSize(text_fac*image.height())
        
        # create size calculator for font
        size_calculator = QFontMetrics(self.voivoifont)
        text_width = size_calculator.boundingRect(entry[3]).width()
        text_height = size_calculator.height()

        #define text-boundary
        margin_hor = 0.01*image.width()
        max_text_bound = QRect(margin_hor,image.height()-image.height()/3, image.width()-image.width()/3, image.height()/3)
        
        #format text for display
        #text_elided = size_calculator.elidedText(entry[3].upper(), Qt.ElideRight, max_text_bound.width(), Qt.TextWordWrap)
        text_upper = entry[3].upper()
        text_bounds = size_calculator.boundingRect(max_text_bound, Qt.TextWordWrap, text_upper)
        text_width = text_bounds.width()
        text_height = text_bounds.height()
        
        #calculate positions
        margin_ver = 0.018*image.height()
        #margin_hor = 0.01*image.width()
        lower_bound = image.height()-margin_ver
        upper_bound = lower_bound-lowerRight.height()-text_height-upperLeft.height()
        
        #begin painting on image
        painter.begin(image)
        
        #first paint category
        painter.drawImage(image.width()-category.width()-margin_hor, margin_ver, category)
        
        # now background rectangle and corners + comment
        if len(text_upper) > 0:
            painter.fillRect(margin_hor, upper_bound , lowerLeft.width()+text_width+lowerRight.width(), lowerLeft.height()+text_height+upperLeft.height(), QColor(qRgb(255,255,255)))
            painter.drawImage(margin_hor, lower_bound-lowerLeft.height(), lowerLeft)
            painter.drawImage(margin_hor, upper_bound, upperLeft)
            painter.drawImage(margin_hor+lowerLeft.width()+text_width, upper_bound, upperRight)
            painter.drawImage(margin_hor+lowerLeft.width()+text_width,lower_bound-lowerRight.height(), lowerRight)
            
            # write text to prepared rectangle
            painter.setPen(QColor(qRgb(17,195,159)))
            painter.setFont(self.voivoifont)
            #print(text_upper)
            painter.drawText(margin_hor+lowerLeft.width(),image.height()-lowerRight.height()-margin_ver-text_height, text_width, text_height, Qt.TextWordWrap, text_upper)                    
                                
        painter.end()
        def _fetch_marvin_cover(border_width=0):
            '''
            Retrieve LargeCoverJpg from cache
            '''
            #self._log_location('border_width: {0}'.format(border_width))
            con = sqlite3.connect(self.marvin_db_path)
            with con:
                con.row_factory = sqlite3.Row

                # Fetch Hash from mainDb
                cover_cur = con.cursor()
                cover_cur.execute('''SELECT
                                      Hash
                                     FROM Books
                                     WHERE ID = '{0}'
                                  '''.format(self.book_id))
                row = cover_cur.fetchone()

            book_hash = row[b'Hash']
            large_covers_subpath = self.connected_device._cover_subpath(size="large")
            cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash])
            stats = self.parent.ios.exists(cover_path)
            if stats:
                self._log("fetching large cover from cache")
                #self._log("cover size: {:,} bytes".format(int(stats['st_size'])))
                cover_bytes = self.parent.ios.read(cover_path, mode='rb')
                m_image = QImage()
                m_image.loadFromData(cover_bytes)

                if border_width:
                    # Construct a QPixmap with oversized yellow background
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE - border_width * 2,
                        Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width() + border_width * 2,
                              m_image.height() + border_width * 2))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.fillRect(self.m_pixmap.rect(), self.MISMATCH_COLOR)
                    m_painter.drawImage(border_width,
                                        border_width,
                                        m_image)
                else:
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE,
                        Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width(),
                              m_image.height()))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.drawImage(0, 0, m_image)

                self.marvin_cover.setPixmap(self.m_pixmap)
            else:
                # No cover available, use generic
                self._log("No cached cover, using generic")
                pixmap = QPixmap()
                pixmap.load(I('book.png'))
                pixmap = pixmap.scaled(self.COVER_ICON_SIZE,
                                       self.COVER_ICON_SIZE,
                                       aspectRatioMode=Qt.KeepAspectRatio,
                                       transformMode=Qt.SmoothTransformation)
                self.marvin_cover.setPixmap(pixmap)
예제 #17
0
    def _populate_covers(self):
        '''
        Display calibre cover for both unless mismatch
        '''
        def _fetch_marvin_cover(with_border=False):
            '''
            Retrieve LargeCoverJpg from cache
            '''
            self._log_location()
            con = sqlite3.connect(self.marvin_db_path)
            with con:
                con.row_factory = sqlite3.Row

                # Fetch Hash from mainDb
                cover_cur = con.cursor()
                cover_cur.execute('''SELECT
                                      Hash
                                     FROM Books
                                     WHERE ID = '{0}'
                                  '''.format(self.book_id))
                row = cover_cur.fetchone()

            book_hash = row[b'Hash']
            large_covers_subpath = self.connected_device._cover_subpath(
                size="large")
            cover_path = '/'.join([large_covers_subpath, '%s.jpg' % book_hash])
            stats = self.parent.ios.exists(cover_path)
            if stats:
                self._log("fetching large cover from cache")
                #self._log("cover size: {:,} bytes".format(int(stats['st_size'])))
                cover_bytes = self.parent.ios.read(cover_path, mode='rb')
                m_image = QImage()
                m_image.loadFromData(cover_bytes)

                if with_border:
                    m_image = m_image.scaledToHeight(
                        self.COVER_ICON_SIZE - self.BORDER_WIDTH * 2,
                        Qt.SmoothTransformation)

                    # Construct a QPixmap with yellow background
                    self.m_pixmap = QPixmap(
                        QSize(m_image.width() + self.BORDER_WIDTH * 2,
                              m_image.height() + self.BORDER_WIDTH * 2))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.fillRect(self.m_pixmap.rect(),
                                       QColor(0xFD, 0xFF, 0x99))
                    m_painter.drawImage(self.BORDER_WIDTH, self.BORDER_WIDTH,
                                        m_image)
                else:
                    m_image = m_image.scaledToHeight(self.COVER_ICON_SIZE,
                                                     Qt.SmoothTransformation)

                    self.m_pixmap = QPixmap(
                        QSize(m_image.width(), m_image.height()))

                    m_painter = QPainter(self.m_pixmap)
                    m_painter.setRenderHints(m_painter.Antialiasing)

                    m_painter.drawImage(0, 0, m_image)

                self.marvin_cover.setPixmap(self.m_pixmap)
            else:
                # No cover available, use generic
                self._log("No cached cover, using generic")
                pixmap = QPixmap()
                pixmap.load(I('book.png'))
                pixmap = pixmap.scaled(self.COVER_ICON_SIZE,
                                       self.COVER_ICON_SIZE,
                                       aspectRatioMode=Qt.KeepAspectRatio,
                                       transformMode=Qt.SmoothTransformation)
                self.marvin_cover.setPixmap(pixmap)

        self.calibre_cover.setMaximumSize(
            QSize(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE))
        self.calibre_cover.setText('')
        self.calibre_cover.setScaledContents(False)

        self.marvin_cover.setMaximumSize(
            QSize(self.COVER_ICON_SIZE, self.COVER_ICON_SIZE))
        self.marvin_cover.setText('')
        self.marvin_cover.setScaledContents(False)

        if self.cid:
            db = self.opts.gui.current_db
            if 'cover_hash' not in self.mismatches:
                mi = db.get_metadata(self.cid,
                                     index_is_id=True,
                                     get_cover=True,
                                     cover_as_data=True)

                c_image = QImage()
                if mi.has_cover:
                    c_image.loadFromData(mi.cover_data[1])
                    c_image = c_image.scaledToHeight(self.COVER_ICON_SIZE,
                                                     Qt.SmoothTransformation)
                    self.c_pixmap = QPixmap(
                        QSize(c_image.width(), c_image.height()))
                    c_painter = QPainter(self.c_pixmap)
                    c_painter.setRenderHints(c_painter.Antialiasing)
                    c_painter.drawImage(0, 0, c_image)
                else:
                    c_image.load(I('book.png'))
                    c_image = c_image.scaledToWidth(135,
                                                    Qt.SmoothTransformation)
                    # Construct a QPixmap with dialog background
                    self.c_pixmap = QPixmap(
                        QSize(c_image.width(), c_image.height()))
                    c_painter = QPainter(self.c_pixmap)
                    c_painter.setRenderHints(c_painter.Antialiasing)
                    bgcolor = self.palette().color(QPalette.Background)
                    c_painter.fillRect(self.c_pixmap.rect(), bgcolor)
                    c_painter.drawImage(0, 0, c_image)

                # Set calibre cover
                self.calibre_cover.setPixmap(self.c_pixmap)

                if self.opts.prefs.get('development_mode', False):
                    # Show individual covers
                    _fetch_marvin_cover()
                else:
                    # Show calibre cover on both sides
                    self.marvin_cover.setPixmap(self.c_pixmap)

            else:
                # Covers don't match - render with border
                # Construct a QImage with the cover sized to fit inside border
                c_image = QImage()
                cdata = db.cover(self.cid, index_is_id=True)
                if cdata is None:
                    c_image.load(I('book.png'))
                else:
                    c_image.loadFromData(cdata)

                c_image = c_image.scaledToHeight(
                    self.COVER_ICON_SIZE - self.BORDER_WIDTH * 2,
                    Qt.SmoothTransformation)

                # Construct a QPixmap with yellow background
                self.c_pixmap = QPixmap(
                    QSize(c_image.width() + self.BORDER_WIDTH * 2,
                          c_image.height() + self.BORDER_WIDTH * 2))
                c_painter = QPainter(self.c_pixmap)
                c_painter.setRenderHints(c_painter.Antialiasing)
                c_painter.fillRect(self.c_pixmap.rect(),
                                   QColor(0xFD, 0xFF, 0x99))
                c_painter.drawImage(self.BORDER_WIDTH, self.BORDER_WIDTH,
                                    c_image)
                self.calibre_cover.setPixmap(self.c_pixmap)
                _fetch_marvin_cover(with_border=True)
        else:
            _fetch_marvin_cover()
예제 #18
0
    def add_image(self, img, cache_key):
        ref = self.get_image(cache_key)
        if ref is not None:
            return ref

        fmt = img.format()
        image = QImage(img)
        if (image.depth() == 1 and img.colorTable().size() == 2 and
            img.colorTable().at(0) == QColor(Qt.black).rgba() and
            img.colorTable().at(1) == QColor(Qt.white).rgba()):
            if fmt == QImage.Format_MonoLSB:
                image = image.convertToFormat(QImage.Format_Mono)
            fmt = QImage.Format_Mono
        else:
            if (fmt != QImage.Format_RGB32 and fmt != QImage.Format_ARGB32):
                image = image.convertToFormat(QImage.Format_ARGB32)
                fmt = QImage.Format_ARGB32

        w = image.width()
        h = image.height()
        d = image.depth()

        if fmt == QImage.Format_Mono:
            bytes_per_line = (w + 7) >> 3
            data = image.constBits().asstring(bytes_per_line * h)
            return self.write_image(data, w, h, d, cache_key=cache_key)

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, 'jpeg', 94)
        data = bytes(ba.data())
        has_alpha = has_mask = False
        soft_mask = mask = None

        if fmt == QImage.Format_ARGB32:
            tmask = image.constBits().asstring(4*w*h)[self.alpha_bit::4]
            sdata = bytearray(tmask)
            vals = set(sdata)
            vals.discard(255)
            has_mask = bool(vals)
            vals.discard(0)
            has_alpha = bool(vals)

        if has_alpha:
            soft_mask = self.write_image(tmask, w, h, 8)
        elif has_mask:
            # dither the soft mask to 1bit and add it. This also helps PDF
            # viewers without transparency support
            bytes_per_line = (w + 7) >> 3
            mdata = bytearray(0 for i in xrange(bytes_per_line * h))
            spos = mpos = 0
            for y in xrange(h):
                for x in xrange(w):
                    if sdata[spos]:
                        mdata[mpos + x>>3] |= (0x80 >> (x&7))
                    spos += 1
                mpos += bytes_per_line
            mdata = bytes(mdata)
            mask = self.write_image(mdata, w, h, 1)

        return self.write_image(data, w, h, 32, mask=mask, dct=True,
                                    soft_mask=soft_mask, cache_key=cache_key)
예제 #19
0
    def add_image(self, img, cache_key):
        ref = self.get_image(cache_key)
        if ref is not None:
            return ref

        fmt = img.format()
        image = QImage(img)
        if (image.depth() == 1 and img.colorTable().size() == 2
                and img.colorTable().at(0) == QColor(Qt.black).rgba()
                and img.colorTable().at(1) == QColor(Qt.white).rgba()):
            if fmt == QImage.Format_MonoLSB:
                image = image.convertToFormat(QImage.Format_Mono)
            fmt = QImage.Format_Mono
        else:
            if (fmt != QImage.Format_RGB32 and fmt != QImage.Format_ARGB32):
                image = image.convertToFormat(QImage.Format_ARGB32)
                fmt = QImage.Format_ARGB32

        w = image.width()
        h = image.height()
        d = image.depth()

        if fmt == QImage.Format_Mono:
            bytes_per_line = (w + 7) >> 3
            data = image.constBits().asstring(bytes_per_line * h)
            return self.write_image(data, w, h, d, cache_key=cache_key)

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, 'jpeg', 94)
        data = bytes(ba.data())
        has_alpha = has_mask = False
        soft_mask = mask = None

        if fmt == QImage.Format_ARGB32:
            tmask = image.constBits().asstring(4 * w * h)[self.alpha_bit::4]
            sdata = bytearray(tmask)
            vals = set(sdata)
            vals.discard(255)
            has_mask = bool(vals)
            vals.discard(0)
            has_alpha = bool(vals)

        if has_alpha:
            soft_mask = self.write_image(tmask, w, h, 8)
        elif has_mask:
            # dither the soft mask to 1bit and add it. This also helps PDF
            # viewers without transparency support
            bytes_per_line = (w + 7) >> 3
            mdata = bytearray(0 for i in xrange(bytes_per_line * h))
            spos = mpos = 0
            for y in xrange(h):
                for x in xrange(w):
                    if sdata[spos]:
                        mdata[mpos + x >> 3] |= (0x80 >> (x & 7))
                    spos += 1
                mpos += bytes_per_line
            mdata = bytes(mdata)
            mask = self.write_image(mdata, w, h, 1)

        return self.write_image(data,
                                w,
                                h,
                                32,
                                mask=mask,
                                dct=True,
                                soft_mask=soft_mask,
                                cache_key=cache_key)