fast_float_testbed.c 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450
  1. //---------------------------------------------------------------------------------
  2. //
  3. // Little Color Management System, fast floating point extensions
  4. // Copyright (c) 1998-2022 Marti Maria Saguer, all rights reserved
  5. //
  6. //
  7. // This program is free software: you can redistribute it and/or modify
  8. // it under the terms of the GNU General Public License as published by
  9. // the Free Software Foundation, either version 3 of the License, or
  10. // (at your option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. // GNU General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public License
  18. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. //
  20. //---------------------------------------------------------------------------------
  21. #include "fast_float_internal.h"
  22. #include <stdlib.h>
  23. #include <memory.h>
  24. // Some pixel representations
  25. typedef struct { cmsUInt8Number r, g, b; } Scanline_rgb8bits;
  26. typedef struct { cmsUInt8Number r, g, b, a; } Scanline_rgba8bits;
  27. typedef struct { cmsUInt8Number c, m, y, k; } Scanline_cmyk8bits;
  28. typedef struct { cmsUInt16Number r, g, b; } Scanline_rgb16bits;
  29. typedef struct { cmsUInt16Number r, g, b, a; } Scanline_rgba16bits;
  30. typedef struct { cmsUInt16Number c, m, y, k; } Scanline_cmyk16bits;
  31. typedef struct { cmsUInt16Number r, g, b; } Scanline_rgb15bits;
  32. typedef struct { cmsUInt16Number r, g, b, a; } Scanline_rgba15bits;
  33. typedef struct { cmsUInt16Number r, g, b, a; } Scanline_cmyk15bits;
  34. typedef struct { cmsFloat32Number r, g, b; } Scanline_rgbFloat;
  35. typedef struct { cmsFloat32Number r, g, b, a; } Scanline_rgbaFloat;
  36. typedef struct { cmsFloat32Number c, m, y, k; } Scanline_cmykFloat;
  37. typedef struct { cmsFloat32Number L, a, b; } Scanline_LabFloat;
  38. // 15 bit mode. <=> 8 bits mode
  39. #define FROM_8_TO_15(x8) (cmsUInt16Number) ((((cmsUInt64Number)x8 << 15)) / 0xFF)
  40. #define FROM_15_TO_8(x15) (cmsUInt8Number) (((cmsUInt64Number) x15 * 0xFF + 0x4000) >> 15)
  41. // Floating point accuracy for tests
  42. #define EPSILON_FLOAT_TESTS 0.005
  43. // A flushed printf
  44. static
  45. void trace(const char* frm, ...)
  46. {
  47. va_list args;
  48. va_start(args, frm);
  49. vfprintf(stderr, frm, args);
  50. fflush(stderr);
  51. va_end(args);
  52. }
  53. // The callback function used by cmsSetLogErrorHandler()
  54. static
  55. void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
  56. {
  57. UNUSED_PARAMETER(ContextID);
  58. UNUSED_PARAMETER(ErrorCode);
  59. trace("** Fatal error: %s\n", Text);
  60. exit(1);
  61. }
  62. // Rise an error and exit
  63. static
  64. void Fail(const char* frm, ...)
  65. {
  66. char ReasonToFailBuffer[1024];
  67. va_list args;
  68. va_start(args, frm);
  69. vsprintf(ReasonToFailBuffer, frm, args);
  70. FatalErrorQuit(0, 0, ReasonToFailBuffer);
  71. // unreachable va_end(args);
  72. }
  73. // Creates a fake profile that only has a curve. Used in several places
  74. static
  75. cmsHPROFILE CreateCurves(void)
  76. {
  77. cmsToneCurve* Gamma = cmsBuildGamma(0, 1.1);
  78. cmsToneCurve* Transfer[3];
  79. cmsHPROFILE h;
  80. Transfer[0] = Transfer[1] = Transfer[2] = Gamma;
  81. h = cmsCreateLinearizationDeviceLink(cmsSigRgbData, Transfer);
  82. cmsFreeToneCurve(Gamma);
  83. return h;
  84. }
  85. // Check for a single 15 bit Photoshop-like formatter
  86. static
  87. void CheckSingleFormatter15(cmsContext id, cmsUInt32Number Type, const char* Text)
  88. {
  89. cmsUInt16Number Values[cmsMAXCHANNELS];
  90. cmsUInt8Number Buffer[1024];
  91. cmsFormatter f, b;
  92. cmsInt32Number i, j, nChannels, bytes;
  93. _xform_head info;
  94. UNUSED_PARAMETER(id);
  95. memset(&info, 0, sizeof(info));
  96. info.OutputFormat = info.InputFormat = Type;
  97. // Get functions to go forth and back
  98. f = Formatter_15Bit_Factory(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
  99. b = Formatter_15Bit_Factory(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
  100. if (f.Fmt16 == NULL || b.Fmt16 == NULL) {
  101. Fail("no formatter for %s", Text);
  102. return;
  103. }
  104. nChannels = T_CHANNELS(Type);
  105. bytes = T_BYTES(Type);
  106. for (j = 0; j < 5; j++) {
  107. for (i = 0; i < nChannels; i++) {
  108. Values[i] = (cmsUInt16Number)(i + j) << 1;
  109. }
  110. b.Fmt16((struct _cmstransform_struct*) &info, Values, Buffer, 1);
  111. memset(Values, 0, sizeof(Values));
  112. f.Fmt16((struct _cmstransform_struct*) &info, Values, Buffer, 1);
  113. for (i = 0; i < nChannels; i++) {
  114. if (Values[i] != ((i + j) << 1)) {
  115. Fail("%s failed", Text);
  116. return;
  117. }
  118. }
  119. }
  120. }
  121. #define C(a) CheckSingleFormatter15(0, a, #a)
  122. // Check for all 15 bits formatters
  123. static
  124. void CheckFormatters15(void)
  125. {
  126. C(TYPE_GRAY_15);
  127. C(TYPE_GRAY_15_REV);
  128. C(TYPE_GRAY_15_SE);
  129. C(TYPE_GRAYA_15);
  130. C(TYPE_GRAYA_15_SE);
  131. C(TYPE_GRAYA_15_PLANAR);
  132. C(TYPE_RGB_15);
  133. C(TYPE_RGB_15_PLANAR);
  134. C(TYPE_RGB_15_SE);
  135. C(TYPE_BGR_15);
  136. C(TYPE_BGR_15_PLANAR);
  137. C(TYPE_BGR_15_SE);
  138. C(TYPE_RGBA_15);
  139. C(TYPE_RGBA_15_PLANAR);
  140. C(TYPE_RGBA_15_SE);
  141. C(TYPE_ARGB_15);
  142. C(TYPE_ABGR_15);
  143. C(TYPE_ABGR_15_PLANAR);
  144. C(TYPE_ABGR_15_SE);
  145. C(TYPE_BGRA_15);
  146. C(TYPE_BGRA_15_SE);
  147. C(TYPE_YMC_15);
  148. C(TYPE_CMY_15);
  149. C(TYPE_CMY_15_PLANAR);
  150. C(TYPE_CMY_15_SE);
  151. C(TYPE_CMYK_15);
  152. C(TYPE_CMYK_15_REV);
  153. C(TYPE_CMYK_15_PLANAR);
  154. C(TYPE_CMYK_15_SE);
  155. C(TYPE_KYMC_15);
  156. C(TYPE_KYMC_15_SE);
  157. C(TYPE_KCMY_15);
  158. C(TYPE_KCMY_15_REV);
  159. C(TYPE_KCMY_15_SE);
  160. }
  161. #undef C
  162. static
  163. cmsInt32Number checkSingleComputeIncrements(cmsUInt32Number Format, cmsUInt32Number planeStride, cmsUInt32Number ExpectedChannels, cmsUInt32Number ExpectedAlpha, ...)
  164. {
  165. cmsUInt32Number nChannels, nAlpha, nTotal, i, rc = 0 ;
  166. cmsUInt32Number ComponentStartingOrder[cmsMAXCHANNELS], ComponentPointerIncrements[cmsMAXCHANNELS];
  167. va_list args;
  168. va_start(args, ExpectedAlpha);
  169. _cmsComputeComponentIncrements(Format, planeStride, &nChannels, &nAlpha, ComponentStartingOrder, ComponentPointerIncrements);
  170. if (nChannels != ExpectedChannels)
  171. return 0;
  172. if (nAlpha != ExpectedAlpha)
  173. return 0;
  174. nTotal = nAlpha + nChannels;
  175. for (i = 0; i < nTotal; i++)
  176. {
  177. cmsUInt32Number so = va_arg(args, cmsUInt32Number);
  178. if (so != ComponentStartingOrder[i])
  179. goto Error;
  180. }
  181. for (i = 0; i < nTotal; i++)
  182. {
  183. cmsUInt32Number so = va_arg(args, cmsUInt32Number);
  184. if (so != ComponentPointerIncrements[i])
  185. goto Error;
  186. }
  187. // Success
  188. rc = 1;
  189. Error:
  190. va_end(args);
  191. return rc;
  192. }
  193. #define CHECK(frm, plane, chans, alpha, ...) if (!checkSingleComputeIncrements(frm, plane, chans, alpha, __VA_ARGS__)) { trace("Format failed!\n"); return 0; }
  194. // Validate the compute increments function
  195. cmsInt32Number CheckComputeIncrements(void)
  196. {
  197. CHECK(TYPE_GRAY_8, 0, 1, 0, /**/ 0, /**/ 1);
  198. CHECK(TYPE_GRAYA_8, 0, 1, 1, /**/ 0, 1, /**/ 2, 2);
  199. CHECK(TYPE_AGRAY_8, 0, 1, 1, /**/ 1, 0, /**/ 2, 2);
  200. CHECK(TYPE_GRAY_16, 0, 1, 0, /**/ 0, /**/ 2);
  201. CHECK(TYPE_GRAYA_16, 0, 1, 1, /**/ 0, 2, /**/ 4, 4);
  202. CHECK(TYPE_AGRAY_16, 0, 1, 1, /**/ 2, 0, /**/ 4, 4);
  203. CHECK(TYPE_GRAY_FLT, 0, 1, 0, /**/ 0, /**/ 4);
  204. CHECK(TYPE_GRAYA_FLT, 0, 1, 1, /**/ 0, 4, /**/ 8, 8);
  205. CHECK(TYPE_AGRAY_FLT, 0, 1, 1, /**/ 4, 0, /**/ 8, 8);
  206. CHECK(TYPE_GRAY_DBL, 0, 1, 0, /**/ 0, /**/ 8);
  207. CHECK(TYPE_AGRAY_DBL, 0, 1, 1, /**/ 8, 0, /**/ 16, 16);
  208. CHECK(TYPE_RGB_8, 0, 3, 0, /**/ 0, 1, 2, /**/ 3, 3, 3);
  209. CHECK(TYPE_RGBA_8, 0, 3, 1, /**/ 0, 1, 2, 3, /**/ 4, 4, 4, 4);
  210. CHECK(TYPE_ARGB_8, 0, 3, 1, /**/ 1, 2, 3, 0, /**/ 4, 4, 4, 4);
  211. CHECK(TYPE_RGB_16, 0, 3, 0, /**/ 0, 2, 4, /**/ 6, 6, 6);
  212. CHECK(TYPE_RGBA_16, 0, 3, 1, /**/ 0, 2, 4, 6, /**/ 8, 8, 8, 8);
  213. CHECK(TYPE_ARGB_16, 0, 3, 1, /**/ 2, 4, 6, 0, /**/ 8, 8, 8, 8);
  214. CHECK(TYPE_RGB_FLT, 0, 3, 0, /**/ 0, 4, 8, /**/ 12, 12, 12);
  215. CHECK(TYPE_RGBA_FLT, 0, 3, 1, /**/ 0, 4, 8, 12, /**/ 16, 16, 16, 16);
  216. CHECK(TYPE_ARGB_FLT, 0, 3, 1, /**/ 4, 8, 12, 0, /**/ 16, 16, 16, 16);
  217. CHECK(TYPE_BGR_8, 0, 3, 0, /**/ 2, 1, 0, /**/ 3, 3, 3);
  218. CHECK(TYPE_BGRA_8, 0, 3, 1, /**/ 2, 1, 0, 3, /**/ 4, 4, 4, 4);
  219. CHECK(TYPE_ABGR_8, 0, 3, 1, /**/ 3, 2, 1, 0, /**/ 4, 4, 4, 4);
  220. CHECK(TYPE_BGR_16, 0, 3, 0, /**/ 4, 2, 0, /**/ 6, 6, 6);
  221. CHECK(TYPE_BGRA_16, 0, 3, 1, /**/ 4, 2, 0, 6, /**/ 8, 8, 8, 8);
  222. CHECK(TYPE_ABGR_16, 0, 3, 1, /**/ 6, 4, 2, 0, /**/ 8, 8, 8, 8);
  223. CHECK(TYPE_BGR_FLT, 0, 3, 0, /**/ 8, 4, 0, /**/ 12, 12, 12);
  224. CHECK(TYPE_BGRA_FLT, 0, 3, 1, /**/ 8, 4, 0, 12, /**/ 16, 16, 16, 16);
  225. CHECK(TYPE_ABGR_FLT, 0, 3, 1, /**/ 12, 8, 4, 0, /**/ 16, 16, 16, 16);
  226. CHECK(TYPE_CMYK_8, 0, 4, 0, /**/ 0, 1, 2, 3, /**/ 4, 4, 4, 4);
  227. CHECK(TYPE_CMYKA_8, 0, 4, 1, /**/ 0, 1, 2, 3, 4, /**/ 5, 5, 5, 5, 5);
  228. CHECK(TYPE_ACMYK_8, 0, 4, 1, /**/ 1, 2, 3, 4, 0, /**/ 5, 5, 5, 5, 5);
  229. CHECK(TYPE_KYMC_8, 0, 4, 0, /**/ 3, 2, 1, 0, /**/ 4, 4, 4, 4);
  230. CHECK(TYPE_KYMCA_8, 0, 4, 1, /**/ 3, 2, 1, 0, 4, /**/ 5, 5, 5, 5, 5);
  231. CHECK(TYPE_AKYMC_8, 0, 4, 1, /**/ 4, 3, 2, 1, 0, /**/ 5, 5, 5, 5, 5);
  232. CHECK(TYPE_KCMY_8, 0, 4, 0, /**/ 1, 2, 3, 0, /**/ 4, 4, 4, 4);
  233. CHECK(TYPE_CMYK_16, 0, 4, 0, /**/ 0, 2, 4, 6, /**/ 8, 8, 8, 8);
  234. CHECK(TYPE_CMYKA_16, 0, 4, 1, /**/ 0, 2, 4, 6, 8, /**/ 10, 10, 10, 10, 10);
  235. CHECK(TYPE_ACMYK_16, 0, 4, 1, /**/ 2, 4, 6, 8, 0, /**/ 10, 10, 10, 10, 10);
  236. CHECK(TYPE_KYMC_16, 0, 4, 0, /**/ 6, 4, 2, 0, /**/ 8, 8, 8, 8);
  237. CHECK(TYPE_KYMCA_16, 0, 4, 1, /**/ 6, 4, 2, 0, 8, /**/ 10, 10, 10, 10, 10);
  238. CHECK(TYPE_AKYMC_16, 0, 4, 1, /**/ 8, 6, 4, 2, 0, /**/ 10, 10, 10, 10, 10);
  239. CHECK(TYPE_KCMY_16, 0, 4, 0, /**/ 2, 4, 6, 0, /**/ 8, 8, 8, 8);
  240. // Planar
  241. CHECK(TYPE_GRAYA_8_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 1, 1);
  242. CHECK(TYPE_AGRAY_8_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 1, 1);
  243. CHECK(TYPE_GRAYA_16_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 2, 2);
  244. CHECK(TYPE_AGRAY_16_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 2, 2);
  245. CHECK(TYPE_GRAYA_FLT_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 4, 4);
  246. CHECK(TYPE_AGRAY_FLT_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 4, 4);
  247. CHECK(TYPE_GRAYA_DBL_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 8, 8);
  248. CHECK(TYPE_AGRAY_DBL_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 8, 8);
  249. CHECK(TYPE_RGB_8_PLANAR, 100, 3, 0, /**/ 0, 100, 200, /**/ 1, 1, 1);
  250. CHECK(TYPE_RGBA_8_PLANAR, 100, 3, 1, /**/ 0, 100, 200, 300, /**/ 1, 1, 1, 1);
  251. CHECK(TYPE_ARGB_8_PLANAR, 100, 3, 1, /**/ 100, 200, 300, 0, /**/ 1, 1, 1, 1);
  252. CHECK(TYPE_BGR_8_PLANAR, 100, 3, 0, /**/ 200, 100, 0, /**/ 1, 1, 1);
  253. CHECK(TYPE_BGRA_8_PLANAR, 100, 3, 1, /**/ 200, 100, 0, 300, /**/ 1, 1, 1, 1);
  254. CHECK(TYPE_ABGR_8_PLANAR, 100, 3, 1, /**/ 300, 200, 100, 0, /**/ 1, 1, 1, 1);
  255. CHECK(TYPE_RGB_16_PLANAR, 100, 3, 0, /**/ 0, 100, 200, /**/ 2, 2, 2);
  256. CHECK(TYPE_RGBA_16_PLANAR, 100, 3, 1, /**/ 0, 100, 200, 300, /**/ 2, 2, 2, 2);
  257. CHECK(TYPE_ARGB_16_PLANAR, 100, 3, 1, /**/ 100, 200, 300, 0, /**/ 2, 2, 2, 2);
  258. CHECK(TYPE_BGR_16_PLANAR, 100, 3, 0, /**/ 200, 100, 0, /**/ 2, 2, 2);
  259. CHECK(TYPE_BGRA_16_PLANAR, 100, 3, 1, /**/ 200, 100, 0, 300, /**/ 2, 2, 2, 2);
  260. CHECK(TYPE_ABGR_16_PLANAR, 100, 3, 1, /**/ 300, 200, 100, 0, /**/ 2, 2, 2, 2);
  261. return 1;
  262. }
  263. // Check 15 bit mode accuracy
  264. static
  265. cmsBool Valid15(cmsUInt16Number a, cmsUInt8Number b)
  266. {
  267. return abs(FROM_15_TO_8(a) - b) <= 2;
  268. }
  269. // Check the test macros itselves
  270. static
  271. void Check15bitMacros(void)
  272. {
  273. int i;
  274. trace("Checking 15 bit <=> 8 bit macros...");
  275. for (i = 0; i < 256; i++)
  276. {
  277. cmsUInt16Number n = FROM_8_TO_15(i);
  278. cmsUInt8Number m = FROM_15_TO_8(n);
  279. if (m != i)
  280. Fail("Failed on %d (->%d->%d)", i, n, m);
  281. }
  282. trace("ok\n");
  283. }
  284. // Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout.
  285. // Results should be same except for 2 contone levels allowed for roundoff. Note 15 bits is more
  286. // precise than 8 bits and this is a source of discrepancies. Cache is disabled
  287. static
  288. void TryAllValues15(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  289. {
  290. Scanline_rgb8bits* buffer8in;
  291. Scanline_rgb15bits* buffer15in;
  292. Scanline_rgb8bits* buffer8out;
  293. Scanline_rgb15bits* buffer15out;
  294. int r, g, b, j;
  295. cmsUInt32Number npixels = 256 * 256 * 256; // All RGB cube in 8 bits
  296. cmsHTRANSFORM xform15 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_15, hlcmsProfileOut, TYPE_RGB_15, Intent, cmsFLAGS_NOCACHE);
  297. cmsHTRANSFORM xform8 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, Intent, cmsFLAGS_NOCACHE); // Transforms already created
  298. cmsCloseProfile(hlcmsProfileIn);
  299. cmsCloseProfile(hlcmsProfileOut);
  300. if (xform15 == NULL || xform8 == NULL) {
  301. Fail("NULL transforms on check for 15 bit conversions");
  302. }
  303. // Since this is just a test, I will not check memory allocation...
  304. buffer8in = (Scanline_rgb8bits*)malloc(npixels * sizeof(Scanline_rgb8bits));
  305. buffer15in = (Scanline_rgb15bits*)malloc(npixels * sizeof(Scanline_rgb15bits));
  306. buffer8out = (Scanline_rgb8bits*)malloc(npixels * sizeof(Scanline_rgb8bits));
  307. buffer15out = (Scanline_rgb15bits*)malloc(npixels * sizeof(Scanline_rgb15bits));
  308. // Fill input values for 8 and 15 bits
  309. j = 0;
  310. for (r = 0; r < 256; r++)
  311. for (g = 0; g < 256; g++)
  312. for (b = 0; b < 256; b++) {
  313. buffer8in[j].r = (cmsUInt8Number)r;
  314. buffer8in[j].g = (cmsUInt8Number)g;
  315. buffer8in[j].b = (cmsUInt8Number)b;
  316. buffer15in[j].r = FROM_8_TO_15(r);
  317. buffer15in[j].g = FROM_8_TO_15(g);
  318. buffer15in[j].b = FROM_8_TO_15(b);
  319. j++;
  320. }
  321. cmsDoTransform(xform15, buffer15in, buffer15out, npixels);
  322. cmsDoTransform(xform8, buffer8in, buffer8out, npixels);
  323. j = 0;
  324. for (r = 0; r < 256; r++)
  325. for (g = 0; g < 256; g++)
  326. for (b = 0; b < 256; b++) {
  327. // Check the results
  328. if (!Valid15(buffer15out[j].r, buffer8out[j].r) ||
  329. !Valid15(buffer15out[j].g, buffer8out[j].g) ||
  330. !Valid15(buffer15out[j].b, buffer8out[j].b))
  331. Fail("Conversion failed at (%d %d %d) != (%d %d %d)", buffer8out[j].r, buffer8out[j].g, buffer8out[j].b,
  332. FROM_15_TO_8(buffer15out[j].r), FROM_15_TO_8(buffer15out[j].g), FROM_15_TO_8(buffer15out[j].b));
  333. j++;
  334. }
  335. free(buffer8in); free(buffer15in);
  336. free(buffer8out); free(buffer15out);
  337. cmsDeleteTransform(xform15);
  338. cmsDeleteTransform(xform8);
  339. }
  340. // Convert some known values
  341. static
  342. void Check15bitsConversions(void)
  343. {
  344. Check15bitMacros();
  345. trace("Checking accuracy of 15 bits on CLUT...");
  346. TryAllValues15(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL);
  347. trace("Ok\n");
  348. trace("Checking accuracy of 15 bits on same profile ...");
  349. TryAllValues15(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  350. trace("Ok\n");
  351. trace("Checking accuracy of 15 bits on Matrix...");
  352. TryAllValues15(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  353. trace("Ok\n");
  354. trace("All 15 bits tests passed OK\n\n");
  355. }
  356. // Next test checks results of optimized 16 bits versus raw 16 bits.
  357. static
  358. void TryAllValues16bits(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  359. {
  360. cmsContext Raw = cmsCreateContext(NULL, NULL);
  361. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  362. Scanline_rgba16bits* bufferIn;
  363. Scanline_rgba16bits* bufferRawOut;
  364. Scanline_rgba16bits* bufferPluginOut;
  365. int r, g, b;
  366. int j;
  367. cmsUInt32Number npixels = 256 * 256 * 256;
  368. cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGBA_16, hlcmsProfileOut, TYPE_RGBA_16, Intent, cmsFLAGS_NOCACHE| cmsFLAGS_COPY_ALPHA);
  369. cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGBA_16, hlcmsProfileOut, TYPE_RGBA_16, Intent, cmsFLAGS_NOCACHE| cmsFLAGS_COPY_ALPHA);
  370. cmsCloseProfile(hlcmsProfileIn);
  371. cmsCloseProfile(hlcmsProfileOut);
  372. if (xformRaw == NULL || xformPlugin == NULL) {
  373. Fail("NULL transforms on check float conversions");
  374. }
  375. // Again, no checking on mem alloc because this is just a test
  376. bufferIn = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits));
  377. bufferRawOut = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits));
  378. bufferPluginOut = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits));
  379. // Same input to both transforms
  380. j = 0;
  381. for (r = 0; r < 256; r++)
  382. for (g = 0; g < 256; g++)
  383. for (b = 0; b < 256; b++) {
  384. bufferIn[j].r = FROM_8_TO_16(0xf8);
  385. bufferIn[j].g = FROM_8_TO_16(0xf8);
  386. bufferIn[j].b = FROM_8_TO_16(0xf8);
  387. bufferIn[j].a = 0xffff;
  388. j++;
  389. }
  390. // Different transforms, different output buffers
  391. cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels);
  392. cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels);
  393. // Lets compare results
  394. j = 0;
  395. for (r = 0; r < 256; r++)
  396. for (g = 0; g < 256; g++)
  397. for (b = 0; b < 256; b++) {
  398. if (bufferRawOut[j].r != bufferPluginOut[j].r ||
  399. bufferRawOut[j].g != bufferPluginOut[j].g ||
  400. bufferRawOut[j].b != bufferPluginOut[j].b ||
  401. bufferRawOut[j].a != bufferPluginOut[j].a)
  402. Fail(
  403. "Conversion failed at [%x %x %x %x] (%x %x %x %x) != (%x %x %x %x)",
  404. bufferIn[j].r, bufferIn[j].g, bufferIn[j].b, bufferIn[j].a,
  405. bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b, bufferRawOut[j].a,
  406. bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b, bufferPluginOut[j].a);
  407. j++;
  408. }
  409. free(bufferIn); free(bufferRawOut);
  410. free(bufferPluginOut);
  411. cmsDeleteTransform(xformRaw);
  412. cmsDeleteTransform(xformPlugin);
  413. cmsDeleteContext(Plugin);
  414. cmsDeleteContext(Raw);
  415. }
  416. static
  417. void CheckAccuracy16Bits(void)
  418. {
  419. // CLUT should be as 16 bits or better
  420. trace("Checking accuracy of 16 bits CLUT...");
  421. TryAllValues16bits(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL);
  422. trace("All 16 bits tests passed OK\n\n");
  423. }
  424. // Try values that are denormalized, not-a-number and out of range
  425. static
  426. void CheckUncommonValues(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  427. {
  428. union
  429. {
  430. cmsFloat32Number subnormal;
  431. cmsUInt32Number Int;
  432. } sub_pos, sub_neg;
  433. Scanline_rgbFloat* bufferIn;
  434. Scanline_rgbFloat* bufferPluginOut;
  435. cmsUInt32Number i, npixels = 100;
  436. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  437. cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, 0);
  438. sub_pos.Int = 0x00000002;
  439. sub_neg.Int = 0x80000002;
  440. cmsCloseProfile(hlcmsProfileIn);
  441. cmsCloseProfile(hlcmsProfileOut);
  442. if (xformPlugin == NULL) {
  443. Fail("NULL transform on check uncommon values");
  444. }
  445. bufferIn = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  446. bufferPluginOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  447. for (i = 0; i < npixels; i++)
  448. {
  449. bufferIn[i].r = i / 40.0 - 0.5;
  450. bufferIn[i].g = i / 20.0 - 0.5;
  451. bufferIn[i].b = i / 60.0 - 0.5;
  452. }
  453. cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels);
  454. bufferIn[0].r = NAN;
  455. bufferIn[0].g = NAN;
  456. bufferIn[0].b = NAN;
  457. bufferIn[1].r = INFINITY;
  458. bufferIn[1].g = INFINITY;
  459. bufferIn[1].b = INFINITY;
  460. bufferIn[2].r = sub_pos.subnormal;
  461. bufferIn[2].g = sub_pos.subnormal;
  462. bufferIn[2].b = sub_pos.subnormal;
  463. bufferIn[3].r = sub_neg.subnormal;
  464. bufferIn[3].g = sub_neg.subnormal;
  465. bufferIn[3].b = sub_neg.subnormal;
  466. cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, 4);
  467. free(bufferIn);
  468. free(bufferPluginOut);
  469. cmsDeleteTransform(xformPlugin);
  470. cmsDeleteContext(Plugin);
  471. }
  472. static
  473. void lab8toLab(cmsUInt8Number lab8[3], cmsCIELab* Lab)
  474. {
  475. cmsUInt16Number lab16[3];
  476. lab16[0] = FROM_8_TO_16(lab8[0]);
  477. lab16[1] = FROM_8_TO_16(lab8[1]);
  478. lab16[2] = FROM_8_TO_16(lab8[2]);
  479. cmsLabEncoded2Float(Lab, lab16);
  480. }
  481. static
  482. void CheckToEncodedLab(void)
  483. {
  484. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  485. cmsContext Raw = cmsCreateContext(NULL, NULL);
  486. cmsHPROFILE hsRGB = cmsCreate_sRGBProfile();
  487. cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
  488. cmsHTRANSFORM xform_plugin = cmsCreateTransformTHR(Plugin, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_8, INTENT_PERCEPTUAL, 0);
  489. cmsHTRANSFORM xform = cmsCreateTransformTHR(Raw, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_8, INTENT_PERCEPTUAL, 0);
  490. int r, g, b;
  491. cmsCIELab Lab1, Lab2;
  492. cmsUInt8Number rgb[3], lab1[3], lab2[3];
  493. double err;
  494. for (r=0; r < 256; r += 5)
  495. for (g = 0; g < 256; g += 5)
  496. for (b = 0; b < 256; b += 5)
  497. {
  498. rgb[0] = (cmsUInt8Number) r; rgb[1] = (cmsUInt8Number) g; rgb[2] = (cmsUInt8Number) b;
  499. cmsDoTransform(xform_plugin, rgb, lab1, 1);
  500. cmsDoTransform(xform, rgb, lab2, 1);
  501. lab8toLab(lab1, &Lab1);
  502. lab8toLab(lab2, &Lab2);
  503. err = cmsDeltaE(&Lab1, &Lab2);
  504. if (err > 0.1)
  505. {
  506. trace("Error on lab encoded (%f, %f, %f) <> (% f, % f, % f)\n",
  507. Lab1.L, Lab1.a, Lab1.b, Lab2.L, Lab2.a, Lab2.b);
  508. }
  509. }
  510. cmsDeleteTransform(xform);
  511. cmsCloseProfile(hsRGB); cmsCloseProfile(hLab);
  512. cmsDeleteContext(Raw);
  513. cmsDeleteContext(Plugin);
  514. }
  515. static
  516. void CheckToFloatLab(void)
  517. {
  518. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  519. cmsContext Raw = cmsCreateContext(NULL, NULL);
  520. cmsHPROFILE hsRGB = cmsCreate_sRGBProfile();
  521. cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
  522. cmsHTRANSFORM xform_plugin = cmsCreateTransformTHR(Plugin, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  523. cmsHTRANSFORM xform = cmsCreateTransformTHR(Raw, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  524. int r, g, b;
  525. cmsCIELab Lab1, Lab2;
  526. cmsUInt8Number rgb[3];
  527. double err;
  528. for (r = 0; r < 256; r += 10)
  529. for (g = 0; g < 256; g += 10)
  530. for (b = 0; b < 256; b += 10)
  531. {
  532. rgb[0] = (cmsUInt8Number)r; rgb[1] = (cmsUInt8Number)g; rgb[2] = (cmsUInt8Number)b;
  533. cmsDoTransform(xform_plugin, rgb, &Lab1, 1);
  534. cmsDoTransform(xform, rgb, &Lab2, 1);
  535. err = cmsDeltaE(&Lab1, &Lab2);
  536. if (err > 0.1)
  537. {
  538. trace("Error on lab encoded (%f, %f, %f) <> (% f, % f, % f)\n",
  539. Lab1.L, Lab1.a, Lab1.b, Lab2.L, Lab2.a, Lab2.b);
  540. }
  541. }
  542. cmsDeleteTransform(xform);
  543. cmsCloseProfile(hsRGB); cmsCloseProfile(hLab);
  544. cmsDeleteContext(Raw);
  545. cmsDeleteContext(Plugin);
  546. }
  547. // --------------------------------------------------------------------------------------------------
  548. // A C C U R A C Y C H E C K S
  549. // --------------------------------------------------------------------------------------------------
  550. // Check result accuracy
  551. static
  552. cmsBool ValidFloat(cmsFloat32Number a, cmsFloat32Number b)
  553. {
  554. return fabsf(a-b) < EPSILON_FLOAT_TESTS;
  555. }
  556. // Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout.
  557. // Values with and without optimization are checked (different contexts, one with the plugin and another without)
  558. // Results should be same except for EPSILON_FLOAT_TESTS allowed for accuracy/speed tradeoff. Cache is disabled
  559. static
  560. void TryAllValuesFloat(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  561. {
  562. cmsContext Raw = cmsCreateContext(NULL, NULL);
  563. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  564. Scanline_rgbFloat* bufferIn;
  565. Scanline_rgbFloat* bufferRawOut;
  566. Scanline_rgbFloat* bufferPluginOut;
  567. int r, g, b;
  568. int j;
  569. cmsUInt32Number npixels = 256 * 256 * 256;
  570. cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE);
  571. cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE);
  572. cmsCloseProfile(hlcmsProfileIn);
  573. cmsCloseProfile(hlcmsProfileOut);
  574. if (xformRaw == NULL || xformPlugin == NULL) {
  575. Fail("NULL transforms on check float conversions");
  576. }
  577. // Again, no checking on mem alloc because this is just a test
  578. bufferIn = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  579. bufferRawOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  580. bufferPluginOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  581. // Same input to both transforms
  582. j = 0;
  583. for (r = 0; r < 256; r++)
  584. for (g = 0; g < 256; g++)
  585. for (b = 0; b < 256; b++) {
  586. bufferIn[j].r = (cmsFloat32Number)r / 255.0f;
  587. bufferIn[j].g = (cmsFloat32Number)g / 255.0f;
  588. bufferIn[j].b = (cmsFloat32Number)b / 255.0f;
  589. j++;
  590. }
  591. // Different transforms, different output buffers
  592. cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels);
  593. cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels);
  594. // Lets compare results
  595. j = 0;
  596. for (r = 0; r < 256; r++)
  597. for (g = 0; g < 256; g++)
  598. for (b = 0; b < 256; b++) {
  599. if (!ValidFloat(bufferRawOut[j].r, bufferPluginOut[j].r) ||
  600. !ValidFloat(bufferRawOut[j].g, bufferPluginOut[j].g) ||
  601. !ValidFloat(bufferRawOut[j].b, bufferPluginOut[j].b))
  602. Fail("Conversion failed at (%f %f %f) != (%f %f %f)", bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b,
  603. bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b);
  604. j++;
  605. }
  606. free(bufferIn); free(bufferRawOut);
  607. free(bufferPluginOut);
  608. cmsDeleteTransform(xformRaw);
  609. cmsDeleteTransform(xformPlugin);
  610. cmsDeleteContext(Plugin);
  611. cmsDeleteContext(Raw);
  612. }
  613. static
  614. void TryAllValuesFloatAlpha(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent, cmsBool copyAlpha)
  615. {
  616. cmsContext Raw = cmsCreateContext(NULL, NULL);
  617. cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  618. Scanline_rgbaFloat* bufferIn;
  619. Scanline_rgbaFloat* bufferRawOut;
  620. Scanline_rgbaFloat* bufferPluginOut;
  621. int r, g, b;
  622. int j;
  623. cmsUInt32Number npixels = 256 * 256 * 256;
  624. cmsUInt32Number flags = cmsFLAGS_NOCACHE | ( copyAlpha? cmsFLAGS_COPY_ALPHA : 0);
  625. cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGBA_FLT, hlcmsProfileOut, TYPE_RGBA_FLT, Intent, flags);
  626. cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGBA_FLT, hlcmsProfileOut, TYPE_RGBA_FLT, Intent, flags);
  627. cmsCloseProfile(hlcmsProfileIn);
  628. cmsCloseProfile(hlcmsProfileOut);
  629. if (xformRaw == NULL || xformPlugin == NULL) {
  630. Fail("NULL transforms on check float conversions");
  631. }
  632. // Again, no checking on mem alloc because this is just a test
  633. bufferIn = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat));
  634. bufferRawOut = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat));
  635. bufferPluginOut = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat));
  636. memset(bufferRawOut, 0, npixels * sizeof(Scanline_rgbaFloat));
  637. memset(bufferPluginOut, 0, npixels * sizeof(Scanline_rgbaFloat));
  638. // Same input to both transforms
  639. j = 0;
  640. for (r = 0; r < 256; r++)
  641. for (g = 0; g < 256; g++)
  642. for (b = 0; b < 256; b++) {
  643. bufferIn[j].r = (cmsFloat32Number)r / 255.0f;
  644. bufferIn[j].g = (cmsFloat32Number)g / 255.0f;
  645. bufferIn[j].b = (cmsFloat32Number)b / 255.0f;
  646. bufferIn[j].a = (cmsFloat32Number) 1.0f;
  647. j++;
  648. }
  649. // Different transforms, different output buffers
  650. cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels);
  651. cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels);
  652. // Lets compare results
  653. j = 0;
  654. for (r = 0; r < 256; r++)
  655. for (g = 0; g < 256; g++)
  656. for (b = 0; b < 256; b++) {
  657. if (!ValidFloat(bufferRawOut[j].r, bufferPluginOut[j].r) ||
  658. !ValidFloat(bufferRawOut[j].g, bufferPluginOut[j].g) ||
  659. !ValidFloat(bufferRawOut[j].b, bufferPluginOut[j].b) ||
  660. !ValidFloat(bufferRawOut[j].a, bufferPluginOut[j].a))
  661. Fail("Conversion failed at (%f %f %f %f) != (%f %f %f %f)", bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b, bufferRawOut[j].a,
  662. bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b, bufferPluginOut[j].a);
  663. j++;
  664. }
  665. free(bufferIn); free(bufferRawOut);
  666. free(bufferPluginOut);
  667. cmsDeleteTransform(xformRaw);
  668. cmsDeleteTransform(xformPlugin);
  669. cmsDeleteContext(Plugin);
  670. cmsDeleteContext(Raw);
  671. }
  672. // Next test checks results of optimized floating point versus 16 bits. That is, converting the float to 16 bits, operating
  673. // in 16 bits and back to float. Results again should be in range of epsilon
  674. static
  675. cmsBool Valid16Float(cmsUInt16Number a, cmsFloat32Number b)
  676. {
  677. return fabs(((cmsFloat32Number)a / (cmsFloat32Number) 0xFFFF) - b) < EPSILON_FLOAT_TESTS;
  678. }
  679. // Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout. 16 bits temporary is used as reference
  680. static
  681. void TryAllValuesFloatVs16(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  682. {
  683. Scanline_rgbFloat* bufferIn;
  684. Scanline_rgb16bits* bufferIn16;
  685. Scanline_rgbFloat* bufferFloatOut;
  686. Scanline_rgb16bits* buffer16Out;
  687. int r, g, b;
  688. int j;
  689. cmsUInt32Number npixels = 256 * 256 * 256;
  690. cmsHTRANSFORM xformRaw = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, Intent, cmsFLAGS_NOCACHE);
  691. cmsHTRANSFORM xformPlugin = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE);
  692. cmsCloseProfile(hlcmsProfileIn);
  693. cmsCloseProfile(hlcmsProfileOut);
  694. if (xformRaw == NULL || xformPlugin == NULL) {
  695. Fail("NULL transforms on check float vs 16 conversions");
  696. }
  697. // Again, no checking on mem alloc because this is just a test
  698. bufferIn = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  699. bufferIn16 = (Scanline_rgb16bits*)malloc(npixels * sizeof(Scanline_rgb16bits));
  700. bufferFloatOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat));
  701. buffer16Out = (Scanline_rgb16bits*)malloc(npixels * sizeof(Scanline_rgb16bits));
  702. // Fill two equivalent input buffers
  703. j = 0;
  704. for (r = 0; r < 256; r++)
  705. for (g = 0; g < 256; g++)
  706. for (b = 0; b < 256; b++) {
  707. bufferIn[j].r = (cmsFloat32Number)r / 255.0f;
  708. bufferIn[j].g = (cmsFloat32Number)g / 255.0f;
  709. bufferIn[j].b = (cmsFloat32Number)b / 255.0f;
  710. bufferIn16[j].r = FROM_8_TO_16(r);
  711. bufferIn16[j].g = FROM_8_TO_16(g);
  712. bufferIn16[j].b = FROM_8_TO_16(b);
  713. j++;
  714. }
  715. // Convert
  716. cmsDoTransform(xformRaw, bufferIn16, buffer16Out, npixels);
  717. cmsDoTransform(xformPlugin, bufferIn, bufferFloatOut, npixels);
  718. j = 0;
  719. for (r = 0; r < 256; r++)
  720. for (g = 0; g < 256; g++)
  721. for (b = 0; b < 256; b++) {
  722. // Check for same values
  723. if (!Valid16Float(buffer16Out[j].r, bufferFloatOut[j].r) ||
  724. !Valid16Float(buffer16Out[j].g, bufferFloatOut[j].g) ||
  725. !Valid16Float(buffer16Out[j].b, bufferFloatOut[j].b))
  726. Fail("Conversion failed at (%f %f %f) != (%f %f %f)", buffer16Out[j].r / 65535.0, buffer16Out[j].g / 65535.0, buffer16Out[j].b / 65535.0,
  727. bufferFloatOut[j].r, bufferFloatOut[j].g, bufferFloatOut[j].b);
  728. j++;
  729. }
  730. free(bufferIn16); free(buffer16Out);
  731. free(bufferIn); free(bufferFloatOut);
  732. cmsDeleteTransform(xformRaw);
  733. cmsDeleteTransform(xformPlugin);
  734. }
  735. // Check change format feature
  736. static
  737. void CheckChangeFormat(void)
  738. {
  739. cmsHPROFILE hsRGB, hLab;
  740. cmsHTRANSFORM xform;
  741. cmsUInt8Number rgb8[3] = { 10, 120, 40 };
  742. cmsUInt16Number rgb16[3] = { 10* 257, 120*257, 40*257 };
  743. cmsUInt16Number lab16_1[3], lab16_2[3];
  744. trace("Checking change format feature...");
  745. hsRGB = cmsCreate_sRGBProfile();
  746. hLab = cmsCreateLab4Profile(NULL);
  747. xform = cmsCreateTransform(hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, 0);
  748. cmsCloseProfile(hsRGB);
  749. cmsCloseProfile(hLab);
  750. cmsDoTransform(xform, rgb16, lab16_1, 1);
  751. cmsChangeBuffersFormat(xform, TYPE_RGB_8, TYPE_Lab_16);
  752. cmsDoTransform(xform, rgb8, lab16_2, 1);
  753. cmsDeleteTransform(xform);
  754. if (memcmp(lab16_1, lab16_2, sizeof(lab16_1)) != 0)
  755. Fail("Change format failed!");
  756. trace("Ok\n");
  757. }
  758. static
  759. cmsBool ValidInt(cmsUInt16Number a, cmsUInt16Number b)
  760. {
  761. return abs(a - b) <= 32;
  762. }
  763. static
  764. void CheckLab2Roundtrip(void)
  765. {
  766. cmsHPROFILE hsRGB, hLab;
  767. cmsHTRANSFORM xform, xform2;
  768. cmsInt8Number* lab;
  769. cmsInt32Number Mb, j;
  770. cmsInt32Number r, g, b;
  771. Scanline_rgb8bits* In;
  772. Scanline_rgb8bits* Out;
  773. trace("Checking lab2 roundtrip...");
  774. hsRGB = cmsCreate_sRGBProfile();
  775. hLab = cmsCreateLab2Profile(NULL);
  776. xform = cmsCreateTransform(hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_BLACKPOINTCOMPENSATION);
  777. xform2 = cmsCreateTransform(hLab, TYPE_Lab_8, hsRGB, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION);
  778. cmsCloseProfile(hsRGB);
  779. cmsCloseProfile(hLab);
  780. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb8bits);
  781. In = (Scanline_rgb8bits*)malloc(Mb);
  782. Out = (Scanline_rgb8bits*)malloc(Mb);
  783. lab = (cmsInt8Number*)malloc(256 * 256 * 256 * 3 * sizeof(cmsInt8Number));
  784. j = 0;
  785. for (r = 0; r < 256; r++)
  786. for (g = 0; g < 256; g++)
  787. for (b = 0; b < 256; b++)
  788. {
  789. In[j].r = (cmsUInt8Number)r;
  790. In[j].g = (cmsUInt8Number)g;
  791. In[j].b = (cmsUInt8Number)b;
  792. j++;
  793. }
  794. cmsDoTransform(xform, In, lab, 256 * 256 * 256);
  795. cmsDoTransform(xform2, lab, Out, 256 * 256 * 256);
  796. cmsDeleteTransform(xform);
  797. cmsDeleteTransform(xform2);
  798. j = 0;
  799. for (r = 0; r < 256; r++)
  800. for (g = 0; g < 256; g++)
  801. for (b = 0; b < 256; b++) {
  802. // Check for same values
  803. if (!ValidInt(In[j].r, Out[j].r) ||
  804. !ValidInt(In[j].g, Out[j].g) ||
  805. !ValidInt(In[j].b, Out[j].b))
  806. Fail("Conversion failed at (%d %d %d) != (%d %d %d)", In[j].r, In[j].g, In[j].b,
  807. Out[j].r, Out[j].g, Out[j].b);
  808. j++;
  809. }
  810. free(In);
  811. free(Out);
  812. free(lab);
  813. trace("Ok\n");
  814. }
  815. // Convert some known values
  816. static
  817. void CheckConversionFloat(void)
  818. {
  819. trace("Crash test.");
  820. TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL, FALSE);
  821. trace("..");
  822. TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL, TRUE);
  823. trace("Ok\n");
  824. trace("Crash (II) test.");
  825. TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL, FALSE);
  826. trace("..");
  827. TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL, TRUE);
  828. trace("Ok\n");
  829. trace("Crash (III) test.");
  830. CheckUncommonValues(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL);
  831. trace("..");
  832. CheckUncommonValues(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  833. trace("Ok\n");
  834. trace("Checking conversion to Lab...");
  835. CheckToEncodedLab();
  836. CheckToFloatLab();
  837. trace("Ok\n");
  838. // Matrix-shaper should be accurate
  839. trace("Checking accuracy on Matrix-shaper...");
  840. TryAllValuesFloat(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  841. trace("Ok\n");
  842. // CLUT should be as 16 bits or better
  843. trace("Checking accuracy of CLUT...");
  844. TryAllValuesFloatVs16(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL);
  845. trace("Ok\n");
  846. // Same profile should give same values (we test both methods)
  847. trace("Checking accuracy on same profile ...");
  848. TryAllValuesFloatVs16(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  849. TryAllValuesFloat(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL);
  850. trace("Ok\n");
  851. }
  852. static
  853. cmsBool ValidFloat2(cmsFloat32Number a, cmsFloat32Number b)
  854. {
  855. return fabsf(a - b) < 0.007;
  856. }
  857. static
  858. cmsFloat32Number distance(cmsFloat32Number rgb1[], cmsFloat32Number rgb2[])
  859. {
  860. cmsFloat32Number dr = rgb2[0] - rgb1[0];
  861. cmsFloat32Number dg = rgb2[1] - rgb1[1];
  862. cmsFloat32Number db = rgb2[2] - rgb1[2];
  863. return dr * dr + dg * dg + db * db;
  864. }
  865. static
  866. void CheckLab2RGB(void)
  867. {
  868. cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
  869. cmsHPROFILE hRGB = cmsOpenProfileFromFile("test3.icc", "r");
  870. cmsContext noPlugin = cmsCreateContext(0, 0);
  871. cmsHTRANSFORM hXformNoPlugin = cmsCreateTransformTHR(noPlugin, hLab, TYPE_Lab_FLT, hRGB, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE);
  872. cmsHTRANSFORM hXformPlugin = cmsCreateTransformTHR(0, hLab, TYPE_Lab_FLT, hRGB, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE);
  873. cmsFloat32Number Lab[3], RGB[3], RGB2[3];
  874. cmsFloat32Number maxInside = 0, maxOutside = 0, L, a, b;
  875. trace("Checking Lab -> RGB...");
  876. for (L = 4; L <= 100; L++)
  877. {
  878. for (a = -30; a < +30; a++)
  879. for (b = -30; b < +30; b++)
  880. {
  881. cmsFloat32Number d;
  882. Lab[0] = L; Lab[1] = a; Lab[2] = b;
  883. cmsDoTransform(hXformNoPlugin, Lab, RGB, 1);
  884. cmsDoTransform(hXformPlugin, Lab, RGB2, 1);
  885. d = distance(RGB, RGB2);
  886. if (d > maxInside)
  887. maxInside = d;
  888. }
  889. }
  890. for (L = 1; L <= 100; L += 5)
  891. {
  892. for (a = -100; a < +100; a += 5)
  893. for (b = -100; b < +100; b += 5)
  894. {
  895. cmsFloat32Number d;
  896. Lab[0] = L; Lab[1] = a; Lab[2] = b;
  897. cmsDoTransform(hXformNoPlugin, Lab, RGB, 1);
  898. cmsDoTransform(hXformPlugin, Lab, RGB2, 1);
  899. d = distance(RGB, RGB2);
  900. if (d > maxOutside)
  901. maxOutside = d;
  902. }
  903. }
  904. trace("Max distance: Inside gamut %f, Outside gamut %f\n", sqrtf(maxInside), sqrtf(maxOutside));
  905. cmsDeleteTransform(hXformNoPlugin);
  906. cmsDeleteTransform(hXformPlugin);
  907. cmsDeleteContext(noPlugin);
  908. }
  909. static
  910. void CheckSoftProofing(void)
  911. {
  912. cmsHPROFILE hRGB1 = cmsOpenProfileFromFile("test5.icc", "r");
  913. cmsHPROFILE hRGB2 = cmsOpenProfileFromFile("test3.icc", "r");
  914. cmsContext noPlugin = cmsCreateContext(0, 0);
  915. cmsHTRANSFORM hXformNoPlugin = cmsCreateProofingTransformTHR(noPlugin, hRGB1, TYPE_RGB_FLT, hRGB1, TYPE_RGB_FLT, hRGB2, INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK | cmsFLAGS_SOFTPROOFING);
  916. cmsHTRANSFORM hXformPlugin = cmsCreateProofingTransformTHR(0, hRGB1, TYPE_RGB_FLT, hRGB1, TYPE_RGB_FLT, hRGB2, INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK | cmsFLAGS_SOFTPROOFING);
  917. cmsUInt32Number Mb, j, r, g, b;
  918. Scanline_rgbFloat* In;
  919. Scanline_rgbFloat* Out1, *Out2;
  920. trace("Checking soft proofing and gamut check ...");
  921. cmsCloseProfile(hRGB1);
  922. cmsCloseProfile(hRGB2);
  923. Mb = 256 * 256 * 256 * sizeof(Scanline_rgbFloat);
  924. In = (Scanline_rgbFloat*)malloc(Mb);
  925. Out1 = (Scanline_rgbFloat*)malloc(Mb);
  926. Out2 = (Scanline_rgbFloat*)malloc(Mb);
  927. j = 0;
  928. for (r = 0; r < 256; r++)
  929. for (g = 0; g < 256; g++)
  930. for (b = 0; b < 256; b++)
  931. {
  932. In[j].r = (cmsFloat32Number)r / 255.0f;
  933. In[j].g = (cmsFloat32Number)g / 255.0f;
  934. In[j].b = (cmsFloat32Number)b / 255.0f;
  935. j++;
  936. }
  937. cmsDoTransform(hXformNoPlugin, In, Out1, 256 * 256 * 256);
  938. cmsDoTransform(hXformPlugin, In, Out2, 256 * 256 * 256);
  939. j = 0;
  940. for (r = 0; r < 256; r++)
  941. for (g = 0; g < 256; g++)
  942. for (b = 0; b < 256; b++) {
  943. // Check for same values
  944. if (!ValidFloat(Out1[j].r, Out2[j].r) ||
  945. !ValidFloat(Out1[j].g, Out2[j].g) ||
  946. !ValidFloat(Out1[j].b, Out2[j].b))
  947. Fail("Conversion failed at (%f %f %f) != (%f %f %f)", Out1[j].r, Out1[j].g, Out1[j].b,
  948. Out2[j].r, Out2[j].g, Out2[j].b);
  949. j++;
  950. }
  951. cmsDeleteTransform(hXformNoPlugin);
  952. cmsDeleteTransform(hXformPlugin);
  953. cmsDeleteContext(noPlugin);
  954. trace("Ok\n");
  955. }
  956. // --------------------------------------------------------------------------------------------------
  957. // P E R F O R M A N C E C H E C K S
  958. // --------------------------------------------------------------------------------------------------
  959. static
  960. cmsFloat64Number MPixSec(cmsFloat64Number diff)
  961. {
  962. cmsFloat64Number seconds = (cmsFloat64Number)diff / (cmsFloat64Number)CLOCKS_PER_SEC;
  963. return (256.0 * 256.0 * 256.0) / (1024.0*1024.0*seconds);
  964. }
  965. typedef cmsFloat64Number(*perf_fn)(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut);
  966. static
  967. void PerformanceHeader(void)
  968. {
  969. trace(" MPixel/sec. MByte/sec.\n");
  970. }
  971. static
  972. cmsHPROFILE loadProfile(const char* name)
  973. {
  974. if (*name == '*')
  975. {
  976. if (strcmp(name, "*lab") == 0)
  977. {
  978. return cmsCreateLab4Profile(NULL);
  979. }
  980. else
  981. if (strcmp(name, "*xyz") == 0)
  982. {
  983. return cmsCreateXYZProfile();
  984. }
  985. else
  986. if (strcmp(name, "*curves") == 0)
  987. {
  988. return CreateCurves();
  989. }
  990. else
  991. Fail("Unknown builtin '%s'", name);
  992. }
  993. return cmsOpenProfileFromFile(name, "r");
  994. }
  995. static
  996. cmsFloat64Number Performance(const char* Title, perf_fn fn, cmsContext ct, const char* inICC, const char* outICC, size_t sz, cmsFloat64Number prev)
  997. {
  998. cmsHPROFILE hlcmsProfileIn = loadProfile(inICC);
  999. cmsHPROFILE hlcmsProfileOut = loadProfile(outICC);
  1000. cmsFloat64Number n = fn(ct, hlcmsProfileIn, hlcmsProfileOut);
  1001. trace("%-30s: ", Title); fflush(stdout);
  1002. trace("%-12.2f %-12.2f", n, n * sz);
  1003. if (prev > 0.0) {
  1004. cmsFloat64Number imp = n / prev;
  1005. if (imp > 1)
  1006. trace(" (x %-2.1f)", imp);
  1007. }
  1008. trace("\n"); fflush(stdout);
  1009. return n;
  1010. }
  1011. static
  1012. void ComparativeCt(cmsContext ct1, cmsContext ct2, const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC)
  1013. {
  1014. cmsHPROFILE hlcmsProfileIn;
  1015. cmsHPROFILE hlcmsProfileOut;
  1016. if (inICC == NULL)
  1017. hlcmsProfileIn = CreateCurves();
  1018. else
  1019. hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r");
  1020. if (outICC == NULL)
  1021. hlcmsProfileOut = CreateCurves();
  1022. else
  1023. hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r");
  1024. cmsFloat64Number n1 = fn1(ct1, hlcmsProfileIn, hlcmsProfileOut);
  1025. if (inICC == NULL)
  1026. hlcmsProfileIn = CreateCurves();
  1027. else
  1028. hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r");
  1029. if (outICC == NULL)
  1030. hlcmsProfileOut = CreateCurves();
  1031. else
  1032. hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r");
  1033. cmsFloat64Number n2 = fn2(ct2, hlcmsProfileIn, hlcmsProfileOut);
  1034. trace("%-30s: ", Title); fflush(stdout);
  1035. trace("%-12.2f %-12.2f\n", n1, n2);
  1036. }
  1037. static
  1038. void Comparative(const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC)
  1039. {
  1040. ComparativeCt(0, 0, Title, fn1, fn2, inICC, outICC);
  1041. }
  1042. // The worst case is used, no cache and all rgb combinations
  1043. static
  1044. cmsFloat64Number SpeedTest8bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1045. {
  1046. cmsInt32Number r, g, b, j;
  1047. clock_t atime;
  1048. cmsFloat64Number diff;
  1049. cmsHTRANSFORM hlcmsxform;
  1050. Scanline_rgb8bits *In;
  1051. cmsUInt32Number Mb;
  1052. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1053. Fail("Unable to open profiles");
  1054. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1055. cmsCloseProfile(hlcmsProfileIn);
  1056. cmsCloseProfile(hlcmsProfileOut);
  1057. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb8bits);
  1058. In = (Scanline_rgb8bits*)malloc(Mb);
  1059. j = 0;
  1060. for (r = 0; r < 256; r++)
  1061. for (g = 0; g < 256; g++)
  1062. for (b = 0; b < 256; b++) {
  1063. In[j].r = (cmsUInt8Number)r;
  1064. In[j].g = (cmsUInt8Number)g;
  1065. In[j].b = (cmsUInt8Number)b;
  1066. j++;
  1067. }
  1068. atime = clock();
  1069. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1070. diff = clock() - atime;
  1071. free(In);
  1072. cmsDeleteTransform(hlcmsxform);
  1073. return MPixSec(diff);
  1074. }
  1075. static
  1076. cmsFloat64Number SpeedTest8bitsRGBA(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1077. {
  1078. cmsInt32Number r, g, b, j;
  1079. clock_t atime;
  1080. cmsFloat64Number diff;
  1081. cmsHTRANSFORM hlcmsxform;
  1082. Scanline_rgba8bits *In;
  1083. cmsUInt32Number Mb;
  1084. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1085. Fail("Unable to open profiles");
  1086. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1087. cmsCloseProfile(hlcmsProfileIn);
  1088. cmsCloseProfile(hlcmsProfileOut);
  1089. Mb = 256 * 256 * 256 * sizeof(Scanline_rgba8bits);
  1090. In = (Scanline_rgba8bits*)malloc(Mb);
  1091. j = 0;
  1092. for (r = 0; r < 256; r++)
  1093. for (g = 0; g < 256; g++)
  1094. for (b = 0; b < 256; b++) {
  1095. In[j].r = (cmsUInt8Number)r;
  1096. In[j].g = (cmsUInt8Number)g;
  1097. In[j].b = (cmsUInt8Number)b;
  1098. In[j].a = 0;
  1099. j++;
  1100. }
  1101. atime = clock();
  1102. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1103. diff = clock() - atime;
  1104. free(In);
  1105. cmsDeleteTransform(hlcmsxform);
  1106. return MPixSec(diff);
  1107. }
  1108. // The worst case is used, no cache and all rgb combinations
  1109. static
  1110. cmsFloat64Number SpeedTest15bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1111. {
  1112. cmsInt32Number r, g, b, j;
  1113. clock_t atime;
  1114. cmsFloat64Number diff;
  1115. cmsHTRANSFORM hlcmsxform;
  1116. Scanline_rgb15bits *In;
  1117. cmsUInt32Number Mb;
  1118. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1119. Fail("Unable to open profiles");
  1120. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_15, hlcmsProfileOut, TYPE_RGB_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1121. cmsCloseProfile(hlcmsProfileIn);
  1122. cmsCloseProfile(hlcmsProfileOut);
  1123. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb15bits);
  1124. In = (Scanline_rgb15bits*)malloc(Mb);
  1125. j = 0;
  1126. for (r = 0; r < 256; r++)
  1127. for (g = 0; g < 256; g++)
  1128. for (b = 0; b < 256; b++) {
  1129. In[j].r = (cmsUInt16Number)r;
  1130. In[j].g = (cmsUInt16Number)g;
  1131. In[j].b = (cmsUInt16Number)b;
  1132. j++;
  1133. }
  1134. atime = clock();
  1135. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1136. diff = clock() - atime;
  1137. free(In);
  1138. cmsDeleteTransform(hlcmsxform);
  1139. return MPixSec(diff);
  1140. }
  1141. static
  1142. cmsFloat64Number SpeedTest15bitsRGBA(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1143. {
  1144. cmsInt32Number r, g, b, j;
  1145. clock_t atime;
  1146. cmsFloat64Number diff;
  1147. cmsHTRANSFORM hlcmsxform;
  1148. Scanline_rgba15bits *In;
  1149. cmsUInt32Number Mb;
  1150. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1151. Fail("Unable to open profiles");
  1152. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_15, hlcmsProfileOut, TYPE_RGBA_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1153. cmsCloseProfile(hlcmsProfileIn);
  1154. cmsCloseProfile(hlcmsProfileOut);
  1155. Mb = 256 * 256 * 256 * sizeof(Scanline_rgba15bits);
  1156. In = (Scanline_rgba15bits*)malloc(Mb);
  1157. j = 0;
  1158. for (r = 0; r < 256; r++)
  1159. for (g = 0; g < 256; g++)
  1160. for (b = 0; b < 256; b++) {
  1161. In[j].r = (cmsUInt16Number)r;
  1162. In[j].g = (cmsUInt16Number)g;
  1163. In[j].b = (cmsUInt16Number)b;
  1164. In[j].a = 0;
  1165. j++;
  1166. }
  1167. atime = clock();
  1168. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1169. diff = clock() - atime;
  1170. free(In);
  1171. cmsDeleteTransform(hlcmsxform);
  1172. return MPixSec(diff);
  1173. }
  1174. static
  1175. cmsFloat64Number SpeedTest15bitsCMYK(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1176. {
  1177. cmsInt32Number r, g, b, j;
  1178. clock_t atime;
  1179. cmsFloat64Number diff;
  1180. cmsHTRANSFORM hlcmsxform;
  1181. Scanline_cmyk15bits *In;
  1182. cmsUInt32Number Mb;
  1183. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1184. Fail("Unable to open profiles");
  1185. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_CMYK_15, hlcmsProfileOut, TYPE_CMYK_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1186. cmsCloseProfile(hlcmsProfileIn);
  1187. cmsCloseProfile(hlcmsProfileOut);
  1188. Mb = 256 * 256 * 256 * sizeof(Scanline_cmyk15bits);
  1189. In = (Scanline_cmyk15bits*)malloc(Mb);
  1190. j = 0;
  1191. for (r = 0; r < 256; r++)
  1192. for (g = 0; g < 256; g++)
  1193. for (b = 0; b < 256; b++) {
  1194. In[j].r = (cmsUInt16Number)r;
  1195. In[j].g = (cmsUInt16Number)g;
  1196. In[j].b = (cmsUInt16Number)b;
  1197. In[j].a = (cmsUInt16Number)0;
  1198. j++;
  1199. }
  1200. atime = clock();
  1201. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1202. diff = clock() - atime;
  1203. free(In);
  1204. cmsDeleteTransform(hlcmsxform);
  1205. return MPixSec(diff);
  1206. }
  1207. // The worst case is used, no cache and all rgb combinations
  1208. static
  1209. cmsFloat64Number SpeedTest16bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1210. {
  1211. cmsInt32Number r, g, b, j;
  1212. clock_t atime;
  1213. cmsFloat64Number diff;
  1214. cmsHTRANSFORM hlcmsxform;
  1215. Scanline_rgb16bits *In;
  1216. cmsUInt32Number Mb;
  1217. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1218. Fail("Unable to open profiles");
  1219. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1220. cmsCloseProfile(hlcmsProfileIn);
  1221. cmsCloseProfile(hlcmsProfileOut);
  1222. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb16bits);
  1223. In = (Scanline_rgb16bits*)malloc(Mb);
  1224. j = 0;
  1225. for (r = 0; r < 256; r++)
  1226. for (g = 0; g < 256; g++)
  1227. for (b = 0; b < 256; b++) {
  1228. In[j].r = (cmsUInt16Number)FROM_8_TO_16(r);
  1229. In[j].g = (cmsUInt16Number)FROM_8_TO_16(g);
  1230. In[j].b = (cmsUInt16Number)FROM_8_TO_16(b);
  1231. j++;
  1232. }
  1233. atime = clock();
  1234. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1235. diff = clock() - atime;
  1236. free(In);
  1237. cmsDeleteTransform(hlcmsxform);
  1238. return MPixSec(diff);
  1239. }
  1240. static
  1241. cmsFloat64Number SpeedTest16bitsCMYK(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1242. {
  1243. cmsInt32Number r, g, b, j;
  1244. clock_t atime;
  1245. cmsFloat64Number diff;
  1246. cmsHTRANSFORM hlcmsxform;
  1247. Scanline_cmyk16bits* In;
  1248. cmsUInt32Number Mb;
  1249. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1250. Fail("Unable to open profiles");
  1251. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_CMYK_16, hlcmsProfileOut, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1252. cmsCloseProfile(hlcmsProfileIn);
  1253. cmsCloseProfile(hlcmsProfileOut);
  1254. Mb = 256 * 256 * 256 * sizeof(Scanline_cmyk16bits);
  1255. In = (Scanline_cmyk16bits*)malloc(Mb);
  1256. j = 0;
  1257. for (r = 0; r < 256; r++)
  1258. for (g = 0; g < 256; g++)
  1259. for (b = 0; b < 256; b++) {
  1260. In[j].c = (cmsUInt16Number)r;
  1261. In[j].m = (cmsUInt16Number)g;
  1262. In[j].y = (cmsUInt16Number)b;
  1263. In[j].k = (cmsUInt16Number)r;
  1264. j++;
  1265. }
  1266. atime = clock();
  1267. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  1268. diff = clock() - atime;
  1269. free(In);
  1270. cmsDeleteTransform(hlcmsxform);
  1271. return MPixSec(diff);
  1272. }
  1273. static
  1274. void SpeedTest8(void)
  1275. {
  1276. cmsContext noPlugin = cmsCreateContext(0, 0);
  1277. cmsFloat64Number t[10];
  1278. trace("\n\n");
  1279. trace("P E R F O R M A N C E T E S T S 8 B I T S (D E F A U L T)\n");
  1280. trace("==============================================================\n\n");
  1281. fflush(stdout);
  1282. PerformanceHeader();
  1283. t[0] = Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), 0);
  1284. t[1] = Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0);
  1285. t[2] = Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0);
  1286. t[3] = Performance("8 bits on curves ", SpeedTest8bitsRGB, noPlugin, "*curves", "*curves", sizeof(Scanline_rgb8bits), 0);
  1287. // Note that context 0 has the plug-in installed
  1288. trace("\n\n");
  1289. trace("P E R F O R M A N C E T E S T S 8 B I T S (P L U G I N)\n");
  1290. trace("===========================================================\n\n");
  1291. fflush(stdout);
  1292. PerformanceHeader();
  1293. Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), t[0]);
  1294. Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[1]);
  1295. Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[2]);
  1296. Performance("8 bits on curves ", SpeedTest8bitsRGB, 0, "*curves", "*curves", sizeof(Scanline_rgb8bits), t[3]);
  1297. cmsDeleteContext(noPlugin);
  1298. }
  1299. static
  1300. void SpeedTest15(void)
  1301. {
  1302. trace("\n\nP E R F O R M A N C E T E S T S 1 5 B I T S (P L U G I N)\n");
  1303. trace( "===============================================================\n\n");
  1304. PerformanceHeader();
  1305. Performance("15 bits on CLUT profiles ", SpeedTest15bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb15bits), 0);
  1306. Performance("15 bits on Matrix-Shaper profiles", SpeedTest15bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb15bits), 0);
  1307. Performance("15 bits on same Matrix-Shaper ", SpeedTest15bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb15bits), 0);
  1308. Performance("15 bits on curves ", SpeedTest15bitsRGB, 0, "*curves", "*curves", sizeof(Scanline_rgb15bits), 0);
  1309. Performance("15 bits on CMYK CLUT profiles ", SpeedTest15bitsCMYK, 0, "test1.icc", "test2.icc", sizeof(Scanline_rgba15bits), 0);
  1310. }
  1311. static
  1312. void SpeedTest16(void)
  1313. {
  1314. cmsContext noPlugin = cmsCreateContext(0, 0);
  1315. trace("\n\n");
  1316. trace("P E R F O R M A N C E T E S T S 1 6 B I T S (D E F A U L T)\n");
  1317. trace("=================================================================\n\n");
  1318. PerformanceHeader();
  1319. Performance("16 bits on CLUT profiles ", SpeedTest16bitsRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgb16bits), 0);
  1320. Performance("16 bits on Matrix-Shaper profiles", SpeedTest16bitsRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  1321. Performance("16 bits on same Matrix-Shaper ", SpeedTest16bitsRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  1322. Performance("16 bits on curves ", SpeedTest16bitsRGB, noPlugin, "*curves", "*curves", sizeof(Scanline_rgb16bits), 0);
  1323. Performance("16 bits on CMYK CLUT profiles ", SpeedTest16bitsCMYK, noPlugin, "test1.icc", "test2.icc", sizeof(Scanline_cmyk16bits), 0);
  1324. trace("\n\n");
  1325. trace("P E R F O R M A N C E T E S T S 1 6 B I T S (P L U G I N)\n");
  1326. trace("===============================================================\n\n");
  1327. PerformanceHeader();
  1328. Performance("16 bits on CLUT profiles ", SpeedTest16bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb16bits), 0);
  1329. Performance("16 bits on Matrix-Shaper profiles", SpeedTest16bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  1330. Performance("16 bits on same Matrix-Shaper ", SpeedTest16bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  1331. Performance("16 bits on curves ", SpeedTest16bitsRGB, 0, "*curves", "*curves", sizeof(Scanline_rgb16bits), 0);
  1332. Performance("16 bits on CMYK CLUT profiles ", SpeedTest16bitsCMYK, 0, "test1.icc", "test2.icc", sizeof(Scanline_cmyk16bits), 0);
  1333. }
  1334. // The worst case is used, no cache and all rgb combinations
  1335. static
  1336. cmsFloat64Number SpeedTestFloatRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1337. {
  1338. cmsInt32Number j;
  1339. clock_t atime;
  1340. cmsFloat64Number diff;
  1341. cmsHTRANSFORM hlcmsxform;
  1342. void *In;
  1343. cmsUInt32Number size, Mb;
  1344. cmsUInt32Number inFormatter=0, outFormatter=0;
  1345. cmsFloat64Number seconds;
  1346. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1347. Fail("Unable to open profiles");
  1348. switch (cmsGetColorSpace(hlcmsProfileIn))
  1349. {
  1350. case cmsSigRgbData: inFormatter = TYPE_RGB_FLT; break;
  1351. case cmsSigLabData: inFormatter = TYPE_Lab_FLT; break;
  1352. default:
  1353. Fail("Invalid colorspace");
  1354. }
  1355. switch (cmsGetColorSpace(hlcmsProfileOut))
  1356. {
  1357. case cmsSigRgbData: outFormatter = TYPE_RGB_FLT; break;
  1358. case cmsSigLabData: outFormatter = TYPE_Lab_FLT; break;
  1359. case cmsSigXYZData: outFormatter = TYPE_XYZ_FLT; break;
  1360. default:
  1361. Fail("Invalid colorspace");
  1362. }
  1363. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, inFormatter, hlcmsProfileOut, outFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1364. cmsCloseProfile(hlcmsProfileIn);
  1365. cmsCloseProfile(hlcmsProfileOut);
  1366. j = 0;
  1367. if (inFormatter == TYPE_RGB_FLT)
  1368. {
  1369. cmsInt32Number r, g, b;
  1370. Scanline_rgbFloat* fill;
  1371. size = 256 * 256 * 256;
  1372. Mb = size * sizeof(Scanline_rgbFloat);
  1373. In = malloc(Mb);
  1374. fill = (Scanline_rgbFloat*)In;
  1375. for (r = 0; r < 256; r++)
  1376. for (g = 0; g < 256; g++)
  1377. for (b = 0; b < 256; b++) {
  1378. fill[j].r = (cmsFloat32Number)r / 255.0f;
  1379. fill[j].g = (cmsFloat32Number)g / 255.0f;
  1380. fill[j].b = (cmsFloat32Number)b / 255.0f;
  1381. j++;
  1382. }
  1383. }
  1384. else
  1385. {
  1386. cmsFloat32Number L, a, b;
  1387. Scanline_LabFloat* fill;
  1388. size = 100 * 256 * 256;
  1389. Mb = size * sizeof(Scanline_LabFloat);
  1390. In = malloc(Mb);
  1391. fill = (Scanline_LabFloat*)In;
  1392. for (L = 0; L < 100; L++)
  1393. for (a = -127.0; a < 127.0; a++)
  1394. for (b = -127.0; b < +127.0; b++) {
  1395. fill[j].L = L;
  1396. fill[j].a = a;
  1397. fill[j].b = b;
  1398. j++;
  1399. }
  1400. }
  1401. atime = clock();
  1402. cmsDoTransform(hlcmsxform, In, In, size);
  1403. diff = clock() - atime;
  1404. free(In);
  1405. cmsDeleteTransform(hlcmsxform);
  1406. seconds = (cmsFloat64Number)diff / (cmsFloat64Number)CLOCKS_PER_SEC;
  1407. return ((cmsFloat64Number)size) / (1024.0 * 1024.0 * seconds);
  1408. }
  1409. static
  1410. cmsFloat64Number SpeedTestFloatCMYK(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1411. {
  1412. cmsInt32Number c, m, y, k, j;
  1413. clock_t atime;
  1414. cmsFloat64Number diff;
  1415. cmsHTRANSFORM hlcmsxform;
  1416. Scanline_cmykFloat* In;
  1417. cmsUInt32Number Mb;
  1418. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1419. Fail("Unable to open profiles");
  1420. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_CMYK_FLT, hlcmsProfileOut, TYPE_CMYK_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1421. cmsCloseProfile(hlcmsProfileIn);
  1422. cmsCloseProfile(hlcmsProfileOut);
  1423. Mb = 64 * 64 * 64 * 64 * sizeof(Scanline_cmykFloat);
  1424. In = (Scanline_cmykFloat*)malloc(Mb);
  1425. j = 0;
  1426. for (c = 0; c < 256; c += 4)
  1427. for (m = 0; m < 256; m += 4)
  1428. for (y = 0; y < 256; y += 4)
  1429. for (k = 0; k < 256; k += 4) {
  1430. In[j].c = (cmsFloat32Number)c / 255.0f;
  1431. In[j].m = (cmsFloat32Number)m / 255.0f;
  1432. In[j].y = (cmsFloat32Number)y / 255.0f;
  1433. In[j].k = (cmsFloat32Number)k / 255.0f;
  1434. j++;
  1435. }
  1436. atime = clock();
  1437. cmsDoTransform(hlcmsxform, In, In, 64 * 64 * 64 * 64);
  1438. diff = clock() - atime;
  1439. free(In);
  1440. cmsDeleteTransform(hlcmsxform);
  1441. return MPixSec(diff);
  1442. }
  1443. static
  1444. cmsFloat64Number SpeedTestFloatLab(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1445. {
  1446. cmsInt32Number j;
  1447. clock_t atime;
  1448. cmsFloat64Number diff;
  1449. cmsHTRANSFORM hlcmsxform;
  1450. void* In;
  1451. cmsUInt32Number size, Mb;
  1452. cmsUInt32Number outFormatter = 0;
  1453. cmsFloat64Number seconds;
  1454. cmsFloat32Number L, a, b;
  1455. Scanline_LabFloat* fill;
  1456. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1457. Fail("Unable to open profiles");
  1458. if (cmsGetColorSpace(hlcmsProfileIn) != cmsSigLabData)
  1459. {
  1460. Fail("Invalid colorspace");
  1461. }
  1462. switch (cmsGetColorSpace(hlcmsProfileOut))
  1463. {
  1464. case cmsSigRgbData: outFormatter = TYPE_RGB_FLT; break;
  1465. case cmsSigLabData: outFormatter = TYPE_Lab_FLT; break;
  1466. case cmsSigXYZData: outFormatter = TYPE_XYZ_FLT; break;
  1467. default:
  1468. Fail("Invalid colorspace");
  1469. }
  1470. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_Lab_FLT, hlcmsProfileOut, outFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1471. cmsCloseProfile(hlcmsProfileIn);
  1472. cmsCloseProfile(hlcmsProfileOut);
  1473. j = 0;
  1474. size = 100 * 256 * 256;
  1475. Mb = size * sizeof(Scanline_LabFloat);
  1476. In = malloc(Mb);
  1477. fill = (Scanline_LabFloat*)In;
  1478. for (L = 0; L < 100; L++)
  1479. for (a = -127.0; a < 127.0; a++)
  1480. for (b = -127.0; b < +127.0; b++) {
  1481. fill[j].L = L;
  1482. fill[j].a = a;
  1483. fill[j].b = b;
  1484. j++;
  1485. }
  1486. atime = clock();
  1487. cmsDoTransform(hlcmsxform, In, In, size);
  1488. diff = clock() - atime;
  1489. free(In);
  1490. cmsDeleteTransform(hlcmsxform);
  1491. seconds = (cmsFloat64Number)diff / (cmsFloat64Number)CLOCKS_PER_SEC;
  1492. return ((cmsFloat64Number)size) / (1024.0 * 1024.0 * seconds);
  1493. }
  1494. static
  1495. void SpeedTestFloat(void)
  1496. {
  1497. cmsContext noPlugin = cmsCreateContext(0, 0);
  1498. cmsFloat64Number t[10] = { 0 };
  1499. trace("\n\n");
  1500. trace("P E R F O R M A N C E T E S T S F L O A T (D E F A U L T)\n");
  1501. trace("==============================================================\n\n");
  1502. fflush(stdout);
  1503. PerformanceHeader();
  1504. t[0] = Performance("Floating point on CLUT profiles ", SpeedTestFloatRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgbFloat), 0);
  1505. t[1] = Performance("Floating point on Matrix-Shaper ", SpeedTestFloatRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgbFloat), 0);
  1506. t[2] = Performance("Floating point on same MatrixSh ", SpeedTestFloatRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgbFloat), 0);
  1507. t[3] = Performance("Floating point on curves ", SpeedTestFloatRGB, noPlugin, "*curves", "*curves", sizeof(Scanline_rgbFloat), 0);
  1508. t[4] = Performance("Floating point on RGB->Lab ", SpeedTestFloatRGB, noPlugin, "test5.icc", "*lab", sizeof(Scanline_rgbFloat), 0);
  1509. t[5] = Performance("Floating point on RGB->XYZ ", SpeedTestFloatRGB, noPlugin, "test3.icc", "*xyz", sizeof(Scanline_rgbFloat), 0);
  1510. t[6] = Performance("Floating point on CMYK->CMYK ", SpeedTestFloatCMYK, noPlugin, "test1.icc", "test2.icc",sizeof(Scanline_cmykFloat), 0);
  1511. t[7] = Performance("Floating point on Lab->RGB ", SpeedTestFloatLab, noPlugin, "*lab", "test3.icc", sizeof(Scanline_LabFloat), 0);
  1512. // Note that context 0 has the plug-in installed
  1513. trace("\n\n");
  1514. trace("P E R F O R M A N C E T E S T S F L O A T (P L U G I N)\n");
  1515. trace("===========================================================\n\n");
  1516. fflush(stdout);
  1517. PerformanceHeader();
  1518. Performance("Floating point on CLUT profiles ", SpeedTestFloatRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgbFloat), t[0]);
  1519. Performance("Floating point on Matrix-Shaper ", SpeedTestFloatRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgbFloat), t[1]);
  1520. Performance("Floating point on same MatrixSh ", SpeedTestFloatRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgbFloat), t[2]);
  1521. Performance("Floating point on curves ", SpeedTestFloatRGB, 0, "*curves", "*curves", sizeof(Scanline_rgbFloat), t[3]);
  1522. Performance("Floating point on RGB->Lab ", SpeedTestFloatRGB, 0, "test5.icc", "*lab", sizeof(Scanline_rgbFloat), t[4]);
  1523. Performance("Floating point on RGB->XYZ ", SpeedTestFloatRGB, 0, "test3.icc", "*xyz", sizeof(Scanline_rgbFloat), t[5]);
  1524. Performance("Floating point on CMYK->CMYK ", SpeedTestFloatCMYK, 0, "test1.icc", "test2.icc", sizeof(Scanline_cmykFloat), t[6]);
  1525. Performance("Floating point on Lab->RGB ", SpeedTestFloatLab, 0, "*lab", "test3.icc", sizeof(Scanline_LabFloat), t[7]);
  1526. cmsDeleteContext(noPlugin);
  1527. }
  1528. static
  1529. cmsFloat64Number SpeedTestFloatByUsing16BitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1530. {
  1531. cmsInt32Number r, g, b, j;
  1532. clock_t atime;
  1533. cmsFloat64Number diff;
  1534. cmsHTRANSFORM xform16;
  1535. Scanline_rgbFloat *In;
  1536. Scanline_rgb16bits *tmp16;
  1537. cmsUInt32Number MbFloat, Mb16;
  1538. UNUSED_PARAMETER(ct);
  1539. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1540. Fail("Unable to open profiles");
  1541. xform16 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1542. cmsCloseProfile(hlcmsProfileIn);
  1543. cmsCloseProfile(hlcmsProfileOut);
  1544. MbFloat = 256 * 256 * 256 * sizeof(Scanline_rgbFloat);
  1545. Mb16 = 256 * 256 * 256 * sizeof(Scanline_rgb16bits);
  1546. In = (Scanline_rgbFloat*)malloc(MbFloat);
  1547. tmp16 = (Scanline_rgb16bits*)malloc(Mb16);
  1548. j = 0;
  1549. for (r = 0; r < 256; r++)
  1550. for (g = 0; g < 256; g++)
  1551. for (b = 0; b < 256; b++) {
  1552. In[j].r = (cmsFloat32Number)r / 255.0f;
  1553. In[j].g = (cmsFloat32Number)g / 255.0f;
  1554. In[j].b = (cmsFloat32Number)b / 255.0f;
  1555. j++;
  1556. }
  1557. atime = clock();
  1558. for (j = 0; j < 256 * 256 * 256; j++) {
  1559. tmp16[j].r = (cmsUInt16Number)floor(In[j].r * 65535.0 + 0.5);
  1560. tmp16[j].g = (cmsUInt16Number)floor(In[j].g * 65535.0 + 0.5);
  1561. tmp16[j].b = (cmsUInt16Number)floor(In[j].b * 65535.0 + 0.5);
  1562. j++;
  1563. }
  1564. cmsDoTransform(xform16, tmp16, tmp16, 256 * 256 * 256);
  1565. for (j = 0; j < 256 * 256 * 256; j++) {
  1566. In[j].r = (cmsFloat32Number) (tmp16[j].r / 65535.0 );
  1567. In[j].g = (cmsFloat32Number) (tmp16[j].g / 65535.0);
  1568. In[j].b = (cmsFloat32Number) (tmp16[j].b / 65535.0);
  1569. j++;
  1570. }
  1571. diff = clock() - atime;
  1572. free(In);
  1573. cmsDeleteTransform(xform16);
  1574. return MPixSec(diff);
  1575. }
  1576. static
  1577. void ComparativeFloatVs16bits(void)
  1578. {
  1579. trace("\n\n");
  1580. trace("C O M P A R A T I V E converting to 16 bit vs. using float plug-in.\n");
  1581. trace(" values given in MegaPixels per second.\n");
  1582. trace("====================================================================\n");
  1583. trace(" 16 bits tmp. Float plugin\n");
  1584. fflush(stdout);
  1585. Comparative("Floating point on CLUT profiles ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test5.icc", "test3.icc");
  1586. Comparative("Floating point on Matrix-Shaper ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test5.icc", "test0.icc");
  1587. Comparative("Floating point on same MatrixSh ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test0.icc", "test0.icc");
  1588. Comparative("Floating point on curves ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, NULL, NULL);
  1589. }
  1590. typedef struct
  1591. {
  1592. Scanline_rgba8bits pixels[256][256];
  1593. cmsUInt8Number padding[4];
  1594. } padded_line;
  1595. typedef struct
  1596. {
  1597. padded_line line[256];
  1598. } big_bitmap;
  1599. static
  1600. cmsFloat64Number SpeedTest8bitDoTransform(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1601. {
  1602. cmsInt32Number r, g, b, j;
  1603. clock_t atime;
  1604. cmsFloat64Number diff;
  1605. cmsHTRANSFORM hlcmsxform;
  1606. big_bitmap* In;
  1607. big_bitmap* Out;
  1608. cmsUInt32Number Mb;
  1609. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1610. Fail("Unable to open profiles");
  1611. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1612. cmsCloseProfile(hlcmsProfileIn);
  1613. cmsCloseProfile(hlcmsProfileOut);
  1614. // Our test bitmap is 256 x 256 padded lines
  1615. Mb = sizeof(big_bitmap);
  1616. In = (big_bitmap*)malloc(Mb);
  1617. Out = (big_bitmap*)malloc(Mb);
  1618. for (r = 0; r < 256; r++)
  1619. for (g = 0; g < 256; g++)
  1620. for (b = 0; b < 256; b++) {
  1621. In->line[r].pixels[g][b].r = (cmsUInt8Number)r;
  1622. In->line[r].pixels[g][b].g = (cmsUInt8Number)g;
  1623. In->line[r].pixels[g][b].b = (cmsUInt8Number)b;
  1624. In->line[r].pixels[g][b].a = 0;
  1625. }
  1626. atime = clock();
  1627. for (j = 0; j < 256; j++) {
  1628. cmsDoTransform(hlcmsxform, In->line[j].pixels, Out->line[j].pixels, 256 * 256);
  1629. }
  1630. diff = clock() - atime;
  1631. free(In); free(Out);
  1632. cmsDeleteTransform(hlcmsxform);
  1633. return MPixSec(diff);
  1634. }
  1635. static
  1636. cmsFloat64Number SpeedTest8bitLineStride(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  1637. {
  1638. cmsInt32Number r, g, b;
  1639. clock_t atime;
  1640. cmsFloat64Number diff;
  1641. cmsHTRANSFORM hlcmsxform;
  1642. big_bitmap* In;
  1643. big_bitmap* Out;
  1644. cmsUInt32Number Mb;
  1645. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  1646. Fail("Unable to open profiles");
  1647. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  1648. cmsCloseProfile(hlcmsProfileIn);
  1649. cmsCloseProfile(hlcmsProfileOut);
  1650. // Our test bitmap is 256 x 256 padded lines
  1651. Mb = sizeof(big_bitmap);
  1652. In = (big_bitmap*)malloc(Mb);
  1653. Out = (big_bitmap*)malloc(Mb);
  1654. for (r = 0; r < 256; r++)
  1655. for (g = 0; g < 256; g++)
  1656. for (b = 0; b < 256; b++) {
  1657. In->line[r].pixels[g][b].r = (cmsUInt8Number)r;
  1658. In->line[r].pixels[g][b].g = (cmsUInt8Number)g;
  1659. In->line[r].pixels[g][b].b = (cmsUInt8Number)b;
  1660. In->line[r].pixels[g][b].a = 0;
  1661. }
  1662. atime = clock();
  1663. cmsDoTransformLineStride(hlcmsxform, In, Out, 256*256, 256, sizeof(padded_line), sizeof(padded_line), 0, 0);
  1664. diff = clock() - atime;
  1665. free(In); free(Out);
  1666. cmsDeleteTransform(hlcmsxform);
  1667. return MPixSec(diff);
  1668. }
  1669. static
  1670. void ComparativeLineStride8bits(void)
  1671. {
  1672. cmsContext NoPlugin, Plugin;
  1673. trace("\n\n");
  1674. trace("C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()\n");
  1675. trace(" values given in MegaPixels per second.\n");
  1676. trace("====================================================================\n");
  1677. fflush(stdout);
  1678. NoPlugin = cmsCreateContext(NULL, NULL);
  1679. Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL);
  1680. ComparativeCt(NoPlugin, Plugin, "CLUT profiles ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test3.icc");
  1681. ComparativeCt(NoPlugin, Plugin, "CLUT 16 bits ", SpeedTest16bitsRGB, SpeedTest16bitsRGB, "test5.icc", "test3.icc");
  1682. ComparativeCt(NoPlugin, Plugin, "Matrix-Shaper ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test0.icc");
  1683. ComparativeCt(NoPlugin, Plugin, "same MatrixSh ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test0.icc", "test0.icc");
  1684. ComparativeCt(NoPlugin, Plugin, "curves ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, NULL, NULL);
  1685. cmsDeleteContext(Plugin);
  1686. cmsDeleteContext(NoPlugin);
  1687. }
  1688. static
  1689. void TestGrayTransformPerformance()
  1690. {
  1691. cmsInt32Number j;
  1692. clock_t atime;
  1693. cmsFloat64Number diff;
  1694. cmsHTRANSFORM hlcmsxform;
  1695. float *In;
  1696. cmsInt32Number pixels;
  1697. cmsUInt32Number Mb;
  1698. cmsToneCurve* gamma18;
  1699. cmsToneCurve* gamma22;
  1700. cmsHPROFILE hlcmsProfileIn;
  1701. cmsHPROFILE hlcmsProfileOut;
  1702. gamma18 = cmsBuildGamma(0, 1.8);
  1703. gamma22 = cmsBuildGamma(0, 2.2);
  1704. hlcmsProfileIn = cmsCreateGrayProfile(NULL, gamma18);
  1705. hlcmsProfileOut = cmsCreateGrayProfile(NULL, gamma22);
  1706. cmsFreeToneCurve(gamma18);
  1707. cmsFreeToneCurve(gamma22);
  1708. hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_GRAY_FLT | EXTRA_SH(1), hlcmsProfileOut, TYPE_GRAY_FLT|EXTRA_SH(1), INTENT_PERCEPTUAL, 0);
  1709. cmsCloseProfile(hlcmsProfileIn);
  1710. cmsCloseProfile(hlcmsProfileOut);
  1711. pixels = 256 * 256 * 256;
  1712. Mb = pixels* 2*sizeof(float);
  1713. In = (float*) malloc(Mb);
  1714. for (j = 0; j < pixels*2; j++)
  1715. In[j] = (j % 256) / 255.0f;
  1716. atime = clock();
  1717. cmsDoTransform(hlcmsxform, In, In, pixels);
  1718. diff = clock() - atime;
  1719. free(In);
  1720. cmsDeleteTransform(hlcmsxform);
  1721. trace("Gray conversion using two gray profiles\t %-12.2f MPixels/Sec.\n", MPixSec(diff));
  1722. }
  1723. static
  1724. void TestGrayTransformPerformance1()
  1725. {
  1726. cmsInt32Number j;
  1727. clock_t atime;
  1728. cmsFloat64Number diff;
  1729. cmsHTRANSFORM hlcmsxform;
  1730. float *In;
  1731. cmsInt32Number pixels;
  1732. cmsUInt32Number Mb;
  1733. cmsToneCurve* gamma18;
  1734. cmsToneCurve* gamma22;
  1735. cmsHPROFILE hlcmsProfileIn;
  1736. cmsHPROFILE hlcmsProfileOut;
  1737. gamma18 = cmsBuildGamma(0, 1.8);
  1738. gamma22 = cmsBuildGamma(0, 1./2.2);
  1739. hlcmsProfileIn = cmsCreateLinearizationDeviceLink(cmsSigGrayData, &gamma18);
  1740. hlcmsProfileOut = cmsCreateLinearizationDeviceLink(cmsSigGrayData, &gamma22);
  1741. cmsFreeToneCurve(gamma18);
  1742. cmsFreeToneCurve(gamma22);
  1743. hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_GRAY_FLT, hlcmsProfileOut, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
  1744. cmsCloseProfile(hlcmsProfileIn);
  1745. cmsCloseProfile(hlcmsProfileOut);
  1746. pixels = 256 * 256 * 256;
  1747. Mb = pixels* sizeof(float);
  1748. In = (float*) malloc(Mb);
  1749. for (j = 0; j < pixels; j++)
  1750. In[j] = (j % 256) / 255.0f;
  1751. atime = clock();
  1752. cmsDoTransform(hlcmsxform, In, In, pixels);
  1753. diff = clock() - atime;
  1754. free(In);
  1755. cmsDeleteTransform(hlcmsxform);
  1756. trace("Gray conversion using two devicelinks\t %-12.2f MPixels/Sec.\n", MPixSec(diff));
  1757. }
  1758. // The harness test
  1759. int main()
  1760. {
  1761. trace("FastFloating point extensions testbed - 1.5\n");
  1762. trace("Copyright (c) 1998-2022 Marti Maria Saguer, all rights reserved\n");
  1763. trace("\nInstalling error logger ... ");
  1764. cmsSetLogErrorHandler(FatalErrorQuit);
  1765. trace("done.\n");
  1766. trace("Installing plug-in ... ");
  1767. cmsPlugin(cmsFastFloatExtensions());
  1768. trace("done.\n\n");
  1769. CheckComputeIncrements();
  1770. // 15 bit functionality
  1771. CheckFormatters15();
  1772. Check15bitsConversions();
  1773. // 16 bits functionality
  1774. CheckAccuracy16Bits();
  1775. // Lab to whatever
  1776. CheckLab2RGB();
  1777. // Change format
  1778. CheckChangeFormat();
  1779. // Soft proofing
  1780. CheckSoftProofing();
  1781. // Floating point functionality
  1782. CheckConversionFloat();
  1783. trace("All floating point tests passed OK\n");
  1784. SpeedTest8();
  1785. SpeedTest16();
  1786. SpeedTest15();
  1787. SpeedTestFloat();
  1788. ComparativeFloatVs16bits();
  1789. ComparativeLineStride8bits();
  1790. // Test gray performance
  1791. trace("\n\n");
  1792. trace("F L O A T G R A Y conversions performance.\n");
  1793. trace("====================================================================\n");
  1794. TestGrayTransformPerformance();
  1795. TestGrayTransformPerformance1();
  1796. trace("\nAll tests passed OK\n");
  1797. return 0;
  1798. }