| OLD | NEW |
| 1 //------------------------------------------------------------------------------
--- | 1 //------------------------------------------------------------------------------
--- |
| 2 // | 2 // |
| 3 // Little Color Management System | 3 // Little Color Management System |
| 4 // Copyright (c) 1998-2011 Marti Maria Saguer | 4 // Copyright (c) 1998-2011 Marti Maria Saguer |
| 5 // | 5 // |
| 6 // Permission is hereby granted, free of charge, to any person obtaining | 6 // Permission is hereby granted, free of charge, to any person obtaining |
| 7 // a copy of this software and associated documentation files (the "Software"), | 7 // a copy of this software and associated documentation files (the "Software"), |
| 8 // to deal in the Software without restriction, including without limitation | 8 // to deal in the Software without restriction, including without limitation |
| 9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, | 9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 10 // and/or sell copies of the Software, and to permit persons to whom the Softwar
e | 10 // and/or sell copies of the Software, and to permit persons to whom the Softwar
e |
| (...skipping 1425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1436 | 1436 |
| 1437 // And across second shaper, | 1437 // And across second shaper, |
| 1438 Out[0] = p->Shaper2R[ri]; | 1438 Out[0] = p->Shaper2R[ri]; |
| 1439 Out[1] = p->Shaper2G[gi]; | 1439 Out[1] = p->Shaper2G[gi]; |
| 1440 Out[2] = p->Shaper2B[bi]; | 1440 Out[2] = p->Shaper2B[bi]; |
| 1441 | 1441 |
| 1442 } | 1442 } |
| 1443 | 1443 |
| 1444 // This table converts from 8 bits to 1.14 after applying the curve | 1444 // This table converts from 8 bits to 1.14 after applying the curve |
| 1445 static | 1445 static |
| 1446 void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) | 1446 cmsBool FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) |
| 1447 { | 1447 { |
| 1448 int i; | 1448 int i; |
| 1449 cmsFloat32Number R, y; | 1449 cmsFloat32Number R, y; |
| 1450 | 1450 |
| 1451 for (i=0; i < 256; i++) { | 1451 for (i=0; i < 256; i++) { |
| 1452 | 1452 |
| 1453 R = (cmsFloat32Number) (i / 255.0); | 1453 R = (cmsFloat32Number) (i / 255.0); |
| 1454 y = cmsEvalToneCurveFloat(Curve, R); | 1454 y = cmsEvalToneCurveFloat(Curve, R); |
| 1455 if (isinf(y)) |
| 1456 return FALSE; |
| 1455 | 1457 |
| 1456 Table[i] = DOUBLE_TO_1FIXED14(y); | 1458 Table[i] = DOUBLE_TO_1FIXED14(y); |
| 1457 } | 1459 } |
| 1460 return TRUE; |
| 1458 } | 1461 } |
| 1459 | 1462 |
| 1460 // This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after a
pplying the curve | 1463 // This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after a
pplying the curve |
| 1461 static | 1464 static |
| 1462 void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
tsOutput) | 1465 cmsBool FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is
8BitsOutput) |
| 1463 { | 1466 { |
| 1464 int i; | 1467 int i; |
| 1465 cmsFloat32Number R, Val; | 1468 cmsFloat32Number R, Val; |
| 1466 | 1469 |
| 1467 for (i=0; i < 16385; i++) { | 1470 for (i=0; i < 16385; i++) { |
| 1468 | 1471 |
| 1469 R = (cmsFloat32Number) (i / 16384.0); | 1472 R = (cmsFloat32Number) (i / 16384.0); |
| 1470 Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 | 1473 Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 |
| 1474 if (isinf(Val)) |
| 1475 return FALSE; |
| 1471 | 1476 |
| 1472 if (Is8BitsOutput) { | 1477 if (Is8BitsOutput) { |
| 1473 | 1478 |
| 1474 // If 8 bits output, we can optimize further by computing the / 257
part. | 1479 // If 8 bits output, we can optimize further by computing the / 257
part. |
| 1475 // first we compute the resulting byte and then we store the byte ti
mes | 1480 // first we compute the resulting byte and then we store the byte ti
mes |
| 1476 // 257. This quantization allows to round very quick by doing a >> 8
, but | 1481 // 257. This quantization allows to round very quick by doing a >> 8
, but |
| 1477 // since the low byte is always equal to msb, we can do a & 0xff and
this works! | 1482 // since the low byte is always equal to msb, we can do a & 0xff and
this works! |
| 1478 cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); | 1483 cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); |
| 1479 cmsUInt8Number b = FROM_16_TO_8(w); | 1484 cmsUInt8Number b = FROM_16_TO_8(w); |
| 1480 | 1485 |
| 1481 Table[i] = FROM_8_TO_16(b); | 1486 Table[i] = FROM_8_TO_16(b); |
| 1482 } | 1487 } |
| 1483 else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); | 1488 else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); |
| 1484 } | 1489 } |
| 1490 return TRUE; |
| 1485 } | 1491 } |
| 1486 | 1492 |
| 1487 // Compute the matrix-shaper structure | 1493 // Compute the matrix-shaper structure |
| 1488 static | 1494 static |
| 1489 cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
msVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) | 1495 cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
msVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) |
| 1490 { | 1496 { |
| 1491 MatShaper8Data* p; | 1497 MatShaper8Data* p; |
| 1492 int i, j; | 1498 int i, j; |
| 1493 cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); | 1499 cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); |
| 1494 | 1500 |
| 1495 // Allocate a big chuck of memory to store precomputed tables | 1501 // Allocate a big chuck of memory to store precomputed tables |
| 1496 p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); | 1502 p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); |
| 1497 if (p == NULL) return FALSE; | 1503 if (p == NULL) return FALSE; |
| 1498 | 1504 |
| 1499 p -> ContextID = Dest -> ContextID; | 1505 p -> ContextID = Dest -> ContextID; |
| 1500 | 1506 |
| 1501 // Precompute tables | 1507 // Precompute tables |
| 1502 FillFirstShaper(p ->Shaper1R, Curve1[0]); | 1508 if (!FillFirstShaper(p ->Shaper1R, Curve1[0])) |
| 1503 FillFirstShaper(p ->Shaper1G, Curve1[1]); | 1509 goto Error; |
| 1504 FillFirstShaper(p ->Shaper1B, Curve1[2]); | 1510 if (!FillFirstShaper(p ->Shaper1G, Curve1[1])) |
| 1511 goto Error; |
| 1512 if (!FillFirstShaper(p ->Shaper1B, Curve1[2])) |
| 1513 goto Error; |
| 1505 | 1514 |
| 1506 FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); | 1515 if (!FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits)) |
| 1507 FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); | 1516 goto Error; |
| 1508 FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); | 1517 if (!FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits)) |
| 1518 goto Error; |
| 1519 if (!FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits)) |
| 1520 goto Error; |
| 1509 | 1521 |
| 1510 // Convert matrix to nFixed14. Note that those values may take more than 16
bits as | 1522 // Convert matrix to nFixed14. Note that those values may take more than 16
bits as |
| 1511 for (i=0; i < 3; i++) { | 1523 for (i=0; i < 3; i++) { |
| 1512 for (j=0; j < 3; j++) { | 1524 for (j=0; j < 3; j++) { |
| 1513 p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); | 1525 p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); |
| 1514 } | 1526 } |
| 1515 } | 1527 } |
| 1516 | 1528 |
| 1517 for (i=0; i < 3; i++) { | 1529 for (i=0; i < 3; i++) { |
| 1518 | 1530 |
| 1519 if (Off == NULL) { | 1531 if (Off == NULL) { |
| 1520 p ->Off[i] = 0; | 1532 p ->Off[i] = 0; |
| 1521 } | 1533 } |
| 1522 else { | 1534 else { |
| 1523 p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); | 1535 p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); |
| 1524 } | 1536 } |
| 1525 } | 1537 } |
| 1526 | 1538 |
| 1527 // Mark as optimized for faster formatter | 1539 // Mark as optimized for faster formatter |
| 1528 if (Is8Bits) | 1540 if (Is8Bits) |
| 1529 *OutputFormat |= OPTIMIZED_SH(1); | 1541 *OutputFormat |= OPTIMIZED_SH(1); |
| 1530 | 1542 |
| 1531 // Fill function pointers | 1543 // Fill function pointers |
| 1532 _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, Free
MatShaper, DupMatShaper); | 1544 _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, Free
MatShaper, DupMatShaper); |
| 1533 return TRUE; | 1545 return TRUE; |
| 1546 Error: |
| 1547 _cmsFree(Dest->ContextID, p); |
| 1548 return FALSE; |
| 1534 } | 1549 } |
| 1535 | 1550 |
| 1536 // 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB
. That's fast! | 1551 // 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB
. That's fast! |
| 1537 // TODO: Allow a third matrix for abs. colorimetric | 1552 // TODO: Allow a third matrix for abs. colorimetric |
| 1538 static | 1553 static |
| 1539 cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
2Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) | 1554 cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
2Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) |
| 1540 { | 1555 { |
| 1541 cmsStage* Curve1, *Curve2; | 1556 cmsStage* Curve1, *Curve2; |
| 1542 cmsStage* Matrix1, *Matrix2; | 1557 cmsStage* Matrix1, *Matrix2; |
| 1543 _cmsStageMatrixData* Data1; | 1558 _cmsStageMatrixData* Data1; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1599 } | 1614 } |
| 1600 else { | 1615 else { |
| 1601 _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData
(Curve1); | 1616 _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData
(Curve1); |
| 1602 _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData
(Curve2); | 1617 _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData
(Curve2); |
| 1603 | 1618 |
| 1604 // In this particular optimization, cach?does not help as it takes more
time to deal with | 1619 // In this particular optimization, cach?does not help as it takes more
time to deal with |
| 1605 // the cach?that with the pixel handling | 1620 // the cach?that with the pixel handling |
| 1606 *dwFlags |= cmsFLAGS_NOCACHE; | 1621 *dwFlags |= cmsFLAGS_NOCACHE; |
| 1607 | 1622 |
| 1608 // Setup the optimizarion routines | 1623 // Setup the optimizarion routines |
| 1609 SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, m
peC2->TheCurves, OutputFormat); | 1624 if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offs
et, mpeC2->TheCurves, OutputFormat)) |
| 1625 goto Error; |
| 1610 } | 1626 } |
| 1611 | 1627 |
| 1612 cmsPipelineFree(Src); | 1628 cmsPipelineFree(Src); |
| 1613 *Lut = Dest; | 1629 *Lut = Dest; |
| 1614 return TRUE; | 1630 return TRUE; |
| 1615 Error: | 1631 Error: |
| 1616 // Leave Src unchanged | 1632 // Leave Src unchanged |
| 1617 cmsPipelineFree(Dest); | 1633 cmsPipelineFree(Dest); |
| 1618 return FALSE; | 1634 return FALSE; |
| 1619 } | 1635 } |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1786 | 1802 |
| 1787 if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dw
Flags)) { | 1803 if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dw
Flags)) { |
| 1788 | 1804 |
| 1789 return TRUE; | 1805 return TRUE; |
| 1790 } | 1806 } |
| 1791 } | 1807 } |
| 1792 | 1808 |
| 1793 // Only simple optimizations succeeded | 1809 // Only simple optimizations succeeded |
| 1794 return AnySuccess; | 1810 return AnySuccess; |
| 1795 } | 1811 } |
| OLD | NEW |