void WebPage::slotIconChanged(void) { QIcon icon = m_browser->GetIcon(); if (icon.isNull()) { //FIXME use a default icon here? m_listItem->setImage(NULL); } else { if (m_listItem) { QPixmap pixmap = icon.pixmap(32, 32); QImage image = pixmap.toImage(); image = image.scaled( QSize(32,32), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); MythImage *mimage = GetMythPainter()->GetFormatImage(); mimage->Assign(image); m_listItem->setImage(mimage); } } m_parent->m_pageList->Refresh(); }
void ZMEvents::eventVisible(MythUIButtonListItem *item) { if (!item) return; if (item->HasImage()) return; Event *event = qVariantValue<Event*> (item->GetData()); if (event) { QImage image; if (ZMClient *zm = ZMClient::get()) { zm->getAnalyseFrame(event, 0, image); if (!image.isNull()) { MythImage *mimage = GetMythPainter()->GetFormatImage(); mimage->Assign(image); item->SetImage(mimage); mimage->SetChanged(); mimage->DecrRef(); } } } }
// Called by the video player to redraw the image. void MHIContext::UpdateOSD(InteractiveScreen *osdWindow, MythPainter *osdPainter) { if (!osdWindow || !osdPainter) return; QMutexLocker locker(&m_display_lock); m_updated = false; osdWindow->DeleteAllChildren(); // Copy all the display items into the display. list<MHIImageData*>::iterator it = m_display.begin(); for (int count = 0; it != m_display.end(); ++it, count++) { MHIImageData *data = *it; MythImage* image = osdPainter->GetFormatImage(); if (!image) continue; image->Assign(data->m_image); MythUIImage *uiimage = new MythUIImage(osdWindow, QString("itv%1") .arg(count)); if (uiimage) { uiimage->SetImage(image); uiimage->SetArea(MythRect(data->m_x, data->m_y, data->m_image.width(), data->m_image.height())); } image->DecrRef(); } osdWindow->OptimiseDisplayedArea(); // N.B. bypasses OSD class hence no expiry set osdWindow->SetVisible(true); }
void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos) { VideoOutput *vo = m_player->GetVideoOutput(); if (!vo) return; QRect scaled = vo->GetImageRect(pos); if (scaled.size() != pos.size()) { img = img.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } MythPainter *osd_painter = vo->GetOSDPainter(); MythImage* image = NULL; if (osd_painter) image = osd_painter->GetFormatImage(); if (image) { image->Assign(img); MythUIImage *uiimage = new MythUIImage(this, "dvd_button"); if (uiimage) { m_refreshArea = true; uiimage->SetImage(image); uiimage->SetArea(MythRect(scaled)); } } }
MythImage *AudioOutputGraph::GetImage(int64_t timecode) const { QMutexLocker lock(&m_mutex); Buffer::range_t avail = m_buffer->Avail(timecode); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("(%1) using [%2..%3] avail [%4..%5]") .arg(timecode).arg(avail.first).arg(avail.second) .arg(m_buffer->First()).arg(m_buffer->Next()) ); const int width = m_buffer->Samples(avail); if (width <= 0) return nullptr; const unsigned range = 1U << m_buffer->BitsPerChannel(); const double threshold = 20 * log10(1.0 / range); // 16bit=-96.3296dB => ~6dB/bit const int height = (int)-ceil(threshold); // 96 if (height <= 0) return nullptr; QImage image(width, height, QImage::Format_ARGB32); image.fill(0); const int channels = m_buffer->Channels(); // Assume signed 16 bit/sample const int16_t *p = m_buffer->Data16(avail); for (int x = 0; x < width; ++x) { int left = p[0]; int right = channels > 1 ? p[1] : left; p += channels; unsigned avg = qAbs(left) + qAbs(right); double db = 20 * log10( (double)(avg ? avg : 1) / range); int idb = (int)ceil(db); QRgb rgb = idb <= m_dBsilence ? qRgb(255, 255, 255) : idb <= m_dBquiet ? qRgb( 0, 255, 255) : idb <= m_dBLoud ? qRgb( 0, 255, 0) : idb <= m_dbMax ? qRgb(255, 255, 0) : qRgb(255, 0, 0); int v = height - (int)(height * (db / threshold)); if (v >= height) v = height - 1; else if (v < 0) v = 0; for (int y = 0; y <= v; ++y) image.setPixel(x, height - 1 - y, rgb); } MythImage *mi = new MythImage(m_painter); mi->Assign(image); return mi; }
MythImage* MythQImagePainter::GetImageFromRect(const QSize &size, int radius, bool drawFill, const QColor &fillColor, bool drawLine, int lineWidth, const QColor &lineColor) { if (size.width() <= 0 || size.height() <= 0) return NULL; QString incoming = QString("RECT") + QString::number(size.width()) + QString::number(size.height()) + QString::number(radius) + QString::number(drawFill) + QString::number(fillColor.rgba()) + QString::number(drawLine) + QString::number(lineWidth) + QString::number(lineColor.rgba()); if (m_StringToImageMap.contains(incoming)) { m_StringExpireList.remove(incoming); m_StringExpireList.push_back(incoming); return m_StringToImageMap[incoming]; } QImage image(QSize(size.width(), size.height()), QImage::Format_ARGB32); image.fill(0x00000000); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); if (drawLine) painter.setPen(QPen(lineColor, lineWidth)); else painter.setPen(QPen(Qt::NoPen)); if (drawFill) painter.setBrush(QBrush(fillColor)); else painter.setBrush(QBrush(Qt::NoBrush)); if ((size.width() / 2) < radius) radius = size.width() / 2; if ((size.height() / 2) < radius) radius = size.height() / 2; QRect r(lineWidth / 2, lineWidth / 2, size.width() - lineWidth, size.height() - lineWidth); painter.drawRoundedRect(r, (qreal)radius, qreal(radius)); painter.end(); MythImage *im = GetFormatImage(); im->Assign(image); m_StringToImageMap[incoming] = im; m_StringExpireList.push_back(incoming); ExpireImages(MAX_CACHE_ITEMS); return im; }
void Player::updateFrame(const unsigned char* buffer) { QImage image(buffer, m_monitor.width, m_monitor.height, QImage::Format_RGB888); MythImage *img = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage(); img->Assign(image); m_frameImage->SetImage(img); img->DecrRef(); }
void ThumbFinder::updatePositionBar(int64_t frame) { if (!m_positionImage) return; QSize size = m_positionImage->GetArea().size(); QPixmap *pixmap = new QPixmap(size.width(), size.height()); QPainter p(pixmap); QBrush brush(Qt::green); p.setBrush(brush); p.setPen(Qt::NoPen); p.fillRect(0, 0, size.width(), size.height(), brush); frm_dir_map_t::const_iterator it; brush.setColor(Qt::red); double startdelta, enddelta; for (it = m_deleteMap.begin(); it != m_deleteMap.end(); ++it) { if (it.key() != 0) startdelta = (m_archiveItem->duration * m_fps) / it.key(); else startdelta = size.width(); ++it; if (it == m_deleteMap.end()) { LOG(VB_GENERAL, LOG_ERR, "ThumbFinder: found a start cut but no cut end"); break; } if (it.key() != 0) enddelta = (m_archiveItem->duration * m_fps) / it.key(); else enddelta = size.width(); int start = (int) (size.width() / startdelta); int end = (int) (size.width() / enddelta); p.fillRect(start - 1, 0, end - start, size.height(), brush); } if (frame == 0) frame = 1; brush.setColor(Qt::yellow); int pos = (int) (size.width() / ((m_archiveItem->duration * m_fps) / frame)); p.fillRect(pos, 0, 3, size.height(), brush); MythImage *image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage(); image->Assign(*pixmap); m_positionImage->SetImage(image); p.end(); delete pixmap; }
void TeletextScreen::OptimiseDisplayedArea(void) { VideoOutput *vo = m_player->GetVideoOutput(); if (!vo) return; MythPainter *osd_painter = vo->GetOSDPainter(); if (!osd_painter) return; QHashIterator<int, QImage*> it(m_rowImages); while (it.hasNext()) { it.next(); MythImage* image = osd_painter->GetFormatImage(); if (!image || !it.value()) continue; int row = it.key(); image->Assign(*(it.value())); MythUIImage *uiimage = new MythUIImage(this, QString("ttrow%1") .arg(row)); if (uiimage) { uiimage->SetImage(image); uiimage->SetArea(MythRect(0, row * m_rowHeight, m_safeArea.width(), m_rowHeight * 2)); } } QRegion visible; QListIterator<MythUIType *> i(m_ChildrenList); while (i.hasNext()) { MythUIType *img = i.next(); visible = visible.united(img->GetArea()); } if (visible.isEmpty()) return; QRect bounding = visible.boundingRect(); bounding = bounding.translated(m_safeArea.topLeft()); bounding = m_safeArea.intersected(bounding); int left = m_safeArea.left() - bounding.left(); int top = m_safeArea.top() - bounding.top(); SetArea(MythRect(bounding)); i.toFront();; while (i.hasNext()) { MythUIType *img = i.next(); img->SetArea(img->GetArea().translated(left, top)); } }
void ZMEvents::eventChanged(MythUIButtonListItem *item) { (void) item; if (m_eventNoText) { if (m_eventGrid->GetCount() > 0) m_eventNoText->SetText(QString("%1/%2") .arg(m_eventGrid->GetCurrentPos() + 1).arg(m_eventGrid->GetCount())); else m_eventNoText->SetText("0/0"); } // update the images for all the visible items for (int x = m_eventGrid->GetCurrentPos() - m_eventGrid->GetVisibleCount(); x < m_eventGrid->GetCurrentPos() + (int)m_eventGrid->GetVisibleCount(); x++) { if (x < 0 || x > (int)m_eventGrid->GetCount() - 1) continue; MythUIButtonListItem *gridItem = m_eventGrid->GetItemAt(x); if (gridItem && !gridItem->getImage()) { if (x < 0 || x > (int)m_eventList->size() - 1) continue; Event *event = m_eventList->at(x); if (event) { QImage image; if (class ZMClient *zm = ZMClient::get()) { zm->getAnalyseFrame(event->monitorID, event->eventID, 0, image); if (!image.isNull()) { MythImage *mimage = GetMythPainter()->GetFormatImage(); mimage->Assign(image); gridItem->setImage(mimage); mimage->SetChanged(); } } } } } }
bool ThumbFinder::getFrameImage(bool needKeyFrame, int64_t requiredPTS) { AVPacket pkt; AVFrame orig; AVFrame retbuf; memset(&orig, 0, sizeof(AVFrame)); memset(&retbuf, 0, sizeof(AVFrame)); av_init_packet(&pkt); int frameFinished = 0; int keyFrame; int frameCount = 0; bool gotKeyFrame = false; while (av_read_frame(m_inputFC, &pkt) >= 0 && !frameFinished) { if (pkt.stream_index == m_videostream) { frameCount++; keyFrame = pkt.flags & AV_PKT_FLAG_KEY; if (m_startPTS == -1 && pkt.dts != AV_NOPTS_VALUE) { m_startPTS = pkt.dts; m_frameTime = pkt.duration; } if (keyFrame) gotKeyFrame = true; if (!gotKeyFrame && needKeyFrame) { av_packet_unref(&pkt); continue; } if (m_firstIFramePTS == -1) m_firstIFramePTS = pkt.dts; av_frame_unref(m_frame); frameFinished = 0; int ret = avcodec_receive_frame(m_codecCtx, m_frame); if (ret == 0) frameFinished = 1; if (ret == 0 || ret == AVERROR(EAGAIN)) ret = avcodec_send_packet(m_codecCtx, &pkt); if (requiredPTS != -1 && pkt.dts != AV_NOPTS_VALUE && pkt.dts < requiredPTS) frameFinished = false; m_currentPTS = pkt.dts; } av_packet_unref(&pkt); } if (frameFinished) { av_image_fill_arrays(retbuf.data, retbuf.linesize, m_outputbuf, AV_PIX_FMT_RGB32, m_frameWidth, m_frameHeight, IMAGE_ALIGN); AVFrame *tmp = m_frame; m_deinterlacer->DeinterlaceSingle(tmp, tmp); m_copy.Copy(&retbuf, AV_PIX_FMT_RGB32, tmp, m_codecCtx->pix_fmt, m_frameWidth, m_frameHeight); QImage img(m_outputbuf, m_frameWidth, m_frameHeight, QImage::Format_RGB32); QByteArray ffile = m_frameFile.toLocal8Bit(); if (!img.save(ffile.constData(), "JPEG")) { LOG(VB_GENERAL, LOG_ERR, "Failed to save thumb: " + m_frameFile); } if (m_updateFrame) { MythImage *mimage = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage(); mimage->Assign(img); m_frameImage->SetImage(mimage); mimage->DecrRef(); } updateCurrentPos(); } return true; }
void BDOverlayScreen::DisplayBDOverlay(BDOverlay *overlay) { if (!overlay || !m_player) return; if (!overlay->m_data) { m_overlayArea = overlay->m_position; SetArea(MythRect(m_overlayArea)); DeleteAllChildren(); m_overlayMap.clear(); SetRedraw(); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Initialised Size: %1x%2 (%3+%4) Plane: %5 Pts: %6") .arg(overlay->m_position.width()) .arg(overlay->m_position.height()) .arg(overlay->m_position.left()) .arg(overlay->m_position.top()) .arg(overlay->m_plane) .arg(overlay->m_pts)); BDOverlay::DeleteOverlay(overlay); return; } if (!m_overlayArea.isValid()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Error: Overlay image submitted before initialisation."); } VideoOutput *vo = m_player->GetVideoOutput(); if (!vo) return; QRect rect = overlay->m_position; QString hash = QString("%1+%2+%3x%4") .arg(rect.left()).arg(rect.top()) .arg(rect.width()).arg(rect.height()); // remove if we already have this overlay if (m_overlayMap.contains(hash)) { LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Removing %1 (%2 left)") .arg(hash).arg(m_overlayMap.size())); MythUIImage *old = m_overlayMap.take(hash); DeleteChild(old); } // convert the overlay palette to ARGB uint32_t *origpalette = (uint32_t *)(overlay->m_palette); QVector<unsigned int> palette; for (int i = 0; i < 256; i++) { int y = (origpalette[i] >> 0) & 0xff; int cr = (origpalette[i] >> 8) & 0xff; int cb = (origpalette[i] >> 16) & 0xff; int a = (origpalette[i] >> 24) & 0xff; int r = int(y + 1.4022 * (cr - 128)); int b = int(y + 1.7710 * (cb - 128)); int g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r)); if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; if (r > 0xff) r = 0xff; if (g > 0xff) g = 0xff; if (b > 0xff) b = 0xff; palette.push_back((a << 24) | (r << 16) | (g << 8) | b); } // convert the image to QImage QImage img(rect.size(), QImage::Format_Indexed8); memcpy(img.bits(), overlay->m_data, rect.width() * rect.height()); img.setColorTable(palette); img.convertToFormat(QImage::Format_ARGB32); // add to screen QRect scaled = vo->GetImageRect(rect); if (scaled.size() != rect.size()) { img = img.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } MythPainter *osd_painter = vo->GetOSDPainter(); MythImage* image = NULL; if (osd_painter) image = osd_painter->GetFormatImage(); if (image) { image->Assign(img); MythUIImage *uiimage = new MythUIImage(this, "bdoverlay"); if (uiimage) { uiimage->SetImage(image); uiimage->SetArea(MythRect(scaled)); m_overlayMap.insert(hash, uiimage); LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Added %1 (%2 tot)") .arg(hash).arg(m_overlayMap.size())); } } SetRedraw(); BDOverlay::DeleteOverlay(overlay); }
/** * Update the various fields of a MythNotificationScreen. */ void MythNotificationScreen::Init(void) { if (!m_refresh) // nothing got changed so far, return return; AdjustYPosition(); if (m_artworkImage && (m_update & kImage)) { if (!m_imagePath.isNull()) { // We have a path to the image, use it m_artworkImage->SetFilename(m_imagePath); m_artworkImage->Load(); } else if (!m_image.isNull()) { // We don't have a path to the image, but the image itself MythImage *img = m_artworkImage->GetPainter()->GetFormatImage(); img->Assign(m_image); m_artworkImage->SetImage(img); img->DecrRef(); } else { // Will default to displaying whatever placeholder image is defined // in the xml by the themer, means we can show _something_ rather than // a big empty hole. Generally you always want to call Reset() in // these circumstances m_artworkImage->Reset(); } } if (m_update != kNone) { InfoMap tmap; tmap["title"] = m_title; if (m_update & kImage) { tmap["image"] = m_imagePath; } tmap["origin"] = m_origin; tmap["description"] = m_description; tmap["extra"] = m_extra; if (m_update & kDuration) { tmap["progress_text"] = m_progresstext; tmap["progress"] = QString("%1").arg((int)(m_progress * 100)); } SetTextFromMap(tmap); } if (m_update & kMetaData) { if (m_titleText && m_title.isNull()) { m_titleText->Reset(); } if (m_originText && m_origin.isNull()) { m_originText->Reset(); } if (m_descriptionText && m_description.isNull()) { m_descriptionText->Reset(); } if (m_extraText && m_extra.isNull()) { m_extraText->Reset(); } } if (m_update & kDuration) { if (m_progresstextText && m_progresstext.isEmpty()) { m_progresstextText->Reset(); } if (m_progressBar) { if (m_progress >= 0) { m_progressBar->SetStart(0); m_progressBar->SetTotal(100); m_progressBar->SetUsed(100 * m_progress); } else { // Same as above, calling Reset() allows for a sane, themer defined //default to be displayed m_progressBar->Reset(); } } } if (m_progressBar) { m_progressBar->SetVisible((m_content & kDuration) != 0); } SetErrorState(); if (m_mediaState && (m_update & kImage)) { m_mediaState->DisplayState(m_update & kNoArtwork ? "noartwork" : "ok"); LOG(VB_GUI, LOG_DEBUG, LOC + QString("Init: Set media state to %1").arg(m_update & kNoArtwork ? "noartwork" : "ok")); } // No field will be refreshed the next time unless specified otherwise m_update = kNone; if (GetScreenStack() && !m_added) { GetScreenStack()->AddScreen(this); m_added = true; } m_refresh = false; }
void SubtitleScreen::DisplayAVSubtitles(void) { if (!m_player || !m_subreader) return; AVSubtitles* subs = m_subreader->GetAVSubtitles(); QMutexLocker lock(&(subs->lock)); if (subs->buffers.empty() && (kDisplayAVSubtitle != m_subtitleType)) return; VideoOutput *videoOut = m_player->GetVideoOutput(); VideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : NULL; if (!currentFrame || !videoOut) return; float tmp = 0.0; QRect dummy; videoOut->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp); while (!subs->buffers.empty()) { const AVSubtitle subtitle = subs->buffers.front(); if (subtitle.start_display_time > currentFrame->timecode) break; ClearDisplayedSubtitles(); subs->buffers.pop_front(); for (std::size_t i = 0; i < subtitle.num_rects; ++i) { AVSubtitleRect* rect = subtitle.rects[i]; bool displaysub = true; if (subs->buffers.size() > 0 && subs->buffers.front().end_display_time < currentFrame->timecode) { displaysub = false; } if (displaysub && rect->type == SUBTITLE_BITMAP) { // AVSubtitleRect's image data's not guaranteed to be 4 byte // aligned. QSize img_size(rect->w, rect->h); QRect img_rect(rect->x, rect->y, rect->w, rect->h); QRect display(rect->display_x, rect->display_y, rect->display_w, rect->display_h); // XSUB and some DVD/DVB subs are based on the original video // size before the video was converted. We need to guess the // original size and allow for the difference int right = rect->x + rect->w; int bottom = rect->y + rect->h; if (subs->fixPosition || (currentFrame->height < bottom) || (currentFrame->width < right)) { int sd_height = 576; if ((m_player->GetFrameRate() > 26.0f) && bottom <= 480) sd_height = 480; int height = ((currentFrame->height <= sd_height) && (bottom <= sd_height)) ? sd_height : ((currentFrame->height <= 720) && bottom <= 720) ? 720 : 1080; int width = ((currentFrame->width <= 720) && (right <= 720)) ? 720 : ((currentFrame->width <= 1280) && (right <= 1280)) ? 1280 : 1920; display = QRect(0, 0, width, height); } QRect scaled = videoOut->GetImageRect(img_rect, &display); QImage qImage(img_size, QImage::Format_ARGB32); for (int y = 0; y < rect->h; ++y) { for (int x = 0; x < rect->w; ++x) { const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x]; const uint32_t pixel = *((uint32_t*)rect->pict.data[1]+color); qImage.setPixel(x, y, pixel); } } if (scaled.size() != img_size) { qImage = qImage.scaled(scaled.width(), scaled.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } MythPainter *osd_painter = videoOut->GetOSDPainter(); MythImage* image = NULL; if (osd_painter) image = osd_painter->GetFormatImage(); long long displayfor = subtitle.end_display_time - subtitle.start_display_time; if (displayfor == 0) displayfor = 60000; displayfor = (displayfor < 50) ? 50 : displayfor; long long late = currentFrame->timecode - subtitle.start_display_time; MythUIImage *uiimage = NULL; if (image) { image->Assign(qImage); QString name = QString("avsub%1").arg(i); uiimage = new MythUIImage(this, name); if (uiimage) { m_refreshArea = true; uiimage->SetImage(image); uiimage->SetArea(MythRect(scaled)); m_expireTimes.insert(uiimage, currentFrame->timecode + displayfor); } } if (uiimage) { LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display %1AV subtitle for %2ms") .arg(subtitle.forced ? "FORCED " : "") .arg(displayfor)); if (late > 50) LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sub was %1ms late").arg(late)); } } #ifdef USING_LIBASS else if (displaysub && rect->type == SUBTITLE_ASS) { InitialiseAssTrack(m_player->GetDecoder()->GetTrack(kTrackTypeSubtitle)); AddAssEvent(rect->ass); } #endif } m_subreader->FreeAVSubtitle(subtitle); } #ifdef USING_LIBASS RenderAssTrack(currentFrame->timecode); #endif }
MythImage *MythQImagePainter::GetImageFromString(const QString &msg, int flags, const QRect &r, const MythFontProperties &font) { QString incoming = font.GetHash() + QString::number(r.width()) + QString::number(r.height()) + QString::number(flags) + QString::number(font.color().rgba()) + msg; if (m_StringToImageMap.contains(incoming)) { m_StringExpireList.remove(incoming); m_StringExpireList.push_back(incoming); return m_StringToImageMap[incoming]; } MythImage *im = GetFormatImage(); QPoint drawOffset; font.GetOffset(drawOffset); QImage pm(r.size(), QImage::Format_ARGB32); QColor fillcolor = font.color(); if (font.hasOutline()) { QColor outlineColor; int outlineSize, outlineAlpha; font.GetOutline(outlineColor, outlineSize, outlineAlpha); fillcolor = outlineColor; } fillcolor.setAlpha(0); pm.fill(fillcolor.rgba()); QPainter tmp(&pm); tmp.setFont(font.face()); if (font.hasShadow()) { QPoint shadowOffset; QColor shadowColor; int shadowAlpha; font.GetShadow(shadowOffset, shadowColor, shadowAlpha); QRect a = QRect(0, 0, r.width(), r.height()); a.translate(shadowOffset.x() + drawOffset.x(), shadowOffset.y() + drawOffset.y()); shadowColor.setAlpha(shadowAlpha); tmp.setPen(shadowColor); tmp.drawText(a, flags, msg); } if (font.hasOutline()) { QColor outlineColor; int outlineSize, outlineAlpha; font.GetOutline(outlineColor, outlineSize, outlineAlpha); /* FIXME: use outlineAlpha */ int outalpha = 16; QRect a = QRect(0, 0, r.width(), r.height()); a.translate(-outlineSize + drawOffset.x(), -outlineSize + drawOffset.y()); outlineColor.setAlpha(outalpha); tmp.setPen(outlineColor); tmp.drawText(a, flags, msg); for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(1, 0); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, 1); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(-1, 0); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, -1); tmp.drawText(a, flags, msg); } } tmp.setPen(font.color()); tmp.drawText(drawOffset.x(), drawOffset.y(), r.width(), r.height(), flags, msg); tmp.end(); im->Assign(pm); m_StringToImageMap[incoming] = im; m_StringExpireList.push_back(incoming); ExpireImages(MAX_CACHE_ITEMS); return im; }
MythImage *MythPainter::GetImageFromTextLayout(const LayoutVector &layouts, const FormatVector &formats, const MythFontProperties &font, QRect &canvas, QRect &dest) { LayoutVector::const_iterator Ipara; QString incoming = QString::number(canvas.x()) + QString::number(canvas.y()) + QString::number(canvas.width()) + QString::number(canvas.height()) + QString::number(dest.width()) + QString::number(dest.height()) + font.GetHash(); for (Ipara = layouts.begin(); Ipara != layouts.end(); ++Ipara) incoming += (*Ipara)->text(); MythImage *im = NULL; if (m_StringToImageMap.contains(incoming)) { m_StringExpireList.remove(incoming); m_StringExpireList.push_back(incoming); im = m_StringToImageMap[incoming]; if (im) im->IncrRef(); } else { im = GetFormatImage(); im->SetFileName("GetImageFromTextLayout"); QImage pm(canvas.size(), QImage::Format_ARGB32_Premultiplied); pm.fill(0); QPainter painter(&pm); if (!painter.isActive()) { LOG(VB_GENERAL, LOG_ERR, "MythPainter::GetImageFromTextLayout: " "Invalid canvas."); return im; } QRect clip; clip.setSize(canvas.size()); QFont tmpfont = font.face(); tmpfont.setStyleStrategy(QFont::OpenGLCompatible); painter.setFont(tmpfont); painter.setRenderHint(QPainter::Antialiasing); if (font.hasShadow()) { QRect shadowRect; QPoint shadowOffset; QColor shadowColor; int shadowAlpha; font.GetShadow(shadowOffset, shadowColor, shadowAlpha); shadowColor.setAlpha(shadowAlpha); MythPoint shadow(shadowOffset); shadow.NormPoint(); // scale it to screen resolution shadowRect = canvas; shadowRect.translate(shadow.x(), shadow.y()); painter.setPen(shadowColor); for (Ipara = layouts.begin(); Ipara != layouts.end(); ++Ipara) (*Ipara)->draw(&painter, shadowRect.topLeft(), formats, clip); } painter.setPen(QPen(font.GetBrush(), 0)); for (Ipara = layouts.begin(); Ipara != layouts.end(); ++Ipara) (*Ipara)->draw(&painter, canvas.topLeft(), formats, clip); painter.end(); pm.setOffset(canvas.topLeft()); im->Assign(pm.copy(0, 0, dest.width(), dest.height())); im->IncrRef(); m_SoftwareCacheSize += im->bytesPerLine() * im->height(); m_StringToImageMap[incoming] = im; m_StringExpireList.push_back(incoming); ExpireImages(m_MaxSoftwareCacheSize); } return im; }