#include "iwa_textfx.h" #include "tparamuiconcept.h" #include #include #include //------------------------------------------------------------------ Iwa_TextFx::Iwa_TextFx() : m_text(L"Lorem ipsum") , m_hAlign(new TIntEnumParam(Qt::AlignLeft, "Left")) , m_center(TPointD(0.0, 0.0)) , m_width(200.0) , m_height(60.0) , m_font(new TFontParam()) , m_textColor(TPixel32::Black) , m_boxColor(TPixel32::Transparent) , m_showBorder(false) { m_targetType->setValue(INPUT_TEXT); m_hAlign->addItem(Qt::AlignRight, "Right"); m_hAlign->addItem(Qt::AlignHCenter, "Center"); m_hAlign->addItem(Qt::AlignJustify, "Justify"); m_text->setMultiLineEnabled(true); m_center->getX()->setMeasureName("fxLength"); m_center->getY()->setMeasureName("fxLength"); m_width->setMeasureName("fxLength"); m_height->setMeasureName("fxLength"); m_width->setValueRange(1.0, (std::numeric_limits::max)()); m_height->setValueRange(1.0, (std::numeric_limits::max)()); // set the initial font size to 30 QFont font; font.fromString(QString::fromStdWString(m_font->getValue())); font.setPixelSize(30); m_font->setValue(font.toString().toStdWString(), true); bindParam(this, "targetType", m_targetType); bindParam(this, "columnIndex", m_columnIndex); bindParam(this, "text", m_text); bindParam(this, "hAlign", m_hAlign); bindParam(this, "center", m_center); bindParam(this, "width", m_width); bindParam(this, "height", m_height); bindParam(this, "font", m_font); bindParam(this, "textColor", m_textColor); bindParam(this, "boxColor", m_boxColor); bindParam(this, "showBorder", m_showBorder); } //------------------------------------------------------------------ bool Iwa_TextFx::doGetBBox(double frame, TRectD &bBox, const TRenderSettings &ri) { bBox = TConsts::infiniteRectD; return true; } //------------------------------------------------------------------ void Iwa_TextFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri) { QString text; if (m_targetType->getValue() == INPUT_TEXT) text = QString::fromStdWString(m_text->getValue()); else text = m_noteLevelStr; if (text.isEmpty()) return; QFont font; font.fromString(QString::fromStdWString(m_font->getValue())); double fac = sqrt(fabs(ri.m_affine.det())); int size = (int)(fac * std::abs(font.pixelSize())); TPoint center = convert( fac * m_center->getValue(frame) - (tile.m_pos + tile.getRaster()->getCenterD()) + TPointD(ri.m_cameraBox.getLx() / 2.0, ri.m_cameraBox.getLy() / 2.0)); QRect textBoxRect(0, 0, fac * m_width->getValue(frame), fac * m_height->getValue(frame)); textBoxRect.moveCenter(QPoint(center.x, center.y)); Qt::AlignmentFlag hAlignFlag = (Qt::AlignmentFlag)m_hAlign->getValue(); // For simplification, text will always be "wrapped". // If user would like to make the line with no break, they can just expand the // boundary or set the smaller font size. int flag = hAlignFlag | Qt::AlignVCenter | Qt::TextWordWrap; QFont tmpFont(font); tmpFont.setPixelSize(100); QFontMetricsF tmpFm(tmpFont); QRectF bbox = tmpFm.boundingRect(textBoxRect, flag, text); float ratio = std::min(textBoxRect.width() / bbox.width(), textBoxRect.height() / bbox.height()); // compute the font size which will just fit the item region int fontSize = (int)(100.0f * ratio); tmpFont.setPixelSize(fontSize); tmpFm = QFontMetricsF(tmpFont); bbox = tmpFm.boundingRect(textBoxRect, flag, text); bool isInRect; if (textBoxRect.width() >= bbox.width() && textBoxRect.height() >= bbox.height()) isInRect = true; else isInRect = false; while (1) { fontSize += (isInRect) ? 1 : -1; if (fontSize <= 0) // cannot draw return; if (isInRect && fontSize >= size) break; tmpFont.setPixelSize(fontSize); tmpFm = QFontMetricsF(tmpFont); bbox = tmpFm.boundingRect(textBoxRect, flag, text); bool newIsInRect = (textBoxRect.width() >= bbox.width() && textBoxRect.height() >= bbox.height()); if (isInRect != newIsInRect) { if (isInRect) fontSize--; break; } } if (size < fontSize) { fontSize = size; } font.setPixelSize(fontSize); tmpFm = QFontMetricsF(font); bbox = tmpFm.boundingRect(textBoxRect, flag, text); double lineWidth = 0.1 * (double)fontSize; // Usually the text bounding box has less horizontal margin than vertical. // So here I added more margin to width. QImage img(bbox.width() + (int)(lineWidth * 4), bbox.height() + (int)(lineWidth * 2), QImage::Format_ARGB32_Premultiplied); img.fill(Qt::transparent); bbox.moveCenter(img.rect().center()); QPainter painter(&img); TPixel32 boxColor = m_boxColor->getValue(frame); TPixel32 color = m_textColor->getValue(frame); if (boxColor.m > 0) painter.fillRect(img.rect(), QColor((int)boxColor.r, (int)boxColor.g, (int)boxColor.b, (int)boxColor.m)); QPen pen(QColor((int)color.r, (int)color.g, (int)color.b, (int)color.m)); painter.setPen(pen); painter.setFont(font); painter.drawText(bbox, flag, text); if (m_showBorder->getValue()) { pen.setWidthF(lineWidth); pen.setJoinStyle(Qt::MiterJoin); painter.setPen(pen); painter.drawRect(img.rect().adjusted(lineWidth / 2, lineWidth / 2, -lineWidth / 2, -lineWidth / 2)); } TPoint imgRootPos = center - TPoint(img.width() / 2, img.height() / 2); tile.getRaster()->clear(); TRaster32P ras32 = (TRaster32P)tile.getRaster(); TRaster64P ras64 = (TRaster64P)tile.getRaster(); if (ras32) putTextImage(ras32, imgRootPos, img); else if (ras64) putTextImage(ras64, imgRootPos, img); else throw TException("Iwa_TextFx: unsupported Pixel Type"); } //------------------------------------------------------------------ void Iwa_TextFx::getParamUIs(TParamUIConcept *&concepts, int &length) { concepts = new TParamUIConcept[length = 2]; concepts[0].m_type = TParamUIConcept::POINT; concepts[0].m_label = "Center"; concepts[0].m_params.push_back(m_center); concepts[1].m_type = TParamUIConcept::RECT; concepts[1].m_params.push_back(m_width); concepts[1].m_params.push_back(m_height); concepts[1].m_params.push_back(m_center); } //------------------------------------------------------------------ std::string Iwa_TextFx::getAlias(double frame, const TRenderSettings &info) const { std::string alias = getFxType(); alias += "["; std::string paramalias(""); for (int i = 0; i < getParams()->getParamCount(); ++i) { TParam *param = getParams()->getParam(i); paramalias += param->getName() + "=" + param->getValueAlias(frame, 3); } if (m_targetType->getValue() == INPUT_TEXT) return alias + "," + std::to_string(getIdentifier()) + paramalias + "]"; else return alias + std::to_string(frame) + "," + std::to_string(getIdentifier()) + paramalias + "]"; } //------------------------------------------------------------------ template void Iwa_TextFx::putTextImage(const RASTER srcRas, TPoint &pos, QImage &img) { for (int j = 0; j < img.height(); j++) { int rasY = pos.y + j; if (rasY < 0) continue; if (srcRas->getLy() <= rasY) break; PIXEL *pix = srcRas->pixels(rasY); QRgb *img_p = (QRgb *)img.scanLine(img.height() - j - 1); for (int i = 0; i < img.width(); i++, img_p++) { int rasX = pos.x + i; if (rasX < 0) continue; if (srcRas->getLx() <= rasX) break; pix[rasX].r = (typename PIXEL::Channel)( qRed(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX); pix[rasX].g = (typename PIXEL::Channel)( qGreen(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX); pix[rasX].b = (typename PIXEL::Channel)( qBlue(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX); pix[rasX].m = (typename PIXEL::Channel)( qAlpha(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX); } } } //============================================================================== FX_PLUGIN_IDENTIFIER(Iwa_TextFx, "iwa_TextFx");