diff --git a/items/icon.cpp b/items/icon.cpp index 994e36cab192835426d7a9e38d96c9b986cf6248..02cac9643c074b1bbc0d7c45e2042ecdc767d64b 100644 --- a/items/icon.cpp +++ b/items/icon.cpp @@ -1132,6 +1132,7 @@ QImage Icon::addIconBox(QImage &image) } //有底图标按照第一方规范裁剪圆角并缩放至背景区域大小 case Icon::RectangleWithBack : { + completeImagePixal(effectiveArea); if(IconBackgroundUtils::instance()->containShadow(image.width())) { effectiveArea = clipBackground(effectiveArea, backImageNoShadow, backImageEffectArea.rect()); cliped = true; @@ -1307,41 +1308,63 @@ bool Icon::isTransparencyBackground(QImage image) || bottomLeft.y() != bottomRight.y() || rightTop.x() != rightBottom.x()) { return true; } - auto threshold = image.width() >= 32? 1 : 0; - if (qAbs((topRight.x() - topLeft.x()) - (bottomRight.x() - bottomLeft.x())) > threshold || qAbs((leftBottom.y() - leftTop.y()) - (rightBottom.y() - rightTop.y())) > threshold) { + + int threshold = image.width() >= 128 ? 5 : image.width()/ 32 + 1; + + if (!judgeSideLengths(leftBottom.y() - leftTop.y(), rightBottom.y() - rightTop.y(), topRight.x() - topLeft.x(), bottomRight.x() - bottomLeft.x(), threshold)) { return true; } - + //找到四条边最长连续不透明像素点个数,排除X形等不规则图形的干扰 int topOpaquePointCount = 0; int bottomOpaquePointCount = 0; int leftOpaquePointCount = 0; int rightOpaquePointCount = 0; + int pointTemp = 0; for (int y = leftTop.y(); y <= leftBottom.y(); ++y) { - if (qAlpha(image.pixel(leftTop.x(), y)) > 25) { - ++leftOpaquePointCount; + if (qAlpha(image.pixel(leftTop.x(), y)) > 127) { + ++pointTemp; + } else { + leftOpaquePointCount = pointTemp > leftOpaquePointCount ? pointTemp : leftOpaquePointCount; + pointTemp = 0; } } - + leftOpaquePointCount = pointTemp > leftOpaquePointCount ? pointTemp : leftOpaquePointCount; + pointTemp = 0; for (int x = topLeft.x(); x <= topRight.x(); ++x) { - if (qAlpha(image.pixel(x, topLeft.y())) > 25) { - ++topOpaquePointCount; + if (qAlpha(image.pixel(x, topLeft.y())) > 127) { + ++pointTemp; + } else { + topOpaquePointCount = pointTemp > topOpaquePointCount ? pointTemp : topOpaquePointCount; + pointTemp = 0; } } + topOpaquePointCount = pointTemp > topOpaquePointCount ? pointTemp : topOpaquePointCount; + pointTemp = 0; for (int y = rightTop.y(); y <= rightBottom.y(); ++y) { - if (qAlpha(image.pixel(rightTop.x(), y)) > 25) { - ++rightOpaquePointCount; + if (qAlpha(image.pixel(rightTop.x(), y)) > 127) { + ++pointTemp; + } else { + rightOpaquePointCount = pointTemp > rightOpaquePointCount ? pointTemp : rightOpaquePointCount; + pointTemp = 0; } } + rightOpaquePointCount = pointTemp > rightOpaquePointCount ? pointTemp : rightOpaquePointCount; + pointTemp = 0; for (int x = bottomLeft.x(); x <= bottomRight.x(); ++x) { - if (qAlpha(image.pixel(x, bottomLeft.y())) > 25) { - ++bottomOpaquePointCount; + if (qAlpha(image.pixel(x, bottomLeft.y())) > 127) { + ++pointTemp; + } else { + bottomOpaquePointCount = pointTemp > bottomOpaquePointCount ? pointTemp : bottomOpaquePointCount; + pointTemp = 0; } } + bottomOpaquePointCount = pointTemp > bottomOpaquePointCount ? pointTemp : bottomOpaquePointCount; + //如果这四条线上的不透明点小于58%则认为无底 (58%来自一个典型的圆形图标 某歌浏览器) - if (topOpaquePointCount < image.width() * 0.58 || - bottomOpaquePointCount < image.width() * 0.58 || - leftOpaquePointCount < image.height() * 0.58 || - rightOpaquePointCount < image.height() * 0.58) { + if (topOpaquePointCount < qRound((rightTop.x() - leftTop.x() + 1) * 0.58) || + bottomOpaquePointCount < qRound((rightBottom.x() - leftBottom.x() + 1) * 0.58) || + leftOpaquePointCount < qRound((bottomLeft.y() - topLeft.y() + 1) * 0.58) || + rightOpaquePointCount < qRound((bottomRight.y() - topRight.y() + 1) * 0.58)) { return true; } return false; @@ -1424,11 +1447,10 @@ void Icon::getImageType(const QImage &effectArea, const QImage &image, int image if(effectArea.isNull()) { d->imageType = Icon::Uninitialized; } - if (isFirstPartyIcon(effectArea, imageSize)) { if (!IconBackgroundUtils::instance()->containShadow(imageSize) && !(effectArea.width() == standardEffectAreaSize && effectArea.height() == effectArea.width())) { - if(!isTransparencyBackground(image)) { + if(!isTransparencyBackground(getNonShadowArea(effectArea))) { d->imageType = RectangleWithBack; } else { d->imageType = Other; @@ -1438,14 +1460,13 @@ void Icon::getImageType(const QImage &effectArea, const QImage &image, int image d->imageType = Icon::FirstParty; return; } - if(qAbs(effectArea.width() - effectArea.height()) >= 2) { if(effectArea.width() > effectArea.height() + 1) { d->imageType = Icon::RectangleHorizontal; } else if (effectArea.width() + 1 < effectArea.height()) { d->imageType = Icon::RectangleVertical; } - } else if(!isTransparencyBackground(image)) { + } else if(!isTransparencyBackground(getNonShadowArea(effectArea))) { d->imageType = Icon::RectangleWithBack; } else { d->imageType = Icon::Other; @@ -1601,4 +1622,486 @@ QHash, int> Icon::getTransparentPoint(const QImage &image) return imageAlphaList; } + +bool Icon::judgeSideLengths(int left, int right, int top, int bottom, int threshold) +{ + int max = std::max({left, right, top}); + int min = std::min({left, right, top}); + if (max - min <= threshold) { + return true; + } + + max = std::max({left, right, bottom}); + min = std::min({left, right, bottom}); + if (max - min <= threshold) { + return true; + } + + max = std::max({left, top, bottom}); + min = std::min({left, top, bottom}); + if (max - min <= threshold) { + return true; + } + + max = std::max({right, top, bottom}); + min = std::min({right, top, bottom}); + if (max - min <= threshold) { + return true; + } + return false; +} + +QImage Icon::getNonShadowArea(QImage image) +{ + if (image.isNull()) { + return image; + } + //找到图标有效区域四个定点的第一个不透明点 + QPoint topLeft; + QPoint topRight; + QPoint leftTop; + QPoint leftBottom; + QPoint rightTop; + QPoint rightBottom; + QPoint bottomLeft; + QPoint bottomRight; + + bool getMax = false; + bool getMin = false; + + uchar *pixels = image.bits(); + const int bytesPerLine = image.bytesPerLine(); // 每行字节数 + + for (int y = 0; y < image.height(); ++y) { + const QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + + for (int x = 0; x < image.width(); ++x) { + if (!getMin && qAlpha(line[x]) > 200) { + topLeft.setX(x); + topLeft.setY(y); + getMin = true; + } + if (!getMax && qAlpha(line[image.width() - x - 1]) > 200) { + topRight.setX(image.width() - x - 1); + topRight.setY(y); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return image; + } + getMax = false; + getMin = false; + + for (int y = image.height() - 1; y > 0; --y) { + const QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for (int x = 0; x < image.width(); ++x) { + if (!getMin && qAlpha(line[x]) > 200) { + bottomLeft.setX(x); + bottomLeft.setY(y); + getMin = true; + } + if (!getMax && qAlpha(line[image.width() - x - 1]) > 200) { + bottomRight.setX(image.width() - x - 1); + bottomRight.setY(y); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return image; + } + getMax = false; + getMin = false; + + for (int x = 0; x < image.width(); ++x) { + for (int y = 0; y < image.height(); ++y) { + const QRgb *lineTop = reinterpret_cast(pixels + y * bytesPerLine); + const QRgb *lineBottom = reinterpret_cast(pixels + (image.height() - y - 1) * bytesPerLine); + if (!getMin && qAlpha(lineTop[x]) > 200) { + leftTop.setX(x); + leftTop.setY(y); + getMin = true; + } + if (!getMax && qAlpha(lineBottom[x]) > 200) { + leftBottom.setX(x ); + leftBottom.setY(image.height() - y - 1); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return image; + } + getMax = false; + getMin = false; + + for (int x = image.width() - 1; x > 0; --x) { + for (int y = 0; y < image.height(); ++y) { + const QRgb *lineTop = reinterpret_cast(pixels + y * bytesPerLine); + const QRgb *lineBottom = reinterpret_cast(pixels + (image.height() - y - 1) * bytesPerLine); + if (!getMin && qAlpha(lineTop[x]) > 200) { + rightTop.setX(x); + rightTop.setY(y); + getMin = true; + } + if (!getMax && qAlpha(lineBottom[x]) > 200) { + rightBottom.setX(x); + rightBottom.setY(image.height() - y - 1); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return image; + } + + //将四个角上,透明度低于150的部分设置为0 + for(int y = 0; y < leftTop.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < topLeft.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 150) { + color = qRgba(0, 0, 0, 0); + } + } + } + + for(int y = leftBottom.y(); y < image.height(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < bottomLeft.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 150) { + color = qRgba(0, 0, 0, 0); + } + } + } + + for(int y = 0; y < rightTop.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = topRight.x(); x < image.width(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 150) { + color = qRgba(0, 0, 0, 0); + } + } + } + + for(int y = rightBottom.y(); y < image.height(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = bottomRight.x(); x < image.width(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 150) { + color = qRgba(0, 0, 0, 0); + } + } + } + + int top = topLeft.y() < topRight.y() ? topLeft.y() : topRight.y(); + int bottom = bottomLeft.y() > bottomRight.y() ? bottomLeft.y() : bottomRight.y(); + int left = leftTop.x() < leftBottom.x() ? leftTop.x() : leftBottom.x(); + int right = rightTop.x() > rightBottom.x() ? rightTop.x() : rightBottom.x(); + + return image.copy(left, top, right - left + 1, bottom - top + 1); +} + +void Icon::completeImagePixal(QImage& image) +{ + if (image.isNull()) { + return; + } + //找到图标有效区域四个定点的第一个不透明点 + QPoint topLeft; + QPoint topRight; + QPoint leftTop; + QPoint leftBottom; + QPoint rightTop; + QPoint rightBottom; + QPoint bottomLeft; + QPoint bottomRight; + + bool getMax = false; + bool getMin = false; + + uchar *pixels = image.bits(); + const int bytesPerLine = image.bytesPerLine(); // 每行字节数 + + for(int y = 0; y < image.height(); ++y) { + const QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < image.width(); ++x) { + if(!getMin && qAlpha(line[x]) == 255) { + topLeft.setX(x); + topLeft.setY(y); + getMin = true; + } + if(!getMax && qAlpha(line[image.width() - x - 1]) == 255) { + topRight.setX(image.width() - x - 1); + topRight.setY(y); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return; + } + getMax = false; + getMin = false; + + for(int y = image.height() - 1; y > 0; --y) { + const QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < image.width(); ++x) { + if(!getMin && qAlpha(line[x]) == 255) { + bottomLeft.setX(x); + bottomLeft.setY(y); + getMin = true; + } + if(!getMax && qAlpha(line[image.width() - x - 1]) == 255) { + bottomRight.setX(image.width() - x - 1); + bottomRight.setY(y); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + if(!getMax || !getMin) { + return; + } + getMax = false; + getMin = false; + + for(int x = 0; x < image.width(); ++x) { + for(int y = 0; y < image.height(); ++y) { + const QRgb* lineTop = reinterpret_cast(pixels + y * bytesPerLine); + const QRgb* lineBottom = reinterpret_cast(pixels + (image.height() - y - 1) * bytesPerLine); + if(!getMin && qAlpha(lineTop[x]) == 255) { + leftTop.setX(x); + leftTop.setY(y); + getMin = true; + } + if(!getMax && qAlpha(lineBottom[x]) == 255) { + leftBottom.setX(x ); + leftBottom.setY(image.height() - y - 1); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return; + } + getMax = false; + getMin = false; + + for(int x = image.width() - 1; x > 0; --x) { + for(int y = 0; y < image.height(); ++y) { + const QRgb* lineTop = reinterpret_cast(pixels + y * bytesPerLine); + const QRgb* lineBottom = reinterpret_cast(pixels + (image.height() - y - 1) * bytesPerLine); + if(!getMin && qAlpha(lineTop[x]) == 255) { + rightTop.setX(x); + rightTop.setY(y); + getMin = true; + } + if(!getMax && qAlpha(lineBottom[x]) == 255) { + rightBottom.setX(x); + rightBottom.setY(image.height() - y - 1); + getMax = true; + } + if(getMax && getMin) { + break; + } + } + if(getMax && getMin) { + break; + } + } + + if(!getMax || !getMin) { + return; + } + + //将四条边上透明部分进行填充,上边下边按照Y轴最近不透明像素点进行填充,左边右边按照X轴最近不透明像素点进行填充 + int top = topLeft.y() > topRight.y() ? topLeft.y() : topRight.y(); + int bottom = bottomLeft.y() < bottomRight.y() ? bottomLeft.y() : bottomRight.y(); + int left = leftTop.x() > leftBottom.x() ? leftTop.x() : leftBottom.x(); + int right = rightTop.x() < rightBottom.x() ? rightTop.x() : rightBottom.x(); + + for(int y = 0; y < top; ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = topLeft.x(); x < topRight.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = y; i < image.height(); ++i) { + QRgb* lineTemp = reinterpret_cast(pixels + i * bytesPerLine); + QRgb &rgb = lineTemp[x]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = bottom; y < image.height(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = bottomLeft.x(); x < bottomRight.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = y; i >= 0; --i) { + QRgb* lineTemp = reinterpret_cast(pixels + i * bytesPerLine); + QRgb &rgb = lineTemp[x]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = leftTop.y(); y < leftBottom.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < left; ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x + 1; i < image.width(); ++i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = rightTop.y(); y < rightBottom.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = image.width() - 1; x > right; --x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x - 1; i > 0; --i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + //将四个角上,透明度小于250的部分设置为x方向上最近的透明度大于250的像素点颜色 + for(int y = 0; y < leftTop.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < topLeft.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x + 1; i < image.width(); ++i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = leftBottom.y(); y < image.height(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = 0; x < bottomLeft.x(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x + 1; i < image.width(); ++i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = 0; y < rightTop.y(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = topRight.x(); x < image.width(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x - 1; i > 0; --i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } + + for(int y = rightBottom.y(); y < image.height(); ++y) { + QRgb* line = reinterpret_cast(pixels + y * bytesPerLine); + for(int x = bottomRight.x(); x < image.width(); ++x) { + QRgb &color = line[x]; + if(qAlpha(color) < 250) { + for(int i = x - 1; i > 0; --i) { + QRgb &rgb = line[i]; + if(qAlpha(rgb) >= 250) { + color = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), 255); + break; + } + } + } + } + } +} + } // UkuiQuick diff --git a/items/icon.h b/items/icon.h index ffb541851b652f5e3515b6808579fd7ec4f255b6..6c515ebbfc968ed3cecbfd8fe23f315afec71490 100644 --- a/items/icon.h +++ b/items/icon.h @@ -186,6 +186,12 @@ private: bool isImagePureColor(QImage &image); QHash, int> getTransparentPoint(const QImage &image); + //判断图片的是否有三条边长度相等 + bool judgeSideLengths(int left, int right, int top, int bottom, int threshold); + //获取图片的无阴影区域 + QImage getNonShadowArea(QImage image); + //按照距离最近不透明像素颜色补全有底图标的边角区域 + void completeImagePixal(QImage& image); }; } // UkuiQuick