277 for (qint32 i = 0; i < 3; i++)
278 source[i] =
new quint8[rect.width()];
280 quint8* transition =
new quint8[rect.width()];
282 pixelSelection->
readBytes(
source[0], rect.x(), rect.y(), rect.width(), 1);
284 if (rect.height() > 1)
285 pixelSelection->
readBytes(
source[2], rect.x(), rect.y() + 1, rect.width(), 1);
290 pixelSelection->
writeBytes(transition, rect.x(), rect.y(), rect.width(), 1);
292 for (qint32 y = 1; y < rect.height(); y++) {
294 if (y + 1 < rect.height())
295 pixelSelection->
readBytes(
source[2], rect.x(), rect.y() + y + 1, rect.width(), 1);
299 pixelSelection->
writeBytes(transition, rect.x(), rect.y() + y, rect.width(), 1);
302 for (qint32 i = 0; i < 3; i++)
308 qint32* max =
new qint32[rect.width() + 2 *
m_xRadius];
309 for (qint32 i = 0; i < (rect.width() + 2 *
m_xRadius); i++)
313 for (qint32 i = 0; i < 3; i++)
314 buf[i] =
new quint8[rect.width()];
317 for (qint32 i = 0; i <
m_yRadius + 1; i++) {
318 transition[i] =
new quint8[rect.width() + 2 *
m_xRadius];
319 memset(transition[i], 0, rect.width() + 2 *
m_xRadius);
322 quint8* out =
new quint8[rect.width()];
323 density =
new quint8*[2 *
m_xRadius + 1];
326 for (qint32 x = 0; x < (
m_xRadius + 1); x++) {
327 density[ x] =
new quint8[2 *
m_yRadius + 1];
329 density[-x] = density[x];
336 const qreal minRadius = maxRadius - 1.0;
338 for (qint32 x = 0; x < (
m_xRadius + 1); x++) {
342 for (qint32 y = 0; y < (
m_yRadius + 1); y++) {
346 if (dist > maxRadius) {
348 }
else if (dist > minRadius) {
349 a = qRound((1.0 - dist + minRadius) * 255.0);
362 for (qint32 x = 0; x < (
m_xRadius + 1); x++) {
363 double tmpx, tmpy, dist;
366 tmpx = x > 0.0 ? x - 0.5 : 0.0;
368 for (qint32 y = 0; y < (
m_yRadius + 1); y++) {
369 tmpy = y > 0.0 ? y - 0.5 : 0.0;
374 a = dist <= 1.0 ? 255 : 0;
384 pixelSelection->
readBytes(buf[0], rect.x(), rect.y(), rect.width(), 1);
385 memcpy(buf[1], buf[0], rect.width());
386 if (rect.height() > 1)
387 pixelSelection->
readBytes(buf[2], rect.x(), rect.y() + 1, rect.width(), 1);
389 memcpy(buf[2], buf[1], rect.width());
392 for (qint32 y = 1; y <
m_yRadius && y + 1 < rect.height(); y++) {
394 pixelSelection->
readBytes(buf[2], rect.x(), rect.y() + y + 1, rect.width(), 1);
397 for (qint32 x = 0; x < rect.width(); x++) {
399 for (qint32 j = 1; j <
m_yRadius + 1; j++)
400 if (transition[j][x]) {
405 for (qint32 y = 0; y < rect.height(); y++) {
408 if (y < rect.height() - (
m_yRadius + 1)) {
409 pixelSelection->
readBytes(buf[2], rect.x(), rect.y() + y +
m_yRadius + 1, rect.width(), 1);
414 for (qint32 x = 0; x < rect.width(); x++) {
421 }
else if (transition[-max[x]][x])
423 else if (transition[-max[x] + 1][x])
424 max[x] = -max[x] + 1;
432 quint8 last_max = max[0][density[-1]];
433 qint32 last_index = 1;
434 for (qint32 x = 0 ; x < rect.width(); x++) {
436 if (last_index >= 0) {
439 if (max[x + i] <=
m_yRadius && max[x + i] >= -
m_yRadius && density[i][max[x+i]] > last_max) {
440 last_max = density[i][max[x + i]];
447 if (max[x + i] <=
m_yRadius && max[x + i] >= -
m_yRadius && density[i][max[x + i]] > last_max) {
448 last_max = density[i][max[x + i]];
455 for (i = x + 1; i < rect.width(); i++) {
467 pixelSelection->
writeBytes(out, rect.x(), rect.y() + y, rect.width(), 1);
471 for (qint32 i = 0; i < 3; i++)
477 for (qint32 i = 0; i <
m_yRadius + 1; i++) {
479 delete transition[i];
483 for (qint32 i = 0; i <
m_xRadius + 1 ; i++) {
1037 const quint32 bytesPerPaddedScanline = ((bytesPerScanline + 7) / 8) * 8;
1046 scanlines[i] = buffer.data() + i * bytesPerPaddedScanline;
1052 memset(scanlines[i], defaultPixel, bytesPerScanline);
1067 memset(scanlines[i], defaultPixel, bytesPerScanline);
1073 for (
int y = 0; y < rect.height(); ++y)
1078 std::rotate(std::begin(scanlines), std::begin(scanlines) + 1, std::end(scanlines));
1092 for (
int x = 0; x < rect.width(); ++x)
1098 const qint32 pixelNW = *(pixelPtrN - 1);
1099 const qint32 pixelN = *(pixelPtrN );
1100 const qint32 pixelNE = *(pixelPtrN + 1);
1101 const qint32 pixelW = *(pixelPtrM - 1);
1102 const qint32 pixelM = *(pixelPtrM );
1103 const qint32 pixelE = *(pixelPtrM + 1);
1104 const qint32 pixelSW = *(pixelPtrS - 1);
1105 const qint32 pixelS = *(pixelPtrS );
1106 const qint32 pixelSE = *(pixelPtrS + 1);
1108 const qint32 rowNSum = (pixelNW >> 2) + (pixelN >> 1) + (pixelNE >> 2);
1109 const qint32 rowMSum = (pixelW >> 2) + (pixelM >> 1) + (pixelE >> 2);
1110 const qint32 rowSSum = (pixelSW >> 2) + (pixelS >> 1) + (pixelSE >> 2);
1111 const qint32 colWSum = (pixelNW >> 2) + (pixelW >> 1) + (pixelSW >> 2);
1112 const qint32 colMSum = (pixelN >> 2) + (pixelM >> 1) + (pixelS >> 2);
1113 const qint32 colESum = (pixelNE >> 2) + (pixelE >> 1) + (pixelSE >> 2);
1114 const qint32 gradientN = qAbs(rowMSum - rowNSum);
1115 const qint32 gradientS = qAbs(rowSSum - rowMSum);
1116 const qint32 gradientW = qAbs(colMSum - colWSum);
1117 const qint32 gradientE = qAbs(colESum - colMSum);
1119 const qint32 maxGradientNS = qMax(gradientN, gradientS);
1120 const qint32 maxGradientWE = qMax(gradientW, gradientE);
1121 const qint32 maxGradient = qMax(maxGradientNS, maxGradientWE);
1125 antialiasedScanline[x] = pixelM;
1129 qint32 neighborPixel, gradient;
1130 qint32 pixelOffset, rowMultiplier, colMultiplier;
1131 if (maxGradientNS > maxGradientWE) {
1133 if (gradientN > gradientS) {
1135 neighborPixel = pixelN;
1136 gradient = gradientN;
1140 neighborPixel = pixelS;
1141 gradient = gradientS;
1148 if (gradientW > gradientE) {
1150 neighborPixel = pixelW;
1151 gradient = gradientW;
1155 neighborPixel = pixelE;
1156 gradient = gradientE;
1163 const qint32 pixelAvg = (neighborPixel + pixelM) >> 1;
1164 const qint32 currentPixelDiff = pixelM - pixelAvg;
1165 qint32 negativePixelDiff, positivePixelDiff;
1166 qint32 negativeSpanEndDistance, positiveSpanEndDistance;
1167 bool negativeSpanExtremeValid, positiveSpanExtremeValid;
1169 rowMultiplier, colMultiplier,
1170 pixelAvg, gradient >> 2, currentPixelDiff,
1171 &negativeSpanEndDistance, &positiveSpanEndDistance,
1172 &negativePixelDiff, &positivePixelDiff,
1173 &negativeSpanExtremeValid, &positiveSpanExtremeValid);
1177 qint32 interpolationValue;
1179 negativePixelDiff, positivePixelDiff, currentPixelDiff,
1180 negativeSpanExtremeValid, positiveSpanExtremeValid, &interpolationValue)) {
1181 antialiasedScanline[x] = pixelM;
1183 antialiasedScanline[x] = neighborPixel + ((pixelM - neighborPixel) * interpolationValue >> 8);
1187 pixelSelection->
writeBytes(antialiasedScanline.data(), rect.x(), rect.y() + y, rect.width(), 1);
1222 growFilter.
process(pixelSelection, rect);
1224 const qint32 maskScanLineSize = rect.width();
1226 const qint32 referencePixelSize = referenceColorSpace->
pixelSize();
1227 const qint32 referenceScanLineSize = maskScanLineSize * referencePixelSize;
1232 quint8 *maskScanLines[2] = {maskBuffer.data(), maskBuffer.data() + maskScanLineSize};
1233 quint8 *referenceScanLines[2] = {referenceBuffer.data(), referenceBuffer.data() + referenceScanLineSize};
1234 quint8 *selectionScanLine = selectionBuffer.data();
1236 auto testSelectPixel =
1237 [referenceColorSpace]
1238 (quint8 pixelOpacity, quint8 pixelIntensity,
1239 const quint8 *testMaskPixel,
const quint8 *testReferencePixel) ->
bool
1241 if (*testMaskPixel) {
1242 const quint8 testOpacity = referenceColorSpace->
opacityU8(testReferencePixel);
1243 if (pixelOpacity >= testOpacity) {
1251 const quint8 testIntensity = referenceColorSpace->
intensity8(testReferencePixel);
1252 if (pixelIntensity <= testIntensity) {
1263 mask->
readBytes(maskScanLines[1], rect.left(), rect.top(), maskScanLineSize, 1);
1265 pixelSelection->
readBytes(selectionScanLine, rect.left(), rect.top(), maskScanLineSize, 1);
1266 quint8 *currentMaskScanLineBegin = maskScanLines[1];
1267 quint8 *currentMaskScanLineEnd = maskScanLines[1] + maskScanLineSize;
1268 quint8 *currentReferenceScanLineBegin = referenceScanLines[1];
1269 quint8 *currentSelectionScanLineBegin = selectionScanLine;
1271 ++currentMaskScanLineBegin;
1272 currentReferenceScanLineBegin += referencePixelSize;
1273 ++currentSelectionScanLineBegin;
1275 while (currentMaskScanLineBegin != currentMaskScanLineEnd) {
1277 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1278 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1280 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1281 currentMaskScanLineBegin - 1,
1282 currentReferenceScanLineBegin - referencePixelSize);
1283 if (pixelIsSelected) {
1287 ++currentMaskScanLineBegin;
1288 currentReferenceScanLineBegin += referencePixelSize;
1289 ++currentSelectionScanLineBegin;
1291 mask->
writeBytes(maskScanLines[1], rect.left(), rect.top(), maskScanLineSize, 1);
1294 for (qint32 y = rect.top() + 1; y <= rect.bottom(); ++y) {
1297 mask->
readBytes(maskScanLines[1], rect.left(), y, maskScanLineSize, 1);
1299 pixelSelection->
readBytes(selectionScanLine, rect.left(), y, maskScanLineSize, 1);
1300 quint8 *currentMaskScanLineBegin = maskScanLines[1];
1301 quint8 *currentMaskScanLineEnd = maskScanLines[1] + maskScanLineSize;
1302 quint8 *currentReferenceScanLineBegin = referenceScanLines[1];
1303 quint8 *topMaskScanLineBegin = maskScanLines[0];
1304 quint8 *topReferenceScanLineBegin = referenceScanLines[0];
1305 quint8 *currentSelectionScanLineBegin = selectionScanLine;
1309 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1310 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1312 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1313 topMaskScanLineBegin,
1314 topReferenceScanLineBegin);
1315 if (!pixelIsSelected) {
1316 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1317 topMaskScanLineBegin + 1,
1318 topReferenceScanLineBegin + referencePixelSize);
1320 if (pixelIsSelected) {
1324 ++currentMaskScanLineBegin;
1325 currentReferenceScanLineBegin += referencePixelSize;
1326 ++topMaskScanLineBegin;
1327 topReferenceScanLineBegin += referencePixelSize;
1328 ++currentSelectionScanLineBegin;
1331 while (currentMaskScanLineBegin != (currentMaskScanLineEnd - 1)) {
1333 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1334 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1336 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1337 topMaskScanLineBegin - 1,
1338 topReferenceScanLineBegin - referencePixelSize);
1339 if (!pixelIsSelected) {
1340 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1341 topMaskScanLineBegin,
1342 topReferenceScanLineBegin);
1343 if (!pixelIsSelected) {
1344 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1345 topMaskScanLineBegin + 1,
1346 topReferenceScanLineBegin + referencePixelSize);
1347 if (!pixelIsSelected) {
1348 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1349 currentMaskScanLineBegin - 1,
1350 currentReferenceScanLineBegin - referencePixelSize);
1354 if (pixelIsSelected) {
1358 ++currentMaskScanLineBegin;
1359 currentReferenceScanLineBegin += referencePixelSize;
1360 ++topMaskScanLineBegin;
1361 topReferenceScanLineBegin += referencePixelSize;
1362 ++currentSelectionScanLineBegin;
1367 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1368 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1370 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1371 topMaskScanLineBegin - 1,
1372 topReferenceScanLineBegin - referencePixelSize);
1373 if (!pixelIsSelected) {
1374 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1375 topMaskScanLineBegin,
1376 topReferenceScanLineBegin);
1377 if (!pixelIsSelected) {
1378 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1379 currentMaskScanLineBegin - 1,
1380 currentReferenceScanLineBegin - referencePixelSize);
1383 if (pixelIsSelected) {
1388 mask->
writeBytes(maskScanLines[1], rect.left(), y, maskScanLineSize, 1);
1394 mask->
readBytes(maskScanLines[1], rect.left(), rect.bottom(), maskScanLineSize, 1);
1396 pixelSelection->
readBytes(selectionScanLine, rect.left(), rect.bottom(), maskScanLineSize, 1);
1397 quint8 *currentMaskScanLineBegin = maskScanLines[1] + maskScanLineSize - 1;
1398 quint8 *currentMaskScanLineEnd = maskScanLines[1] - 1;
1399 quint8 *currentReferenceScanLineBegin = referenceScanLines[1] + referenceScanLineSize - referencePixelSize;
1400 quint8 *currentSelectionScanLineBegin = selectionScanLine + maskScanLineSize - 1;
1402 --currentMaskScanLineBegin;
1403 currentReferenceScanLineBegin -= referencePixelSize;
1404 --currentSelectionScanLineBegin;
1406 while (currentMaskScanLineBegin != currentMaskScanLineEnd) {
1408 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1409 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1411 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1412 currentMaskScanLineBegin + 1,
1413 currentReferenceScanLineBegin + referencePixelSize);
1414 if (pixelIsSelected) {
1418 --currentMaskScanLineBegin;
1419 currentReferenceScanLineBegin -= referencePixelSize;
1420 --currentSelectionScanLineBegin;
1422 mask->
writeBytes(maskScanLines[1], rect.left(), rect.top(), maskScanLineSize, 1);
1425 for (qint32 y = rect.bottom() - 1; y >= rect.top(); --y) {
1428 mask->
readBytes(maskScanLines[1], rect.left(), y, maskScanLineSize, 1);
1430 pixelSelection->
readBytes(selectionScanLine, rect.left(), y, maskScanLineSize, 1);
1431 quint8 *currentMaskScanLineBegin = maskScanLines[1] + maskScanLineSize - 1;
1432 quint8 *currentMaskScanLineEnd = maskScanLines[1] - 1;
1433 quint8 *currentReferenceScanLineBegin = referenceScanLines[1] + referenceScanLineSize - referencePixelSize;
1434 quint8 *bottomMaskScanLineBegin = maskScanLines[0] + maskScanLineSize - 1;
1435 quint8 *bottomReferenceScanLineBegin = referenceScanLines[0] + referenceScanLineSize - referencePixelSize;
1436 quint8 *currentSelectionScanLineBegin = selectionScanLine + maskScanLineSize - 1;
1440 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1441 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1443 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1444 bottomMaskScanLineBegin,
1445 bottomReferenceScanLineBegin);
1446 if (!pixelIsSelected) {
1447 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1448 bottomMaskScanLineBegin - 1,
1449 bottomReferenceScanLineBegin - referencePixelSize);
1451 if (pixelIsSelected) {
1455 --currentMaskScanLineBegin;
1456 currentReferenceScanLineBegin -= referencePixelSize;
1457 --bottomMaskScanLineBegin;
1458 bottomReferenceScanLineBegin -= referencePixelSize;
1459 --currentSelectionScanLineBegin;
1462 while (currentMaskScanLineBegin != (currentMaskScanLineEnd + 1)) {
1464 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1465 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1467 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1468 bottomMaskScanLineBegin + 1,
1469 bottomReferenceScanLineBegin + referencePixelSize);
1470 if (!pixelIsSelected) {
1471 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1472 bottomMaskScanLineBegin,
1473 bottomReferenceScanLineBegin);
1474 if (!pixelIsSelected) {
1475 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1476 bottomMaskScanLineBegin - 1,
1477 bottomReferenceScanLineBegin - referencePixelSize);
1478 if (!pixelIsSelected) {
1479 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1480 currentMaskScanLineBegin + 1,
1481 currentReferenceScanLineBegin + referencePixelSize);
1485 if (pixelIsSelected) {
1489 --currentMaskScanLineBegin;
1490 currentReferenceScanLineBegin -= referencePixelSize;
1491 --bottomMaskScanLineBegin;
1492 bottomReferenceScanLineBegin -= referencePixelSize;
1493 --currentSelectionScanLineBegin;
1498 const quint8 currentOpacity = referenceColorSpace->
opacityU8(currentReferenceScanLineBegin);
1499 const quint8 currentIntensity = referenceColorSpace->
intensity8(currentReferenceScanLineBegin);
1501 bool pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1502 bottomMaskScanLineBegin + 1,
1503 bottomReferenceScanLineBegin + referencePixelSize);
1504 if (!pixelIsSelected) {
1505 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1506 bottomMaskScanLineBegin,
1507 bottomReferenceScanLineBegin);
1508 if (!pixelIsSelected) {
1509 pixelIsSelected = testSelectPixel(currentOpacity, currentIntensity,
1510 currentMaskScanLineBegin + 1,
1511 currentReferenceScanLineBegin + referencePixelSize);
1514 if (pixelIsSelected) {
1519 mask->
writeBytes(maskScanLines[1], rect.left(), y, maskScanLineSize, 1);