testcms2.c 278 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799
  1. //---------------------------------------------------------------------------------
  2. //
  3. // Little Color Management System
  4. // Copyright (c) 1998-2023 Marti Maria Saguer
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining
  7. // a copy of this software and associated documentation files (the "Software"),
  8. // to deal in the Software without restriction, including without limitation
  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 Software
  11. // is furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  18. // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //
  24. //---------------------------------------------------------------------------------
  25. //
  26. #include "testcms2.h"
  27. // A single check. Returns 1 if success, 0 if failed
  28. typedef cmsInt32Number (*TestFn)(cmsContext);
  29. // A parametric Tone curve test function
  30. typedef cmsFloat32Number (* dblfnptr)(cmsFloat32Number x, const cmsFloat64Number Params[]);
  31. // Some globals to keep track of error
  32. #define TEXT_ERROR_BUFFER_SIZE 4096
  33. static char ReasonToFailBuffer[TEXT_ERROR_BUFFER_SIZE];
  34. static char SubTestBuffer[TEXT_ERROR_BUFFER_SIZE];
  35. static cmsInt32Number TotalTests = 0, TotalFail = 0;
  36. static cmsBool TrappedError;
  37. static cmsInt32Number SimultaneousErrors;
  38. #define cmsmin(a, b) (((a) < (b)) ? (a) : (b))
  39. // Die, a fatal unexpected error is detected!
  40. void Die(const char* Reason, ...)
  41. {
  42. va_list args;
  43. va_start(args, Reason);
  44. vsprintf(ReasonToFailBuffer, Reason, args);
  45. va_end(args);
  46. printf("\n%s\n", ReasonToFailBuffer);
  47. fflush(stdout);
  48. exit(1);
  49. }
  50. static
  51. void* chknull(void* mem)
  52. {
  53. if (mem == NULL)
  54. Die("Memory may be corrupted");
  55. return mem;
  56. }
  57. // Memory management replacement -----------------------------------------------------------------------------
  58. // This is just a simple plug-in for malloc, free and realloc to keep track of memory allocated,
  59. // maximum requested as a single block and maximum allocated at a given time. Results are printed at the end
  60. static cmsUInt32Number SingleHit, MaxAllocated=0, TotalMemory=0;
  61. // I'm hiding the size before the block. This is a well-known technique and probably the blocks coming from
  62. // malloc are built in a way similar to that, but I do on my own to be portable.
  63. typedef struct {
  64. cmsUInt32Number KeepSize;
  65. cmsContext WhoAllocated;
  66. cmsUInt32Number DontCheck;
  67. union {
  68. cmsUInt64Number HiSparc;
  69. // '_cmsMemoryBlock' block is prepended by the
  70. // allocator for any requested size. Thus, union holds
  71. // "widest" type to guarantee proper '_cmsMemoryBlock'
  72. // alignment for any requested size.
  73. } alignment;
  74. } _cmsMemoryBlock;
  75. #define SIZE_OF_MEM_HEADER (sizeof(_cmsMemoryBlock))
  76. // This is a fake thread descriptor used to check thread integrity.
  77. // Basically it returns a different threadID each time it is called.
  78. // Then the memory management replacement functions does check if each
  79. // free() is being called with same ContextID used on malloc()
  80. static
  81. cmsContext DbgThread(void)
  82. {
  83. static cmsUInt32Number n = 1;
  84. return (cmsContext) (void*) ((cmsUInt8Number*) NULL + (n++ % 0xff0));
  85. }
  86. // The allocate routine
  87. static
  88. void* DebugMalloc(cmsContext ContextID, cmsUInt32Number size)
  89. {
  90. _cmsMemoryBlock* blk;
  91. if (size <= 0) {
  92. Die("malloc requested with zero bytes");
  93. }
  94. TotalMemory += size;
  95. if (TotalMemory > MaxAllocated)
  96. MaxAllocated = TotalMemory;
  97. if (size > SingleHit)
  98. SingleHit = size;
  99. blk = (_cmsMemoryBlock*) chknull(malloc(size + SIZE_OF_MEM_HEADER));
  100. if (blk == NULL) return NULL;
  101. blk ->KeepSize = size;
  102. blk ->WhoAllocated = ContextID;
  103. blk ->DontCheck = 0;
  104. return (void*) ((cmsUInt8Number*) blk + SIZE_OF_MEM_HEADER);
  105. }
  106. // The free routine
  107. static
  108. void DebugFree(cmsContext ContextID, void *Ptr)
  109. {
  110. _cmsMemoryBlock* blk;
  111. if (Ptr == NULL) {
  112. Die("NULL free (which is a no-op in C, but may be an clue of something going wrong)");
  113. }
  114. blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
  115. TotalMemory -= blk ->KeepSize;
  116. if (blk ->WhoAllocated != ContextID && !blk->DontCheck) {
  117. Die("Trying to free memory allocated by a different thread");
  118. }
  119. free(blk);
  120. }
  121. // Reallocate, just a malloc, a copy and a free in this case.
  122. static
  123. void * DebugRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize)
  124. {
  125. _cmsMemoryBlock* blk;
  126. void* NewPtr;
  127. cmsUInt32Number max_sz;
  128. NewPtr = DebugMalloc(ContextID, NewSize);
  129. if (Ptr == NULL) return NewPtr;
  130. blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
  131. max_sz = blk -> KeepSize > NewSize ? NewSize : blk ->KeepSize;
  132. memmove(NewPtr, Ptr, max_sz);
  133. DebugFree(ContextID, Ptr);
  134. return NewPtr;
  135. }
  136. // Let's know the totals
  137. static
  138. void DebugMemPrintTotals(void)
  139. {
  140. printf("[Memory statistics]\n");
  141. printf("Allocated = %u MaxAlloc = %u Single block hit = %u\n", TotalMemory, MaxAllocated, SingleHit);
  142. }
  143. void DebugMemDontCheckThis(void *Ptr)
  144. {
  145. _cmsMemoryBlock* blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
  146. blk ->DontCheck = 1;
  147. }
  148. // Memory string
  149. static
  150. const char* MemStr(cmsUInt32Number size)
  151. {
  152. static char Buffer[1024];
  153. if (size > 1024*1024) {
  154. sprintf(Buffer, "%g Mb", (cmsFloat64Number) size / (1024.0*1024.0));
  155. }
  156. else
  157. if (size > 1024) {
  158. sprintf(Buffer, "%g Kb", (cmsFloat64Number) size / 1024.0);
  159. }
  160. else
  161. sprintf(Buffer, "%g bytes", (cmsFloat64Number) size);
  162. return Buffer;
  163. }
  164. void TestMemoryLeaks(cmsBool ok)
  165. {
  166. if (TotalMemory > 0)
  167. printf("Ok, but %s are left!\n", MemStr(TotalMemory));
  168. else {
  169. if (ok) printf("Ok.\n");
  170. }
  171. }
  172. // Here we go with the plug-in declaration
  173. static cmsPluginMemHandler DebugMemHandler = {{ cmsPluginMagicNumber, 2060-2000, cmsPluginMemHandlerSig, NULL },
  174. DebugMalloc, DebugFree, DebugRealloc, NULL, NULL, NULL };
  175. // Returns a pointer to the memhandler plugin
  176. void* PluginMemHandler(void)
  177. {
  178. return (void*) &DebugMemHandler;
  179. }
  180. cmsContext WatchDogContext(void* usr)
  181. {
  182. cmsContext ctx;
  183. ctx = cmsCreateContext(&DebugMemHandler, usr);
  184. if (ctx == NULL)
  185. Die("Unable to create memory managed context");
  186. DebugMemDontCheckThis(ctx);
  187. return ctx;
  188. }
  189. static
  190. void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
  191. {
  192. Die(Text);
  193. cmsUNUSED_PARAMETER(ContextID);
  194. cmsUNUSED_PARAMETER(ErrorCode);
  195. }
  196. void ResetFatalError(cmsContext ContextID)
  197. {
  198. cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
  199. }
  200. // Print a dot for gauging
  201. void Dot(void)
  202. {
  203. fprintf(stdout, "."); fflush(stdout);
  204. }
  205. void Say(const char* str)
  206. {
  207. fprintf(stdout, "%s", str); fflush(stdout);
  208. }
  209. // Keep track of the reason to fail
  210. void Fail(const char* frm, ...)
  211. {
  212. va_list args;
  213. va_start(args, frm);
  214. vsprintf(ReasonToFailBuffer, frm, args);
  215. va_end(args);
  216. }
  217. // Keep track of subtest
  218. void SubTest(const char* frm, ...)
  219. {
  220. va_list args;
  221. Dot();
  222. va_start(args, frm);
  223. vsprintf(SubTestBuffer, frm, args);
  224. va_end(args);
  225. }
  226. // The check framework
  227. static
  228. void Check(cmsContext ContextID, const char* Title, TestFn Fn)
  229. {
  230. cmsContext ctx = DbgThread();
  231. printf("Checking %s ...", Title);
  232. fflush(stdout);
  233. ReasonToFailBuffer[0] = 0;
  234. SubTestBuffer[0] = 0;
  235. TrappedError = FALSE;
  236. SimultaneousErrors = 0;
  237. TotalTests++;
  238. if (Fn(ctx) && !TrappedError) {
  239. // It is a good place to check memory
  240. TestMemoryLeaks(TRUE);
  241. }
  242. else {
  243. printf("FAIL!\n");
  244. if (SubTestBuffer[0])
  245. printf("%s: [%s]\n\t%s\n", Title, SubTestBuffer, ReasonToFailBuffer);
  246. else
  247. printf("%s:\n\t%s\n", Title, ReasonToFailBuffer);
  248. if (SimultaneousErrors > 1)
  249. printf("\tMore than one (%d) errors were reported\n", SimultaneousErrors);
  250. TotalFail++;
  251. }
  252. fflush(stdout);
  253. }
  254. // Dump a tone curve, for easy diagnostic
  255. void DumpToneCurve(cmsContext ContextID, cmsToneCurve* gamma, const char* FileName)
  256. {
  257. cmsHANDLE hIT8;
  258. cmsUInt32Number i;
  259. hIT8 = cmsIT8Alloc(ContextID);
  260. cmsIT8SetPropertyDbl(ContextID, hIT8, "NUMBER_OF_FIELDS", 2);
  261. cmsIT8SetPropertyDbl(ContextID, hIT8, "NUMBER_OF_SETS", gamma ->nEntries);
  262. cmsIT8SetDataFormat(ContextID, hIT8, 0, "SAMPLE_ID");
  263. cmsIT8SetDataFormat(ContextID, hIT8, 1, "VALUE");
  264. for (i=0; i < gamma ->nEntries; i++) {
  265. char Val[30];
  266. sprintf(Val, "%u", i);
  267. cmsIT8SetDataRowCol(ContextID, hIT8, i, 0, Val);
  268. sprintf(Val, "0x%x", gamma ->Table16[i]);
  269. cmsIT8SetDataRowCol(ContextID, hIT8, i, 1, Val);
  270. }
  271. cmsIT8SaveToFile(ContextID, hIT8, FileName);
  272. cmsIT8Free(ContextID, hIT8);
  273. }
  274. // -------------------------------------------------------------------------------------------------
  275. // Used to perform several checks.
  276. // The space used is a clone of a well-known commercial
  277. // color space which I will name "Above RGB"
  278. static
  279. cmsHPROFILE Create_AboveRGB(cmsContext ctx)
  280. {
  281. cmsToneCurve* Curve[3];
  282. cmsHPROFILE hProfile;
  283. cmsCIExyY D65;
  284. cmsCIExyYTRIPLE Primaries = {{0.64, 0.33, 1 },
  285. {0.21, 0.71, 1 },
  286. {0.15, 0.06, 1 }};
  287. Curve[0] = Curve[1] = Curve[2] = cmsBuildGamma(ctx, 2.19921875);
  288. cmsWhitePointFromTemp(ctx, &D65, 6504);
  289. hProfile = cmsCreateRGBProfile(ctx, &D65, &Primaries, Curve);
  290. cmsFreeToneCurve(ctx, Curve[0]);
  291. return hProfile;
  292. }
  293. // A gamma-2.2 gray space
  294. static
  295. cmsHPROFILE Create_Gray22(cmsContext ctx)
  296. {
  297. cmsHPROFILE hProfile;
  298. cmsToneCurve* Curve = cmsBuildGamma(ctx, 2.2);
  299. if (Curve == NULL) return NULL;
  300. hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
  301. cmsFreeToneCurve(ctx, Curve);
  302. return hProfile;
  303. }
  304. // A gamma-3.0 gray space
  305. static
  306. cmsHPROFILE Create_Gray30(cmsContext ctx)
  307. {
  308. cmsHPROFILE hProfile;
  309. cmsToneCurve* Curve = cmsBuildGamma(ctx, 3.0);
  310. if (Curve == NULL) return NULL;
  311. hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
  312. cmsFreeToneCurve(ctx, Curve);
  313. return hProfile;
  314. }
  315. static
  316. cmsHPROFILE Create_GrayLab(cmsContext ctx)
  317. {
  318. cmsHPROFILE hProfile;
  319. cmsToneCurve* Curve = cmsBuildGamma(ctx, 1.0);
  320. if (Curve == NULL) return NULL;
  321. hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
  322. cmsFreeToneCurve(ctx, Curve);
  323. cmsSetPCS(ctx, hProfile, cmsSigLabData);
  324. return hProfile;
  325. }
  326. // A CMYK devicelink that adds gamma 3.0 to each channel
  327. static
  328. cmsHPROFILE Create_CMYK_DeviceLink(cmsContext ctx)
  329. {
  330. cmsHPROFILE hProfile;
  331. cmsToneCurve* Tab[4];
  332. cmsToneCurve* Curve = cmsBuildGamma(ctx, 3.0);
  333. if (Curve == NULL) return NULL;
  334. Tab[0] = Curve;
  335. Tab[1] = Curve;
  336. Tab[2] = Curve;
  337. Tab[3] = Curve;
  338. hProfile = cmsCreateLinearizationDeviceLink(ctx, cmsSigCmykData, Tab);
  339. if (hProfile == NULL) return NULL;
  340. cmsFreeToneCurve(ctx, Curve);
  341. return hProfile;
  342. }
  343. // Create a fake CMYK profile, without any other requirement that being coarse CMYK.
  344. // DON'T USE THIS PROFILE FOR ANYTHING, IT IS USELESS BUT FOR TESTING PURPOSES.
  345. typedef struct {
  346. cmsHTRANSFORM hLab2sRGB;
  347. cmsHTRANSFORM sRGB2Lab;
  348. cmsHTRANSFORM hIlimit;
  349. } FakeCMYKParams;
  350. static
  351. cmsFloat64Number Clip(cmsFloat64Number v)
  352. {
  353. if (v < 0) return 0;
  354. if (v > 1) return 1;
  355. return v;
  356. }
  357. static
  358. cmsInt32Number ForwardSampler(cmsContext ContextID, CMSREGISTER const cmsUInt16Number In[], cmsUInt16Number Out[], void* Cargo)
  359. {
  360. FakeCMYKParams* p = (FakeCMYKParams*) Cargo;
  361. cmsFloat64Number rgb[3], cmyk[4];
  362. cmsFloat64Number c, m, y, k;
  363. cmsDoTransform(ContextID, p ->hLab2sRGB, In, rgb, 1);
  364. c = 1 - rgb[0];
  365. m = 1 - rgb[1];
  366. y = 1 - rgb[2];
  367. k = (c < m ? cmsmin(c, y) : cmsmin(m, y));
  368. // NONSENSE WARNING!: I'm doing this just because this is a test
  369. // profile that may have ink limit up to 400%. There is no UCR here
  370. // so the profile is basically useless for anything but testing.
  371. cmyk[0] = c;
  372. cmyk[1] = m;
  373. cmyk[2] = y;
  374. cmyk[3] = k;
  375. cmsDoTransform(ContextID, p ->hIlimit, cmyk, Out, 1);
  376. return 1;
  377. }
  378. static
  379. cmsInt32Number ReverseSampler(cmsContext ContextID, CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
  380. {
  381. FakeCMYKParams* p = (FakeCMYKParams*) Cargo;
  382. cmsFloat64Number c, m, y, k, rgb[3];
  383. c = In[0] / 65535.0;
  384. m = In[1] / 65535.0;
  385. y = In[2] / 65535.0;
  386. k = In[3] / 65535.0;
  387. if (k == 0) {
  388. rgb[0] = Clip(1 - c);
  389. rgb[1] = Clip(1 - m);
  390. rgb[2] = Clip(1 - y);
  391. }
  392. else
  393. if (k == 1) {
  394. rgb[0] = rgb[1] = rgb[2] = 0;
  395. }
  396. else {
  397. rgb[0] = Clip((1 - c) * (1 - k));
  398. rgb[1] = Clip((1 - m) * (1 - k));
  399. rgb[2] = Clip((1 - y) * (1 - k));
  400. }
  401. cmsDoTransform(ContextID, p ->sRGB2Lab, rgb, Out, 1);
  402. return 1;
  403. }
  404. static
  405. cmsHPROFILE CreateFakeCMYK(cmsContext ContextID, cmsFloat64Number InkLimit, cmsBool lUseAboveRGB)
  406. {
  407. cmsHPROFILE hICC;
  408. cmsPipeline* AToB0, *BToA0;
  409. cmsStage* CLUT;
  410. FakeCMYKParams p;
  411. cmsHPROFILE hLab, hsRGB, hLimit;
  412. cmsUInt32Number cmykfrm;
  413. if (lUseAboveRGB)
  414. hsRGB = Create_AboveRGB(ContextID);
  415. else
  416. hsRGB = cmsCreate_sRGBProfile(ContextID);
  417. hLab = cmsCreateLab4Profile(ContextID, NULL);
  418. hLimit = cmsCreateInkLimitingDeviceLink(ContextID, cmsSigCmykData, InkLimit);
  419. cmykfrm = FLOAT_SH(1) | BYTES_SH(0)|CHANNELS_SH(4);
  420. p.hLab2sRGB = cmsCreateTransform(ContextID, hLab, TYPE_Lab_16, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
  421. p.sRGB2Lab = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_DBL, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
  422. p.hIlimit = cmsCreateTransform(ContextID, hLimit, cmykfrm, NULL, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
  423. cmsCloseProfile(ContextID, hLab); cmsCloseProfile(ContextID, hsRGB); cmsCloseProfile(ContextID, hLimit);
  424. hICC = cmsCreateProfilePlaceholder(ContextID);
  425. if (!hICC) return NULL;
  426. cmsSetProfileVersion(ContextID, hICC, 4.3);
  427. cmsSetDeviceClass(ContextID, hICC, cmsSigOutputClass);
  428. cmsSetColorSpace(ContextID, hICC, cmsSigCmykData);
  429. cmsSetPCS(ContextID, hICC, cmsSigLabData);
  430. BToA0 = cmsPipelineAlloc(ContextID, 3, 4);
  431. if (BToA0 == NULL) return 0;
  432. CLUT = cmsStageAllocCLut16bit(ContextID, 17, 3, 4, NULL);
  433. if (CLUT == NULL) return 0;
  434. if (!cmsStageSampleCLut16bit(ContextID, CLUT, ForwardSampler, &p, 0)) return 0;
  435. cmsPipelineInsertStage(ContextID, BToA0, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
  436. cmsPipelineInsertStage(ContextID, BToA0, cmsAT_END, CLUT);
  437. cmsPipelineInsertStage(ContextID, BToA0, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 4));
  438. if (!cmsWriteTag(ContextID, hICC, cmsSigBToA0Tag, (void*) BToA0)) return 0;
  439. cmsPipelineFree(ContextID, BToA0);
  440. AToB0 = cmsPipelineAlloc(ContextID, 4, 3);
  441. if (AToB0 == NULL) return 0;
  442. CLUT = cmsStageAllocCLut16bit(ContextID, 17, 4, 3, NULL);
  443. if (CLUT == NULL) return 0;
  444. if (!cmsStageSampleCLut16bit(ContextID, CLUT, ReverseSampler, &p, 0)) return 0;
  445. cmsPipelineInsertStage(ContextID, AToB0, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 4));
  446. cmsPipelineInsertStage(ContextID, AToB0, cmsAT_END, CLUT);
  447. cmsPipelineInsertStage(ContextID, AToB0, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 3));
  448. if (!cmsWriteTag(ContextID, hICC, cmsSigAToB0Tag, (void*) AToB0)) return 0;
  449. cmsPipelineFree(ContextID, AToB0);
  450. cmsDeleteTransform(ContextID, p.hLab2sRGB);
  451. cmsDeleteTransform(ContextID, p.sRGB2Lab);
  452. cmsDeleteTransform(ContextID, p.hIlimit);
  453. cmsLinkTag(ContextID, hICC, cmsSigAToB1Tag, cmsSigAToB0Tag);
  454. cmsLinkTag(ContextID, hICC, cmsSigAToB2Tag, cmsSigAToB0Tag);
  455. cmsLinkTag(ContextID, hICC, cmsSigBToA1Tag, cmsSigBToA0Tag);
  456. cmsLinkTag(ContextID, hICC, cmsSigBToA2Tag, cmsSigBToA0Tag);
  457. return hICC;
  458. }
  459. // Does create several profiles for latter use------------------------------------------------------------------------------------------------
  460. static
  461. cmsInt32Number OneVirtual(cmsContext ctx, cmsHPROFILE h, const char* SubTestTxt, const char* FileName)
  462. {
  463. SubTest(SubTestTxt);
  464. if (h == NULL) return 0;
  465. if (!cmsSaveProfileToFile(ctx, h, FileName)) return 0;
  466. cmsCloseProfile(ctx, h);
  467. h = cmsOpenProfileFromFile(ctx, FileName, "r");
  468. if (h == NULL) return 0;
  469. cmsCloseProfile(ctx, h);
  470. return 1;
  471. }
  472. // This test checks the ability of lcms2 to save its built-ins as valid profiles.
  473. // It does not check the functionality of such profiles
  474. static
  475. cmsInt32Number CreateTestProfiles(cmsContext ctx)
  476. {
  477. cmsHPROFILE h;
  478. h = cmsCreate_sRGBProfile(ctx);
  479. if (!OneVirtual(ctx, h, "sRGB profile", "sRGBlcms2.icc")) return 0;
  480. // ----
  481. h = Create_AboveRGB(ctx);
  482. if (!OneVirtual(ctx, h, "aRGB profile", "aRGBlcms2.icc")) return 0;
  483. // ----
  484. h = Create_Gray22(ctx);
  485. if (!OneVirtual(ctx, h, "Gray profile", "graylcms2.icc")) return 0;
  486. // ----
  487. h = Create_Gray30(ctx);
  488. if (!OneVirtual(ctx, h, "Gray 3.0 profile", "gray3lcms2.icc")) return 0;
  489. // ----
  490. h = Create_GrayLab(ctx);
  491. if (!OneVirtual(ctx, h, "Gray Lab profile", "glablcms2.icc")) return 0;
  492. // ----
  493. h = Create_CMYK_DeviceLink(ctx);
  494. if (!OneVirtual(ctx, h, "Linearization profile", "linlcms2.icc")) return 0;
  495. // -------
  496. h = cmsCreateInkLimitingDeviceLink(ctx, cmsSigCmykData, 150);
  497. if (h == NULL) return 0;
  498. if (!OneVirtual(ctx, h, "Ink-limiting profile", "limitlcms2.icc")) return 0;
  499. // ------
  500. h = cmsCreateLab2Profile(ctx, NULL);
  501. if (!OneVirtual(ctx, h, "Lab 2 identity profile", "labv2lcms2.icc")) return 0;
  502. // ----
  503. h = cmsCreateLab4Profile(ctx, NULL);
  504. if (!OneVirtual(ctx, h, "Lab 4 identity profile", "labv4lcms2.icc")) return 0;
  505. // ----
  506. h = cmsCreateXYZProfile(ctx);
  507. if (!OneVirtual(ctx, h, "XYZ identity profile", "xyzlcms2.icc")) return 0;
  508. // ----
  509. h = cmsCreateNULLProfile(ctx);
  510. if (!OneVirtual(ctx, h, "NULL profile", "nullcms2.icc")) return 0;
  511. // ---
  512. h = cmsCreateBCHSWabstractProfile(ctx, 17, 0, 0, 0, 0, 5000, 6000);
  513. if (!OneVirtual(ctx, h, "BCHS profile", "bchslcms2.icc")) return 0;
  514. // ---
  515. h = CreateFakeCMYK(ctx, 300, FALSE);
  516. if (!OneVirtual(ctx, h, "Fake CMYK profile", "lcms2cmyk.icc")) return 0;
  517. // ---
  518. h = cmsCreateBCHSWabstractProfile(ctx, 17, 0, 1.2, 0, 3, 5000, 5000);
  519. if (!OneVirtual(ctx, h, "Brightness", "brightness.icc")) return 0;
  520. return 1;
  521. }
  522. static
  523. void RemoveTestProfiles(void)
  524. {
  525. remove("sRGBlcms2.icc");
  526. remove("aRGBlcms2.icc");
  527. remove("graylcms2.icc");
  528. remove("gray3lcms2.icc");
  529. remove("linlcms2.icc");
  530. remove("limitlcms2.icc");
  531. remove("labv2lcms2.icc");
  532. remove("labv4lcms2.icc");
  533. remove("xyzlcms2.icc");
  534. remove("nullcms2.icc");
  535. remove("bchslcms2.icc");
  536. remove("lcms2cmyk.icc");
  537. remove("glablcms2.icc");
  538. remove("lcms2link.icc");
  539. remove("lcms2link2.icc");
  540. remove("brightness.icc");
  541. }
  542. // -------------------------------------------------------------------------------------------------
  543. // Check the size of basic types. If this test fails, nothing is going to work anyway
  544. static
  545. cmsInt32Number CheckBaseTypes(cmsContext ContextID)
  546. {
  547. // Ignore warnings about conditional expression
  548. #ifdef _MSC_VER
  549. #pragma warning(disable: 4127)
  550. #endif
  551. if (sizeof(cmsUInt8Number) != 1) return 0;
  552. if (sizeof(cmsInt8Number) != 1) return 0;
  553. if (sizeof(cmsUInt16Number) != 2) return 0;
  554. if (sizeof(cmsInt16Number) != 2) return 0;
  555. if (sizeof(cmsUInt32Number) != 4) return 0;
  556. if (sizeof(cmsInt32Number) != 4) return 0;
  557. if (sizeof(cmsUInt64Number) != 8) return 0;
  558. if (sizeof(cmsInt64Number) != 8) return 0;
  559. if (sizeof(cmsFloat32Number) != 4) return 0;
  560. if (sizeof(cmsFloat64Number) != 8) return 0;
  561. if (sizeof(cmsSignature) != 4) return 0;
  562. if (sizeof(cmsU8Fixed8Number) != 2) return 0;
  563. if (sizeof(cmsS15Fixed16Number) != 4) return 0;
  564. if (sizeof(cmsU16Fixed16Number) != 4) return 0;
  565. return 1;
  566. }
  567. // -------------------------------------------------------------------------------------------------
  568. // Are we little or big endian? From Harbison&Steele.
  569. static
  570. cmsInt32Number CheckEndianness(cmsContext ContextID)
  571. {
  572. cmsInt32Number BigEndian, IsOk;
  573. union {
  574. long l;
  575. char c[sizeof (long)];
  576. } u;
  577. u.l = 1;
  578. BigEndian = (u.c[sizeof (long) - 1] == 1);
  579. #ifdef CMS_USE_BIG_ENDIAN
  580. IsOk = BigEndian;
  581. #else
  582. IsOk = !BigEndian;
  583. #endif
  584. if (!IsOk) {
  585. Die("\nOOOPPSS! You have CMS_USE_BIG_ENDIAN toggle misconfigured!\n\n"
  586. "Please, edit lcms2mt.h and %s the CMS_USE_BIG_ENDIAN toggle.\n", BigEndian? "uncomment" : "comment");
  587. return 0;
  588. }
  589. return 1;
  590. }
  591. // Check quick floor
  592. static
  593. cmsInt32Number CheckQuickFloor(cmsContext ContextID)
  594. {
  595. if ((_cmsQuickFloor(1.234) != 1) ||
  596. (_cmsQuickFloor(32767.234) != 32767) ||
  597. (_cmsQuickFloor(-1.234) != -2) ||
  598. (_cmsQuickFloor(-32767.1) != -32768)) {
  599. Die("\nOOOPPSS! _cmsQuickFloor() does not work as expected in your machine!\n\n"
  600. "Please, edit lcms2mt.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
  601. return 0;
  602. }
  603. return 1;
  604. }
  605. // Quick floor restricted to word
  606. static
  607. cmsInt32Number CheckQuickFloorWord(cmsContext ContextID)
  608. {
  609. cmsUInt32Number i;
  610. for (i=0; i < 65535; i++) {
  611. if (_cmsQuickFloorWord((cmsFloat64Number) i + 0.1234) != i) {
  612. Die("\nOOOPPSS! _cmsQuickFloorWord() does not work as expected in your machine!\n\n"
  613. "Please, edit lcms2mt.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
  614. return 0;
  615. }
  616. }
  617. return 1;
  618. }
  619. // -------------------------------------------------------------------------------------------------
  620. // Precision stuff.
  621. // On 15.16 fixed point, this is the maximum we can obtain. Remember ICC profiles have storage limits on this number
  622. #define FIXED_PRECISION_15_16 (1.0 / 65535.0)
  623. // On 8.8 fixed point, that is the max we can obtain.
  624. #define FIXED_PRECISION_8_8 (1.0 / 255.0)
  625. // On cmsFloat32Number type, this is the precision we expect
  626. #define FLOAT_PRECISSION (0.00001)
  627. static cmsFloat64Number MaxErr;
  628. cmsBool IsGoodVal(const char *title, cmsFloat64Number in, cmsFloat64Number out, cmsFloat64Number max)
  629. {
  630. cmsFloat64Number Err = fabs(in - out);
  631. if (Err > MaxErr) MaxErr = Err;
  632. if ((Err > max )) {
  633. Fail("(%s): Must be %f, But is %f ", title, in, out);
  634. return FALSE;
  635. }
  636. return TRUE;
  637. }
  638. cmsBool IsGoodFixed15_16(const char *title, cmsFloat64Number in, cmsFloat64Number out)
  639. {
  640. return IsGoodVal(title, in, out, FIXED_PRECISION_15_16);
  641. }
  642. cmsBool IsGoodFixed8_8(const char *title, cmsFloat64Number in, cmsFloat64Number out)
  643. {
  644. return IsGoodVal(title, in, out, FIXED_PRECISION_8_8);
  645. }
  646. cmsBool IsGoodWord(const char *title, cmsUInt16Number in, cmsUInt16Number out)
  647. {
  648. if ((abs(in - out) > 0 )) {
  649. Fail("(%s): Must be %x, But is %x ", title, in, out);
  650. return FALSE;
  651. }
  652. return TRUE;
  653. }
  654. cmsBool IsGoodWordPrec(const char *title, cmsUInt16Number in, cmsUInt16Number out, cmsUInt16Number maxErr)
  655. {
  656. if ((abs(in - out) > maxErr )) {
  657. Fail("(%s): Must be %x, But is %x ", title, in, out);
  658. return FALSE;
  659. }
  660. return TRUE;
  661. }
  662. // Fixed point ----------------------------------------------------------------------------------------------
  663. static
  664. cmsInt32Number TestSingleFixed15_16(cmsContext ContextID, cmsFloat64Number d)
  665. {
  666. cmsS15Fixed16Number f = _cmsDoubleTo15Fixed16(ContextID, d);
  667. cmsFloat64Number RoundTrip = _cms15Fixed16toDouble(ContextID, f);
  668. cmsFloat64Number Error = fabs(d - RoundTrip);
  669. return ( Error <= FIXED_PRECISION_15_16);
  670. }
  671. static
  672. cmsInt32Number CheckFixedPoint15_16(cmsContext ContextID)
  673. {
  674. if (!TestSingleFixed15_16(ContextID, 1.0)) return 0;
  675. if (!TestSingleFixed15_16(ContextID, 2.0)) return 0;
  676. if (!TestSingleFixed15_16(ContextID, 1.23456)) return 0;
  677. if (!TestSingleFixed15_16(ContextID, 0.99999)) return 0;
  678. if (!TestSingleFixed15_16(ContextID, 0.1234567890123456789099999)) return 0;
  679. if (!TestSingleFixed15_16(ContextID, -1.0)) return 0;
  680. if (!TestSingleFixed15_16(ContextID, -2.0)) return 0;
  681. if (!TestSingleFixed15_16(ContextID, -1.23456)) return 0;
  682. if (!TestSingleFixed15_16(ContextID, -1.1234567890123456789099999)) return 0;
  683. if (!TestSingleFixed15_16(ContextID, +32767.1234567890123456789099999)) return 0;
  684. if (!TestSingleFixed15_16(ContextID, -32767.1234567890123456789099999)) return 0;
  685. return 1;
  686. }
  687. static
  688. cmsInt32Number TestSingleFixed8_8(cmsContext ContextID, cmsFloat64Number d)
  689. {
  690. cmsS15Fixed16Number f = _cmsDoubleTo8Fixed8(ContextID, d);
  691. cmsFloat64Number RoundTrip = _cms8Fixed8toDouble(ContextID, (cmsUInt16Number) f);
  692. cmsFloat64Number Error = fabs(d - RoundTrip);
  693. return ( Error <= FIXED_PRECISION_8_8);
  694. }
  695. static
  696. cmsInt32Number CheckFixedPoint8_8(cmsContext ContextID)
  697. {
  698. if (!TestSingleFixed8_8(ContextID, 1.0)) return 0;
  699. if (!TestSingleFixed8_8(ContextID, 2.0)) return 0;
  700. if (!TestSingleFixed8_8(ContextID, 1.23456)) return 0;
  701. if (!TestSingleFixed8_8(ContextID, 0.99999)) return 0;
  702. if (!TestSingleFixed8_8(ContextID, 0.1234567890123456789099999)) return 0;
  703. if (!TestSingleFixed8_8(ContextID, +255.1234567890123456789099999)) return 0;
  704. return 1;
  705. }
  706. // D50 constant --------------------------------------------------------------------------------------------
  707. static
  708. cmsInt32Number CheckD50Roundtrip(cmsContext ContextID)
  709. {
  710. cmsFloat64Number cmsD50X_2 = 0.96420288;
  711. cmsFloat64Number cmsD50Y_2 = 1.0;
  712. cmsFloat64Number cmsD50Z_2 = 0.82490540;
  713. cmsS15Fixed16Number xe = _cmsDoubleTo15Fixed16(ContextID, cmsD50X);
  714. cmsS15Fixed16Number ye = _cmsDoubleTo15Fixed16(ContextID, cmsD50Y);
  715. cmsS15Fixed16Number ze = _cmsDoubleTo15Fixed16(ContextID, cmsD50Z);
  716. cmsFloat64Number x = _cms15Fixed16toDouble(ContextID, xe);
  717. cmsFloat64Number y = _cms15Fixed16toDouble(ContextID, ye);
  718. cmsFloat64Number z = _cms15Fixed16toDouble(ContextID, ze);
  719. double dx = fabs(cmsD50X - x);
  720. double dy = fabs(cmsD50Y - y);
  721. double dz = fabs(cmsD50Z - z);
  722. double euc = sqrt(dx*dx + dy*dy + dz* dz);
  723. if (euc > 1E-5) {
  724. Fail("D50 roundtrip |err| > (%f) ", euc);
  725. return 0;
  726. }
  727. xe = _cmsDoubleTo15Fixed16(ContextID, cmsD50X_2);
  728. ye = _cmsDoubleTo15Fixed16(ContextID, cmsD50Y_2);
  729. ze = _cmsDoubleTo15Fixed16(ContextID, cmsD50Z_2);
  730. x = _cms15Fixed16toDouble(ContextID, xe);
  731. y = _cms15Fixed16toDouble(ContextID, ye);
  732. z = _cms15Fixed16toDouble(ContextID, ze);
  733. dx = fabs(cmsD50X_2 - x);
  734. dy = fabs(cmsD50Y_2 - y);
  735. dz = fabs(cmsD50Z_2 - z);
  736. euc = sqrt(dx*dx + dy*dy + dz* dz);
  737. if (euc > 1E-5) {
  738. Fail("D50 roundtrip |err| > (%f) ", euc);
  739. return 0;
  740. }
  741. return 1;
  742. }
  743. // Linear interpolation -----------------------------------------------------------------------------------------------
  744. // Since prime factors of 65535 (FFFF) are,
  745. //
  746. // 0xFFFF = 3 * 5 * 17 * 257
  747. //
  748. // I test tables of 2, 4, 6, and 18 points, that will be exact.
  749. static
  750. void BuildTable(cmsInt32Number n, cmsUInt16Number Tab[], cmsBool Descending)
  751. {
  752. cmsInt32Number i;
  753. for (i=0; i < n; i++) {
  754. cmsFloat64Number v = (cmsFloat64Number) ((cmsFloat64Number) 65535.0 * i ) / (n-1);
  755. Tab[Descending ? (n - i - 1) : i ] = (cmsUInt16Number) floor(v + 0.5);
  756. }
  757. }
  758. // A single function that does check 1D interpolation
  759. // nNodesToCheck = number on nodes to check
  760. // Down = Create decreasing tables
  761. // Reverse = Check reverse interpolation
  762. // max_err = max allowed error
  763. static
  764. cmsInt32Number Check1D(cmsContext ContextID, cmsInt32Number nNodesToCheck, cmsBool Down, cmsInt32Number max_err)
  765. {
  766. cmsUInt32Number i;
  767. cmsUInt16Number in, out;
  768. cmsInterpParams* p;
  769. cmsUInt16Number* Tab;
  770. Tab = (cmsUInt16Number*) chknull(malloc(sizeof(cmsUInt16Number)* nNodesToCheck));
  771. if (Tab == NULL) return 0;
  772. p = _cmsComputeInterpParams(ContextID, nNodesToCheck, 1, 1, Tab, CMS_LERP_FLAGS_16BITS);
  773. if (p == NULL) return 0;
  774. BuildTable(nNodesToCheck, Tab, Down);
  775. for (i=0; i <= 0xffff; i++) {
  776. in = (cmsUInt16Number) i;
  777. out = 0;
  778. p ->Interpolation.Lerp16(ContextID, &in, &out, p);
  779. if (Down) out = 0xffff - out;
  780. if (abs(out - in) > max_err) {
  781. Fail("(%dp): Must be %x, But is %x : ", nNodesToCheck, in, out);
  782. _cmsFreeInterpParams(ContextID, p);
  783. free(Tab);
  784. return 0;
  785. }
  786. }
  787. _cmsFreeInterpParams(ContextID, p);
  788. free(Tab);
  789. return 1;
  790. }
  791. static
  792. cmsInt32Number Check1DLERP2(cmsContext ContextID)
  793. {
  794. return Check1D(ContextID, 2, FALSE, 0);
  795. }
  796. static
  797. cmsInt32Number Check1DLERP3(cmsContext ContextID)
  798. {
  799. return Check1D(ContextID, 3, FALSE, 1);
  800. }
  801. static
  802. cmsInt32Number Check1DLERP4(cmsContext ContextID)
  803. {
  804. return Check1D(ContextID, 4, FALSE, 0);
  805. }
  806. static
  807. cmsInt32Number Check1DLERP6(cmsContext ContextID)
  808. {
  809. return Check1D(ContextID, 6, FALSE, 0);
  810. }
  811. static
  812. cmsInt32Number Check1DLERP18(cmsContext ContextID)
  813. {
  814. return Check1D(ContextID, 18, FALSE, 0);
  815. }
  816. static
  817. cmsInt32Number Check1DLERP2Down(cmsContext ContextID)
  818. {
  819. return Check1D(ContextID, 2, TRUE, 0);
  820. }
  821. static
  822. cmsInt32Number Check1DLERP3Down(cmsContext ContextID)
  823. {
  824. return Check1D(ContextID, 3, TRUE, 1);
  825. }
  826. static
  827. cmsInt32Number Check1DLERP6Down(cmsContext ContextID)
  828. {
  829. return Check1D(ContextID, 6, TRUE, 0);
  830. }
  831. static
  832. cmsInt32Number Check1DLERP18Down(cmsContext ContextID)
  833. {
  834. return Check1D(ContextID, 18, TRUE, 0);
  835. }
  836. static
  837. cmsInt32Number ExhaustiveCheck1DLERP(cmsContext ContextID)
  838. {
  839. cmsUInt32Number j;
  840. printf("\n");
  841. for (j=10; j <= 4096; j++) {
  842. if ((j % 10) == 0) printf("%u \r", j);
  843. if (!Check1D(ContextID, j, FALSE, 1)) return 0;
  844. }
  845. printf("\rResult is ");
  846. return 1;
  847. }
  848. static
  849. cmsInt32Number ExhaustiveCheck1DLERPDown(cmsContext ContextID)
  850. {
  851. cmsUInt32Number j;
  852. printf("\n");
  853. for (j=10; j <= 4096; j++) {
  854. if ((j % 10) == 0) printf("%u \r", j);
  855. if (!Check1D(ContextID, j, TRUE, 1)) return 0;
  856. }
  857. printf("\rResult is ");
  858. return 1;
  859. }
  860. // 3D interpolation -------------------------------------------------------------------------------------------------
  861. static
  862. cmsInt32Number Check3DinterpolationFloatTetrahedral(cmsContext ContextID)
  863. {
  864. cmsInterpParams* p;
  865. cmsInt32Number i;
  866. cmsFloat32Number In[3], Out[3];
  867. cmsFloat32Number FloatTable[] = { //R G B
  868. 0, 0, 0, // B=0,G=0,R=0
  869. 0, 0, .25, // B=1,G=0,R=0
  870. 0, .5, 0, // B=0,G=1,R=0
  871. 0, .5, .25, // B=1,G=1,R=0
  872. 1, 0, 0, // B=0,G=0,R=1
  873. 1, 0, .25, // B=1,G=0,R=1
  874. 1, .5, 0, // B=0,G=1,R=1
  875. 1, .5, .25 // B=1,G=1,R=1
  876. };
  877. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT);
  878. MaxErr = 0.0;
  879. for (i=0; i < 0xffff; i++) {
  880. In[0] = In[1] = In[2] = (cmsFloat32Number) ( (cmsFloat32Number) i / 65535.0F);
  881. p ->Interpolation.LerpFloat(ContextID, In, Out, p);
  882. if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
  883. if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
  884. if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
  885. }
  886. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  887. _cmsFreeInterpParams(ContextID, p);
  888. return 1;
  889. Error:
  890. _cmsFreeInterpParams(ContextID, p);
  891. return 0;
  892. }
  893. static
  894. cmsInt32Number Check3DinterpolationFloatTrilinear(cmsContext ContextID)
  895. {
  896. cmsInterpParams* p;
  897. cmsInt32Number i;
  898. cmsFloat32Number In[3], Out[3];
  899. cmsFloat32Number FloatTable[] = { //R G B
  900. 0, 0, 0, // B=0,G=0,R=0
  901. 0, 0, .25, // B=1,G=0,R=0
  902. 0, .5, 0, // B=0,G=1,R=0
  903. 0, .5, .25, // B=1,G=1,R=0
  904. 1, 0, 0, // B=0,G=0,R=1
  905. 1, 0, .25, // B=1,G=0,R=1
  906. 1, .5, 0, // B=0,G=1,R=1
  907. 1, .5, .25 // B=1,G=1,R=1
  908. };
  909. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT|CMS_LERP_FLAGS_TRILINEAR);
  910. MaxErr = 0.0;
  911. for (i=0; i < 0xffff; i++) {
  912. In[0] = In[1] = In[2] = (cmsFloat32Number) ( (cmsFloat32Number) i / 65535.0F);
  913. p ->Interpolation.LerpFloat(ContextID, In, Out, p);
  914. if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
  915. if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
  916. if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
  917. }
  918. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  919. _cmsFreeInterpParams(ContextID, p);
  920. return 1;
  921. Error:
  922. _cmsFreeInterpParams(ContextID, p);
  923. return 0;
  924. }
  925. static
  926. cmsInt32Number Check3DinterpolationTetrahedral16(cmsContext ContextID)
  927. {
  928. cmsInterpParams* p;
  929. cmsInt32Number i;
  930. cmsUInt16Number In[3], Out[3];
  931. cmsUInt16Number Table[] = {
  932. 0, 0, 0,
  933. 0, 0, 0xffff,
  934. 0, 0xffff, 0,
  935. 0, 0xffff, 0xffff,
  936. 0xffff, 0, 0,
  937. 0xffff, 0, 0xffff,
  938. 0xffff, 0xffff, 0,
  939. 0xffff, 0xffff, 0xffff
  940. };
  941. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_16BITS);
  942. MaxErr = 0.0;
  943. for (i=0; i < 0xffff; i++) {
  944. In[0] = In[1] = In[2] = (cmsUInt16Number) i;
  945. p ->Interpolation.Lerp16(ContextID, In, Out, p);
  946. if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
  947. if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
  948. if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
  949. }
  950. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  951. _cmsFreeInterpParams(ContextID, p);
  952. return 1;
  953. Error:
  954. _cmsFreeInterpParams(ContextID, p);
  955. return 0;
  956. }
  957. static
  958. cmsInt32Number Check3DinterpolationTrilinear16(cmsContext ContextID)
  959. {
  960. cmsInterpParams* p;
  961. cmsInt32Number i;
  962. cmsUInt16Number In[3], Out[3];
  963. cmsUInt16Number Table[] = {
  964. 0, 0, 0,
  965. 0, 0, 0xffff,
  966. 0, 0xffff, 0,
  967. 0, 0xffff, 0xffff,
  968. 0xffff, 0, 0,
  969. 0xffff, 0, 0xffff,
  970. 0xffff, 0xffff, 0,
  971. 0xffff, 0xffff, 0xffff
  972. };
  973. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_TRILINEAR);
  974. MaxErr = 0.0;
  975. for (i=0; i < 0xffff; i++) {
  976. In[0] = In[1] = In[2] = (cmsUInt16Number) i;
  977. p ->Interpolation.Lerp16(ContextID, In, Out, p);
  978. if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
  979. if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
  980. if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
  981. }
  982. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  983. _cmsFreeInterpParams(ContextID, p);
  984. return 1;
  985. Error:
  986. _cmsFreeInterpParams(ContextID, p);
  987. return 0;
  988. }
  989. static
  990. cmsInt32Number ExaustiveCheck3DinterpolationFloatTetrahedral(cmsContext ContextID)
  991. {
  992. cmsInterpParams* p;
  993. cmsInt32Number r, g, b;
  994. cmsFloat32Number In[3], Out[3];
  995. cmsFloat32Number FloatTable[] = { //R G B
  996. 0, 0, 0, // B=0,G=0,R=0
  997. 0, 0, .25, // B=1,G=0,R=0
  998. 0, .5, 0, // B=0,G=1,R=0
  999. 0, .5, .25, // B=1,G=1,R=0
  1000. 1, 0, 0, // B=0,G=0,R=1
  1001. 1, 0, .25, // B=1,G=0,R=1
  1002. 1, .5, 0, // B=0,G=1,R=1
  1003. 1, .5, .25 // B=1,G=1,R=1
  1004. };
  1005. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT);
  1006. MaxErr = 0.0;
  1007. for (r=0; r < 0xff; r++)
  1008. for (g=0; g < 0xff; g++)
  1009. for (b=0; b < 0xff; b++)
  1010. {
  1011. In[0] = (cmsFloat32Number) r / 255.0F;
  1012. In[1] = (cmsFloat32Number) g / 255.0F;
  1013. In[2] = (cmsFloat32Number) b / 255.0F;
  1014. p ->Interpolation.LerpFloat(ContextID, In, Out, p);
  1015. if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
  1016. if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
  1017. if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
  1018. }
  1019. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  1020. _cmsFreeInterpParams(ContextID, p);
  1021. return 1;
  1022. Error:
  1023. _cmsFreeInterpParams(ContextID, p);
  1024. return 0;
  1025. }
  1026. static
  1027. cmsInt32Number ExaustiveCheck3DinterpolationFloatTrilinear(cmsContext ContextID)
  1028. {
  1029. cmsInterpParams* p;
  1030. cmsInt32Number r, g, b;
  1031. cmsFloat32Number In[3], Out[3];
  1032. cmsFloat32Number FloatTable[] = { //R G B
  1033. 0, 0, 0, // B=0,G=0,R=0
  1034. 0, 0, .25, // B=1,G=0,R=0
  1035. 0, .5, 0, // B=0,G=1,R=0
  1036. 0, .5, .25, // B=1,G=1,R=0
  1037. 1, 0, 0, // B=0,G=0,R=1
  1038. 1, 0, .25, // B=1,G=0,R=1
  1039. 1, .5, 0, // B=0,G=1,R=1
  1040. 1, .5, .25 // B=1,G=1,R=1
  1041. };
  1042. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT|CMS_LERP_FLAGS_TRILINEAR);
  1043. MaxErr = 0.0;
  1044. for (r=0; r < 0xff; r++)
  1045. for (g=0; g < 0xff; g++)
  1046. for (b=0; b < 0xff; b++)
  1047. {
  1048. In[0] = (cmsFloat32Number) r / 255.0F;
  1049. In[1] = (cmsFloat32Number) g / 255.0F;
  1050. In[2] = (cmsFloat32Number) b / 255.0F;
  1051. p ->Interpolation.LerpFloat(ContextID, In, Out, p);
  1052. if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
  1053. if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
  1054. if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
  1055. }
  1056. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
  1057. _cmsFreeInterpParams(ContextID, p);
  1058. return 1;
  1059. Error:
  1060. _cmsFreeInterpParams(ContextID, p);
  1061. return 0;
  1062. }
  1063. static
  1064. cmsInt32Number ExhaustiveCheck3DinterpolationTetrahedral16(cmsContext ContextID)
  1065. {
  1066. cmsInterpParams* p;
  1067. cmsInt32Number r, g, b;
  1068. cmsUInt16Number In[3], Out[3];
  1069. cmsUInt16Number Table[] = {
  1070. 0, 0, 0,
  1071. 0, 0, 0xffff,
  1072. 0, 0xffff, 0,
  1073. 0, 0xffff, 0xffff,
  1074. 0xffff, 0, 0,
  1075. 0xffff, 0, 0xffff,
  1076. 0xffff, 0xffff, 0,
  1077. 0xffff, 0xffff, 0xffff
  1078. };
  1079. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_16BITS);
  1080. for (r=0; r < 0xff; r++)
  1081. for (g=0; g < 0xff; g++)
  1082. for (b=0; b < 0xff; b++)
  1083. {
  1084. In[0] = (cmsUInt16Number) r ;
  1085. In[1] = (cmsUInt16Number) g ;
  1086. In[2] = (cmsUInt16Number) b ;
  1087. p ->Interpolation.Lerp16(ContextID, In, Out, p);
  1088. if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
  1089. if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
  1090. if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
  1091. }
  1092. _cmsFreeInterpParams(ContextID, p);
  1093. return 1;
  1094. Error:
  1095. _cmsFreeInterpParams(ContextID, p);
  1096. return 0;
  1097. }
  1098. static
  1099. cmsInt32Number ExhaustiveCheck3DinterpolationTrilinear16(cmsContext ContextID)
  1100. {
  1101. cmsInterpParams* p;
  1102. cmsInt32Number r, g, b;
  1103. cmsUInt16Number In[3], Out[3];
  1104. cmsUInt16Number Table[] = {
  1105. 0, 0, 0,
  1106. 0, 0, 0xffff,
  1107. 0, 0xffff, 0,
  1108. 0, 0xffff, 0xffff,
  1109. 0xffff, 0, 0,
  1110. 0xffff, 0, 0xffff,
  1111. 0xffff, 0xffff, 0,
  1112. 0xffff, 0xffff, 0xffff
  1113. };
  1114. p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_TRILINEAR);
  1115. for (r=0; r < 0xff; r++)
  1116. for (g=0; g < 0xff; g++)
  1117. for (b=0; b < 0xff; b++)
  1118. {
  1119. In[0] = (cmsUInt16Number) r ;
  1120. In[1] = (cmsUInt16Number)g ;
  1121. In[2] = (cmsUInt16Number)b ;
  1122. p ->Interpolation.Lerp16(ContextID, In, Out, p);
  1123. if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
  1124. if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
  1125. if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
  1126. }
  1127. _cmsFreeInterpParams(ContextID, p);
  1128. return 1;
  1129. Error:
  1130. _cmsFreeInterpParams(ContextID, p);
  1131. return 0;
  1132. }
  1133. // Check reverse interpolation on LUTS. This is right now exclusively used by K preservation algorithm
  1134. static
  1135. cmsInt32Number CheckReverseInterpolation3x3(cmsContext ContextID)
  1136. {
  1137. cmsPipeline* Lut;
  1138. cmsStage* clut;
  1139. cmsFloat32Number Target[4], Result[4], Hint[4];
  1140. cmsFloat32Number err, max;
  1141. cmsInt32Number i;
  1142. cmsUInt16Number Table[] = {
  1143. 0, 0, 0, // 0 0 0
  1144. 0, 0, 0xffff, // 0 0 1
  1145. 0, 0xffff, 0, // 0 1 0
  1146. 0, 0xffff, 0xffff, // 0 1 1
  1147. 0xffff, 0, 0, // 1 0 0
  1148. 0xffff, 0, 0xffff, // 1 0 1
  1149. 0xffff, 0xffff, 0, // 1 1 0
  1150. 0xffff, 0xffff, 0xffff, // 1 1 1
  1151. };
  1152. Lut = cmsPipelineAlloc(ContextID, 3, 3);
  1153. clut = cmsStageAllocCLut16bit(ContextID, 2, 3, 3, Table);
  1154. cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, clut);
  1155. Target[0] = 0; Target[1] = 0; Target[2] = 0;
  1156. Hint[0] = 0; Hint[1] = 0; Hint[2] = 0;
  1157. cmsPipelineEvalReverseFloat(ContextID, Target, Result, NULL, Lut);
  1158. if (Result[0] != 0 || Result[1] != 0 || Result[2] != 0){
  1159. Fail("Reverse interpolation didn't find zero");
  1160. goto Error;
  1161. }
  1162. // Transverse identity
  1163. max = 0;
  1164. for (i=0; i <= 100; i++) {
  1165. cmsFloat32Number in = i / 100.0F;
  1166. Target[0] = in; Target[1] = 0; Target[2] = 0;
  1167. cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
  1168. err = fabsf(in - Result[0]);
  1169. if (err > max) max = err;
  1170. memcpy(Hint, Result, sizeof(Hint));
  1171. }
  1172. cmsPipelineFree(ContextID, Lut);
  1173. return (max <= FLOAT_PRECISSION);
  1174. Error:
  1175. cmsPipelineFree(ContextID, Lut);
  1176. return 0;
  1177. }
  1178. static
  1179. cmsInt32Number CheckReverseInterpolation4x3(cmsContext ContextID)
  1180. {
  1181. cmsPipeline* Lut;
  1182. cmsStage* clut;
  1183. cmsFloat32Number Target[4], Result[4], Hint[4];
  1184. cmsFloat32Number err, max;
  1185. cmsInt32Number i;
  1186. // 4 -> 3, output gets 3 first channels copied
  1187. cmsUInt16Number Table[] = {
  1188. 0, 0, 0, // 0 0 0 0 = ( 0, 0, 0)
  1189. 0, 0, 0, // 0 0 0 1 = ( 0, 0, 0)
  1190. 0, 0, 0xffff, // 0 0 1 0 = ( 0, 0, 1)
  1191. 0, 0, 0xffff, // 0 0 1 1 = ( 0, 0, 1)
  1192. 0, 0xffff, 0, // 0 1 0 0 = ( 0, 1, 0)
  1193. 0, 0xffff, 0, // 0 1 0 1 = ( 0, 1, 0)
  1194. 0, 0xffff, 0xffff, // 0 1 1 0 = ( 0, 1, 1)
  1195. 0, 0xffff, 0xffff, // 0 1 1 1 = ( 0, 1, 1)
  1196. 0xffff, 0, 0, // 1 0 0 0 = ( 1, 0, 0)
  1197. 0xffff, 0, 0, // 1 0 0 1 = ( 1, 0, 0)
  1198. 0xffff, 0, 0xffff, // 1 0 1 0 = ( 1, 0, 1)
  1199. 0xffff, 0, 0xffff, // 1 0 1 1 = ( 1, 0, 1)
  1200. 0xffff, 0xffff, 0, // 1 1 0 0 = ( 1, 1, 0)
  1201. 0xffff, 0xffff, 0, // 1 1 0 1 = ( 1, 1, 0)
  1202. 0xffff, 0xffff, 0xffff, // 1 1 1 0 = ( 1, 1, 1)
  1203. 0xffff, 0xffff, 0xffff, // 1 1 1 1 = ( 1, 1, 1)
  1204. };
  1205. Lut = cmsPipelineAlloc(ContextID, 4, 3);
  1206. clut = cmsStageAllocCLut16bit(ContextID, 2, 4, 3, Table);
  1207. cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, clut);
  1208. // Check if the LUT is behaving as expected
  1209. SubTest("4->3 feasibility");
  1210. for (i=0; i <= 100; i++) {
  1211. Target[0] = i / 100.0F;
  1212. Target[1] = Target[0];
  1213. Target[2] = 0;
  1214. Target[3] = 12;
  1215. cmsPipelineEvalFloat(ContextID, Target, Result, Lut);
  1216. if (!IsGoodFixed15_16("0", Target[0], Result[0])) goto Error;
  1217. if (!IsGoodFixed15_16("1", Target[1], Result[1])) goto Error;
  1218. if (!IsGoodFixed15_16("2", Target[2], Result[2])) goto Error;
  1219. }
  1220. SubTest("4->3 zero");
  1221. Target[0] = 0;
  1222. Target[1] = 0;
  1223. Target[2] = 0;
  1224. // This one holds the fixed K
  1225. Target[3] = 0;
  1226. // This is our hint (which is a big lie in this case)
  1227. Hint[0] = 0.1F; Hint[1] = 0.1F; Hint[2] = 0.1F;
  1228. cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
  1229. if (Result[0] != 0 || Result[1] != 0 || Result[2] != 0 || Result[3] != 0){
  1230. Fail("Reverse interpolation didn't find zero");
  1231. goto Error;
  1232. }
  1233. SubTest("4->3 find CMY");
  1234. max = 0;
  1235. for (i=0; i <= 100; i++) {
  1236. cmsFloat32Number in = i / 100.0F;
  1237. Target[0] = in; Target[1] = 0; Target[2] = 0;
  1238. cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
  1239. err = fabsf(in - Result[0]);
  1240. if (err > max) max = err;
  1241. memcpy(Hint, Result, sizeof(Hint));
  1242. }
  1243. cmsPipelineFree(ContextID, Lut);
  1244. return (max <= FLOAT_PRECISSION);
  1245. Error:
  1246. cmsPipelineFree(ContextID, Lut);
  1247. return 0;
  1248. }
  1249. // Check all interpolation.
  1250. static
  1251. cmsUInt16Number Fn8D1(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
  1252. cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
  1253. cmsUInt32Number m)
  1254. {
  1255. return (cmsUInt16Number) ((a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8) / m);
  1256. }
  1257. static
  1258. cmsUInt16Number Fn8D2(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
  1259. cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
  1260. cmsUInt32Number m)
  1261. {
  1262. return (cmsUInt16Number) ((a1 + 3* a2 + 3* a3 + a4 + a5 + a6 + a7 + a8 ) / (m + 4));
  1263. }
  1264. static
  1265. cmsUInt16Number Fn8D3(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
  1266. cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
  1267. cmsUInt32Number m)
  1268. {
  1269. return (cmsUInt16Number) ((3*a1 + 2*a2 + 3*a3 + a4 + a5 + a6 + a7 + a8) / (m + 5));
  1270. }
  1271. static
  1272. cmsInt32Number Sampler3D(cmsContext ContextID,
  1273. CMSREGISTER const cmsUInt16Number In[],
  1274. CMSREGISTER cmsUInt16Number Out[],
  1275. CMSREGISTER void * Cargo)
  1276. {
  1277. Out[0] = Fn8D1(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
  1278. Out[1] = Fn8D2(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
  1279. Out[2] = Fn8D3(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
  1280. return 1;
  1281. cmsUNUSED_PARAMETER(Cargo);
  1282. }
  1283. static
  1284. cmsInt32Number Sampler4D(cmsContext ContextID,
  1285. CMSREGISTER const cmsUInt16Number In[],
  1286. CMSREGISTER cmsUInt16Number Out[],
  1287. CMSREGISTER void * Cargo)
  1288. {
  1289. Out[0] = Fn8D1(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
  1290. Out[1] = Fn8D2(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
  1291. Out[2] = Fn8D3(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
  1292. return 1;
  1293. cmsUNUSED_PARAMETER(Cargo);
  1294. }
  1295. static
  1296. cmsInt32Number Sampler5D(cmsContext ContextID,
  1297. CMSREGISTER const cmsUInt16Number In[],
  1298. CMSREGISTER cmsUInt16Number Out[],
  1299. CMSREGISTER void * Cargo)
  1300. {
  1301. Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
  1302. Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
  1303. Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
  1304. return 1;
  1305. cmsUNUSED_PARAMETER(Cargo);
  1306. }
  1307. static
  1308. cmsInt32Number Sampler6D(cmsContext ContextID,
  1309. CMSREGISTER const cmsUInt16Number In[],
  1310. CMSREGISTER cmsUInt16Number Out[],
  1311. CMSREGISTER void * Cargo)
  1312. {
  1313. Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
  1314. Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
  1315. Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
  1316. return 1;
  1317. cmsUNUSED_PARAMETER(Cargo);
  1318. }
  1319. static
  1320. cmsInt32Number Sampler7D(cmsContext ContextID,
  1321. CMSREGISTER const cmsUInt16Number In[],
  1322. CMSREGISTER cmsUInt16Number Out[],
  1323. CMSREGISTER void * Cargo)
  1324. {
  1325. Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
  1326. Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
  1327. Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
  1328. return 1;
  1329. cmsUNUSED_PARAMETER(Cargo);
  1330. }
  1331. static
  1332. cmsInt32Number Sampler8D(cmsContext ContextID,
  1333. CMSREGISTER const cmsUInt16Number In[],
  1334. CMSREGISTER cmsUInt16Number Out[],
  1335. CMSREGISTER void * Cargo)
  1336. {
  1337. Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
  1338. Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
  1339. Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
  1340. return 1;
  1341. cmsUNUSED_PARAMETER(Cargo);
  1342. }
  1343. static
  1344. cmsBool CheckOne3D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3)
  1345. {
  1346. cmsUInt16Number In[3], Out1[3], Out2[3];
  1347. In[0] = a1; In[1] = a2; In[2] = a3;
  1348. // This is the interpolated value
  1349. cmsPipelineEval16(ContextID, In, Out1, lut);
  1350. // This is the real value
  1351. Sampler3D(ContextID, In, Out2, NULL);
  1352. // Let's see the difference
  1353. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1354. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1355. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1356. return TRUE;
  1357. }
  1358. static
  1359. cmsBool CheckOne4D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4)
  1360. {
  1361. cmsUInt16Number In[4], Out1[3], Out2[3];
  1362. In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4;
  1363. // This is the interpolated value
  1364. cmsPipelineEval16(ContextID, In, Out1, lut);
  1365. // This is the real value
  1366. Sampler4D(ContextID, In, Out2, NULL);
  1367. // Let's see the difference
  1368. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1369. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1370. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1371. return TRUE;
  1372. }
  1373. static
  1374. cmsBool CheckOne5D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
  1375. cmsUInt16Number a3, cmsUInt16Number a4, cmsUInt16Number a5)
  1376. {
  1377. cmsUInt16Number In[5], Out1[3], Out2[3];
  1378. In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5;
  1379. // This is the interpolated value
  1380. cmsPipelineEval16(ContextID, In, Out1, lut);
  1381. // This is the real value
  1382. Sampler5D(ContextID, In, Out2, NULL);
  1383. // Let's see the difference
  1384. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1385. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1386. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1387. return TRUE;
  1388. }
  1389. static
  1390. cmsBool CheckOne6D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
  1391. cmsUInt16Number a3, cmsUInt16Number a4,
  1392. cmsUInt16Number a5, cmsUInt16Number a6)
  1393. {
  1394. cmsUInt16Number In[6], Out1[3], Out2[3];
  1395. In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6;
  1396. // This is the interpolated value
  1397. cmsPipelineEval16(ContextID, In, Out1, lut);
  1398. // This is the real value
  1399. Sampler6D(ContextID, In, Out2, NULL);
  1400. // Let's see the difference
  1401. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1402. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1403. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1404. return TRUE;
  1405. }
  1406. static
  1407. cmsBool CheckOne7D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
  1408. cmsUInt16Number a3, cmsUInt16Number a4,
  1409. cmsUInt16Number a5, cmsUInt16Number a6,
  1410. cmsUInt16Number a7)
  1411. {
  1412. cmsUInt16Number In[7], Out1[3], Out2[3];
  1413. In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6; In[6] = a7;
  1414. // This is the interpolated value
  1415. cmsPipelineEval16(ContextID, In, Out1, lut);
  1416. // This is the real value
  1417. Sampler7D(ContextID, In, Out2, NULL);
  1418. // Let's see the difference
  1419. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1420. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1421. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1422. return TRUE;
  1423. }
  1424. static
  1425. cmsBool CheckOne8D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
  1426. cmsUInt16Number a3, cmsUInt16Number a4,
  1427. cmsUInt16Number a5, cmsUInt16Number a6,
  1428. cmsUInt16Number a7, cmsUInt16Number a8)
  1429. {
  1430. cmsUInt16Number In[8], Out1[3], Out2[3];
  1431. In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6; In[6] = a7; In[7] = a8;
  1432. // This is the interpolated value
  1433. cmsPipelineEval16(ContextID, In, Out1, lut);
  1434. // This is the real value
  1435. Sampler8D(ContextID, In, Out2, NULL);
  1436. // Let's see the difference
  1437. if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
  1438. if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
  1439. if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
  1440. return TRUE;
  1441. }
  1442. static
  1443. cmsInt32Number Check3Dinterp(cmsContext ContextID)
  1444. {
  1445. cmsPipeline* lut;
  1446. cmsStage* mpe;
  1447. lut = cmsPipelineAlloc(ContextID, 3, 3);
  1448. mpe = cmsStageAllocCLut16bit(ContextID, 9, 3, 3, NULL);
  1449. cmsStageSampleCLut16bit(ContextID, mpe, Sampler3D, NULL, 0);
  1450. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1451. // Check accuracy
  1452. if (!CheckOne3D(ContextID, lut, 0, 0, 0)) return 0;
  1453. if (!CheckOne3D(ContextID, lut, 0xffff, 0xffff, 0xffff)) return 0;
  1454. if (!CheckOne3D(ContextID, lut, 0x8080, 0x8080, 0x8080)) return 0;
  1455. if (!CheckOne3D(ContextID, lut, 0x0000, 0xFE00, 0x80FF)) return 0;
  1456. if (!CheckOne3D(ContextID, lut, 0x1111, 0x2222, 0x3333)) return 0;
  1457. if (!CheckOne3D(ContextID, lut, 0x0000, 0x0012, 0x0013)) return 0;
  1458. if (!CheckOne3D(ContextID, lut, 0x3141, 0x1415, 0x1592)) return 0;
  1459. if (!CheckOne3D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12)) return 0;
  1460. cmsPipelineFree(ContextID, lut);
  1461. return 1;
  1462. }
  1463. static
  1464. cmsInt32Number Check3DinterpGranular(cmsContext ContextID)
  1465. {
  1466. cmsPipeline* lut;
  1467. cmsStage* mpe;
  1468. cmsUInt32Number Dimensions[] = { 7, 8, 9 };
  1469. lut = cmsPipelineAlloc(ContextID, 3, 3);
  1470. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
  1471. cmsStageSampleCLut16bit(ContextID, mpe, Sampler3D, NULL, 0);
  1472. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1473. // Check accuracy
  1474. if (!CheckOne3D(ContextID, lut, 0, 0, 0)) return 0;
  1475. if (!CheckOne3D(ContextID, lut, 0xffff, 0xffff, 0xffff)) return 0;
  1476. if (!CheckOne3D(ContextID, lut, 0x8080, 0x8080, 0x8080)) return 0;
  1477. if (!CheckOne3D(ContextID, lut, 0x0000, 0xFE00, 0x80FF)) return 0;
  1478. if (!CheckOne3D(ContextID, lut, 0x1111, 0x2222, 0x3333)) return 0;
  1479. if (!CheckOne3D(ContextID, lut, 0x0000, 0x0012, 0x0013)) return 0;
  1480. if (!CheckOne3D(ContextID, lut, 0x3141, 0x1415, 0x1592)) return 0;
  1481. if (!CheckOne3D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12)) return 0;
  1482. cmsPipelineFree(ContextID, lut);
  1483. return 1;
  1484. }
  1485. static
  1486. cmsInt32Number Check4Dinterp(cmsContext ContextID)
  1487. {
  1488. cmsPipeline* lut;
  1489. cmsStage* mpe;
  1490. lut = cmsPipelineAlloc(ContextID, 4, 3);
  1491. mpe = cmsStageAllocCLut16bit(ContextID, 9, 4, 3, NULL);
  1492. cmsStageSampleCLut16bit(ContextID, mpe, Sampler4D, NULL, 0);
  1493. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1494. // Check accuracy
  1495. if (!CheckOne4D(ContextID, lut, 0, 0, 0, 0)) return 0;
  1496. if (!CheckOne4D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1497. if (!CheckOne4D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
  1498. if (!CheckOne4D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
  1499. if (!CheckOne4D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
  1500. if (!CheckOne4D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
  1501. if (!CheckOne4D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
  1502. if (!CheckOne4D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
  1503. cmsPipelineFree(ContextID, lut);
  1504. return 1;
  1505. }
  1506. static
  1507. cmsInt32Number Check4DinterpGranular(cmsContext ContextID)
  1508. {
  1509. cmsPipeline* lut;
  1510. cmsStage* mpe;
  1511. cmsUInt32Number Dimensions[] = { 9, 8, 7, 6 };
  1512. lut = cmsPipelineAlloc(ContextID, 4, 3);
  1513. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 4, 3, NULL);
  1514. cmsStageSampleCLut16bit(ContextID, mpe, Sampler4D, NULL, 0);
  1515. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1516. // Check accuracy
  1517. if (!CheckOne4D(ContextID, lut, 0, 0, 0, 0)) return 0;
  1518. if (!CheckOne4D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1519. if (!CheckOne4D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
  1520. if (!CheckOne4D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
  1521. if (!CheckOne4D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
  1522. if (!CheckOne4D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
  1523. if (!CheckOne4D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
  1524. if (!CheckOne4D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
  1525. cmsPipelineFree(ContextID, lut);
  1526. return 1;
  1527. }
  1528. static
  1529. cmsInt32Number Check5DinterpGranular(cmsContext ContextID)
  1530. {
  1531. cmsPipeline* lut;
  1532. cmsStage* mpe;
  1533. cmsUInt32Number Dimensions[] = { 3, 2, 2, 2, 2 };
  1534. lut = cmsPipelineAlloc(ContextID, 5, 3);
  1535. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 5, 3, NULL);
  1536. cmsStageSampleCLut16bit(ContextID, mpe, Sampler5D, NULL, 0);
  1537. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1538. // Check accuracy
  1539. if (!CheckOne5D(ContextID, lut, 0, 0, 0, 0, 0)) return 0;
  1540. if (!CheckOne5D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1541. if (!CheckOne5D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234)) return 0;
  1542. if (!CheckOne5D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078)) return 0;
  1543. if (!CheckOne5D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455)) return 0;
  1544. if (!CheckOne5D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333)) return 0;
  1545. if (!CheckOne5D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567)) return 0;
  1546. if (!CheckOne5D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344)) return 0;
  1547. cmsPipelineFree(ContextID, lut);
  1548. return 1;
  1549. }
  1550. static
  1551. cmsInt32Number Check6DinterpGranular(cmsContext ContextID)
  1552. {
  1553. cmsPipeline* lut;
  1554. cmsStage* mpe;
  1555. cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2 };
  1556. lut = cmsPipelineAlloc(ContextID, 6, 3);
  1557. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 6, 3, NULL);
  1558. cmsStageSampleCLut16bit(ContextID, mpe, Sampler6D, NULL, 0);
  1559. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1560. // Check accuracy
  1561. if (!CheckOne6D(ContextID, lut, 0, 0, 0, 0, 0, 0)) return 0;
  1562. if (!CheckOne6D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1563. if (!CheckOne6D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122)) return 0;
  1564. if (!CheckOne6D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233)) return 0;
  1565. if (!CheckOne6D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344)) return 0;
  1566. if (!CheckOne6D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455)) return 0;
  1567. if (!CheckOne6D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566)) return 0;
  1568. if (!CheckOne6D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677)) return 0;
  1569. cmsPipelineFree(ContextID, lut);
  1570. return 1;
  1571. }
  1572. static
  1573. cmsInt32Number Check7DinterpGranular(cmsContext ContextID)
  1574. {
  1575. cmsPipeline* lut;
  1576. cmsStage* mpe;
  1577. cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2, 2 };
  1578. lut = cmsPipelineAlloc(ContextID, 7, 3);
  1579. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 7, 3, NULL);
  1580. cmsStageSampleCLut16bit(ContextID, mpe, Sampler7D, NULL, 0);
  1581. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1582. // Check accuracy
  1583. if (!CheckOne7D(ContextID, lut, 0, 0, 0, 0, 0, 0, 0)) return 0;
  1584. if (!CheckOne7D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1585. if (!CheckOne7D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056)) return 0;
  1586. if (!CheckOne7D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088)) return 0;
  1587. if (!CheckOne7D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987)) return 0;
  1588. if (!CheckOne7D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988)) return 0;
  1589. if (!CheckOne7D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56)) return 0;
  1590. if (!CheckOne7D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe)) return 0;
  1591. cmsPipelineFree(ContextID, lut);
  1592. return 1;
  1593. }
  1594. static
  1595. cmsInt32Number Check8DinterpGranular(cmsContext ContextID)
  1596. {
  1597. cmsPipeline* lut;
  1598. cmsStage* mpe;
  1599. cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2, 2, 2 };
  1600. lut = cmsPipelineAlloc(ContextID, 8, 3);
  1601. mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 8, 3, NULL);
  1602. cmsStageSampleCLut16bit(ContextID, mpe, Sampler8D, NULL, 0);
  1603. cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
  1604. // Check accuracy
  1605. if (!CheckOne8D(ContextID, lut, 0, 0, 0, 0, 0, 0, 0, 0)) return 0;
  1606. if (!CheckOne8D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
  1607. if (!CheckOne8D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056, 0x0011)) return 0;
  1608. if (!CheckOne8D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088, 0x2020)) return 0;
  1609. if (!CheckOne8D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987, 0x4532)) return 0;
  1610. if (!CheckOne8D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988, 0x1200)) return 0;
  1611. if (!CheckOne8D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56, 0x6666)) return 0;
  1612. if (!CheckOne8D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe, 0xface)) return 0;
  1613. cmsPipelineFree(ContextID, lut);
  1614. return 1;
  1615. }
  1616. // Colorimetric conversions -------------------------------------------------------------------------------------------------
  1617. // Lab to LCh and back should be performed at 1E-12 accuracy at least
  1618. static
  1619. cmsInt32Number CheckLab2LCh(cmsContext ContextID)
  1620. {
  1621. cmsInt32Number l, a, b;
  1622. cmsFloat64Number dist, Max = 0;
  1623. cmsCIELab Lab, Lab2;
  1624. cmsCIELCh LCh;
  1625. for (l=0; l <= 100; l += 10) {
  1626. for (a=-128; a <= +128; a += 8) {
  1627. for (b=-128; b <= 128; b += 8) {
  1628. Lab.L = l;
  1629. Lab.a = a;
  1630. Lab.b = b;
  1631. cmsLab2LCh(ContextID, &LCh, &Lab);
  1632. cmsLCh2Lab(ContextID, &Lab2, &LCh);
  1633. dist = cmsDeltaE(ContextID, &Lab, &Lab2);
  1634. if (dist > Max) Max = dist;
  1635. }
  1636. }
  1637. }
  1638. return Max < 1E-12;
  1639. }
  1640. // Lab to LCh and back should be performed at 1E-12 accuracy at least
  1641. static
  1642. cmsInt32Number CheckLab2XYZ(cmsContext ContextID)
  1643. {
  1644. cmsInt32Number l, a, b;
  1645. cmsFloat64Number dist, Max = 0;
  1646. cmsCIELab Lab, Lab2;
  1647. cmsCIEXYZ XYZ;
  1648. for (l=0; l <= 100; l += 10) {
  1649. for (a=-128; a <= +128; a += 8) {
  1650. for (b=-128; b <= 128; b += 8) {
  1651. Lab.L = l;
  1652. Lab.a = a;
  1653. Lab.b = b;
  1654. cmsLab2XYZ(ContextID, NULL, &XYZ, &Lab);
  1655. cmsXYZ2Lab(ContextID, NULL, &Lab2, &XYZ);
  1656. dist = cmsDeltaE(ContextID, &Lab, &Lab2);
  1657. if (dist > Max) Max = dist;
  1658. }
  1659. }
  1660. }
  1661. return Max < 1E-12;
  1662. }
  1663. // Lab to xyY and back should be performed at 1E-12 accuracy at least
  1664. static
  1665. cmsInt32Number CheckLab2xyY(cmsContext ContextID)
  1666. {
  1667. cmsInt32Number l, a, b;
  1668. cmsFloat64Number dist, Max = 0;
  1669. cmsCIELab Lab, Lab2;
  1670. cmsCIEXYZ XYZ;
  1671. cmsCIExyY xyY;
  1672. for (l=0; l <= 100; l += 10) {
  1673. for (a=-128; a <= +128; a += 8) {
  1674. for (b=-128; b <= 128; b += 8) {
  1675. Lab.L = l;
  1676. Lab.a = a;
  1677. Lab.b = b;
  1678. cmsLab2XYZ(ContextID, NULL, &XYZ, &Lab);
  1679. cmsXYZ2xyY(ContextID, &xyY, &XYZ);
  1680. cmsxyY2XYZ(ContextID, &XYZ, &xyY);
  1681. cmsXYZ2Lab(ContextID, NULL, &Lab2, &XYZ);
  1682. dist = cmsDeltaE(ContextID, &Lab, &Lab2);
  1683. if (dist > Max) Max = dist;
  1684. }
  1685. }
  1686. }
  1687. return Max < 1E-12;
  1688. }
  1689. static
  1690. cmsInt32Number CheckLabV2encoding(cmsContext ContextID)
  1691. {
  1692. cmsInt32Number n2, i, j;
  1693. cmsUInt16Number Inw[3], aw[3];
  1694. cmsCIELab Lab;
  1695. n2=0;
  1696. for (j=0; j < 65535; j++) {
  1697. Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
  1698. cmsLabEncoded2FloatV2(ContextID, &Lab, Inw);
  1699. cmsFloat2LabEncodedV2(ContextID, aw, &Lab);
  1700. for (i=0; i < 3; i++) {
  1701. if (aw[i] != j) {
  1702. n2++;
  1703. }
  1704. }
  1705. }
  1706. return (n2 == 0);
  1707. }
  1708. static
  1709. cmsInt32Number CheckLabV4encoding(cmsContext ContextID)
  1710. {
  1711. cmsInt32Number n2, i, j;
  1712. cmsUInt16Number Inw[3], aw[3];
  1713. cmsCIELab Lab;
  1714. n2=0;
  1715. for (j=0; j < 65535; j++) {
  1716. Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
  1717. cmsLabEncoded2Float(ContextID, &Lab, Inw);
  1718. cmsFloat2LabEncoded(ContextID, aw, &Lab);
  1719. for (i=0; i < 3; i++) {
  1720. if (aw[i] != j) {
  1721. n2++;
  1722. }
  1723. }
  1724. }
  1725. return (n2 == 0);
  1726. }
  1727. // BlackBody -----------------------------------------------------------------------------------------------------
  1728. static
  1729. cmsInt32Number CheckTemp2CHRM(cmsContext ContextID)
  1730. {
  1731. cmsInt32Number j;
  1732. cmsFloat64Number d, v, Max = 0;
  1733. cmsCIExyY White;
  1734. for (j=4000; j < 25000; j++) {
  1735. cmsWhitePointFromTemp(ContextID, &White, j);
  1736. if (!cmsTempFromWhitePoint(ContextID, &v, &White)) return 0;
  1737. d = fabs(v - j);
  1738. if (d > Max) Max = d;
  1739. }
  1740. // 100 degree is the actual resolution
  1741. return (Max < 100);
  1742. }
  1743. // Tone curves -----------------------------------------------------------------------------------------------------
  1744. static
  1745. cmsInt32Number CheckGammaEstimation(cmsContext ContextID, cmsToneCurve* c, cmsFloat64Number g)
  1746. {
  1747. cmsFloat64Number est = cmsEstimateGamma(ContextID, c, 0.001);
  1748. SubTest("Gamma estimation");
  1749. if (fabs(est - g) > 0.001) return 0;
  1750. return 1;
  1751. }
  1752. static
  1753. cmsInt32Number CheckGammaCreation16(cmsContext ContextID)
  1754. {
  1755. cmsToneCurve* LinGamma = cmsBuildGamma(ContextID, 1.0);
  1756. cmsInt32Number i;
  1757. cmsUInt16Number in, out;
  1758. for (i=0; i < 0xffff; i++) {
  1759. in = (cmsUInt16Number) i;
  1760. out = cmsEvalToneCurve16(ContextID, LinGamma, in);
  1761. if (in != out) {
  1762. Fail("(lin gamma): Must be %x, But is %x : ", in, out);
  1763. cmsFreeToneCurve(ContextID, LinGamma);
  1764. return 0;
  1765. }
  1766. }
  1767. if (!CheckGammaEstimation(ContextID, LinGamma, 1.0)) return 0;
  1768. cmsFreeToneCurve(ContextID, LinGamma);
  1769. return 1;
  1770. }
  1771. static
  1772. cmsInt32Number CheckGammaCreationFlt(cmsContext ContextID)
  1773. {
  1774. cmsToneCurve* LinGamma = cmsBuildGamma(ContextID, 1.0);
  1775. cmsInt32Number i;
  1776. cmsFloat32Number in, out;
  1777. for (i=0; i < 0xffff; i++) {
  1778. in = (cmsFloat32Number) (i / 65535.0);
  1779. out = cmsEvalToneCurveFloat(ContextID, LinGamma, in);
  1780. if (fabs(in - out) > (1/65535.0)) {
  1781. Fail("(lin gamma): Must be %f, But is %f : ", in, out);
  1782. cmsFreeToneCurve(ContextID, LinGamma);
  1783. return 0;
  1784. }
  1785. }
  1786. if (!CheckGammaEstimation(ContextID, LinGamma, 1.0)) return 0;
  1787. cmsFreeToneCurve(ContextID, LinGamma);
  1788. return 1;
  1789. }
  1790. // Curve curves using a single power function
  1791. // Error is given in 0..ffff counts
  1792. static
  1793. cmsInt32Number CheckGammaFloat(cmsContext ContextID, cmsFloat64Number g)
  1794. {
  1795. cmsToneCurve* Curve = cmsBuildGamma(ContextID, g);
  1796. cmsInt32Number i;
  1797. cmsFloat32Number in, out;
  1798. cmsFloat64Number val, Err;
  1799. MaxErr = 0.0;
  1800. for (i=0; i < 0xffff; i++) {
  1801. in = (cmsFloat32Number) (i / 65535.0);
  1802. out = cmsEvalToneCurveFloat(ContextID, Curve, in);
  1803. val = pow((cmsFloat64Number) in, g);
  1804. Err = fabs( val - out);
  1805. if (Err > MaxErr) MaxErr = Err;
  1806. }
  1807. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
  1808. if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
  1809. cmsFreeToneCurve(ContextID, Curve);
  1810. return 1;
  1811. }
  1812. static cmsInt32Number CheckGamma18(cmsContext ContextID)
  1813. {
  1814. return CheckGammaFloat(ContextID, 1.8);
  1815. }
  1816. static cmsInt32Number CheckGamma22(cmsContext ContextID)
  1817. {
  1818. return CheckGammaFloat(ContextID, 2.2);
  1819. }
  1820. static cmsInt32Number CheckGamma30(cmsContext ContextID)
  1821. {
  1822. return CheckGammaFloat(ContextID, 3.0);
  1823. }
  1824. // Check table-based gamma functions
  1825. static
  1826. cmsInt32Number CheckGammaFloatTable(cmsContext ContextID, cmsFloat64Number g)
  1827. {
  1828. cmsFloat32Number Values[1025];
  1829. cmsToneCurve* Curve;
  1830. cmsInt32Number i;
  1831. cmsFloat32Number in, out;
  1832. cmsFloat64Number val, Err;
  1833. for (i=0; i <= 1024; i++) {
  1834. in = (cmsFloat32Number) (i / 1024.0);
  1835. Values[i] = powf(in, (float) g);
  1836. }
  1837. Curve = cmsBuildTabulatedToneCurveFloat(ContextID, 1025, Values);
  1838. MaxErr = 0.0;
  1839. for (i=0; i <= 0xffff; i++) {
  1840. in = (cmsFloat32Number) (i / 65535.0);
  1841. out = cmsEvalToneCurveFloat(ContextID, Curve, in);
  1842. val = pow(in, g);
  1843. Err = fabs(val - out);
  1844. if (Err > MaxErr) MaxErr = Err;
  1845. }
  1846. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
  1847. if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
  1848. cmsFreeToneCurve(ContextID, Curve);
  1849. return 1;
  1850. }
  1851. static cmsInt32Number CheckGamma18Table(cmsContext ContextID)
  1852. {
  1853. return CheckGammaFloatTable(ContextID, 1.8);
  1854. }
  1855. static cmsInt32Number CheckGamma22Table(cmsContext ContextID)
  1856. {
  1857. return CheckGammaFloatTable(ContextID, 2.2);
  1858. }
  1859. static cmsInt32Number CheckGamma30Table(cmsContext ContextID)
  1860. {
  1861. return CheckGammaFloatTable(ContextID, 3.0);
  1862. }
  1863. // Create a curve from a table (which is a pure gamma function) and check it against the pow function.
  1864. static
  1865. cmsInt32Number CheckGammaWordTable(cmsContext ContextID, cmsFloat64Number g)
  1866. {
  1867. cmsUInt16Number Values[1025];
  1868. cmsToneCurve* Curve;
  1869. cmsInt32Number i;
  1870. cmsFloat32Number in, out;
  1871. cmsFloat64Number val, Err;
  1872. for (i=0; i <= 1024; i++) {
  1873. in = (cmsFloat32Number) (i / 1024.0);
  1874. Values[i] = (cmsUInt16Number) floor(pow(in, g) * 65535.0 + 0.5);
  1875. }
  1876. Curve = cmsBuildTabulatedToneCurve16(ContextID, 1025, Values);
  1877. MaxErr = 0.0;
  1878. for (i=0; i <= 0xffff; i++) {
  1879. in = (cmsFloat32Number) (i / 65535.0);
  1880. out = cmsEvalToneCurveFloat(ContextID, Curve, in);
  1881. val = pow(in, g);
  1882. Err = fabs(val - out);
  1883. if (Err > MaxErr) MaxErr = Err;
  1884. }
  1885. if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
  1886. if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
  1887. cmsFreeToneCurve(ContextID, Curve);
  1888. return 1;
  1889. }
  1890. static cmsInt32Number CheckGamma18TableWord(cmsContext ContextID)
  1891. {
  1892. return CheckGammaWordTable(ContextID, 1.8);
  1893. }
  1894. static cmsInt32Number CheckGamma22TableWord(cmsContext ContextID)
  1895. {
  1896. return CheckGammaWordTable(ContextID, 2.2);
  1897. }
  1898. static cmsInt32Number CheckGamma30TableWord(cmsContext ContextID)
  1899. {
  1900. return CheckGammaWordTable(ContextID, 3.0);
  1901. }
  1902. // Curve joining test. Joining two high-gamma of 3.0 curves should
  1903. // give something like linear
  1904. static
  1905. cmsInt32Number CheckJointCurves(cmsContext ContextID)
  1906. {
  1907. cmsToneCurve *Forward, *Reverse, *Result;
  1908. cmsBool rc;
  1909. Forward = cmsBuildGamma(ContextID, 3.0);
  1910. Reverse = cmsBuildGamma(ContextID, 3.0);
  1911. Result = cmsJoinToneCurve(ContextID, Forward, Reverse, 256);
  1912. cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
  1913. rc = cmsIsToneCurveLinear(ContextID, Result);
  1914. cmsFreeToneCurve(ContextID, Result);
  1915. if (!rc)
  1916. Fail("Joining same curve twice does not result in a linear ramp");
  1917. return rc;
  1918. }
  1919. #if 0
  1920. // Create a gamma curve by cheating the table
  1921. static
  1922. cmsToneCurve* GammaTableLinear(cmsContext ContextID, cmsInt32Number nEntries, cmsBool Dir)
  1923. {
  1924. cmsInt32Number i;
  1925. cmsToneCurve* g = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
  1926. for (i=0; i < nEntries; i++) {
  1927. cmsInt32Number v = _cmsQuantizeVal(i, nEntries);
  1928. if (Dir)
  1929. g->Table16[i] = (cmsUInt16Number) v;
  1930. else
  1931. g->Table16[i] = (cmsUInt16Number) (0xFFFF - v);
  1932. }
  1933. return g;
  1934. }
  1935. #endif
  1936. static
  1937. cmsInt32Number CheckJointCurvesDescending(cmsContext ContextID)
  1938. {
  1939. cmsToneCurve *Forward, *Reverse, *Result;
  1940. cmsInt32Number i, rc;
  1941. Forward = cmsBuildGamma(ContextID, 2.2);
  1942. // Fake the curve to be table-based
  1943. for (i=0; i < 4096; i++)
  1944. Forward ->Table16[i] = 0xffff - Forward->Table16[i];
  1945. Forward ->Segments[0].Type = 0;
  1946. Reverse = cmsReverseToneCurve(ContextID, Forward);
  1947. Result = cmsJoinToneCurve(ContextID, Reverse, Reverse, 256);
  1948. cmsFreeToneCurve(ContextID, Forward);
  1949. cmsFreeToneCurve(ContextID, Reverse);
  1950. rc = cmsIsToneCurveLinear(ContextID, Result);
  1951. cmsFreeToneCurve(ContextID, Result);
  1952. return rc;
  1953. }
  1954. static
  1955. cmsInt32Number CheckFToneCurvePoint(cmsContext ContextID, cmsToneCurve* c, cmsUInt16Number Point, cmsInt32Number Value)
  1956. {
  1957. cmsInt32Number Result;
  1958. Result = cmsEvalToneCurve16(ContextID, c, Point);
  1959. return (abs(Value - Result) < 2);
  1960. }
  1961. static
  1962. cmsInt32Number CheckReverseDegenerated(cmsContext ContextID)
  1963. {
  1964. cmsToneCurve* p, *g;
  1965. cmsUInt16Number Tab[16];
  1966. Tab[0] = 0;
  1967. Tab[1] = 0;
  1968. Tab[2] = 0;
  1969. Tab[3] = 0;
  1970. Tab[4] = 0;
  1971. Tab[5] = 0x5555;
  1972. Tab[6] = 0x6666;
  1973. Tab[7] = 0x7777;
  1974. Tab[8] = 0x8888;
  1975. Tab[9] = 0x9999;
  1976. Tab[10]= 0xffff;
  1977. Tab[11]= 0xffff;
  1978. Tab[12]= 0xffff;
  1979. Tab[13]= 0xffff;
  1980. Tab[14]= 0xffff;
  1981. Tab[15]= 0xffff;
  1982. p = cmsBuildTabulatedToneCurve16(ContextID, 16, Tab);
  1983. g = cmsReverseToneCurve(ContextID, p);
  1984. // Now let's check some points
  1985. if (!CheckFToneCurvePoint(ContextID, g, 0x5555, 0x5555)) return 0;
  1986. if (!CheckFToneCurvePoint(ContextID, g, 0x7777, 0x7777)) return 0;
  1987. // First point for zero
  1988. if (!CheckFToneCurvePoint(ContextID, g, 0x0000, 0x4444)) return 0;
  1989. // Last point
  1990. if (!CheckFToneCurvePoint(ContextID, g, 0xFFFF, 0xFFFF)) return 0;
  1991. cmsFreeToneCurve(ContextID, p);
  1992. cmsFreeToneCurve(ContextID, g);
  1993. return 1;
  1994. }
  1995. // Build a parametric sRGB-like curve
  1996. static
  1997. cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
  1998. {
  1999. cmsFloat64Number Parameters[5];
  2000. Parameters[0] = 2.4;
  2001. Parameters[1] = 1. / 1.055;
  2002. Parameters[2] = 0.055 / 1.055;
  2003. Parameters[3] = 1. / 12.92;
  2004. Parameters[4] = 0.04045; // d
  2005. return cmsBuildParametricToneCurve(ContextID, 4, Parameters);
  2006. }
  2007. // Join two gamma tables in floating point format. Result should be a straight line
  2008. static
  2009. cmsToneCurve* CombineGammaFloat(cmsContext ContextID, cmsToneCurve* g1, cmsToneCurve* g2)
  2010. {
  2011. cmsUInt16Number Tab[256];
  2012. cmsFloat32Number f;
  2013. cmsInt32Number i;
  2014. for (i=0; i < 256; i++) {
  2015. f = (cmsFloat32Number) i / 255.0F;
  2016. f = cmsEvalToneCurveFloat(ContextID, g2, cmsEvalToneCurveFloat(ContextID, g1, f));
  2017. Tab[i] = (cmsUInt16Number) floor(f * 65535.0 + 0.5);
  2018. }
  2019. return cmsBuildTabulatedToneCurve16(ContextID, 256, Tab);
  2020. }
  2021. // Same of anterior, but using quantized tables
  2022. static
  2023. cmsToneCurve* CombineGamma16(cmsContext ContextID, cmsToneCurve* g1, cmsToneCurve* g2)
  2024. {
  2025. cmsUInt16Number Tab[256];
  2026. cmsInt32Number i;
  2027. for (i=0; i < 256; i++) {
  2028. cmsUInt16Number wValIn;
  2029. wValIn = _cmsQuantizeVal(i, 256);
  2030. Tab[i] = cmsEvalToneCurve16(ContextID, g2, cmsEvalToneCurve16(ContextID, g1, wValIn));
  2031. }
  2032. return cmsBuildTabulatedToneCurve16(ContextID, 256, Tab);
  2033. }
  2034. static
  2035. cmsInt32Number CheckJointFloatCurves_sRGB(cmsContext ContextID)
  2036. {
  2037. cmsToneCurve *Forward, *Reverse, *Result;
  2038. cmsBool rc;
  2039. Forward = Build_sRGBGamma(ContextID);
  2040. Reverse = cmsReverseToneCurve(ContextID, Forward);
  2041. Result = CombineGammaFloat(ContextID, Forward, Reverse);
  2042. cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
  2043. rc = cmsIsToneCurveLinear(ContextID, Result);
  2044. cmsFreeToneCurve(ContextID, Result);
  2045. return rc;
  2046. }
  2047. static
  2048. cmsInt32Number CheckJoint16Curves_sRGB(cmsContext ContextID)
  2049. {
  2050. cmsToneCurve *Forward, *Reverse, *Result;
  2051. cmsBool rc;
  2052. Forward = Build_sRGBGamma(ContextID);
  2053. Reverse = cmsReverseToneCurve(ContextID, Forward);
  2054. Result = CombineGamma16(ContextID, Forward, Reverse);
  2055. cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
  2056. rc = cmsIsToneCurveLinear(ContextID, Result);
  2057. cmsFreeToneCurve(ContextID, Result);
  2058. return rc;
  2059. }
  2060. // sigmoidal curve f(x) = (1-x^g) ^(1/g)
  2061. static
  2062. cmsInt32Number CheckJointCurvesSShaped(cmsContext ContextID)
  2063. {
  2064. cmsFloat64Number p = 3.2;
  2065. cmsToneCurve *Forward, *Reverse, *Result;
  2066. cmsInt32Number rc;
  2067. Forward = cmsBuildParametricToneCurve(ContextID, 108, &p);
  2068. Reverse = cmsReverseToneCurve(ContextID, Forward);
  2069. Result = cmsJoinToneCurve(ContextID, Forward, Forward, 4096);
  2070. cmsFreeToneCurve(ContextID, Forward);
  2071. cmsFreeToneCurve(ContextID, Reverse);
  2072. rc = cmsIsToneCurveLinear(ContextID, Result);
  2073. cmsFreeToneCurve(ContextID, Result);
  2074. return rc;
  2075. }
  2076. // --------------------------------------------------------------------------------------------------------
  2077. // Implementation of some tone curve functions
  2078. static
  2079. cmsFloat32Number Gamma(cmsFloat32Number x, const cmsFloat64Number Params[])
  2080. {
  2081. return (cmsFloat32Number) pow(x, Params[0]);
  2082. }
  2083. static
  2084. cmsFloat32Number CIE122(cmsFloat32Number x, const cmsFloat64Number Params[])
  2085. {
  2086. cmsFloat64Number e, Val;
  2087. if (x >= -Params[2] / Params[1]) {
  2088. e = Params[1]*x + Params[2];
  2089. if (e > 0)
  2090. Val = pow(e, Params[0]);
  2091. else
  2092. Val = 0;
  2093. }
  2094. else
  2095. Val = 0;
  2096. return (cmsFloat32Number) Val;
  2097. }
  2098. static
  2099. cmsFloat32Number IEC61966_3(cmsFloat32Number x, const cmsFloat64Number Params[])
  2100. {
  2101. cmsFloat64Number e, Val;
  2102. if (x >= -Params[2] / Params[1]) {
  2103. e = Params[1]*x + Params[2];
  2104. if (e > 0)
  2105. Val = pow(e, Params[0]) + Params[3];
  2106. else
  2107. Val = 0;
  2108. }
  2109. else
  2110. Val = Params[3];
  2111. return (cmsFloat32Number) Val;
  2112. }
  2113. static
  2114. cmsFloat32Number IEC61966_21(cmsFloat32Number x, const cmsFloat64Number Params[])
  2115. {
  2116. cmsFloat64Number e, Val;
  2117. if (x >= Params[4]) {
  2118. e = Params[1]*x + Params[2];
  2119. if (e > 0)
  2120. Val = pow(e, Params[0]);
  2121. else
  2122. Val = 0;
  2123. }
  2124. else
  2125. Val = x * Params[3];
  2126. return (cmsFloat32Number) Val;
  2127. }
  2128. static
  2129. cmsFloat32Number param_5(cmsFloat32Number x, const cmsFloat64Number Params[])
  2130. {
  2131. cmsFloat64Number e, Val;
  2132. // Y = (aX + b)^Gamma + e | X >= d
  2133. // Y = cX + f | else
  2134. if (x >= Params[4]) {
  2135. e = Params[1]*x + Params[2];
  2136. if (e > 0)
  2137. Val = pow(e, Params[0]) + Params[5];
  2138. else
  2139. Val = 0;
  2140. }
  2141. else
  2142. Val = x*Params[3] + Params[6];
  2143. return (cmsFloat32Number) Val;
  2144. }
  2145. static
  2146. cmsFloat32Number param_6(cmsFloat32Number x, const cmsFloat64Number Params[])
  2147. {
  2148. cmsFloat64Number e, Val;
  2149. e = Params[1]*x + Params[2];
  2150. if (e > 0)
  2151. Val = pow(e, Params[0]) + Params[3];
  2152. else
  2153. Val = 0;
  2154. return (cmsFloat32Number) Val;
  2155. }
  2156. static
  2157. cmsFloat32Number param_7(cmsFloat32Number x, const cmsFloat64Number Params[])
  2158. {
  2159. cmsFloat64Number Val;
  2160. Val = Params[1]*log10(Params[2] * pow(x, Params[0]) + Params[3]) + Params[4];
  2161. return (cmsFloat32Number) Val;
  2162. }
  2163. static
  2164. cmsFloat32Number param_8(cmsFloat32Number x, const cmsFloat64Number Params[])
  2165. {
  2166. cmsFloat64Number Val;
  2167. Val = (Params[0] * pow(Params[1], Params[2] * x + Params[3]) + Params[4]);
  2168. return (cmsFloat32Number) Val;
  2169. }
  2170. static
  2171. cmsFloat32Number sigmoidal(cmsFloat32Number x, const cmsFloat64Number Params[])
  2172. {
  2173. cmsFloat64Number Val;
  2174. Val = pow(1.0 - pow(1 - x, 1/Params[0]), 1/Params[0]);
  2175. return (cmsFloat32Number) Val;
  2176. }
  2177. static
  2178. cmsBool CheckSingleParametric(cmsContext ContextID, const char* Name, dblfnptr fn, cmsInt32Number Type, const cmsFloat64Number Params[])
  2179. {
  2180. cmsInt32Number i;
  2181. cmsToneCurve* tc;
  2182. cmsToneCurve* tc_1;
  2183. char InverseText[256];
  2184. tc = cmsBuildParametricToneCurve(ContextID, Type, Params);
  2185. tc_1 = cmsBuildParametricToneCurve(ContextID, -Type, Params);
  2186. for (i=0; i <= 1000; i++) {
  2187. cmsFloat32Number x = (cmsFloat32Number) i / 1000;
  2188. cmsFloat32Number y_fn, y_param, x_param, y_param2;
  2189. y_fn = fn(x, Params);
  2190. y_param = cmsEvalToneCurveFloat(ContextID, tc, x);
  2191. x_param = cmsEvalToneCurveFloat(ContextID, tc_1, y_param);
  2192. y_param2 = fn(x_param, Params);
  2193. if (!IsGoodVal(Name, y_fn, y_param, FIXED_PRECISION_15_16))
  2194. goto Error;
  2195. sprintf(InverseText, "Inverse %s", Name);
  2196. if (!IsGoodVal(InverseText, y_fn, y_param2, FIXED_PRECISION_15_16))
  2197. goto Error;
  2198. }
  2199. cmsFreeToneCurve(ContextID, tc);
  2200. cmsFreeToneCurve(ContextID, tc_1);
  2201. return TRUE;
  2202. Error:
  2203. cmsFreeToneCurve(ContextID, tc);
  2204. cmsFreeToneCurve(ContextID, tc_1);
  2205. return FALSE;
  2206. }
  2207. // Check against some known values
  2208. static
  2209. cmsInt32Number CheckParametricToneCurves(cmsContext ContextID)
  2210. {
  2211. cmsFloat64Number Params[10];
  2212. // 1) X = Y ^ Gamma
  2213. Params[0] = 2.2;
  2214. if (!CheckSingleParametric(ContextID, "Gamma", Gamma, 1, Params)) return 0;
  2215. // 2) CIE 122-1966
  2216. // Y = (aX + b)^Gamma | X >= -b/a
  2217. // Y = 0 | else
  2218. Params[0] = 2.2;
  2219. Params[1] = 1.5;
  2220. Params[2] = -0.5;
  2221. if (!CheckSingleParametric(ContextID, "CIE122-1966", CIE122, 2, Params)) return 0;
  2222. // 3) IEC 61966-3
  2223. // Y = (aX + b)^Gamma | X <= -b/a
  2224. // Y = c | else
  2225. Params[0] = 2.2;
  2226. Params[1] = 1.5;
  2227. Params[2] = -0.5;
  2228. Params[3] = 0.3;
  2229. if (!CheckSingleParametric(ContextID, "IEC 61966-3", IEC61966_3, 3, Params)) return 0;
  2230. // 4) IEC 61966-2.1 (sRGB)
  2231. // Y = (aX + b)^Gamma | X >= d
  2232. // Y = cX | X < d
  2233. Params[0] = 2.4;
  2234. Params[1] = 1. / 1.055;
  2235. Params[2] = 0.055 / 1.055;
  2236. Params[3] = 1. / 12.92;
  2237. Params[4] = 0.04045;
  2238. if (!CheckSingleParametric(ContextID, "IEC 61966-2.1", IEC61966_21, 4, Params)) return 0;
  2239. // 5) Y = (aX + b)^Gamma + e | X >= d
  2240. // Y = cX + f | else
  2241. Params[0] = 2.2;
  2242. Params[1] = 0.7;
  2243. Params[2] = 0.2;
  2244. Params[3] = 0.3;
  2245. Params[4] = 0.1;
  2246. Params[5] = 0.5;
  2247. Params[6] = 0.2;
  2248. if (!CheckSingleParametric(ContextID, "param_5", param_5, 5, Params)) return 0;
  2249. // 6) Y = (aX + b) ^ Gamma + c
  2250. Params[0] = 2.2;
  2251. Params[1] = 0.7;
  2252. Params[2] = 0.2;
  2253. Params[3] = 0.3;
  2254. if (!CheckSingleParametric(ContextID, "param_6", param_6, 6, Params)) return 0;
  2255. // 7) Y = a * log (b * X^Gamma + c) + d
  2256. Params[0] = 2.2;
  2257. Params[1] = 0.9;
  2258. Params[2] = 0.9;
  2259. Params[3] = 0.02;
  2260. Params[4] = 0.1;
  2261. if (!CheckSingleParametric(ContextID, "param_7", param_7, 7, Params)) return 0;
  2262. // 8) Y = a * b ^ (c*X+d) + e
  2263. Params[0] = 0.9;
  2264. Params[1] = 0.9;
  2265. Params[2] = 1.02;
  2266. Params[3] = 0.1;
  2267. Params[4] = 0.2;
  2268. if (!CheckSingleParametric(ContextID, "param_8", param_8, 8, Params)) return 0;
  2269. // 108: S-Shaped: (1 - (1-x)^1/g)^1/g
  2270. Params[0] = 1.9;
  2271. if (!CheckSingleParametric(ContextID, "sigmoidal", sigmoidal, 108, Params)) return 0;
  2272. // All OK
  2273. return 1;
  2274. }
  2275. // LUT checks ------------------------------------------------------------------------------
  2276. static
  2277. cmsInt32Number CheckLUTcreation(cmsContext ContextID)
  2278. {
  2279. cmsPipeline* lut;
  2280. cmsPipeline* lut2;
  2281. cmsInt32Number n1, n2;
  2282. lut = cmsPipelineAlloc(ContextID, 1, 1);
  2283. n1 = cmsPipelineStageCount(ContextID, lut);
  2284. lut2 = cmsPipelineDup(ContextID, lut);
  2285. n2 = cmsPipelineStageCount(ContextID, lut2);
  2286. cmsPipelineFree(ContextID, lut);
  2287. cmsPipelineFree(ContextID, lut2);
  2288. return (n1 == 0) && (n2 == 0);
  2289. }
  2290. // Create a MPE for a identity matrix
  2291. static
  2292. void AddIdentityMatrix(cmsContext ContextID, cmsPipeline* lut)
  2293. {
  2294. const cmsFloat64Number Identity[] = { 1, 0, 0,
  2295. 0, 1, 0,
  2296. 0, 0, 1,
  2297. 0, 0, 0 };
  2298. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, Identity, NULL));
  2299. }
  2300. // Create a MPE for identity cmsFloat32Number CLUT
  2301. static
  2302. void AddIdentityCLUTfloat(cmsContext ContextID, cmsPipeline* lut)
  2303. {
  2304. const cmsFloat32Number Table[] = {
  2305. 0, 0, 0,
  2306. 0, 0, 1.0,
  2307. 0, 1.0, 0,
  2308. 0, 1.0, 1.0,
  2309. 1.0, 0, 0,
  2310. 1.0, 0, 1.0,
  2311. 1.0, 1.0, 0,
  2312. 1.0, 1.0, 1.0
  2313. };
  2314. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocCLutFloat(ContextID, 2, 3, 3, Table));
  2315. }
  2316. // Create a MPE for identity cmsFloat32Number CLUT
  2317. static
  2318. void AddIdentityCLUT16(cmsContext ContextID, cmsPipeline* lut)
  2319. {
  2320. const cmsUInt16Number Table[] = {
  2321. 0, 0, 0,
  2322. 0, 0, 0xffff,
  2323. 0, 0xffff, 0,
  2324. 0, 0xffff, 0xffff,
  2325. 0xffff, 0, 0,
  2326. 0xffff, 0, 0xffff,
  2327. 0xffff, 0xffff, 0,
  2328. 0xffff, 0xffff, 0xffff
  2329. };
  2330. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocCLut16bit(ContextID, 2, 3, 3, Table));
  2331. }
  2332. // Create a 3 fn identity curves
  2333. static
  2334. void Add3GammaCurves(cmsContext ContextID, cmsPipeline* lut, cmsFloat64Number Curve)
  2335. {
  2336. cmsToneCurve* id = cmsBuildGamma(ContextID, Curve);
  2337. cmsToneCurve* id3[3];
  2338. id3[0] = id;
  2339. id3[1] = id;
  2340. id3[2] = id;
  2341. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, id3));
  2342. cmsFreeToneCurve(ContextID, id);
  2343. }
  2344. static
  2345. cmsInt32Number CheckFloatLUT(cmsContext ContextID, cmsPipeline* lut)
  2346. {
  2347. cmsInt32Number n1, i, j;
  2348. cmsFloat32Number Inf[3], Outf[3];
  2349. n1=0;
  2350. for (j=0; j < 65535; j++) {
  2351. cmsInt32Number af[3];
  2352. Inf[0] = Inf[1] = Inf[2] = (cmsFloat32Number) j / 65535.0F;
  2353. cmsPipelineEvalFloat(ContextID, Inf, Outf, lut);
  2354. af[0] = (cmsInt32Number) floor(Outf[0]*65535.0 + 0.5);
  2355. af[1] = (cmsInt32Number) floor(Outf[1]*65535.0 + 0.5);
  2356. af[2] = (cmsInt32Number) floor(Outf[2]*65535.0 + 0.5);
  2357. for (i=0; i < 3; i++) {
  2358. if (af[i] != j) {
  2359. n1++;
  2360. }
  2361. }
  2362. }
  2363. return (n1 == 0);
  2364. }
  2365. static
  2366. cmsInt32Number Check16LUT(cmsContext ContextID, cmsPipeline* lut)
  2367. {
  2368. cmsInt32Number n2, i, j;
  2369. cmsUInt16Number Inw[3], Outw[3];
  2370. n2=0;
  2371. for (j=0; j < 65535; j++) {
  2372. cmsInt32Number aw[3];
  2373. Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
  2374. cmsPipelineEval16(ContextID, Inw, Outw, lut);
  2375. aw[0] = Outw[0];
  2376. aw[1] = Outw[1];
  2377. aw[2] = Outw[2];
  2378. for (i=0; i < 3; i++) {
  2379. if (aw[i] != j) {
  2380. n2++;
  2381. }
  2382. }
  2383. }
  2384. return (n2 == 0);
  2385. }
  2386. // Check any LUT that is linear
  2387. static
  2388. cmsInt32Number CheckStagesLUT(cmsContext ContextID, cmsPipeline* lut, cmsInt32Number ExpectedStages)
  2389. {
  2390. cmsInt32Number nInpChans, nOutpChans, nStages;
  2391. nInpChans = cmsPipelineInputChannels(ContextID, lut);
  2392. nOutpChans = cmsPipelineOutputChannels(ContextID, lut);
  2393. nStages = cmsPipelineStageCount(ContextID, lut);
  2394. return (nInpChans == 3) && (nOutpChans == 3) && (nStages == ExpectedStages);
  2395. }
  2396. static
  2397. cmsInt32Number CheckFullLUT(cmsContext ContextID, cmsPipeline* lut, cmsInt32Number ExpectedStages)
  2398. {
  2399. cmsInt32Number rc = CheckStagesLUT(ContextID, lut, ExpectedStages) && Check16LUT(ContextID, lut) && CheckFloatLUT(ContextID, lut);
  2400. cmsPipelineFree(ContextID, lut);
  2401. return rc;
  2402. }
  2403. static
  2404. cmsInt32Number Check1StageLUT(cmsContext ContextID)
  2405. {
  2406. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2407. AddIdentityMatrix(ContextID, lut);
  2408. return CheckFullLUT(ContextID, lut, 1);
  2409. }
  2410. static
  2411. cmsInt32Number Check2StageLUT(cmsContext ContextID)
  2412. {
  2413. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2414. AddIdentityMatrix(ContextID, lut);
  2415. AddIdentityCLUTfloat(ContextID, lut);
  2416. return CheckFullLUT(ContextID, lut, 2);
  2417. }
  2418. static
  2419. cmsInt32Number Check2Stage16LUT(cmsContext ContextID)
  2420. {
  2421. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2422. AddIdentityMatrix(ContextID, lut);
  2423. AddIdentityCLUT16(ContextID, lut);
  2424. return CheckFullLUT(ContextID, lut, 2);
  2425. }
  2426. static
  2427. cmsInt32Number Check3StageLUT(cmsContext ContextID)
  2428. {
  2429. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2430. AddIdentityMatrix(ContextID, lut);
  2431. AddIdentityCLUTfloat(ContextID, lut);
  2432. Add3GammaCurves(ContextID, lut, 1.0);
  2433. return CheckFullLUT(ContextID, lut, 3);
  2434. }
  2435. static
  2436. cmsInt32Number Check3Stage16LUT(cmsContext ContextID)
  2437. {
  2438. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2439. AddIdentityMatrix(ContextID, lut);
  2440. AddIdentityCLUT16(ContextID, lut);
  2441. Add3GammaCurves(ContextID, lut, 1.0);
  2442. return CheckFullLUT(ContextID, lut, 3);
  2443. }
  2444. static
  2445. cmsInt32Number Check4StageLUT(cmsContext ContextID)
  2446. {
  2447. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2448. AddIdentityMatrix(ContextID, lut);
  2449. AddIdentityCLUTfloat(ContextID, lut);
  2450. Add3GammaCurves(ContextID, lut, 1.0);
  2451. AddIdentityMatrix(ContextID, lut);
  2452. return CheckFullLUT(ContextID, lut, 4);
  2453. }
  2454. static
  2455. cmsInt32Number Check4Stage16LUT(cmsContext ContextID)
  2456. {
  2457. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2458. AddIdentityMatrix(ContextID, lut);
  2459. AddIdentityCLUT16(ContextID, lut);
  2460. Add3GammaCurves(ContextID, lut, 1.0);
  2461. AddIdentityMatrix(ContextID, lut);
  2462. return CheckFullLUT(ContextID, lut, 4);
  2463. }
  2464. static
  2465. cmsInt32Number Check5StageLUT(cmsContext ContextID)
  2466. {
  2467. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2468. AddIdentityMatrix(ContextID, lut);
  2469. AddIdentityCLUTfloat(ContextID, lut);
  2470. Add3GammaCurves(ContextID, lut, 1.0);
  2471. AddIdentityMatrix(ContextID, lut);
  2472. Add3GammaCurves(ContextID, lut, 1.0);
  2473. return CheckFullLUT(ContextID, lut, 5);
  2474. }
  2475. static
  2476. cmsInt32Number Check5Stage16LUT(cmsContext ContextID)
  2477. {
  2478. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2479. AddIdentityMatrix(ContextID, lut);
  2480. AddIdentityCLUT16(ContextID, lut);
  2481. Add3GammaCurves(ContextID, lut, 1.0);
  2482. AddIdentityMatrix(ContextID, lut);
  2483. Add3GammaCurves(ContextID, lut, 1.0);
  2484. return CheckFullLUT(ContextID, lut, 5);
  2485. }
  2486. static
  2487. cmsInt32Number Check6StageLUT(cmsContext ContextID)
  2488. {
  2489. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2490. AddIdentityMatrix(ContextID, lut);
  2491. Add3GammaCurves(ContextID, lut, 1.0);
  2492. AddIdentityCLUTfloat(ContextID, lut);
  2493. Add3GammaCurves(ContextID, lut, 1.0);
  2494. AddIdentityMatrix(ContextID, lut);
  2495. Add3GammaCurves(ContextID, lut, 1.0);
  2496. return CheckFullLUT(ContextID, lut, 6);
  2497. }
  2498. static
  2499. cmsInt32Number Check6Stage16LUT(cmsContext ContextID)
  2500. {
  2501. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2502. AddIdentityMatrix(ContextID, lut);
  2503. Add3GammaCurves(ContextID, lut, 1.0);
  2504. AddIdentityCLUT16(ContextID, lut);
  2505. Add3GammaCurves(ContextID, lut, 1.0);
  2506. AddIdentityMatrix(ContextID, lut);
  2507. Add3GammaCurves(ContextID, lut, 1.0);
  2508. return CheckFullLUT(ContextID, lut, 6);
  2509. }
  2510. static
  2511. cmsInt32Number CheckLab2LabLUT(cmsContext ContextID)
  2512. {
  2513. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2514. cmsInt32Number rc;
  2515. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
  2516. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
  2517. rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 2);
  2518. cmsPipelineFree(ContextID, lut);
  2519. return rc;
  2520. }
  2521. static
  2522. cmsInt32Number CheckXYZ2XYZLUT(cmsContext ContextID)
  2523. {
  2524. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2525. cmsInt32Number rc;
  2526. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
  2527. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
  2528. rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 2);
  2529. cmsPipelineFree(ContextID, lut);
  2530. return rc;
  2531. }
  2532. static
  2533. cmsInt32Number CheckLab2LabMatLUT(cmsContext ContextID)
  2534. {
  2535. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2536. cmsInt32Number rc;
  2537. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
  2538. AddIdentityMatrix(ContextID, lut);
  2539. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
  2540. rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 3);
  2541. cmsPipelineFree(ContextID, lut);
  2542. return rc;
  2543. }
  2544. static
  2545. cmsInt32Number CheckNamedColorLUT(cmsContext ContextID)
  2546. {
  2547. cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
  2548. cmsNAMEDCOLORLIST* nc;
  2549. cmsInt32Number i,j, rc = 1, n2;
  2550. cmsUInt16Number PCS[3];
  2551. cmsUInt16Number Colorant[cmsMAXCHANNELS];
  2552. char Name[255];
  2553. cmsUInt16Number Inw[3], Outw[3];
  2554. nc = cmsAllocNamedColorList(ContextID, 256, 3, "pre", "post");
  2555. if (nc == NULL) return 0;
  2556. for (i=0; i < 256; i++) {
  2557. PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
  2558. Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) i;
  2559. sprintf(Name, "#%d", i);
  2560. if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { rc = 0; break; }
  2561. }
  2562. cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocNamedColor(ContextID, nc, FALSE));
  2563. cmsFreeNamedColorList(ContextID, nc);
  2564. if (rc == 0) return 0;
  2565. n2=0;
  2566. for (j=0; j < 256; j++) {
  2567. Inw[0] = (cmsUInt16Number) j;
  2568. cmsPipelineEval16(ContextID, Inw, Outw, lut);
  2569. for (i=0; i < 3; i++) {
  2570. if (Outw[i] != j) {
  2571. n2++;
  2572. }
  2573. }
  2574. }
  2575. cmsPipelineFree(ContextID, lut);
  2576. return (n2 == 0);
  2577. }
  2578. // --------------------------------------------------------------------------------------------
  2579. // A lightweight test of multilocalized unicode structures.
  2580. static
  2581. cmsInt32Number CheckMLU(cmsContext ContextID)
  2582. {
  2583. cmsMLU* mlu, *mlu2, *mlu3;
  2584. char Buffer[256], Buffer2[256];
  2585. cmsInt32Number rc = 1;
  2586. cmsInt32Number i;
  2587. cmsHPROFILE h= NULL;
  2588. // Allocate a MLU structure, no preferred size
  2589. mlu = cmsMLUalloc(ContextID, 0);
  2590. // Add some localizations
  2591. cmsMLUsetWide(ContextID, mlu, "en", "US", L"Hello, world");
  2592. cmsMLUsetWide(ContextID, mlu, "es", "ES", L"Hola, mundo");
  2593. cmsMLUsetWide(ContextID, mlu, "fr", "FR", L"Bonjour, le monde");
  2594. cmsMLUsetWide(ContextID, mlu, "ca", "CA", L"Hola, mon");
  2595. // Check the returned string for each language
  2596. cmsMLUgetASCII(ContextID, mlu, "en", "US", Buffer, 256);
  2597. if (strcmp(Buffer, "Hello, world") != 0) rc = 0;
  2598. cmsMLUgetASCII(ContextID, mlu, "es", "ES", Buffer, 256);
  2599. if (strcmp(Buffer, "Hola, mundo") != 0) rc = 0;
  2600. cmsMLUgetASCII(ContextID, mlu, "fr", "FR", Buffer, 256);
  2601. if (strcmp(Buffer, "Bonjour, le monde") != 0) rc = 0;
  2602. cmsMLUgetASCII(ContextID, mlu, "ca", "CA", Buffer, 256);
  2603. if (strcmp(Buffer, "Hola, mon") != 0) rc = 0;
  2604. if (rc == 0)
  2605. Fail("Unexpected string '%s'", Buffer);
  2606. // So far, so good.
  2607. cmsMLUfree(ContextID, mlu);
  2608. // Now for performance, allocate an empty struct
  2609. mlu = cmsMLUalloc(ContextID, 0);
  2610. // Fill it with several thousands of different lenguages
  2611. for (i=0; i < 4096; i++) {
  2612. char Lang[3];
  2613. Lang[0] = (char) (i % 255);
  2614. Lang[1] = (char) (i / 255);
  2615. Lang[2] = 0;
  2616. sprintf(Buffer, "String #%i", i);
  2617. cmsMLUsetASCII(ContextID, mlu, Lang, Lang, Buffer);
  2618. }
  2619. // Duplicate it
  2620. mlu2 = cmsMLUdup(ContextID, mlu);
  2621. // Get rid of original
  2622. cmsMLUfree(ContextID, mlu);
  2623. // Check all is still in place
  2624. for (i=0; i < 4096; i++) {
  2625. char Lang[3];
  2626. Lang[0] = (char)(i % 255);
  2627. Lang[1] = (char)(i / 255);
  2628. Lang[2] = 0;
  2629. cmsMLUgetASCII(ContextID, mlu2, Lang, Lang, Buffer2, 256);
  2630. sprintf(Buffer, "String #%i", i);
  2631. if (strcmp(Buffer, Buffer2) != 0) { rc = 0; break; }
  2632. }
  2633. if (rc == 0)
  2634. Fail("Unexpected string '%s'", Buffer2);
  2635. // Check profile IO
  2636. h = cmsOpenProfileFromFile(ContextID, "mlucheck.icc", "w");
  2637. cmsSetProfileVersion(ContextID, h, 4.3);
  2638. cmsWriteTag(ContextID, h, cmsSigProfileDescriptionTag, mlu2);
  2639. cmsCloseProfile(ContextID, h);
  2640. cmsMLUfree(ContextID, mlu2);
  2641. h = cmsOpenProfileFromFile(ContextID, "mlucheck.icc", "r");
  2642. mlu3 = (cmsMLU *) cmsReadTag(ContextID, h, cmsSigProfileDescriptionTag);
  2643. if (mlu3 == NULL) { Fail("Profile didn't get the MLU\n"); rc = 0; goto Error; }
  2644. // Check all is still in place
  2645. for (i=0; i < 4096; i++) {
  2646. char Lang[3];
  2647. Lang[0] = (char) (i % 255);
  2648. Lang[1] = (char) (i / 255);
  2649. Lang[2] = 0;
  2650. cmsMLUgetASCII(ContextID, mlu3, Lang, Lang, Buffer2, 256);
  2651. sprintf(Buffer, "String #%i", i);
  2652. if (strcmp(Buffer, Buffer2) != 0) { rc = 0; break; }
  2653. }
  2654. if (rc == 0) Fail("Unexpected string '%s'", Buffer2);
  2655. Error:
  2656. if (h != NULL) cmsCloseProfile(ContextID, h);
  2657. remove("mlucheck.icc");
  2658. return rc;
  2659. }
  2660. // Check UTF8 encoding
  2661. static
  2662. cmsInt32Number CheckMLU_UTF8(void)
  2663. {
  2664. cmsMLU* mlu;
  2665. char Buffer[256];
  2666. cmsInt32Number rc = 1;
  2667. mlu = cmsMLUalloc(DbgThread(), 0);
  2668. cmsMLUsetWide(mlu, "en", "US", L"\x3b2\x14b");
  2669. cmsMLUgetUTF8(mlu, "en", "US", Buffer, 256);
  2670. if (strcmp(Buffer, "\xce\xb2\xc5\x8b") != 0) rc = 0;
  2671. if (rc == 0)
  2672. Fail("Unexpected string '%s'", Buffer);
  2673. cmsMLUfree(mlu);
  2674. return rc;
  2675. }
  2676. // A lightweight test of named color structures.
  2677. static
  2678. cmsInt32Number CheckNamedColorList(cmsContext ContextID)
  2679. {
  2680. cmsNAMEDCOLORLIST* nc = NULL, *nc2;
  2681. cmsInt32Number i, j, rc=1;
  2682. char Name[cmsMAX_PATH];
  2683. cmsUInt16Number PCS[3];
  2684. cmsUInt16Number Colorant[cmsMAXCHANNELS];
  2685. char CheckName[cmsMAX_PATH];
  2686. cmsUInt16Number CheckPCS[3];
  2687. cmsUInt16Number CheckColorant[cmsMAXCHANNELS];
  2688. cmsHPROFILE h;
  2689. nc = cmsAllocNamedColorList(ContextID, 0, 4, "prefix", "suffix");
  2690. if (nc == NULL) return 0;
  2691. for (i=0; i < 4096; i++) {
  2692. PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
  2693. Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) (4096 - i);
  2694. sprintf(Name, "#%d", i);
  2695. if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { rc = 0; break; }
  2696. }
  2697. for (i=0; i < 4096; i++) {
  2698. CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
  2699. CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (4096 - i);
  2700. sprintf(CheckName, "#%d", i);
  2701. if (!cmsNamedColorInfo(ContextID, nc, i, Name, NULL, NULL, PCS, Colorant)) { rc = 0; goto Error; }
  2702. for (j=0; j < 3; j++) {
  2703. if (CheckPCS[j] != PCS[j]) { rc = 0; Fail("Invalid PCS"); goto Error; }
  2704. }
  2705. for (j=0; j < 4; j++) {
  2706. if (CheckColorant[j] != Colorant[j]) { rc = 0; Fail("Invalid Colorant"); goto Error; };
  2707. }
  2708. if (strcmp(Name, CheckName) != 0) {rc = 0; Fail("Invalid Name"); goto Error; };
  2709. }
  2710. h = cmsOpenProfileFromFile(ContextID, "namedcol.icc", "w");
  2711. if (h == NULL) return 0;
  2712. if (!cmsWriteTag(ContextID, h, cmsSigNamedColor2Tag, nc)) return 0;
  2713. cmsCloseProfile(ContextID, h);
  2714. cmsFreeNamedColorList(ContextID, nc);
  2715. nc = NULL;
  2716. h = cmsOpenProfileFromFile(ContextID, "namedcol.icc", "r");
  2717. nc2 = (cmsNAMEDCOLORLIST *) cmsReadTag(ContextID, h, cmsSigNamedColor2Tag);
  2718. if (cmsNamedColorCount(ContextID, nc2) != 4096) { rc = 0; Fail("Invalid count"); goto Error; }
  2719. i = cmsNamedColorIndex(ContextID, nc2, "#123");
  2720. if (i != 123) { rc = 0; Fail("Invalid index"); goto Error; }
  2721. for (i=0; i < 4096; i++) {
  2722. CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
  2723. CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (4096 - i);
  2724. sprintf(CheckName, "#%d", i);
  2725. if (!cmsNamedColorInfo(ContextID, nc2, i, Name, NULL, NULL, PCS, Colorant)) { rc = 0; goto Error; }
  2726. for (j=0; j < 3; j++) {
  2727. if (CheckPCS[j] != PCS[j]) { rc = 0; Fail("Invalid PCS"); goto Error; }
  2728. }
  2729. for (j=0; j < 4; j++) {
  2730. if (CheckColorant[j] != Colorant[j]) { rc = 0; Fail("Invalid Colorant"); goto Error; };
  2731. }
  2732. if (strcmp(Name, CheckName) != 0) {rc = 0; Fail("Invalid Name"); goto Error; };
  2733. }
  2734. cmsCloseProfile(ContextID, h);
  2735. remove("namedcol.icc");
  2736. Error:
  2737. if (nc != NULL) cmsFreeNamedColorList(ContextID, nc);
  2738. return rc;
  2739. }
  2740. // For educational purposes ONLY. No error checking is performed!
  2741. static
  2742. cmsInt32Number CreateNamedColorProfile(cmsContext ContextID)
  2743. {
  2744. // Color list database
  2745. cmsNAMEDCOLORLIST* colors = cmsAllocNamedColorList(ContextID, 10, 4, "PANTONE", "TCX");
  2746. // Containers for names
  2747. cmsMLU* DescriptionMLU, *CopyrightMLU;
  2748. // Create n empty profile
  2749. cmsHPROFILE hProfile = cmsOpenProfileFromFile(ContextID, "named.icc", "w");
  2750. // Values
  2751. cmsCIELab Lab;
  2752. cmsUInt16Number PCS[3], Colorant[cmsMAXCHANNELS];
  2753. // Set profile class
  2754. cmsSetProfileVersion(ContextID, hProfile, 4.3);
  2755. cmsSetDeviceClass(ContextID, hProfile, cmsSigNamedColorClass);
  2756. cmsSetColorSpace(ContextID, hProfile, cmsSigCmykData);
  2757. cmsSetPCS(ContextID, hProfile, cmsSigLabData);
  2758. cmsSetHeaderRenderingIntent(ContextID, hProfile, INTENT_PERCEPTUAL);
  2759. // Add description and copyright only in english/US
  2760. DescriptionMLU = cmsMLUalloc(ContextID, 1);
  2761. CopyrightMLU = cmsMLUalloc(ContextID, 1);
  2762. cmsMLUsetWide(ContextID, DescriptionMLU, "en", "US", L"Profile description");
  2763. cmsMLUsetWide(ContextID, CopyrightMLU, "en", "US", L"Profile copyright");
  2764. cmsWriteTag(ContextID, hProfile, cmsSigProfileDescriptionTag, DescriptionMLU);
  2765. cmsWriteTag(ContextID, hProfile, cmsSigCopyrightTag, CopyrightMLU);
  2766. // Set the media white point
  2767. cmsWriteTag(ContextID, hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ(ContextID));
  2768. // Populate one value, Colorant = CMYK values in 16 bits, PCS[] = Encoded Lab values (in V2 format!!)
  2769. Lab.L = 50; Lab.a = 10; Lab.b = -10;
  2770. cmsFloat2LabEncodedV2(ContextID, PCS, &Lab);
  2771. Colorant[0] = 10 * 257; Colorant[1] = 20 * 257; Colorant[2] = 30 * 257; Colorant[3] = 40 * 257;
  2772. cmsAppendNamedColor(ContextID, colors, "Hazelnut 14-1315", PCS, Colorant);
  2773. // Another one. Consider to write a routine for that
  2774. Lab.L = 40; Lab.a = -5; Lab.b = 8;
  2775. cmsFloat2LabEncodedV2(ContextID, PCS, &Lab);
  2776. Colorant[0] = 10 * 257; Colorant[1] = 20 * 257; Colorant[2] = 30 * 257; Colorant[3] = 40 * 257;
  2777. cmsAppendNamedColor(ContextID, colors, "Kale 18-0107", PCS, Colorant);
  2778. // Write the colors database
  2779. cmsWriteTag(ContextID, hProfile, cmsSigNamedColor2Tag, colors);
  2780. // That will create the file
  2781. cmsCloseProfile(ContextID, hProfile);
  2782. // Free resources
  2783. cmsFreeNamedColorList(ContextID, colors);
  2784. cmsMLUfree(ContextID, DescriptionMLU);
  2785. cmsMLUfree(ContextID, CopyrightMLU);
  2786. remove("named.icc");
  2787. return 1;
  2788. }
  2789. // ----------------------------------------------------------------------------------------------------------
  2790. // Formatters
  2791. static cmsBool FormatterFailed;
  2792. static
  2793. void CheckSingleFormatter16(cmsContext id, cmsUInt32Number Type, const char* Text)
  2794. {
  2795. cmsUInt16Number Values[cmsMAXCHANNELS];
  2796. cmsUInt8Number Buffer[1024];
  2797. cmsFormatter f, b;
  2798. cmsInt32Number i, j, nChannels, bytes;
  2799. _cmsTRANSFORM info;
  2800. // Already failed?
  2801. if (FormatterFailed) return;
  2802. memset(&info, 0, sizeof(info));
  2803. info.OutputFormat = info.InputFormat = Type;
  2804. // Go forth and back
  2805. f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
  2806. b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
  2807. if (f.Fmt16 == NULL || b.Fmt16 == NULL) {
  2808. Fail("no formatter for %s", Text);
  2809. FormatterFailed = TRUE;
  2810. // Useful for debug
  2811. f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
  2812. b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
  2813. return;
  2814. }
  2815. nChannels = T_CHANNELS(Type);
  2816. bytes = T_BYTES(Type);
  2817. for (j=0; j < 5; j++) {
  2818. for (i=0; i < nChannels; i++) {
  2819. Values[i] = (cmsUInt16Number) (i+j);
  2820. // For 8-bit
  2821. if (bytes == 1)
  2822. Values[i] <<= 8;
  2823. }
  2824. b.Fmt16(id, &info, Values, Buffer, 2);
  2825. memset(Values, 0, sizeof(Values));
  2826. f.Fmt16(id, &info, Values, Buffer, 2);
  2827. for (i=0; i < nChannels; i++) {
  2828. if (bytes == 1)
  2829. Values[i] >>= 8;
  2830. if (Values[i] != i+j) {
  2831. Fail("%s failed", Text);
  2832. FormatterFailed = TRUE;
  2833. // Useful for debug
  2834. for (i=0; i < nChannels; i++) {
  2835. Values[i] = (cmsUInt16Number) (i+j);
  2836. // For 8-bit
  2837. if (bytes == 1)
  2838. Values[i] <<= 8;
  2839. }
  2840. b.Fmt16(id, &info, Values, Buffer, 1);
  2841. f.Fmt16(id, &info, Values, Buffer, 1);
  2842. return;
  2843. }
  2844. }
  2845. }
  2846. }
  2847. #define C(a) CheckSingleFormatter16(0, a, #a)
  2848. // Check all formatters
  2849. static
  2850. cmsInt32Number CheckFormatters16(cmsContext ContextID)
  2851. {
  2852. FormatterFailed = FALSE;
  2853. C( TYPE_GRAY_8 );
  2854. C( TYPE_GRAY_8_REV );
  2855. C( TYPE_GRAY_16 );
  2856. C( TYPE_GRAY_16_REV );
  2857. C( TYPE_GRAY_16_SE );
  2858. C( TYPE_GRAYA_8 );
  2859. C( TYPE_GRAYA_16 );
  2860. C( TYPE_GRAYA_16_SE );
  2861. C( TYPE_GRAYA_8_PLANAR );
  2862. C( TYPE_GRAYA_16_PLANAR );
  2863. C( TYPE_RGB_8 );
  2864. C( TYPE_RGB_8_PLANAR );
  2865. C( TYPE_BGR_8 );
  2866. C( TYPE_BGR_8_PLANAR );
  2867. C( TYPE_RGB_16 );
  2868. C( TYPE_RGB_16_PLANAR );
  2869. C( TYPE_RGB_16_SE );
  2870. C( TYPE_BGR_16 );
  2871. C( TYPE_BGR_16_PLANAR );
  2872. C( TYPE_BGR_16_SE );
  2873. C( TYPE_RGBA_8 );
  2874. C( TYPE_RGBA_8_PLANAR );
  2875. C( TYPE_RGBA_16 );
  2876. C( TYPE_RGBA_16_PLANAR );
  2877. C( TYPE_RGBA_16_SE );
  2878. C( TYPE_ARGB_8 );
  2879. C( TYPE_ARGB_8_PLANAR );
  2880. C( TYPE_ARGB_16 );
  2881. C( TYPE_ABGR_8 );
  2882. C( TYPE_ABGR_8_PLANAR );
  2883. C( TYPE_ABGR_16 );
  2884. C( TYPE_ABGR_16_PLANAR );
  2885. C( TYPE_ABGR_16_SE );
  2886. C( TYPE_BGRA_8 );
  2887. C( TYPE_BGRA_8_PLANAR );
  2888. C( TYPE_BGRA_16 );
  2889. C( TYPE_BGRA_16_SE );
  2890. C( TYPE_CMY_8 );
  2891. C( TYPE_CMY_8_PLANAR );
  2892. C( TYPE_CMY_16 );
  2893. C( TYPE_CMY_16_PLANAR );
  2894. C( TYPE_CMY_16_SE );
  2895. C( TYPE_CMYK_8 );
  2896. C( TYPE_CMYKA_8 );
  2897. C( TYPE_CMYK_8_REV );
  2898. C( TYPE_YUVK_8 );
  2899. C( TYPE_CMYK_8_PLANAR );
  2900. C( TYPE_CMYK_16 );
  2901. C( TYPE_CMYK_16_REV );
  2902. C( TYPE_YUVK_16 );
  2903. C( TYPE_CMYK_16_PLANAR );
  2904. C( TYPE_CMYK_16_SE );
  2905. C( TYPE_KYMC_8 );
  2906. C( TYPE_KYMC_16 );
  2907. C( TYPE_KYMC_16_SE );
  2908. C( TYPE_KCMY_8 );
  2909. C( TYPE_KCMY_8_REV );
  2910. C( TYPE_KCMY_16 );
  2911. C( TYPE_KCMY_16_REV );
  2912. C( TYPE_KCMY_16_SE );
  2913. C( TYPE_CMYK5_8 );
  2914. C( TYPE_CMYK5_16 );
  2915. C( TYPE_CMYK5_16_SE );
  2916. C( TYPE_KYMC5_8 );
  2917. C( TYPE_KYMC5_16 );
  2918. C( TYPE_KYMC5_16_SE );
  2919. C( TYPE_CMYK6_8 );
  2920. C( TYPE_CMYK6_8_PLANAR );
  2921. C( TYPE_CMYK6_16 );
  2922. C( TYPE_CMYK6_16_PLANAR );
  2923. C( TYPE_CMYK6_16_SE );
  2924. C( TYPE_CMYK7_8 );
  2925. C( TYPE_CMYK7_16 );
  2926. C( TYPE_CMYK7_16_SE );
  2927. C( TYPE_KYMC7_8 );
  2928. C( TYPE_KYMC7_16 );
  2929. C( TYPE_KYMC7_16_SE );
  2930. C( TYPE_CMYK8_8 );
  2931. C( TYPE_CMYK8_16 );
  2932. C( TYPE_CMYK8_16_SE );
  2933. C( TYPE_KYMC8_8 );
  2934. C( TYPE_KYMC8_16 );
  2935. C( TYPE_KYMC8_16_SE );
  2936. C( TYPE_CMYK9_8 );
  2937. C( TYPE_CMYK9_16 );
  2938. C( TYPE_CMYK9_16_SE );
  2939. C( TYPE_KYMC9_8 );
  2940. C( TYPE_KYMC9_16 );
  2941. C( TYPE_KYMC9_16_SE );
  2942. C( TYPE_CMYK10_8 );
  2943. C( TYPE_CMYK10_16 );
  2944. C( TYPE_CMYK10_16_SE );
  2945. C( TYPE_KYMC10_8 );
  2946. C( TYPE_KYMC10_16 );
  2947. C( TYPE_KYMC10_16_SE );
  2948. C( TYPE_CMYK11_8 );
  2949. C( TYPE_CMYK11_16 );
  2950. C( TYPE_CMYK11_16_SE );
  2951. C( TYPE_KYMC11_8 );
  2952. C( TYPE_KYMC11_16 );
  2953. C( TYPE_KYMC11_16_SE );
  2954. C( TYPE_CMYK12_8 );
  2955. C( TYPE_CMYK12_16 );
  2956. C( TYPE_CMYK12_16_SE );
  2957. C( TYPE_KYMC12_8 );
  2958. C( TYPE_KYMC12_16 );
  2959. C( TYPE_KYMC12_16_SE );
  2960. C( TYPE_XYZ_16 );
  2961. C( TYPE_Lab_8 );
  2962. C( TYPE_ALab_8 );
  2963. C( TYPE_Lab_16 );
  2964. C( TYPE_Yxy_16 );
  2965. C( TYPE_YCbCr_8 );
  2966. C( TYPE_YCbCr_8_PLANAR );
  2967. C( TYPE_YCbCr_16 );
  2968. C( TYPE_YCbCr_16_PLANAR );
  2969. C( TYPE_YCbCr_16_SE );
  2970. C( TYPE_YUV_8 );
  2971. C( TYPE_YUV_8_PLANAR );
  2972. C( TYPE_YUV_16 );
  2973. C( TYPE_YUV_16_PLANAR );
  2974. C( TYPE_YUV_16_SE );
  2975. C( TYPE_HLS_8 );
  2976. C( TYPE_HLS_8_PLANAR );
  2977. C( TYPE_HLS_16 );
  2978. C( TYPE_HLS_16_PLANAR );
  2979. C( TYPE_HLS_16_SE );
  2980. C( TYPE_HSV_8 );
  2981. C( TYPE_HSV_8_PLANAR );
  2982. C( TYPE_HSV_16 );
  2983. C( TYPE_HSV_16_PLANAR );
  2984. C( TYPE_HSV_16_SE );
  2985. C( TYPE_XYZ_FLT );
  2986. C( TYPE_Lab_FLT );
  2987. C( TYPE_GRAY_FLT );
  2988. C( TYPE_RGB_FLT );
  2989. C( TYPE_BGR_FLT );
  2990. C( TYPE_CMYK_FLT );
  2991. C( TYPE_LabA_FLT );
  2992. C( TYPE_RGBA_FLT );
  2993. C( TYPE_ARGB_FLT );
  2994. C( TYPE_BGRA_FLT );
  2995. C( TYPE_ABGR_FLT );
  2996. C( TYPE_XYZ_DBL );
  2997. C( TYPE_Lab_DBL );
  2998. C( TYPE_GRAY_DBL );
  2999. C( TYPE_RGB_DBL );
  3000. C( TYPE_BGR_DBL );
  3001. C( TYPE_CMYK_DBL );
  3002. C( TYPE_LabV2_8 );
  3003. C( TYPE_ALabV2_8 );
  3004. C( TYPE_LabV2_16 );
  3005. #ifndef CMS_NO_HALF_SUPPORT
  3006. C( TYPE_GRAY_HALF_FLT );
  3007. C( TYPE_RGB_HALF_FLT );
  3008. C( TYPE_CMYK_HALF_FLT );
  3009. C( TYPE_RGBA_HALF_FLT );
  3010. C( TYPE_RGBA_HALF_FLT );
  3011. C( TYPE_ARGB_HALF_FLT );
  3012. C( TYPE_BGR_HALF_FLT );
  3013. C( TYPE_BGRA_HALF_FLT );
  3014. C( TYPE_ABGR_HALF_FLT );
  3015. #endif
  3016. return FormatterFailed == 0 ? 1 : 0;
  3017. }
  3018. #undef C
  3019. static
  3020. void CheckSingleFormatterFloat(cmsContext ContextID, cmsUInt32Number Type, const char* Text)
  3021. {
  3022. cmsFloat32Number Values[cmsMAXCHANNELS];
  3023. cmsUInt8Number Buffer[1024];
  3024. cmsFormatter f, b;
  3025. cmsInt32Number i, j, nChannels;
  3026. _cmsTRANSFORM info;
  3027. // Already failed?
  3028. if (FormatterFailed) return;
  3029. memset(&info, 0, sizeof(info));
  3030. info.OutputFormat = info.InputFormat = Type;
  3031. // Go forth and back
  3032. f = _cmsGetFormatter(ContextID, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT);
  3033. b = _cmsGetFormatter(ContextID, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT);
  3034. if (f.FmtFloat == NULL || b.FmtFloat == NULL) {
  3035. Fail("no formatter for %s", Text);
  3036. FormatterFailed = TRUE;
  3037. // Useful for debug
  3038. f = _cmsGetFormatter(ContextID, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT);
  3039. b = _cmsGetFormatter(ContextID, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT);
  3040. return;
  3041. }
  3042. nChannels = T_CHANNELS(Type);
  3043. for (j=0; j < 5; j++) {
  3044. for (i=0; i < nChannels; i++) {
  3045. Values[i] = (cmsFloat32Number) (i+j);
  3046. }
  3047. b.FmtFloat(ContextID, &info, Values, Buffer, 1);
  3048. memset(Values, 0, sizeof(Values));
  3049. f.FmtFloat(ContextID, &info, Values, Buffer, 1);
  3050. for (i=0; i < nChannels; i++) {
  3051. cmsFloat64Number delta = fabs(Values[i] - ( i+j));
  3052. if (delta > 0.000000001) {
  3053. Fail("%s failed", Text);
  3054. FormatterFailed = TRUE;
  3055. // Useful for debug
  3056. for (i=0; i < nChannels; i++) {
  3057. Values[i] = (cmsFloat32Number) (i+j);
  3058. }
  3059. b.FmtFloat(ContextID, &info, Values, Buffer, 1);
  3060. f.FmtFloat(ContextID, &info, Values, Buffer, 1);
  3061. return;
  3062. }
  3063. }
  3064. }
  3065. }
  3066. #define C(a) CheckSingleFormatterFloat(ContextID, a, #a)
  3067. static
  3068. cmsInt32Number CheckFormattersFloat(cmsContext ContextID)
  3069. {
  3070. FormatterFailed = FALSE;
  3071. C( TYPE_XYZ_FLT );
  3072. C( TYPE_Lab_FLT );
  3073. C( TYPE_GRAY_FLT );
  3074. C( TYPE_RGB_FLT );
  3075. C( TYPE_BGR_FLT );
  3076. C( TYPE_CMYK_FLT );
  3077. C( TYPE_LabA_FLT );
  3078. C( TYPE_RGBA_FLT );
  3079. C( TYPE_ARGB_FLT );
  3080. C( TYPE_BGRA_FLT );
  3081. C( TYPE_ABGR_FLT );
  3082. C( TYPE_XYZ_DBL );
  3083. C( TYPE_Lab_DBL );
  3084. C( TYPE_GRAY_DBL );
  3085. C( TYPE_RGB_DBL );
  3086. C( TYPE_BGR_DBL );
  3087. C( TYPE_CMYK_DBL );
  3088. C( TYPE_XYZ_FLT );
  3089. #ifndef CMS_NO_HALF_SUPPORT
  3090. C( TYPE_GRAY_HALF_FLT );
  3091. C( TYPE_RGB_HALF_FLT );
  3092. C( TYPE_CMYK_HALF_FLT );
  3093. C( TYPE_RGBA_HALF_FLT );
  3094. C( TYPE_RGBA_HALF_FLT );
  3095. C( TYPE_ARGB_HALF_FLT );
  3096. C( TYPE_BGR_HALF_FLT );
  3097. C( TYPE_BGRA_HALF_FLT );
  3098. C( TYPE_ABGR_HALF_FLT );
  3099. #endif
  3100. return FormatterFailed == 0 ? 1 : 0;
  3101. }
  3102. #undef C
  3103. #ifndef CMS_NO_HALF_SUPPORT
  3104. // Check half float
  3105. #define my_isfinite(x) ((x) != (x))
  3106. static
  3107. cmsInt32Number CheckFormattersHalf(cmsContext ContextID)
  3108. {
  3109. int i, j;
  3110. for (i=0; i < 0xffff; i++) {
  3111. cmsFloat32Number f = _cmsHalf2Float((cmsUInt16Number) i);
  3112. if (!my_isfinite(f)) {
  3113. j = _cmsFloat2Half(f);
  3114. if (i != j) {
  3115. Fail("%d != %d in Half float support!\n", i, j);
  3116. return 0;
  3117. }
  3118. }
  3119. }
  3120. return 1;
  3121. }
  3122. #endif
  3123. static
  3124. cmsInt32Number CheckOneRGB(cmsContext ContextID, cmsHTRANSFORM xform, cmsUInt16Number R, cmsUInt16Number G, cmsUInt16Number B, cmsUInt16Number Ro, cmsUInt16Number Go, cmsUInt16Number Bo)
  3125. {
  3126. cmsUInt16Number RGB[3];
  3127. cmsUInt16Number Out[3];
  3128. RGB[0] = R;
  3129. RGB[1] = G;
  3130. RGB[2] = B;
  3131. cmsDoTransform(ContextID, xform, RGB, Out, 1);
  3132. return IsGoodWord("R", Ro , Out[0]) &&
  3133. IsGoodWord("G", Go , Out[1]) &&
  3134. IsGoodWord("B", Bo , Out[2]);
  3135. }
  3136. // Check known values going from sRGB to XYZ
  3137. static
  3138. cmsInt32Number CheckOneRGB_double(cmsContext ContextID, cmsHTRANSFORM xform, cmsFloat64Number R, cmsFloat64Number G, cmsFloat64Number B, cmsFloat64Number Ro, cmsFloat64Number Go, cmsFloat64Number Bo)
  3139. {
  3140. cmsFloat64Number RGB[3];
  3141. cmsFloat64Number Out[3];
  3142. RGB[0] = R;
  3143. RGB[1] = G;
  3144. RGB[2] = B;
  3145. cmsDoTransform(ContextID, xform, RGB, Out, 1);
  3146. return IsGoodVal("R", Ro , Out[0], 0.01) &&
  3147. IsGoodVal("G", Go , Out[1], 0.01) &&
  3148. IsGoodVal("B", Bo , Out[2], 0.01);
  3149. }
  3150. static
  3151. cmsInt32Number CheckChangeBufferFormat(cmsContext ContextID)
  3152. {
  3153. cmsHPROFILE hsRGB = cmsCreate_sRGBProfile(ContextID);
  3154. cmsHTRANSFORM xform;
  3155. cmsHTRANSFORM xform2;
  3156. xform = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_16, hsRGB, TYPE_RGB_16, INTENT_PERCEPTUAL, 0);
  3157. cmsCloseProfile(ContextID, hsRGB);
  3158. if (xform == NULL) return 0;
  3159. if (!CheckOneRGB(ContextID, xform, 0, 0, 0, 0, 0, 0)) return 0;
  3160. if (!CheckOneRGB(ContextID, xform, 120, 0, 0, 120, 0, 0)) return 0;
  3161. if (!CheckOneRGB(ContextID, xform, 0, 222, 255, 0, 222, 255)) return 0;
  3162. xform2 = cmsCloneTransformChangingFormats(ContextID, xform, TYPE_BGR_16, TYPE_RGB_16);
  3163. if (!xform2) return 0;
  3164. if (!CheckOneRGB(ContextID, xform2, 0, 0, 123, 123, 0, 0)) return 0;
  3165. if (!CheckOneRGB(ContextID, xform2, 154, 234, 0, 0, 234, 154)) return 0;
  3166. cmsDeleteTransform(ContextID,xform2);
  3167. xform2 = cmsCloneTransformChangingFormats(ContextID, xform, TYPE_RGB_DBL, TYPE_RGB_DBL);
  3168. if (!xform2) return 0;
  3169. if (!CheckOneRGB_double(ContextID, xform2, 0.20, 0, 0, 0.20, 0, 0)) return 0;
  3170. if (!CheckOneRGB_double(ContextID, xform2, 0, 0.9, 1, 0, 0.9, 1)) return 0;
  3171. cmsDeleteTransform(ContextID,xform2);
  3172. cmsDeleteTransform(ContextID,xform);
  3173. return 1;
  3174. }
  3175. // Write tag testbed ----------------------------------------------------------------------------------------
  3176. static
  3177. cmsInt32Number CheckXYZ(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3178. {
  3179. cmsCIEXYZ XYZ, *Pt;
  3180. switch (Pass) {
  3181. case 1:
  3182. XYZ.X = 1.0; XYZ.Y = 1.1; XYZ.Z = 1.2;
  3183. return cmsWriteTag(ContextID, hProfile, tag, &XYZ);
  3184. case 2:
  3185. Pt = (cmsCIEXYZ *) cmsReadTag(ContextID, hProfile, tag);
  3186. if (Pt == NULL) return 0;
  3187. return IsGoodFixed15_16("X", 1.0, Pt ->X) &&
  3188. IsGoodFixed15_16("Y", 1.1, Pt->Y) &&
  3189. IsGoodFixed15_16("Z", 1.2, Pt -> Z);
  3190. default:
  3191. return 0;
  3192. }
  3193. }
  3194. static
  3195. cmsInt32Number CheckGamma(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3196. {
  3197. cmsToneCurve *g, *Pt;
  3198. cmsInt32Number rc;
  3199. switch (Pass) {
  3200. case 1:
  3201. g = cmsBuildGamma(ContextID, 1.0);
  3202. rc = cmsWriteTag(ContextID, hProfile, tag, g);
  3203. cmsFreeToneCurve(ContextID, g);
  3204. return rc;
  3205. case 2:
  3206. Pt = (cmsToneCurve *) cmsReadTag(ContextID, hProfile, tag);
  3207. if (Pt == NULL) return 0;
  3208. return cmsIsToneCurveLinear(ContextID, Pt);
  3209. default:
  3210. return 0;
  3211. }
  3212. }
  3213. static
  3214. cmsInt32Number CheckTextSingle(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3215. {
  3216. cmsMLU *m, *Pt;
  3217. cmsInt32Number rc;
  3218. char Buffer[256];
  3219. switch (Pass) {
  3220. case 1:
  3221. m = cmsMLUalloc(ContextID, 0);
  3222. cmsMLUsetASCII(ContextID, m, cmsNoLanguage, cmsNoCountry, "Test test");
  3223. rc = cmsWriteTag(ContextID, hProfile, tag, m);
  3224. cmsMLUfree(ContextID, m);
  3225. return rc;
  3226. case 2:
  3227. Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, tag);
  3228. if (Pt == NULL) return 0;
  3229. cmsMLUgetASCII(ContextID, Pt, cmsNoLanguage, cmsNoCountry, Buffer, 256);
  3230. if (strcmp(Buffer, "Test test") != 0) return FALSE;
  3231. return TRUE;
  3232. default:
  3233. return 0;
  3234. }
  3235. }
  3236. static
  3237. cmsInt32Number CheckText(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3238. {
  3239. cmsMLU *m, *Pt;
  3240. cmsInt32Number rc;
  3241. char Buffer[256];
  3242. switch (Pass) {
  3243. case 1:
  3244. m = cmsMLUalloc(ContextID, 0);
  3245. cmsMLUsetASCII(ContextID, m, cmsNoLanguage, cmsNoCountry, "Test test");
  3246. cmsMLUsetASCII(ContextID, m, "en", "US", "1 1 1 1");
  3247. cmsMLUsetASCII(ContextID, m, "es", "ES", "2 2 2 2");
  3248. cmsMLUsetASCII(ContextID, m, "ct", "ES", "3 3 3 3");
  3249. cmsMLUsetASCII(ContextID, m, "en", "GB", "444444444");
  3250. rc = cmsWriteTag(ContextID, hProfile, tag, m);
  3251. cmsMLUfree(ContextID, m);
  3252. return rc;
  3253. case 2:
  3254. Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, tag);
  3255. if (Pt == NULL) return 0;
  3256. cmsMLUgetASCII(ContextID, Pt, cmsNoLanguage, cmsNoCountry, Buffer, 256);
  3257. if (strcmp(Buffer, "Test test") != 0) return FALSE;
  3258. cmsMLUgetASCII(ContextID, Pt, "en", "US", Buffer, 256);
  3259. if (strcmp(Buffer, "1 1 1 1") != 0) return FALSE;
  3260. cmsMLUgetASCII(ContextID, Pt, "es", "ES", Buffer, 256);
  3261. if (strcmp(Buffer, "2 2 2 2") != 0) return FALSE;
  3262. cmsMLUgetASCII(ContextID, Pt, "ct", "ES", Buffer, 256);
  3263. if (strcmp(Buffer, "3 3 3 3") != 0) return FALSE;
  3264. cmsMLUgetASCII(ContextID, Pt, "en", "GB", Buffer, 256);
  3265. if (strcmp(Buffer, "444444444") != 0) return FALSE;
  3266. return TRUE;
  3267. default:
  3268. return 0;
  3269. }
  3270. }
  3271. static
  3272. cmsInt32Number CheckData(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3273. {
  3274. cmsICCData *Pt;
  3275. cmsICCData d = { 1, 0, { '?' }};
  3276. cmsInt32Number rc;
  3277. switch (Pass) {
  3278. case 1:
  3279. rc = cmsWriteTag(ContextID, hProfile, tag, &d);
  3280. return rc;
  3281. case 2:
  3282. Pt = (cmsICCData *) cmsReadTag(ContextID, hProfile, tag);
  3283. if (Pt == NULL) return 0;
  3284. return (Pt ->data[0] == '?') && (Pt ->flag == 0) && (Pt ->len == 1);
  3285. default:
  3286. return 0;
  3287. }
  3288. }
  3289. static
  3290. cmsInt32Number CheckSignature(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3291. {
  3292. cmsTagSignature *Pt, Holder;
  3293. switch (Pass) {
  3294. case 1:
  3295. Holder = (cmsTagSignature) cmsSigPerceptualReferenceMediumGamut;
  3296. return cmsWriteTag(ContextID, hProfile, tag, &Holder);
  3297. case 2:
  3298. Pt = (cmsTagSignature *) cmsReadTag(ContextID, hProfile, tag);
  3299. if (Pt == NULL) return 0;
  3300. return *Pt == cmsSigPerceptualReferenceMediumGamut;
  3301. default:
  3302. return 0;
  3303. }
  3304. }
  3305. static
  3306. cmsInt32Number CheckDateTime(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3307. {
  3308. struct tm *Pt, Holder;
  3309. switch (Pass) {
  3310. case 1:
  3311. Holder.tm_hour = 1;
  3312. Holder.tm_min = 2;
  3313. Holder.tm_sec = 3;
  3314. Holder.tm_mday = 4;
  3315. Holder.tm_mon = 5;
  3316. Holder.tm_year = 2009 - 1900;
  3317. return cmsWriteTag(ContextID, hProfile, tag, &Holder);
  3318. case 2:
  3319. Pt = (struct tm *) cmsReadTag(ContextID, hProfile, tag);
  3320. if (Pt == NULL) return 0;
  3321. return (Pt ->tm_hour == 1 &&
  3322. Pt ->tm_min == 2 &&
  3323. Pt ->tm_sec == 3 &&
  3324. Pt ->tm_mday == 4 &&
  3325. Pt ->tm_mon == 5 &&
  3326. Pt ->tm_year == 2009 - 1900);
  3327. default:
  3328. return 0;
  3329. }
  3330. }
  3331. static
  3332. cmsInt32Number CheckNamedColor(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag, cmsInt32Number max_check, cmsBool colorant_check)
  3333. {
  3334. cmsNAMEDCOLORLIST* nc;
  3335. cmsInt32Number i, j, rc;
  3336. char Name[255];
  3337. cmsUInt16Number PCS[3];
  3338. cmsUInt16Number Colorant[cmsMAXCHANNELS];
  3339. char CheckName[255];
  3340. cmsUInt16Number CheckPCS[3];
  3341. cmsUInt16Number CheckColorant[cmsMAXCHANNELS];
  3342. switch (Pass) {
  3343. case 1:
  3344. nc = cmsAllocNamedColorList(ContextID, 0, 4, "prefix", "suffix");
  3345. if (nc == NULL) return 0;
  3346. for (i=0; i < max_check; i++) {
  3347. PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
  3348. Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) (max_check - i);
  3349. sprintf(Name, "#%d", i);
  3350. if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { Fail("Couldn't append named color"); return 0; }
  3351. }
  3352. rc = cmsWriteTag(ContextID, hProfile, tag, nc);
  3353. cmsFreeNamedColorList(ContextID, nc);
  3354. return rc;
  3355. case 2:
  3356. nc = (cmsNAMEDCOLORLIST *) cmsReadTag(ContextID, hProfile, tag);
  3357. if (nc == NULL) return 0;
  3358. for (i=0; i < max_check; i++) {
  3359. CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
  3360. CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (max_check - i);
  3361. sprintf(CheckName, "#%d", i);
  3362. if (!cmsNamedColorInfo(ContextID, nc, i, Name, NULL, NULL, PCS, Colorant)) { Fail("Invalid string"); return 0; }
  3363. for (j=0; j < 3; j++) {
  3364. if (CheckPCS[j] != PCS[j]) { Fail("Invalid PCS"); return 0; }
  3365. }
  3366. // This is only used on named color list
  3367. if (colorant_check) {
  3368. for (j=0; j < 4; j++) {
  3369. if (CheckColorant[j] != Colorant[j]) { Fail("Invalid Colorant"); return 0; };
  3370. }
  3371. }
  3372. if (strcmp(Name, CheckName) != 0) { Fail("Invalid Name"); return 0; };
  3373. }
  3374. return 1;
  3375. default: return 0;
  3376. }
  3377. }
  3378. static
  3379. cmsInt32Number CheckLUT(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3380. {
  3381. cmsPipeline* Lut, *Pt;
  3382. cmsInt32Number rc;
  3383. switch (Pass) {
  3384. case 1:
  3385. Lut = cmsPipelineAlloc(ContextID, 3, 3);
  3386. if (Lut == NULL) return 0;
  3387. // Create an identity LUT
  3388. cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
  3389. cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocIdentityCLut(ContextID, 3));
  3390. cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 3));
  3391. rc = cmsWriteTag(ContextID, hProfile, tag, Lut);
  3392. cmsPipelineFree(ContextID, Lut);
  3393. return rc;
  3394. case 2:
  3395. Pt = (cmsPipeline *) cmsReadTag(ContextID, hProfile, tag);
  3396. if (Pt == NULL) return 0;
  3397. // Transform values, check for identity
  3398. return Check16LUT(ContextID, Pt);
  3399. default:
  3400. return 0;
  3401. }
  3402. }
  3403. static
  3404. cmsInt32Number CheckCHAD(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3405. {
  3406. cmsFloat64Number *Pt;
  3407. cmsFloat64Number CHAD[] = { 0, .1, .2, .3, .4, .5, .6, .7, .8 };
  3408. cmsInt32Number i;
  3409. switch (Pass) {
  3410. case 1:
  3411. return cmsWriteTag(ContextID, hProfile, tag, CHAD);
  3412. case 2:
  3413. Pt = (cmsFloat64Number *) cmsReadTag(ContextID, hProfile, tag);
  3414. if (Pt == NULL) return 0;
  3415. for (i=0; i < 9; i++) {
  3416. if (!IsGoodFixed15_16("CHAD", Pt[i], CHAD[i])) return 0;
  3417. }
  3418. return 1;
  3419. default:
  3420. return 0;
  3421. }
  3422. }
  3423. static
  3424. cmsInt32Number CheckChromaticity(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3425. {
  3426. cmsCIExyYTRIPLE *Pt, c = { {0, .1, 1 }, { .3, .4, 1 }, { .6, .7, 1 }};
  3427. switch (Pass) {
  3428. case 1:
  3429. return cmsWriteTag(ContextID, hProfile, tag, &c);
  3430. case 2:
  3431. Pt = (cmsCIExyYTRIPLE *) cmsReadTag(ContextID, hProfile, tag);
  3432. if (Pt == NULL) return 0;
  3433. if (!IsGoodFixed15_16("xyY", Pt ->Red.x, c.Red.x)) return 0;
  3434. if (!IsGoodFixed15_16("xyY", Pt ->Red.y, c.Red.y)) return 0;
  3435. if (!IsGoodFixed15_16("xyY", Pt ->Green.x, c.Green.x)) return 0;
  3436. if (!IsGoodFixed15_16("xyY", Pt ->Green.y, c.Green.y)) return 0;
  3437. if (!IsGoodFixed15_16("xyY", Pt ->Blue.x, c.Blue.x)) return 0;
  3438. if (!IsGoodFixed15_16("xyY", Pt ->Blue.y, c.Blue.y)) return 0;
  3439. return 1;
  3440. default:
  3441. return 0;
  3442. }
  3443. }
  3444. static
  3445. cmsInt32Number CheckColorantOrder(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3446. {
  3447. cmsUInt8Number *Pt, c[cmsMAXCHANNELS];
  3448. cmsInt32Number i;
  3449. switch (Pass) {
  3450. case 1:
  3451. for (i=0; i < cmsMAXCHANNELS; i++) c[i] = (cmsUInt8Number) (cmsMAXCHANNELS - i - 1);
  3452. return cmsWriteTag(ContextID, hProfile, tag, c);
  3453. case 2:
  3454. Pt = (cmsUInt8Number *) cmsReadTag(ContextID, hProfile, tag);
  3455. if (Pt == NULL) return 0;
  3456. for (i=0; i < cmsMAXCHANNELS; i++) {
  3457. if (Pt[i] != ( cmsMAXCHANNELS - i - 1 )) return 0;
  3458. }
  3459. return 1;
  3460. default:
  3461. return 0;
  3462. }
  3463. }
  3464. static
  3465. cmsInt32Number CheckMeasurement(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3466. {
  3467. cmsICCMeasurementConditions *Pt, m;
  3468. switch (Pass) {
  3469. case 1:
  3470. m.Backing.X = 0.1;
  3471. m.Backing.Y = 0.2;
  3472. m.Backing.Z = 0.3;
  3473. m.Flare = 1.0;
  3474. m.Geometry = 1;
  3475. m.IlluminantType = cmsILLUMINANT_TYPE_D50;
  3476. m.Observer = 1;
  3477. return cmsWriteTag(ContextID, hProfile, tag, &m);
  3478. case 2:
  3479. Pt = (cmsICCMeasurementConditions *) cmsReadTag(ContextID, hProfile, tag);
  3480. if (Pt == NULL) return 0;
  3481. if (!IsGoodFixed15_16("Backing", Pt ->Backing.X, 0.1)) return 0;
  3482. if (!IsGoodFixed15_16("Backing", Pt ->Backing.Y, 0.2)) return 0;
  3483. if (!IsGoodFixed15_16("Backing", Pt ->Backing.Z, 0.3)) return 0;
  3484. if (!IsGoodFixed15_16("Flare", Pt ->Flare, 1.0)) return 0;
  3485. if (Pt ->Geometry != 1) return 0;
  3486. if (Pt ->IlluminantType != cmsILLUMINANT_TYPE_D50) return 0;
  3487. if (Pt ->Observer != 1) return 0;
  3488. return 1;
  3489. default:
  3490. return 0;
  3491. }
  3492. }
  3493. static
  3494. cmsInt32Number CheckUcrBg(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3495. {
  3496. cmsUcrBg *Pt, m;
  3497. cmsInt32Number rc;
  3498. char Buffer[256];
  3499. switch (Pass) {
  3500. case 1:
  3501. m.Ucr = cmsBuildGamma(ContextID, 2.4);
  3502. m.Bg = cmsBuildGamma(ContextID, -2.2);
  3503. m.Desc = cmsMLUalloc(ContextID, 1);
  3504. cmsMLUsetASCII(ContextID, m.Desc, cmsNoLanguage, cmsNoCountry, "test UCR/BG");
  3505. rc = cmsWriteTag(ContextID, hProfile, tag, &m);
  3506. cmsMLUfree(ContextID, m.Desc);
  3507. cmsFreeToneCurve(ContextID, m.Bg);
  3508. cmsFreeToneCurve(ContextID, m.Ucr);
  3509. return rc;
  3510. case 2:
  3511. Pt = (cmsUcrBg *) cmsReadTag(ContextID, hProfile, tag);
  3512. if (Pt == NULL) return 0;
  3513. cmsMLUgetASCII(ContextID, Pt ->Desc, cmsNoLanguage, cmsNoCountry, Buffer, 256);
  3514. if (strcmp(Buffer, "test UCR/BG") != 0) return 0;
  3515. return 1;
  3516. default:
  3517. return 0;
  3518. }
  3519. }
  3520. static
  3521. cmsInt32Number CheckCRDinfo(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3522. {
  3523. cmsMLU *mlu;
  3524. char Buffer[256];
  3525. cmsInt32Number rc;
  3526. switch (Pass) {
  3527. case 1:
  3528. mlu = cmsMLUalloc(ContextID, 5);
  3529. cmsMLUsetWide(ContextID, mlu, "PS", "nm", L"test postscript");
  3530. cmsMLUsetWide(ContextID, mlu, "PS", "#0", L"perceptual");
  3531. cmsMLUsetWide(ContextID, mlu, "PS", "#1", L"relative_colorimetric");
  3532. cmsMLUsetWide(ContextID, mlu, "PS", "#2", L"saturation");
  3533. cmsMLUsetWide(ContextID, mlu, "PS", "#3", L"absolute_colorimetric");
  3534. rc = cmsWriteTag(ContextID, hProfile, tag, mlu);
  3535. cmsMLUfree(ContextID, mlu);
  3536. return rc;
  3537. case 2:
  3538. mlu = (cmsMLU*) cmsReadTag(ContextID, hProfile, tag);
  3539. if (mlu == NULL) return 0;
  3540. cmsMLUgetASCII(ContextID, mlu, "PS", "nm", Buffer, 256);
  3541. if (strcmp(Buffer, "test postscript") != 0) return 0;
  3542. cmsMLUgetASCII(ContextID, mlu, "PS", "#0", Buffer, 256);
  3543. if (strcmp(Buffer, "perceptual") != 0) return 0;
  3544. cmsMLUgetASCII(ContextID, mlu, "PS", "#1", Buffer, 256);
  3545. if (strcmp(Buffer, "relative_colorimetric") != 0) return 0;
  3546. cmsMLUgetASCII(ContextID, mlu, "PS", "#2", Buffer, 256);
  3547. if (strcmp(Buffer, "saturation") != 0) return 0;
  3548. cmsMLUgetASCII(ContextID, mlu, "PS", "#3", Buffer, 256);
  3549. if (strcmp(Buffer, "absolute_colorimetric") != 0) return 0;
  3550. return 1;
  3551. default:
  3552. return 0;
  3553. }
  3554. }
  3555. static
  3556. cmsToneCurve *CreateSegmentedCurve(cmsContext ContextID)
  3557. {
  3558. cmsCurveSegment Seg[3];
  3559. cmsFloat32Number Sampled[2] = { 0, 1};
  3560. Seg[0].Type = 6;
  3561. Seg[0].Params[0] = 1;
  3562. Seg[0].Params[1] = 0;
  3563. Seg[0].Params[2] = 0;
  3564. Seg[0].Params[3] = 0;
  3565. Seg[0].x0 = -1E22F;
  3566. Seg[0].x1 = 0;
  3567. Seg[1].Type = 0;
  3568. Seg[1].nGridPoints = 2;
  3569. Seg[1].SampledPoints = Sampled;
  3570. Seg[1].x0 = 0;
  3571. Seg[1].x1 = 1;
  3572. Seg[2].Type = 6;
  3573. Seg[2].Params[0] = 1;
  3574. Seg[2].Params[1] = 0;
  3575. Seg[2].Params[2] = 0;
  3576. Seg[2].Params[3] = 0;
  3577. Seg[2].x0 = 1;
  3578. Seg[2].x1 = 1E22F;
  3579. return cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
  3580. }
  3581. static
  3582. cmsInt32Number CheckMPE(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3583. {
  3584. cmsPipeline* Lut, *Pt;
  3585. cmsToneCurve* G[3];
  3586. cmsInt32Number rc;
  3587. switch (Pass) {
  3588. case 1:
  3589. Lut = cmsPipelineAlloc(ContextID, 3, 3);
  3590. cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4(ContextID));
  3591. cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID));
  3592. AddIdentityCLUTfloat(ContextID, Lut);
  3593. G[0] = G[1] = G[2] = CreateSegmentedCurve(ContextID);
  3594. cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, G));
  3595. cmsFreeToneCurve(ContextID, G[0]);
  3596. rc = cmsWriteTag(ContextID, hProfile, tag, Lut);
  3597. cmsPipelineFree(ContextID, Lut);
  3598. return rc;
  3599. case 2:
  3600. Pt = (cmsPipeline *) cmsReadTag(ContextID, hProfile, tag);
  3601. if (Pt == NULL) return 0;
  3602. return CheckFloatLUT(ContextID, Pt);
  3603. default:
  3604. return 0;
  3605. }
  3606. }
  3607. static
  3608. cmsInt32Number CheckScreening(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
  3609. {
  3610. cmsScreening *Pt, sc;
  3611. cmsInt32Number rc;
  3612. switch (Pass) {
  3613. case 1:
  3614. sc.Flag = 0;
  3615. sc.nChannels = 1;
  3616. sc.Channels[0].Frequency = 2.0;
  3617. sc.Channels[0].ScreenAngle = 3.0;
  3618. sc.Channels[0].SpotShape = cmsSPOT_ELLIPSE;
  3619. rc = cmsWriteTag(ContextID, hProfile, tag, &sc);
  3620. return rc;
  3621. case 2:
  3622. Pt = (cmsScreening *) cmsReadTag(ContextID, hProfile, tag);
  3623. if (Pt == NULL) return 0;
  3624. if (Pt ->nChannels != 1) return 0;
  3625. if (Pt ->Flag != 0) return 0;
  3626. if (!IsGoodFixed15_16("Freq", Pt ->Channels[0].Frequency, 2.0)) return 0;
  3627. if (!IsGoodFixed15_16("Angle", Pt ->Channels[0].ScreenAngle, 3.0)) return 0;
  3628. if (Pt ->Channels[0].SpotShape != cmsSPOT_ELLIPSE) return 0;
  3629. return 1;
  3630. default:
  3631. return 0;
  3632. }
  3633. }
  3634. static
  3635. cmsBool CheckOneStr(cmsContext ContextID, cmsMLU* mlu, cmsInt32Number n)
  3636. {
  3637. char Buffer[256], Buffer2[256];
  3638. cmsMLUgetASCII(ContextID, mlu, "en", "US", Buffer, 255);
  3639. sprintf(Buffer2, "Hello, world %d", n);
  3640. if (strcmp(Buffer, Buffer2) != 0) return FALSE;
  3641. cmsMLUgetASCII(ContextID, mlu, "es", "ES", Buffer, 255);
  3642. sprintf(Buffer2, "Hola, mundo %d", n);
  3643. if (strcmp(Buffer, Buffer2) != 0) return FALSE;
  3644. return TRUE;
  3645. }
  3646. static
  3647. void SetOneStr(cmsContext ContextID, cmsMLU** mlu, const wchar_t* s1, const wchar_t* s2)
  3648. {
  3649. *mlu = cmsMLUalloc(ContextID, 0);
  3650. cmsMLUsetWide(ContextID, *mlu, "en", "US", s1);
  3651. cmsMLUsetWide(ContextID, *mlu, "es", "ES", s2);
  3652. }
  3653. static
  3654. cmsInt32Number CheckProfileSequenceTag(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3655. {
  3656. cmsSEQ* s;
  3657. cmsInt32Number i;
  3658. switch (Pass) {
  3659. case 1:
  3660. s = cmsAllocProfileSequenceDescription(ContextID, 3);
  3661. if (s == NULL) return 0;
  3662. SetOneStr(ContextID, &s -> seq[0].Manufacturer, L"Hello, world 0", L"Hola, mundo 0");
  3663. SetOneStr(ContextID, &s -> seq[0].Model, L"Hello, world 0", L"Hola, mundo 0");
  3664. SetOneStr(ContextID, &s -> seq[1].Manufacturer, L"Hello, world 1", L"Hola, mundo 1");
  3665. SetOneStr(ContextID, &s -> seq[1].Model, L"Hello, world 1", L"Hola, mundo 1");
  3666. SetOneStr(ContextID, &s -> seq[2].Manufacturer, L"Hello, world 2", L"Hola, mundo 2");
  3667. SetOneStr(ContextID, &s -> seq[2].Model, L"Hello, world 2", L"Hola, mundo 2");
  3668. #ifdef CMS_DONT_USE_INT64
  3669. s ->seq[0].attributes[0] = cmsTransparency|cmsMatte;
  3670. s ->seq[0].attributes[1] = 0;
  3671. #else
  3672. s ->seq[0].attributes = cmsTransparency|cmsMatte;
  3673. #endif
  3674. #ifdef CMS_DONT_USE_INT64
  3675. s ->seq[1].attributes[0] = cmsReflective|cmsMatte;
  3676. s ->seq[1].attributes[1] = 0;
  3677. #else
  3678. s ->seq[1].attributes = cmsReflective|cmsMatte;
  3679. #endif
  3680. #ifdef CMS_DONT_USE_INT64
  3681. s ->seq[2].attributes[0] = cmsTransparency|cmsGlossy;
  3682. s ->seq[2].attributes[1] = 0;
  3683. #else
  3684. s ->seq[2].attributes = cmsTransparency|cmsGlossy;
  3685. #endif
  3686. if (!cmsWriteTag(ContextID, hProfile, cmsSigProfileSequenceDescTag, s)) return 0;
  3687. cmsFreeProfileSequenceDescription(ContextID, s);
  3688. return 1;
  3689. case 2:
  3690. s = (cmsSEQ *) cmsReadTag(ContextID, hProfile, cmsSigProfileSequenceDescTag);
  3691. if (s == NULL) return 0;
  3692. if (s ->n != 3) return 0;
  3693. #ifdef CMS_DONT_USE_INT64
  3694. if (s ->seq[0].attributes[0] != (cmsTransparency|cmsMatte)) return 0;
  3695. if (s ->seq[0].attributes[1] != 0) return 0;
  3696. #else
  3697. if (s ->seq[0].attributes != (cmsTransparency|cmsMatte)) return 0;
  3698. #endif
  3699. #ifdef CMS_DONT_USE_INT64
  3700. if (s ->seq[1].attributes[0] != (cmsReflective|cmsMatte)) return 0;
  3701. if (s ->seq[1].attributes[1] != 0) return 0;
  3702. #else
  3703. if (s ->seq[1].attributes != (cmsReflective|cmsMatte)) return 0;
  3704. #endif
  3705. #ifdef CMS_DONT_USE_INT64
  3706. if (s ->seq[2].attributes[0] != (cmsTransparency|cmsGlossy)) return 0;
  3707. if (s ->seq[2].attributes[1] != 0) return 0;
  3708. #else
  3709. if (s ->seq[2].attributes != (cmsTransparency|cmsGlossy)) return 0;
  3710. #endif
  3711. // Check MLU
  3712. for (i=0; i < 3; i++) {
  3713. if (!CheckOneStr(ContextID, s -> seq[i].Manufacturer, i)) return 0;
  3714. if (!CheckOneStr(ContextID, s -> seq[i].Model, i)) return 0;
  3715. }
  3716. return 1;
  3717. default:
  3718. return 0;
  3719. }
  3720. }
  3721. static
  3722. cmsInt32Number CheckProfileSequenceIDTag(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3723. {
  3724. cmsSEQ* s;
  3725. cmsInt32Number i;
  3726. switch (Pass) {
  3727. case 1:
  3728. s = cmsAllocProfileSequenceDescription(ContextID, 3);
  3729. if (s == NULL) return 0;
  3730. memcpy(s ->seq[0].ProfileID.ID8, "0123456789ABCDEF", 16);
  3731. memcpy(s ->seq[1].ProfileID.ID8, "1111111111111111", 16);
  3732. memcpy(s ->seq[2].ProfileID.ID8, "2222222222222222", 16);
  3733. SetOneStr(ContextID, &s -> seq[0].Description, L"Hello, world 0", L"Hola, mundo 0");
  3734. SetOneStr(ContextID, &s -> seq[1].Description, L"Hello, world 1", L"Hola, mundo 1");
  3735. SetOneStr(ContextID, &s -> seq[2].Description, L"Hello, world 2", L"Hola, mundo 2");
  3736. if (!cmsWriteTag(ContextID, hProfile, cmsSigProfileSequenceIdTag, s)) return 0;
  3737. cmsFreeProfileSequenceDescription(ContextID, s);
  3738. return 1;
  3739. case 2:
  3740. s = (cmsSEQ *) cmsReadTag(ContextID, hProfile, cmsSigProfileSequenceIdTag);
  3741. if (s == NULL) return 0;
  3742. if (s ->n != 3) return 0;
  3743. if (memcmp(s ->seq[0].ProfileID.ID8, "0123456789ABCDEF", 16) != 0) return 0;
  3744. if (memcmp(s ->seq[1].ProfileID.ID8, "1111111111111111", 16) != 0) return 0;
  3745. if (memcmp(s ->seq[2].ProfileID.ID8, "2222222222222222", 16) != 0) return 0;
  3746. for (i=0; i < 3; i++) {
  3747. if (!CheckOneStr(ContextID, s -> seq[i].Description, i)) return 0;
  3748. }
  3749. return 1;
  3750. default:
  3751. return 0;
  3752. }
  3753. }
  3754. static
  3755. cmsInt32Number CheckICCViewingConditions(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3756. {
  3757. cmsICCViewingConditions* v;
  3758. cmsICCViewingConditions s;
  3759. switch (Pass) {
  3760. case 1:
  3761. s.IlluminantType = 1;
  3762. s.IlluminantXYZ.X = 0.1;
  3763. s.IlluminantXYZ.Y = 0.2;
  3764. s.IlluminantXYZ.Z = 0.3;
  3765. s.SurroundXYZ.X = 0.4;
  3766. s.SurroundXYZ.Y = 0.5;
  3767. s.SurroundXYZ.Z = 0.6;
  3768. if (!cmsWriteTag(ContextID, hProfile, cmsSigViewingConditionsTag, &s)) return 0;
  3769. return 1;
  3770. case 2:
  3771. v = (cmsICCViewingConditions *) cmsReadTag(ContextID, hProfile, cmsSigViewingConditionsTag);
  3772. if (v == NULL) return 0;
  3773. if (v ->IlluminantType != 1) return 0;
  3774. if (!IsGoodVal("IlluminantXYZ.X", v ->IlluminantXYZ.X, 0.1, 0.001)) return 0;
  3775. if (!IsGoodVal("IlluminantXYZ.Y", v ->IlluminantXYZ.Y, 0.2, 0.001)) return 0;
  3776. if (!IsGoodVal("IlluminantXYZ.Z", v ->IlluminantXYZ.Z, 0.3, 0.001)) return 0;
  3777. if (!IsGoodVal("SurroundXYZ.X", v ->SurroundXYZ.X, 0.4, 0.001)) return 0;
  3778. if (!IsGoodVal("SurroundXYZ.Y", v ->SurroundXYZ.Y, 0.5, 0.001)) return 0;
  3779. if (!IsGoodVal("SurroundXYZ.Z", v ->SurroundXYZ.Z, 0.6, 0.001)) return 0;
  3780. return 1;
  3781. default:
  3782. return 0;
  3783. }
  3784. }
  3785. static
  3786. cmsInt32Number CheckVCGT(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3787. {
  3788. cmsToneCurve* Curves[3];
  3789. cmsToneCurve** PtrCurve;
  3790. switch (Pass) {
  3791. case 1:
  3792. Curves[0] = cmsBuildGamma(ContextID, 1.1);
  3793. Curves[1] = cmsBuildGamma(ContextID, 2.2);
  3794. Curves[2] = cmsBuildGamma(ContextID, 3.4);
  3795. if (!cmsWriteTag(ContextID, hProfile, cmsSigVcgtTag, Curves)) return 0;
  3796. cmsFreeToneCurveTriple(ContextID, Curves);
  3797. return 1;
  3798. case 2:
  3799. PtrCurve = (cmsToneCurve **) cmsReadTag(ContextID, hProfile, cmsSigVcgtTag);
  3800. if (PtrCurve == NULL) return 0;
  3801. if (!IsGoodVal("VCGT R", cmsEstimateGamma(ContextID, PtrCurve[0], 0.01), 1.1, 0.001)) return 0;
  3802. if (!IsGoodVal("VCGT G", cmsEstimateGamma(ContextID, PtrCurve[1], 0.01), 2.2, 0.001)) return 0;
  3803. if (!IsGoodVal("VCGT B", cmsEstimateGamma(ContextID, PtrCurve[2], 0.01), 3.4, 0.001)) return 0;
  3804. return 1;
  3805. default:;
  3806. }
  3807. return 0;
  3808. }
  3809. // Only one of the two following may be used, as they share the same tag
  3810. static
  3811. cmsInt32Number CheckDictionary16(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3812. {
  3813. cmsHANDLE hDict;
  3814. const cmsDICTentry* e;
  3815. switch (Pass) {
  3816. case 1:
  3817. hDict = cmsDictAlloc(ContextID);
  3818. cmsDictAddEntry(ContextID, hDict, L"Name0", NULL, NULL, NULL);
  3819. cmsDictAddEntry(ContextID, hDict, L"Name1", L"", NULL, NULL);
  3820. cmsDictAddEntry(ContextID, hDict, L"Name", L"String", NULL, NULL);
  3821. cmsDictAddEntry(ContextID, hDict, L"Name2", L"12", NULL, NULL);
  3822. if (!cmsWriteTag(ContextID, hProfile, cmsSigMetaTag, hDict)) return 0;
  3823. cmsDictFree(ContextID, hDict);
  3824. return 1;
  3825. case 2:
  3826. hDict = cmsReadTag(ContextID, hProfile, cmsSigMetaTag);
  3827. if (hDict == NULL) return 0;
  3828. e = cmsDictGetEntryList(ContextID, hDict);
  3829. if (memcmp(e ->Name, L"Name2", sizeof(wchar_t) * 5) != 0) return 0;
  3830. if (memcmp(e ->Value, L"12", sizeof(wchar_t) * 2) != 0) return 0;
  3831. e = cmsDictNextEntry(ContextID, e);
  3832. if (memcmp(e ->Name, L"Name", sizeof(wchar_t) * 4) != 0) return 0;
  3833. if (memcmp(e ->Value, L"String", sizeof(wchar_t) * 5) != 0) return 0;
  3834. e = cmsDictNextEntry(ContextID, e);
  3835. if (memcmp(e ->Name, L"Name1", sizeof(wchar_t) *5) != 0) return 0;
  3836. if (e ->Value == NULL) return 0;
  3837. if (*e->Value != 0) return 0;
  3838. e = cmsDictNextEntry(ContextID, e);
  3839. if (memcmp(e ->Name, L"Name0", sizeof(wchar_t) * 5) != 0) return 0;
  3840. if (e ->Value != NULL) return 0;
  3841. return 1;
  3842. default:;
  3843. }
  3844. return 0;
  3845. }
  3846. static
  3847. cmsInt32Number CheckDictionary24(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3848. {
  3849. cmsHANDLE hDict;
  3850. const cmsDICTentry* e;
  3851. cmsMLU* DisplayName;
  3852. char Buffer[256];
  3853. cmsInt32Number rc = 1;
  3854. switch (Pass) {
  3855. case 1:
  3856. hDict = cmsDictAlloc(ContextID);
  3857. DisplayName = cmsMLUalloc(ContextID, 0);
  3858. cmsMLUsetWide(ContextID, DisplayName, "en", "US", L"Hello, world");
  3859. cmsMLUsetWide(ContextID, DisplayName, "es", "ES", L"Hola, mundo");
  3860. cmsMLUsetWide(ContextID, DisplayName, "fr", "FR", L"Bonjour, le monde");
  3861. cmsMLUsetWide(ContextID, DisplayName, "ca", "CA", L"Hola, mon");
  3862. cmsDictAddEntry(ContextID, hDict, L"Name", L"String", DisplayName, NULL);
  3863. cmsMLUfree(ContextID, DisplayName);
  3864. cmsDictAddEntry(ContextID, hDict, L"Name2", L"12", NULL, NULL);
  3865. if (!cmsWriteTag(ContextID, hProfile, cmsSigMetaTag, hDict)) return 0;
  3866. cmsDictFree(ContextID, hDict);
  3867. return 1;
  3868. case 2:
  3869. hDict = cmsReadTag(ContextID, hProfile, cmsSigMetaTag);
  3870. if (hDict == NULL) return 0;
  3871. e = cmsDictGetEntryList(ContextID, hDict);
  3872. if (memcmp(e ->Name, L"Name2", sizeof(wchar_t) * 5) != 0) return 0;
  3873. if (memcmp(e ->Value, L"12", sizeof(wchar_t) * 2) != 0) return 0;
  3874. e = cmsDictNextEntry(ContextID, e);
  3875. if (memcmp(e ->Name, L"Name", sizeof(wchar_t) * 4) != 0) return 0;
  3876. if (memcmp(e ->Value, L"String", sizeof(wchar_t) * 5) != 0) return 0;
  3877. cmsMLUgetASCII(ContextID, e->DisplayName, "en", "US", Buffer, 256);
  3878. if (strcmp(Buffer, "Hello, world") != 0) rc = 0;
  3879. cmsMLUgetASCII(ContextID, e->DisplayName, "es", "ES", Buffer, 256);
  3880. if (strcmp(Buffer, "Hola, mundo") != 0) rc = 0;
  3881. cmsMLUgetASCII(ContextID, e->DisplayName, "fr", "FR", Buffer, 256);
  3882. if (strcmp(Buffer, "Bonjour, le monde") != 0) rc = 0;
  3883. cmsMLUgetASCII(ContextID, e->DisplayName, "ca", "CA", Buffer, 256);
  3884. if (strcmp(Buffer, "Hola, mon") != 0) rc = 0;
  3885. if (rc == 0)
  3886. Fail("Unexpected string '%s'", Buffer);
  3887. return 1;
  3888. default:;
  3889. }
  3890. return 0;
  3891. }
  3892. static
  3893. cmsInt32Number CheckRAWtags(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
  3894. {
  3895. char Buffer[7];
  3896. switch (Pass) {
  3897. case 1:
  3898. return cmsWriteRawTag(ContextID, hProfile, (cmsTagSignature) 0x31323334, "data123", 7);
  3899. case 2:
  3900. if (!cmsReadRawTag(ContextID, hProfile, (cmsTagSignature) 0x31323334, Buffer, 7)) return 0;
  3901. if (memcmp(Buffer, "data123", 7) != 0) return 0;
  3902. return 1;
  3903. default:
  3904. return 0;
  3905. }
  3906. }
  3907. static
  3908. cmsInt32Number Check_cicp(cmsInt32Number Pass, cmsHPROFILE hProfile)
  3909. {
  3910. cmsVideoSignalType* v;
  3911. cmsVideoSignalType s;
  3912. switch (Pass) {
  3913. case 1:
  3914. s.ColourPrimaries = 1;
  3915. s.TransferCharacteristics = 13;
  3916. s.MatrixCoefficients = 0;
  3917. s.VideoFullRangeFlag = 1;
  3918. if (!cmsWriteTag(hProfile, cmsSigcicpTag, &s)) return 0;
  3919. return 1;
  3920. case 2:
  3921. v = (cmsVideoSignalType*)cmsReadTag(hProfile, cmsSigcicpTag);
  3922. if (v == NULL) return 0;
  3923. if (v->ColourPrimaries != 1) return 0;
  3924. if (v->TransferCharacteristics != 13) return 0;
  3925. if (v->MatrixCoefficients != 0) return 0;
  3926. if (v->VideoFullRangeFlag != 1) return 0;
  3927. return 1;
  3928. default:
  3929. return 0;
  3930. }
  3931. }
  3932. static
  3933. void SetMHC2Matrix(cmsFloat64Number XYZ2XYZmatrix[3][4])
  3934. {
  3935. XYZ2XYZmatrix[0][0] = 0.5; XYZ2XYZmatrix[0][1] = 0.1; XYZ2XYZmatrix[0][2] = 0.1; XYZ2XYZmatrix[0][3] = 0.0;
  3936. XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0;
  3937. XYZ2XYZmatrix[2][0] = 0.3; XYZ2XYZmatrix[2][1] = 0.2; XYZ2XYZmatrix[2][2] = 0.4; XYZ2XYZmatrix[2][3] = 0.0;
  3938. }
  3939. static
  3940. cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
  3941. {
  3942. return fabs(b - a) < (1.0 / 65535.0);
  3943. }
  3944. cmsBool IsOriginalMHC2Matrix(cmsFloat64Number XYZ2XYZmatrix[3][4])
  3945. {
  3946. cmsFloat64Number m[3][4];
  3947. int i, j;
  3948. SetMHC2Matrix(m);
  3949. for (i = 0; i < 3; i++)
  3950. for (j = 0; j < 4; j++)
  3951. if (!CloseEnough(XYZ2XYZmatrix[i][j], m[i][j])) return FALSE;
  3952. return TRUE;
  3953. }
  3954. static
  3955. cmsInt32Number Check_MHC2(cmsInt32Number Pass, cmsHPROFILE hProfile)
  3956. {
  3957. cmsMHC2Type* v;
  3958. cmsMHC2Type s;
  3959. double curve[] = { 0, 0.5, 1.0 };
  3960. switch (Pass) {
  3961. case 1:
  3962. SetMHC2Matrix(s.XYZ2XYZmatrix);
  3963. s.CurveEntries = 3;
  3964. s.GreenCurve = curve;
  3965. s.RedCurve = curve;
  3966. s.BlueCurve = curve;
  3967. s.MinLuminance = 0.1;
  3968. s.PeakLuminance = 100.0;
  3969. if (!cmsWriteTag(hProfile, cmsSigMHC2Tag, &s)) return 0;
  3970. return 1;
  3971. case 2:
  3972. v = (cmsMHC2Type*)cmsReadTag(hProfile, cmsSigMHC2Tag);
  3973. if (v == NULL) return 0;
  3974. if (!IsOriginalMHC2Matrix(v->XYZ2XYZmatrix)) return 0;
  3975. if (v->CurveEntries != 3) return 0;
  3976. return 1;
  3977. default:
  3978. return 0;
  3979. }
  3980. }
  3981. // This is a very big test that checks every single tag
  3982. static
  3983. cmsInt32Number CheckProfileCreation(cmsContext ContextID)
  3984. {
  3985. cmsHPROFILE h;
  3986. cmsInt32Number Pass;
  3987. h = cmsCreateProfilePlaceholder(ContextID);
  3988. if (h == NULL) return 0;
  3989. cmsSetProfileVersion(ContextID, h, 4.3);
  3990. if (cmsGetTagCount(ContextID, h) != 0) { Fail("Empty profile with nonzero number of tags"); goto Error; }
  3991. if (cmsIsTag(ContextID, h, cmsSigAToB0Tag)) { Fail("Found a tag in an empty profile"); goto Error; }
  3992. cmsSetColorSpace(ContextID, h, cmsSigRgbData);
  3993. if (cmsGetColorSpace(ContextID, h) != cmsSigRgbData) { Fail("Unable to set colorspace"); goto Error; }
  3994. cmsSetPCS(ContextID, h, cmsSigLabData);
  3995. if (cmsGetPCS(ContextID, h) != cmsSigLabData) { Fail("Unable to set colorspace"); goto Error; }
  3996. cmsSetDeviceClass(ContextID, h, cmsSigDisplayClass);
  3997. if (cmsGetDeviceClass(ContextID, h) != cmsSigDisplayClass) { Fail("Unable to set deviceclass"); goto Error; }
  3998. cmsSetHeaderRenderingIntent(ContextID, h, INTENT_SATURATION);
  3999. if (cmsGetHeaderRenderingIntent(ContextID, h) != INTENT_SATURATION) { Fail("Unable to set rendering intent"); goto Error; }
  4000. for (Pass = 1; Pass <= 2; Pass++) {
  4001. SubTest("Tags holding XYZ");
  4002. if (!CheckXYZ(ContextID, Pass, h, cmsSigBlueColorantTag)) goto Error;
  4003. if (!CheckXYZ(ContextID, Pass, h, cmsSigGreenColorantTag)) goto Error;
  4004. if (!CheckXYZ(ContextID, Pass, h, cmsSigRedColorantTag)) goto Error;
  4005. if (!CheckXYZ(ContextID, Pass, h, cmsSigMediaBlackPointTag)) goto Error;
  4006. if (!CheckXYZ(ContextID, Pass, h, cmsSigMediaWhitePointTag)) goto Error;
  4007. if (!CheckXYZ(ContextID, Pass, h, cmsSigLuminanceTag)) goto Error;
  4008. SubTest("Tags holding curves");
  4009. if (!CheckGamma(ContextID, Pass, h, cmsSigBlueTRCTag)) goto Error;
  4010. if (!CheckGamma(ContextID, Pass, h, cmsSigGrayTRCTag)) goto Error;
  4011. if (!CheckGamma(ContextID, Pass, h, cmsSigGreenTRCTag)) goto Error;
  4012. if (!CheckGamma(ContextID, Pass, h, cmsSigRedTRCTag)) goto Error;
  4013. SubTest("Tags holding text");
  4014. if (!CheckTextSingle(ContextID, Pass, h, cmsSigCharTargetTag)) goto Error;
  4015. if (!CheckTextSingle(ContextID, Pass, h, cmsSigScreeningDescTag)) goto Error;
  4016. if (!CheckText(ContextID, Pass, h, cmsSigCopyrightTag)) goto Error;
  4017. if (!CheckText(ContextID, Pass, h, cmsSigProfileDescriptionTag)) goto Error;
  4018. if (!CheckText(ContextID, Pass, h, cmsSigDeviceMfgDescTag)) goto Error;
  4019. if (!CheckText(ContextID, Pass, h, cmsSigDeviceModelDescTag)) goto Error;
  4020. if (!CheckText(ContextID, Pass, h, cmsSigViewingCondDescTag)) goto Error;
  4021. SubTest("Tags holding cmsICCData");
  4022. if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD0Tag)) goto Error;
  4023. if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD1Tag)) goto Error;
  4024. if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD2Tag)) goto Error;
  4025. if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD3Tag)) goto Error;
  4026. if (!CheckData(ContextID, Pass, h, cmsSigPs2CSATag)) goto Error;
  4027. if (!CheckData(ContextID, Pass, h, cmsSigPs2RenderingIntentTag)) goto Error;
  4028. SubTest("Tags holding signatures");
  4029. if (!CheckSignature(ContextID, Pass, h, cmsSigColorimetricIntentImageStateTag)) goto Error;
  4030. if (!CheckSignature(ContextID, Pass, h, cmsSigPerceptualRenderingIntentGamutTag)) goto Error;
  4031. if (!CheckSignature(ContextID, Pass, h, cmsSigSaturationRenderingIntentGamutTag)) goto Error;
  4032. if (!CheckSignature(ContextID, Pass, h, cmsSigTechnologyTag)) goto Error;
  4033. SubTest("Tags holding date_time");
  4034. if (!CheckDateTime(ContextID, Pass, h, cmsSigCalibrationDateTimeTag)) goto Error;
  4035. if (!CheckDateTime(ContextID, Pass, h, cmsSigDateTimeTag)) goto Error;
  4036. SubTest("Tags holding named color lists");
  4037. if (!CheckNamedColor(ContextID, Pass, h, cmsSigColorantTableTag, 15, FALSE)) goto Error;
  4038. if (!CheckNamedColor(ContextID, Pass, h, cmsSigColorantTableOutTag, 15, FALSE)) goto Error;
  4039. if (!CheckNamedColor(ContextID, Pass, h, cmsSigNamedColor2Tag, 4096, TRUE)) goto Error;
  4040. SubTest("Tags holding LUTs");
  4041. if (!CheckLUT(ContextID, Pass, h, cmsSigAToB0Tag)) goto Error;
  4042. if (!CheckLUT(ContextID, Pass, h, cmsSigAToB1Tag)) goto Error;
  4043. if (!CheckLUT(ContextID, Pass, h, cmsSigAToB2Tag)) goto Error;
  4044. if (!CheckLUT(ContextID, Pass, h, cmsSigBToA0Tag)) goto Error;
  4045. if (!CheckLUT(ContextID, Pass, h, cmsSigBToA1Tag)) goto Error;
  4046. if (!CheckLUT(ContextID, Pass, h, cmsSigBToA2Tag)) goto Error;
  4047. if (!CheckLUT(ContextID, Pass, h, cmsSigPreview0Tag)) goto Error;
  4048. if (!CheckLUT(ContextID, Pass, h, cmsSigPreview1Tag)) goto Error;
  4049. if (!CheckLUT(ContextID, Pass, h, cmsSigPreview2Tag)) goto Error;
  4050. if (!CheckLUT(ContextID, Pass, h, cmsSigGamutTag)) goto Error;
  4051. SubTest("Tags holding CHAD");
  4052. if (!CheckCHAD(ContextID, Pass, h, cmsSigChromaticAdaptationTag)) goto Error;
  4053. SubTest("Tags holding Chromaticity");
  4054. if (!CheckChromaticity(ContextID, Pass, h, cmsSigChromaticityTag)) goto Error;
  4055. SubTest("Tags holding colorant order");
  4056. if (!CheckColorantOrder(ContextID, Pass, h, cmsSigColorantOrderTag)) goto Error;
  4057. SubTest("Tags holding measurement");
  4058. if (!CheckMeasurement(ContextID, Pass, h, cmsSigMeasurementTag)) goto Error;
  4059. SubTest("Tags holding CRD info");
  4060. if (!CheckCRDinfo(ContextID, Pass, h, cmsSigCrdInfoTag)) goto Error;
  4061. SubTest("Tags holding UCR/BG");
  4062. if (!CheckUcrBg(ContextID, Pass, h, cmsSigUcrBgTag)) goto Error;
  4063. SubTest("Tags holding MPE");
  4064. if (!CheckMPE(ContextID, Pass, h, cmsSigDToB0Tag)) goto Error;
  4065. if (!CheckMPE(ContextID, Pass, h, cmsSigDToB1Tag)) goto Error;
  4066. if (!CheckMPE(ContextID, Pass, h, cmsSigDToB2Tag)) goto Error;
  4067. if (!CheckMPE(ContextID, Pass, h, cmsSigDToB3Tag)) goto Error;
  4068. if (!CheckMPE(ContextID, Pass, h, cmsSigBToD0Tag)) goto Error;
  4069. if (!CheckMPE(ContextID, Pass, h, cmsSigBToD1Tag)) goto Error;
  4070. if (!CheckMPE(ContextID, Pass, h, cmsSigBToD2Tag)) goto Error;
  4071. if (!CheckMPE(ContextID, Pass, h, cmsSigBToD3Tag)) goto Error;
  4072. SubTest("Tags using screening");
  4073. if (!CheckScreening(ContextID, Pass, h, cmsSigScreeningTag)) goto Error;
  4074. SubTest("Tags holding profile sequence description");
  4075. if (!CheckProfileSequenceTag(ContextID, Pass, h)) goto Error;
  4076. if (!CheckProfileSequenceIDTag(ContextID, Pass, h)) goto Error;
  4077. SubTest("Tags holding ICC viewing conditions");
  4078. if (!CheckICCViewingConditions(ContextID, Pass, h)) goto Error;
  4079. SubTest("VCGT tags");
  4080. if (!CheckVCGT(ContextID, Pass, h)) goto Error;
  4081. SubTest("RAW tags");
  4082. if (!CheckRAWtags(ContextID, Pass, h)) goto Error;
  4083. SubTest("Dictionary meta tags");
  4084. // if (!CheckDictionary16(ContextID, Pass, h)) goto Error;
  4085. if (!CheckDictionary24(ContextID, Pass, h)) goto Error;
  4086. SubTest("cicp Video Signal Type");
  4087. if (!Check_cicp(Pass, h)) goto Error;
  4088. SubTest("Microsoft MHC2 tag");
  4089. if (!Check_MHC2(Pass, h)) goto Error;
  4090. if (Pass == 1) {
  4091. cmsSaveProfileToFile(ContextID, h, "alltags.icc");
  4092. cmsCloseProfile(ContextID, h);
  4093. h = cmsOpenProfileFromFile(ContextID, "alltags.icc", "r");
  4094. }
  4095. }
  4096. /*
  4097. Not implemented (by design):
  4098. cmsSigDataTag = 0x64617461, // 'data' -- Unused
  4099. cmsSigDeviceSettingsTag = 0x64657673, // 'devs' -- Unused
  4100. cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' -- Don't use this one, deprecated by ICC
  4101. cmsSigOutputResponseTag = 0x72657370, // 'resp' -- Possible patent on this
  4102. */
  4103. cmsCloseProfile(ContextID, h);
  4104. remove("alltags.icc");
  4105. return 1;
  4106. Error:
  4107. cmsCloseProfile(ContextID, h);
  4108. remove("alltags.icc");
  4109. return 0;
  4110. }
  4111. // Thanks to Christopher James Halse Rogers for the bugfixing and providing this test
  4112. static
  4113. cmsInt32Number CheckVersionHeaderWriting(cmsContext ContextID)
  4114. {
  4115. cmsHPROFILE h;
  4116. int index;
  4117. float test_versions[] = {
  4118. 2.3f,
  4119. 4.08f,
  4120. 4.09f,
  4121. 4.3f
  4122. };
  4123. for (index = 0; index < sizeof(test_versions)/sizeof(test_versions[0]); index++) {
  4124. h = cmsCreateProfilePlaceholder(ContextID);
  4125. if (h == NULL) return 0;
  4126. cmsSetProfileVersion(ContextID, h, test_versions[index]);
  4127. cmsSaveProfileToFile(ContextID, h, "versions.icc");
  4128. cmsCloseProfile(ContextID, h);
  4129. h = cmsOpenProfileFromFile(ContextID, "versions.icc", "r");
  4130. // Only the first 3 digits are significant
  4131. if (fabs(cmsGetProfileVersion(ContextID, h) - test_versions[index]) > 0.005) {
  4132. Fail("Version failed to round-trip: wrote %.2f, read %.2f",
  4133. test_versions[index], cmsGetProfileVersion(ContextID, h));
  4134. return 0;
  4135. }
  4136. cmsCloseProfile(ContextID, h);
  4137. remove("versions.icc");
  4138. }
  4139. return 1;
  4140. }
  4141. // Test on Richard Hughes "crayons.icc"
  4142. static
  4143. cmsInt32Number CheckMultilocalizedProfile(cmsContext ContextID)
  4144. {
  4145. cmsHPROFILE hProfile;
  4146. cmsMLU *Pt;
  4147. char Buffer[256];
  4148. hProfile = cmsOpenProfileFromFile(ContextID, "crayons.icc", "r");
  4149. Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, cmsSigProfileDescriptionTag);
  4150. cmsMLUgetASCII(ContextID, Pt, "en", "GB", Buffer, 256);
  4151. if (strcmp(Buffer, "Crayon Colours") != 0) return FALSE;
  4152. cmsMLUgetASCII(ContextID, Pt, "en", "US", Buffer, 256);
  4153. if (strcmp(Buffer, "Crayon Colors") != 0) return FALSE;
  4154. cmsCloseProfile(ContextID, hProfile);
  4155. return TRUE;
  4156. }
  4157. // Error reporting -------------------------------------------------------------------------------------------------------
  4158. static
  4159. void ErrorReportingFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
  4160. {
  4161. TrappedError = TRUE;
  4162. SimultaneousErrors++;
  4163. strncpy(ReasonToFailBuffer, Text, TEXT_ERROR_BUFFER_SIZE-1);
  4164. cmsUNUSED_PARAMETER(ContextID);
  4165. cmsUNUSED_PARAMETER(ErrorCode);
  4166. }
  4167. static
  4168. cmsInt32Number CheckBadProfiles(cmsContext ContextID)
  4169. {
  4170. cmsHPROFILE h;
  4171. h = cmsOpenProfileFromFile(ContextID, "IDoNotExist.icc", "r");
  4172. if (h != NULL) {
  4173. cmsCloseProfile(ContextID, h);
  4174. return 0;
  4175. }
  4176. h = cmsOpenProfileFromFile(ContextID, "IAmIllFormed*.icc", "r");
  4177. if (h != NULL) {
  4178. cmsCloseProfile(ContextID, h);
  4179. return 0;
  4180. }
  4181. // No profile name given
  4182. h = cmsOpenProfileFromFile(ContextID, "", "r");
  4183. if (h != NULL) {
  4184. cmsCloseProfile(ContextID, h);
  4185. return 0;
  4186. }
  4187. h = cmsOpenProfileFromFile(ContextID, "..", "r");
  4188. if (h != NULL) {
  4189. cmsCloseProfile(ContextID, h);
  4190. return 0;
  4191. }
  4192. h = cmsOpenProfileFromFile(ContextID, "IHaveBadAccessMode.icc", "@");
  4193. if (h != NULL) {
  4194. cmsCloseProfile(ContextID, h);
  4195. return 0;
  4196. }
  4197. h = cmsOpenProfileFromFile(ContextID, "bad.icc", "r");
  4198. if (h != NULL) {
  4199. cmsCloseProfile(ContextID, h);
  4200. return 0;
  4201. }
  4202. h = cmsOpenProfileFromFile(ContextID, "toosmall.icc", "r");
  4203. if (h != NULL) {
  4204. cmsCloseProfile(ContextID, h);
  4205. return 0;
  4206. }
  4207. h = cmsOpenProfileFromMem(ContextID, NULL, 3);
  4208. if (h != NULL) {
  4209. cmsCloseProfile(ContextID, h);
  4210. return 0;
  4211. }
  4212. h = cmsOpenProfileFromMem(ContextID, "123", 3);
  4213. if (h != NULL) {
  4214. cmsCloseProfile(ContextID, h);
  4215. return 0;
  4216. }
  4217. if (SimultaneousErrors != 9) return 0;
  4218. return 1;
  4219. }
  4220. static
  4221. cmsInt32Number CheckErrReportingOnBadProfiles(cmsContext ContextID)
  4222. {
  4223. cmsInt32Number rc;
  4224. cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
  4225. rc = CheckBadProfiles(ContextID);
  4226. cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
  4227. // Reset the error state
  4228. TrappedError = FALSE;
  4229. return rc;
  4230. }
  4231. static
  4232. cmsInt32Number CheckBadTransforms(cmsContext ContextID)
  4233. {
  4234. cmsHPROFILE h1 = cmsCreate_sRGBProfile(ContextID);
  4235. cmsHTRANSFORM x1;
  4236. x1 = cmsCreateTransform(ContextID, NULL, 0, NULL, 0, 0, 0);
  4237. if (x1 != NULL) {
  4238. cmsDeleteTransform(ContextID, x1);
  4239. return 0;
  4240. }
  4241. x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, h1, TYPE_RGB_8, 12345, 0);
  4242. if (x1 != NULL) {
  4243. cmsDeleteTransform(ContextID, x1);
  4244. return 0;
  4245. }
  4246. x1 = cmsCreateTransform(ContextID, h1, TYPE_CMYK_8, h1, TYPE_RGB_8, 0, 0);
  4247. if (x1 != NULL) {
  4248. cmsDeleteTransform(ContextID, x1);
  4249. return 0;
  4250. }
  4251. x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, h1, TYPE_CMYK_8, 1, 0);
  4252. if (x1 != NULL) {
  4253. cmsDeleteTransform(ContextID, x1);
  4254. return 0;
  4255. }
  4256. // sRGB does its output as XYZ!
  4257. x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, NULL, TYPE_Lab_8, 1, 0);
  4258. if (x1 != NULL) {
  4259. cmsDeleteTransform(ContextID, x1);
  4260. return 0;
  4261. }
  4262. cmsCloseProfile(ContextID, h1);
  4263. {
  4264. cmsHPROFILE hp1 = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  4265. cmsHPROFILE hp2 = cmsCreate_sRGBProfile(ContextID);
  4266. x1 = cmsCreateTransform(ContextID, hp1, TYPE_BGR_8, hp2, TYPE_BGR_8, INTENT_PERCEPTUAL, 0);
  4267. cmsCloseProfile(ContextID, hp1); cmsCloseProfile(ContextID, hp2);
  4268. if (x1 != NULL) {
  4269. cmsDeleteTransform(ContextID, x1);
  4270. return 0;
  4271. }
  4272. }
  4273. return 1;
  4274. }
  4275. static
  4276. cmsInt32Number CheckErrReportingOnBadTransforms(cmsContext ContextID)
  4277. {
  4278. cmsInt32Number rc;
  4279. cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
  4280. rc = CheckBadTransforms(ContextID);
  4281. cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
  4282. // Reset the error state
  4283. TrappedError = FALSE;
  4284. return rc;
  4285. }
  4286. // ---------------------------------------------------------------------------------------------------------
  4287. // Check a linear xform
  4288. static
  4289. cmsInt32Number Check8linearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
  4290. {
  4291. cmsInt32Number n2, i, j;
  4292. cmsUInt8Number Inw[cmsMAXCHANNELS], Outw[cmsMAXCHANNELS];
  4293. n2=0;
  4294. for (j=0; j < 0xFF; j++) {
  4295. memset(Inw, j, sizeof(Inw));
  4296. cmsDoTransform(ContextID, xform, Inw, Outw, 1);
  4297. for (i=0; i < nChan; i++) {
  4298. cmsInt32Number dif = abs(Outw[i] - j);
  4299. if (dif > n2) n2 = dif;
  4300. }
  4301. }
  4302. // We allow 2 contone of difference on 8 bits
  4303. if (n2 > 2) {
  4304. Fail("Differences too big (%x)", n2);
  4305. return 0;
  4306. }
  4307. return 1;
  4308. }
  4309. static
  4310. cmsInt32Number Compare8bitXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
  4311. {
  4312. cmsInt32Number n2, i, j;
  4313. cmsUInt8Number Inw[cmsMAXCHANNELS], Outw1[cmsMAXCHANNELS], Outw2[cmsMAXCHANNELS];;
  4314. n2=0;
  4315. for (j=0; j < 0xFF; j++) {
  4316. memset(Inw, j, sizeof(Inw));
  4317. cmsDoTransform(ContextID, xform1, Inw, Outw1, 1);
  4318. cmsDoTransform(ContextID, xform2, Inw, Outw2, 1);
  4319. for (i=0; i < nChan; i++) {
  4320. cmsInt32Number dif = abs(Outw2[i] - Outw1[i]);
  4321. if (dif > n2) n2 = dif;
  4322. }
  4323. }
  4324. // We allow 2 contone of difference on 8 bits
  4325. if (n2 > 2) {
  4326. Fail("Differences too big (%x)", n2);
  4327. return 0;
  4328. }
  4329. return 1;
  4330. }
  4331. // Check a linear xform
  4332. static
  4333. cmsInt32Number Check16linearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
  4334. {
  4335. cmsInt32Number n2, i, j;
  4336. cmsUInt16Number Inw[cmsMAXCHANNELS], Outw[cmsMAXCHANNELS];
  4337. n2=0;
  4338. for (j=0; j < 0xFFFF; j++) {
  4339. for (i=0; i < nChan; i++) Inw[i] = (cmsUInt16Number) j;
  4340. cmsDoTransform(ContextID, xform, Inw, Outw, 1);
  4341. for (i=0; i < nChan; i++) {
  4342. cmsInt32Number dif = abs(Outw[i] - j);
  4343. if (dif > n2) n2 = dif;
  4344. }
  4345. // We allow 2 contone of difference on 16 bits
  4346. if (n2 > 0x200) {
  4347. Fail("Differences too big (%x)", n2);
  4348. return 0;
  4349. }
  4350. }
  4351. return 1;
  4352. }
  4353. static
  4354. cmsInt32Number Compare16bitXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
  4355. {
  4356. cmsInt32Number n2, i, j;
  4357. cmsUInt16Number Inw[cmsMAXCHANNELS], Outw1[cmsMAXCHANNELS], Outw2[cmsMAXCHANNELS];;
  4358. n2=0;
  4359. for (j=0; j < 0xFFFF; j++) {
  4360. for (i=0; i < nChan; i++) Inw[i] = (cmsUInt16Number) j;
  4361. cmsDoTransform(ContextID, xform1, Inw, Outw1, 1);
  4362. cmsDoTransform(ContextID, xform2, Inw, Outw2, 1);
  4363. for (i=0; i < nChan; i++) {
  4364. cmsInt32Number dif = abs(Outw2[i] - Outw1[i]);
  4365. if (dif > n2) n2 = dif;
  4366. }
  4367. }
  4368. // We allow 2 contone of difference on 16 bits
  4369. if (n2 > 0x200) {
  4370. Fail("Differences too big (%x)", n2);
  4371. return 0;
  4372. }
  4373. return 1;
  4374. }
  4375. // Check a linear xform
  4376. static
  4377. cmsInt32Number CheckFloatlinearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
  4378. {
  4379. cmsInt32Number i, j;
  4380. cmsFloat32Number In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS];
  4381. for (j=0; j < 0xFFFF; j++) {
  4382. for (i=0; i < nChan; i++) In[i] = (cmsFloat32Number) (j / 65535.0);;
  4383. cmsDoTransform(ContextID, xform, In, Out, 1);
  4384. for (i=0; i < nChan; i++) {
  4385. // We allow no difference in floating point
  4386. if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out[i], (cmsFloat32Number) (j / 65535.0)))
  4387. return 0;
  4388. }
  4389. }
  4390. return 1;
  4391. }
  4392. // Check a linear xform
  4393. static
  4394. cmsInt32Number CompareFloatXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
  4395. {
  4396. cmsInt32Number i, j;
  4397. cmsFloat32Number In[cmsMAXCHANNELS], Out1[cmsMAXCHANNELS], Out2[cmsMAXCHANNELS];
  4398. for (j=0; j < 0xFFFF; j++) {
  4399. for (i=0; i < nChan; i++) In[i] = (cmsFloat32Number) (j / 65535.0);;
  4400. cmsDoTransform(ContextID, xform1, In, Out1, 1);
  4401. cmsDoTransform(ContextID, xform2, In, Out2, 1);
  4402. for (i=0; i < nChan; i++) {
  4403. // We allow no difference in floating point
  4404. if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out1[i], Out2[i]))
  4405. return 0;
  4406. }
  4407. }
  4408. return 1;
  4409. }
  4410. // Curves only transforms ----------------------------------------------------------------------------------------
  4411. static
  4412. cmsInt32Number CheckCurvesOnlyTransforms(cmsContext ContextID)
  4413. {
  4414. cmsHTRANSFORM xform1, xform2;
  4415. cmsHPROFILE h1, h2, h3;
  4416. cmsToneCurve* c1, *c2, *c3;
  4417. cmsInt32Number rc = 1;
  4418. c1 = cmsBuildGamma(ContextID, 2.2);
  4419. c2 = cmsBuildGamma(ContextID, 1/2.2);
  4420. c3 = cmsBuildGamma(ContextID, 4.84);
  4421. h1 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c1);
  4422. h2 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c2);
  4423. h3 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c3);
  4424. SubTest("Gray float optimizeable transform");
  4425. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_FLT, h2, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
  4426. rc &= CheckFloatlinearXFORM(ContextID, xform1, 1);
  4427. cmsDeleteTransform(ContextID, xform1);
  4428. if (rc == 0) goto Error;
  4429. SubTest("Gray 8 optimizeable transform");
  4430. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_8, h2, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
  4431. rc &= Check8linearXFORM(ContextID, xform1, 1);
  4432. cmsDeleteTransform(ContextID, xform1);
  4433. if (rc == 0) goto Error;
  4434. SubTest("Gray 16 optimizeable transform");
  4435. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_16, h2, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
  4436. rc &= Check16linearXFORM(ContextID, xform1, 1);
  4437. cmsDeleteTransform(ContextID, xform1);
  4438. if (rc == 0) goto Error;
  4439. SubTest("Gray float non-optimizeable transform");
  4440. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_FLT, h1, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
  4441. xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_FLT, NULL, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
  4442. rc &= CompareFloatXFORM(ContextID, xform1, xform2, 1);
  4443. cmsDeleteTransform(ContextID, xform1);
  4444. cmsDeleteTransform(ContextID, xform2);
  4445. if (rc == 0) goto Error;
  4446. SubTest("Gray 8 non-optimizeable transform");
  4447. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_8, h1, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
  4448. xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_8, NULL, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
  4449. rc &= Compare8bitXFORM(ContextID, xform1, xform2, 1);
  4450. cmsDeleteTransform(ContextID, xform1);
  4451. cmsDeleteTransform(ContextID, xform2);
  4452. if (rc == 0) goto Error;
  4453. SubTest("Gray 16 non-optimizeable transform");
  4454. xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_16, h1, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
  4455. xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_16, NULL, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
  4456. rc &= Compare16bitXFORM(ContextID, xform1, xform2, 1);
  4457. cmsDeleteTransform(ContextID, xform1);
  4458. cmsDeleteTransform(ContextID, xform2);
  4459. if (rc == 0) goto Error;
  4460. Error:
  4461. cmsCloseProfile(ContextID, h1); cmsCloseProfile(ContextID, h2); cmsCloseProfile(ContextID, h3);
  4462. cmsFreeToneCurve(ContextID, c1); cmsFreeToneCurve(ContextID, c2); cmsFreeToneCurve(ContextID, c3);
  4463. return rc;
  4464. }
  4465. // Lab to Lab trivial transforms ----------------------------------------------------------------------------------------
  4466. static cmsFloat64Number MaxDE;
  4467. static
  4468. cmsInt32Number CheckOneLab(cmsContext ContextID, cmsHTRANSFORM xform, cmsFloat64Number L, cmsFloat64Number a, cmsFloat64Number b)
  4469. {
  4470. cmsCIELab In, Out;
  4471. cmsFloat64Number dE;
  4472. In.L = L; In.a = a; In.b = b;
  4473. cmsDoTransform(ContextID, xform, &In, &Out, 1);
  4474. dE = cmsDeltaE(ContextID, &In, &Out);
  4475. if (dE > MaxDE) MaxDE = dE;
  4476. if (MaxDE > 0.003) {
  4477. Fail("dE=%f Lab1=(%f, %f, %f)\n\tLab2=(%f %f %f)", MaxDE, In.L, In.a, In.b, Out.L, Out.a, Out.b);
  4478. cmsDoTransform(ContextID, xform, &In, &Out, 1);
  4479. return 0;
  4480. }
  4481. return 1;
  4482. }
  4483. // Check several Lab, slicing at non-exact values. Precision should be 16 bits. 50x50x50 checks aprox.
  4484. static
  4485. cmsInt32Number CheckSeveralLab(cmsContext ContextID, cmsHTRANSFORM xform)
  4486. {
  4487. cmsInt32Number L, a, b;
  4488. MaxDE = 0;
  4489. for (L=0; L < 65536; L += 1311) {
  4490. for (a = 0; a < 65536; a += 1232) {
  4491. for (b = 0; b < 65536; b += 1111) {
  4492. if (!CheckOneLab(ContextID, xform, (L * 100.0) / 65535.0,
  4493. (a / 257.0) - 128, (b / 257.0) - 128))
  4494. return 0;
  4495. }
  4496. }
  4497. }
  4498. return 1;
  4499. }
  4500. static
  4501. cmsInt32Number OneTrivialLab(cmsContext ContextID, cmsHPROFILE hLab1, cmsHPROFILE hLab2, const char* txt)
  4502. {
  4503. cmsHTRANSFORM xform;
  4504. cmsInt32Number rc;
  4505. SubTest(txt);
  4506. xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4507. cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
  4508. rc = CheckSeveralLab(ContextID, xform);
  4509. cmsDeleteTransform(ContextID, xform);
  4510. return rc;
  4511. }
  4512. static
  4513. cmsInt32Number CheckFloatLabTransforms(cmsContext ContextID)
  4514. {
  4515. return OneTrivialLab(ContextID, cmsCreateLab4Profile(ContextID, NULL), cmsCreateLab4Profile(ContextID, NULL), "Lab4/Lab4") &&
  4516. OneTrivialLab(ContextID, cmsCreateLab2Profile(ContextID, NULL), cmsCreateLab2Profile(ContextID, NULL), "Lab2/Lab2") &&
  4517. OneTrivialLab(ContextID, cmsCreateLab4Profile(ContextID, NULL), cmsCreateLab2Profile(ContextID, NULL), "Lab4/Lab2") &&
  4518. OneTrivialLab(ContextID, cmsCreateLab2Profile(ContextID, NULL), cmsCreateLab4Profile(ContextID, NULL), "Lab2/Lab4");
  4519. }
  4520. static
  4521. cmsInt32Number CheckEncodedLabTransforms(cmsContext ContextID)
  4522. {
  4523. cmsHTRANSFORM xform;
  4524. cmsUInt16Number In[3];
  4525. cmsUInt16Number wLab[3];
  4526. cmsCIELab Lab;
  4527. cmsCIELab White = { 100, 0, 0 };
  4528. cmsCIELab Color = { 7.11070, -76, 26 };
  4529. cmsHPROFILE hLab1 = cmsCreateLab4Profile(ContextID, NULL);
  4530. cmsHPROFILE hLab2 = cmsCreateLab4Profile(ContextID, NULL);
  4531. xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_16, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4532. cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
  4533. In[0] = 0xFFFF;
  4534. In[1] = 0x8080;
  4535. In[2] = 0x8080;
  4536. cmsDoTransform(ContextID, xform, In, &Lab, 1);
  4537. if (cmsDeltaE(ContextID, &Lab, &White) > 0.0001) return 0;
  4538. In[0] = 0x1234;
  4539. In[1] = 0x3434;
  4540. In[2] = 0x9A9A;
  4541. cmsDoTransform(xform, In, &Lab, 1);
  4542. cmsFloat2LabEncoded(wLab, &Lab);
  4543. if (memcmp(In, wLab, sizeof(wLab)) != 0) return 0;
  4544. if (cmsDeltaE(&Lab, &Color) > 0.0001) return 0;
  4545. cmsDeleteTransform(ContextID, xform);
  4546. hLab1 = cmsCreateLab2Profile(ContextID, NULL);
  4547. hLab2 = cmsCreateLab4Profile(ContextID, NULL);
  4548. xform = cmsCreateTransform(ContextID, hLab1, TYPE_LabV2_16, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4549. cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
  4550. In[0] = 0xFF00;
  4551. In[1] = 0x8000;
  4552. In[2] = 0x8000;
  4553. cmsDoTransform(ContextID, xform, In, &Lab, 1);
  4554. if (cmsDeltaE(ContextID, &Lab, &White) > 0.0001) return 0;
  4555. cmsDeleteTransform(ContextID, xform);
  4556. hLab2 = cmsCreateLab2Profile(ContextID, NULL);
  4557. hLab1 = cmsCreateLab4Profile(ContextID, NULL);
  4558. xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_LabV2_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  4559. cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
  4560. Lab.L = 100;
  4561. Lab.a = 0;
  4562. Lab.b = 0;
  4563. cmsDoTransform(ContextID, xform, &Lab, In, 1);
  4564. if (In[0] != 0xFF00 ||
  4565. In[1] != 0x8000 ||
  4566. In[2] != 0x8000) return 0;
  4567. cmsDeleteTransform(ContextID, xform);
  4568. hLab1 = cmsCreateLab4Profile(ContextID, NULL);
  4569. hLab2 = cmsCreateLab4Profile(ContextID, NULL);
  4570. xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  4571. cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
  4572. Lab.L = 100;
  4573. Lab.a = 0;
  4574. Lab.b = 0;
  4575. cmsDoTransform(ContextID, xform, &Lab, In, 1);
  4576. if (In[0] != 0xFFFF ||
  4577. In[1] != 0x8080 ||
  4578. In[2] != 0x8080) return 0;
  4579. cmsDeleteTransform(ContextID, xform);
  4580. return 1;
  4581. }
  4582. static
  4583. cmsInt32Number CheckStoredIdentities(cmsContext ContextID)
  4584. {
  4585. cmsHPROFILE hLab, hLink, h4, h2;
  4586. cmsHTRANSFORM xform;
  4587. cmsInt32Number rc = 1;
  4588. hLab = cmsCreateLab4Profile(ContextID, NULL);
  4589. xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_8, hLab, TYPE_Lab_8, 0, 0);
  4590. hLink = cmsTransform2DeviceLink(ContextID, xform, 3.4, 0);
  4591. cmsSaveProfileToFile(ContextID, hLink, "abstractv2.icc");
  4592. cmsCloseProfile(ContextID, hLink);
  4593. hLink = cmsTransform2DeviceLink(ContextID, xform, 4.3, 0);
  4594. cmsSaveProfileToFile(ContextID, hLink, "abstractv4.icc");
  4595. cmsCloseProfile(ContextID, hLink);
  4596. cmsDeleteTransform(ContextID, xform);
  4597. cmsCloseProfile(ContextID, hLab);
  4598. h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
  4599. xform = cmsCreateTransform(ContextID, h4, TYPE_Lab_DBL, h4, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4600. SubTest("V4");
  4601. rc &= CheckSeveralLab(ContextID, xform);
  4602. cmsDeleteTransform(ContextID, xform);
  4603. cmsCloseProfile(ContextID, h4);
  4604. if (!rc) goto Error;
  4605. SubTest("V2");
  4606. h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
  4607. xform = cmsCreateTransform(ContextID, h2, TYPE_Lab_DBL, h2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4608. rc &= CheckSeveralLab(ContextID, xform);
  4609. cmsDeleteTransform(ContextID, xform);
  4610. cmsCloseProfile(ContextID, h2);
  4611. if (!rc) goto Error;
  4612. SubTest("V2 -> V4");
  4613. h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
  4614. h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
  4615. xform = cmsCreateTransform(ContextID, h4, TYPE_Lab_DBL, h2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4616. rc &= CheckSeveralLab(ContextID, xform);
  4617. cmsDeleteTransform(ContextID, xform);
  4618. cmsCloseProfile(ContextID, h2);
  4619. cmsCloseProfile(ContextID, h4);
  4620. SubTest("V4 -> V2");
  4621. h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
  4622. h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
  4623. xform = cmsCreateTransform(ContextID, h2, TYPE_Lab_DBL, h4, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  4624. rc &= CheckSeveralLab(ContextID, xform);
  4625. cmsDeleteTransform(ContextID, xform);
  4626. cmsCloseProfile(ContextID, h2);
  4627. cmsCloseProfile(ContextID, h4);
  4628. Error:
  4629. remove("abstractv2.icc");
  4630. remove("abstractv4.icc");
  4631. return rc;
  4632. }
  4633. // Check a simple xform from a matrix profile to itself. Test floating point accuracy.
  4634. static
  4635. cmsInt32Number CheckMatrixShaperXFORMFloat(cmsContext ContextID)
  4636. {
  4637. cmsHPROFILE hAbove, hSRGB;
  4638. cmsHTRANSFORM xform;
  4639. cmsInt32Number rc1, rc2;
  4640. hAbove = Create_AboveRGB(ContextID);
  4641. xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  4642. cmsCloseProfile(ContextID, hAbove);
  4643. rc1 = CheckFloatlinearXFORM(ContextID, xform, 3);
  4644. cmsDeleteTransform(ContextID, xform);
  4645. hSRGB = cmsCreate_sRGBProfile(ContextID);
  4646. xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_FLT, hSRGB, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  4647. cmsCloseProfile(ContextID, hSRGB);
  4648. rc2 = CheckFloatlinearXFORM(ContextID, xform, 3);
  4649. cmsDeleteTransform(ContextID, xform);
  4650. return rc1 && rc2;
  4651. }
  4652. // Check a simple xform from a matrix profile to itself. Test 16 bits accuracy.
  4653. static
  4654. cmsInt32Number CheckMatrixShaperXFORM16(cmsContext ContextID)
  4655. {
  4656. cmsHPROFILE hAbove, hSRGB;
  4657. cmsHTRANSFORM xform;
  4658. cmsInt32Number rc1, rc2;
  4659. hAbove = Create_AboveRGB(ContextID);
  4660. xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  4661. cmsCloseProfile(ContextID, hAbove);
  4662. rc1 = Check16linearXFORM(ContextID, xform, 3);
  4663. cmsDeleteTransform(ContextID, xform);
  4664. hSRGB = cmsCreate_sRGBProfile(ContextID);
  4665. xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_16, hSRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  4666. cmsCloseProfile(ContextID, hSRGB);
  4667. rc2 = Check16linearXFORM(ContextID, xform, 3);
  4668. cmsDeleteTransform(ContextID, xform);
  4669. return rc1 && rc2;
  4670. }
  4671. // Check a simple xform from a matrix profile to itself. Test 8 bits accuracy.
  4672. static
  4673. cmsInt32Number CheckMatrixShaperXFORM8(cmsContext ContextID)
  4674. {
  4675. cmsHPROFILE hAbove, hSRGB;
  4676. cmsHTRANSFORM xform;
  4677. cmsInt32Number rc1, rc2;
  4678. hAbove = Create_AboveRGB(ContextID);
  4679. xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_8, hAbove, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, 0);
  4680. cmsCloseProfile(ContextID, hAbove);
  4681. rc1 = Check8linearXFORM(ContextID, xform, 3);
  4682. cmsDeleteTransform(ContextID, xform);
  4683. hSRGB = cmsCreate_sRGBProfile(ContextID);
  4684. xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_8, hSRGB, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, 0);
  4685. cmsCloseProfile(ContextID, hSRGB);
  4686. rc2 = Check8linearXFORM(ContextID, xform, 3);
  4687. cmsDeleteTransform(ContextID, xform);
  4688. return rc1 && rc2;
  4689. }
  4690. // TODO: Check LUT based to LUT based transforms for CMYK
  4691. // -----------------------------------------------------------------------------------------------------------------
  4692. // Check known values going from sRGB to XYZ
  4693. static
  4694. cmsInt32Number CheckOneRGB_f(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number R, cmsInt32Number G, cmsInt32Number B, cmsFloat64Number X, cmsFloat64Number Y, cmsFloat64Number Z, cmsFloat64Number err)
  4695. {
  4696. cmsFloat32Number RGB[3];
  4697. cmsFloat64Number Out[3];
  4698. RGB[0] = (cmsFloat32Number) (R / 255.0);
  4699. RGB[1] = (cmsFloat32Number) (G / 255.0);
  4700. RGB[2] = (cmsFloat32Number) (B / 255.0);
  4701. cmsDoTransform(ContextID, xform, RGB, Out, 1);
  4702. return IsGoodVal("X", X , Out[0], err) &&
  4703. IsGoodVal("Y", Y , Out[1], err) &&
  4704. IsGoodVal("Z", Z , Out[2], err);
  4705. }
  4706. static
  4707. cmsInt32Number Chack_sRGB_Float(cmsContext ContextID)
  4708. {
  4709. cmsHPROFILE hsRGB, hXYZ, hLab;
  4710. cmsHTRANSFORM xform1, xform2;
  4711. cmsInt32Number rc;
  4712. hsRGB = cmsCreate_sRGBProfile(ContextID);
  4713. hXYZ = cmsCreateXYZProfile(ContextID);
  4714. hLab = cmsCreateLab4Profile(ContextID, NULL);
  4715. xform1 = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_FLT, hXYZ, TYPE_XYZ_DBL,
  4716. INTENT_RELATIVE_COLORIMETRIC, 0);
  4717. xform2 = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_FLT, hLab, TYPE_Lab_DBL,
  4718. INTENT_RELATIVE_COLORIMETRIC, 0);
  4719. cmsCloseProfile(ContextID, hsRGB);
  4720. cmsCloseProfile(ContextID, hXYZ);
  4721. cmsCloseProfile(ContextID, hLab);
  4722. MaxErr = 0;
  4723. // Xform 1 goes from 8 bits to XYZ,
  4724. rc = CheckOneRGB_f(ContextID, xform1, 1, 1, 1, 0.0002927, 0.0003035, 0.000250, 0.0001);
  4725. rc &= CheckOneRGB_f(ContextID, xform1, 127, 127, 127, 0.2046329, 0.212230, 0.175069, 0.0001);
  4726. rc &= CheckOneRGB_f(ContextID, xform1, 12, 13, 15, 0.0038364, 0.0039928, 0.003853, 0.0001);
  4727. rc &= CheckOneRGB_f(ContextID, xform1, 128, 0, 0, 0.0941240, 0.0480256, 0.003005, 0.0001);
  4728. rc &= CheckOneRGB_f(ContextID, xform1, 190, 25, 210, 0.3204592, 0.1605926, 0.468213, 0.0001);
  4729. // Xform 2 goes from 8 bits to Lab, we allow 0.01 error max
  4730. rc &= CheckOneRGB_f(ContextID, xform2, 1, 1, 1, 0.2741748, 0, 0, 0.01);
  4731. rc &= CheckOneRGB_f(ContextID, xform2, 127, 127, 127, 53.192776, 0, 0, 0.01);
  4732. rc &= CheckOneRGB_f(ContextID, xform2, 190, 25, 210, 47.052136, 74.565610, -56.883274, 0.01);
  4733. rc &= CheckOneRGB_f(ContextID, xform2, 128, 0, 0, 26.164701, 48.478171, 39.4384713, 0.01);
  4734. cmsDeleteTransform(ContextID, xform1);
  4735. cmsDeleteTransform(ContextID, xform2);
  4736. return rc;
  4737. }
  4738. // ---------------------------------------------------
  4739. static
  4740. cmsBool GetProfileRGBPrimaries(cmsContext ContextID,
  4741. cmsHPROFILE hProfile,
  4742. cmsCIEXYZTRIPLE *result,
  4743. cmsUInt32Number intent)
  4744. {
  4745. cmsHPROFILE hXYZ;
  4746. cmsHTRANSFORM hTransform;
  4747. cmsFloat64Number rgb[3][3] = {{1., 0., 0.},
  4748. {0., 1., 0.},
  4749. {0., 0., 1.}};
  4750. hXYZ = cmsCreateXYZProfile(ContextID);
  4751. if (hXYZ == NULL) return FALSE;
  4752. hTransform = cmsCreateTransform(ContextID, hProfile, TYPE_RGB_DBL, hXYZ, TYPE_XYZ_DBL,
  4753. intent, cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
  4754. cmsCloseProfile(ContextID, hXYZ);
  4755. if (hTransform == NULL) return FALSE;
  4756. cmsDoTransform(ContextID, hTransform, rgb, result, 3);
  4757. cmsDeleteTransform(ContextID, hTransform);
  4758. return TRUE;
  4759. }
  4760. static
  4761. int CheckRGBPrimaries(cmsContext ContextID)
  4762. {
  4763. cmsHPROFILE hsRGB;
  4764. cmsCIEXYZTRIPLE tripXYZ;
  4765. cmsCIExyYTRIPLE tripxyY;
  4766. cmsBool result;
  4767. cmsSetAdaptationState(ContextID, 0);
  4768. hsRGB = cmsCreate_sRGBProfile(ContextID);
  4769. if (!hsRGB) return 0;
  4770. result = GetProfileRGBPrimaries(ContextID, hsRGB, &tripXYZ,
  4771. INTENT_ABSOLUTE_COLORIMETRIC);
  4772. cmsCloseProfile(ContextID, hsRGB);
  4773. if (!result) return 0;
  4774. cmsXYZ2xyY(ContextID, &tripxyY.Red, &tripXYZ.Red);
  4775. cmsXYZ2xyY(ContextID, &tripxyY.Green, &tripXYZ.Green);
  4776. cmsXYZ2xyY(ContextID, &tripxyY.Blue, &tripXYZ.Blue);
  4777. /* valus were taken from
  4778. http://en.wikipedia.org/wiki/RGB_color_spaces#Specifications */
  4779. if (!IsGoodFixed15_16("xRed", tripxyY.Red.x, 0.64) ||
  4780. !IsGoodFixed15_16("yRed", tripxyY.Red.y, 0.33) ||
  4781. !IsGoodFixed15_16("xGreen", tripxyY.Green.x, 0.30) ||
  4782. !IsGoodFixed15_16("yGreen", tripxyY.Green.y, 0.60) ||
  4783. !IsGoodFixed15_16("xBlue", tripxyY.Blue.x, 0.15) ||
  4784. !IsGoodFixed15_16("yBlue", tripxyY.Blue.y, 0.06)) {
  4785. Fail("One or more primaries are wrong.");
  4786. return FALSE;
  4787. }
  4788. return TRUE;
  4789. }
  4790. // -----------------------------------------------------------------------------------------------------------------
  4791. // This function will check CMYK -> CMYK transforms. It uses FOGRA29 and SWOP ICC profiles
  4792. static
  4793. cmsInt32Number CheckCMYK(cmsContext ContextID, cmsInt32Number Intent, const char *Profile1, const char* Profile2)
  4794. {
  4795. cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, Profile1, "r");
  4796. cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, Profile2, "r");
  4797. cmsHTRANSFORM xform, swop_lab, fogra_lab;
  4798. cmsFloat32Number CMYK1[4], CMYK2[4];
  4799. cmsCIELab Lab1, Lab2;
  4800. cmsHPROFILE hLab;
  4801. cmsFloat64Number DeltaL, Max;
  4802. cmsInt32Number i;
  4803. hLab = cmsCreateLab4Profile(ContextID, NULL);
  4804. xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, Intent, 0);
  4805. swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, Intent, 0);
  4806. fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, Intent, 0);
  4807. Max = 0;
  4808. for (i=0; i <= 100; i++) {
  4809. CMYK1[0] = 10;
  4810. CMYK1[1] = 20;
  4811. CMYK1[2] = 30;
  4812. CMYK1[3] = (cmsFloat32Number) i;
  4813. cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
  4814. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4815. cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
  4816. DeltaL = fabs(Lab1.L - Lab2.L);
  4817. if (DeltaL > Max) Max = DeltaL;
  4818. }
  4819. cmsDeleteTransform(ContextID, xform);
  4820. xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, Intent, 0);
  4821. for (i=0; i <= 100; i++) {
  4822. CMYK1[0] = 10;
  4823. CMYK1[1] = 20;
  4824. CMYK1[2] = 30;
  4825. CMYK1[3] = (cmsFloat32Number) i;
  4826. cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
  4827. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4828. cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
  4829. DeltaL = fabs(Lab1.L - Lab2.L);
  4830. if (DeltaL > Max) Max = DeltaL;
  4831. }
  4832. cmsCloseProfile(ContextID, hSWOP);
  4833. cmsCloseProfile(ContextID, hFOGRA);
  4834. cmsCloseProfile(ContextID, hLab);
  4835. cmsDeleteTransform(ContextID, xform);
  4836. cmsDeleteTransform(ContextID, swop_lab);
  4837. cmsDeleteTransform(ContextID, fogra_lab);
  4838. return Max < 3.0;
  4839. }
  4840. static
  4841. cmsInt32Number CheckCMYKRoundtrip(cmsContext ContextID)
  4842. {
  4843. return CheckCMYK(ContextID, INTENT_RELATIVE_COLORIMETRIC, "test1.icc", "test1.icc");
  4844. }
  4845. static
  4846. cmsInt32Number CheckCMYKPerceptual(cmsContext ContextID)
  4847. {
  4848. return CheckCMYK(ContextID, INTENT_PERCEPTUAL, "test1.icc", "test2.icc");
  4849. }
  4850. #if 0
  4851. static
  4852. cmsInt32Number CheckCMYKRelCol(cmsContext ContextID)
  4853. {
  4854. return CheckCMYK(ContextID, INTENT_RELATIVE_COLORIMETRIC, "test1.icc", "test2.icc");
  4855. }
  4856. #endif
  4857. static
  4858. cmsInt32Number CheckKOnlyBlackPreserving(cmsContext ContextID)
  4859. {
  4860. cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  4861. cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
  4862. cmsHTRANSFORM xform, swop_lab, fogra_lab;
  4863. cmsFloat32Number CMYK1[4], CMYK2[4];
  4864. cmsCIELab Lab1, Lab2;
  4865. cmsHPROFILE hLab;
  4866. cmsFloat64Number DeltaL, Max;
  4867. cmsInt32Number i;
  4868. hLab = cmsCreateLab4Profile(ContextID, NULL);
  4869. xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, INTENT_PRESERVE_K_ONLY_PERCEPTUAL, 0);
  4870. swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  4871. fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  4872. Max = 0;
  4873. for (i=0; i <= 100; i++) {
  4874. CMYK1[0] = 0;
  4875. CMYK1[1] = 0;
  4876. CMYK1[2] = 0;
  4877. CMYK1[3] = (cmsFloat32Number) i;
  4878. // SWOP CMYK to Lab1
  4879. cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
  4880. // SWOP To FOGRA using black preservation
  4881. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4882. // Obtained FOGRA CMYK to Lab2
  4883. cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
  4884. // We care only on L*
  4885. DeltaL = fabs(Lab1.L - Lab2.L);
  4886. if (DeltaL > Max) Max = DeltaL;
  4887. }
  4888. cmsDeleteTransform(ContextID, xform);
  4889. // dL should be below 3.0
  4890. // Same, but FOGRA to SWOP
  4891. xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, INTENT_PRESERVE_K_ONLY_PERCEPTUAL, 0);
  4892. for (i=0; i <= 100; i++) {
  4893. CMYK1[0] = 0;
  4894. CMYK1[1] = 0;
  4895. CMYK1[2] = 0;
  4896. CMYK1[3] = (cmsFloat32Number) i;
  4897. cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
  4898. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4899. cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
  4900. DeltaL = fabs(Lab1.L - Lab2.L);
  4901. if (DeltaL > Max) Max = DeltaL;
  4902. }
  4903. cmsCloseProfile(ContextID, hSWOP);
  4904. cmsCloseProfile(ContextID, hFOGRA);
  4905. cmsCloseProfile(ContextID, hLab);
  4906. cmsDeleteTransform(ContextID, xform);
  4907. cmsDeleteTransform(ContextID, swop_lab);
  4908. cmsDeleteTransform(ContextID, fogra_lab);
  4909. return Max < 3.0;
  4910. }
  4911. static
  4912. cmsInt32Number CheckKPlaneBlackPreserving(cmsContext ContextID)
  4913. {
  4914. cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  4915. cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
  4916. cmsHTRANSFORM xform, swop_lab, fogra_lab;
  4917. cmsFloat32Number CMYK1[4], CMYK2[4];
  4918. cmsCIELab Lab1, Lab2;
  4919. cmsHPROFILE hLab;
  4920. cmsFloat64Number DeltaE, Max;
  4921. cmsInt32Number i;
  4922. hLab = cmsCreateLab4Profile(ContextID, NULL);
  4923. xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, INTENT_PERCEPTUAL, 0);
  4924. swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  4925. fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
  4926. Max = 0;
  4927. for (i=0; i <= 100; i++) {
  4928. CMYK1[0] = 0;
  4929. CMYK1[1] = 0;
  4930. CMYK1[2] = 0;
  4931. CMYK1[3] = (cmsFloat32Number) i;
  4932. cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
  4933. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4934. cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
  4935. DeltaE = cmsDeltaE(ContextID, &Lab1, &Lab2);
  4936. if (DeltaE > Max) Max = DeltaE;
  4937. }
  4938. cmsDeleteTransform(ContextID, xform);
  4939. xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, INTENT_PRESERVE_K_PLANE_PERCEPTUAL, 0);
  4940. for (i=0; i <= 100; i++) {
  4941. CMYK1[0] = 30;
  4942. CMYK1[1] = 20;
  4943. CMYK1[2] = 10;
  4944. CMYK1[3] = (cmsFloat32Number) i;
  4945. cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
  4946. cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
  4947. cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
  4948. DeltaE = cmsDeltaE(ContextID, &Lab1, &Lab2);
  4949. if (DeltaE > Max) Max = DeltaE;
  4950. }
  4951. cmsDeleteTransform(ContextID, xform);
  4952. cmsCloseProfile(ContextID, hSWOP);
  4953. cmsCloseProfile(ContextID, hFOGRA);
  4954. cmsCloseProfile(ContextID, hLab);
  4955. cmsDeleteTransform(ContextID, swop_lab);
  4956. cmsDeleteTransform(ContextID, fogra_lab);
  4957. return Max < 30.0;
  4958. }
  4959. // ------------------------------------------------------------------------------------------------------
  4960. static
  4961. cmsInt32Number CheckProofingXFORMFloat(cmsContext ContextID)
  4962. {
  4963. cmsHPROFILE hAbove;
  4964. cmsHTRANSFORM xform;
  4965. cmsInt32Number rc;
  4966. hAbove = Create_AboveRGB(ContextID);
  4967. xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, hAbove,
  4968. INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_SOFTPROOFING);
  4969. cmsCloseProfile(ContextID, hAbove);
  4970. rc = CheckFloatlinearXFORM(ContextID, xform, 3);
  4971. cmsDeleteTransform(ContextID, xform);
  4972. return rc;
  4973. }
  4974. static
  4975. cmsInt32Number CheckProofingXFORM16(cmsContext ContextID)
  4976. {
  4977. cmsHPROFILE hAbove;
  4978. cmsHTRANSFORM xform;
  4979. cmsInt32Number rc;
  4980. hAbove = Create_AboveRGB(ContextID);
  4981. xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hAbove,
  4982. INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_SOFTPROOFING|cmsFLAGS_NOCACHE);
  4983. cmsCloseProfile(ContextID, hAbove);
  4984. rc = Check16linearXFORM(ContextID, xform, 3);
  4985. cmsDeleteTransform(ContextID, xform);
  4986. return rc;
  4987. }
  4988. static
  4989. cmsInt32Number CheckGamutCheck(cmsContext ContextID)
  4990. {
  4991. cmsHPROFILE hSRGB, hAbove;
  4992. cmsHTRANSFORM xform;
  4993. cmsInt32Number rc;
  4994. cmsUInt16Number Alarm[16] = { 0xDEAD, 0xBABE, 0xFACE };
  4995. // Set alarm codes to fancy values so we could check the out of gamut condition
  4996. cmsSetAlarmCodes(ContextID, Alarm);
  4997. // Create the profiles
  4998. hSRGB = cmsCreate_sRGBProfile(ContextID);
  4999. hAbove = Create_AboveRGB(ContextID);
  5000. if (hSRGB == NULL || hAbove == NULL) return 0; // Failed
  5001. SubTest("Gamut check on floating point");
  5002. // Create a gamut checker in the same space. No value should be out of gamut
  5003. xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, hAbove,
  5004. INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK);
  5005. if (!CheckFloatlinearXFORM(ContextID, xform, 3)) {
  5006. cmsCloseProfile(ContextID, hSRGB);
  5007. cmsCloseProfile(ContextID, hAbove);
  5008. cmsDeleteTransform(ContextID, xform);
  5009. Fail("Gamut check on same profile failed");
  5010. return 0;
  5011. }
  5012. cmsDeleteTransform(ContextID, xform);
  5013. SubTest("Gamut check on 16 bits");
  5014. xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hSRGB,
  5015. INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK);
  5016. cmsCloseProfile(ContextID, hSRGB);
  5017. cmsCloseProfile(ContextID, hAbove);
  5018. rc = Check16linearXFORM(ContextID, xform, 3);
  5019. cmsDeleteTransform(ContextID, xform);
  5020. return rc;
  5021. }
  5022. // -------------------------------------------------------------------------------------------------------------------
  5023. static
  5024. cmsInt32Number CheckBlackPoint(cmsContext ContextID)
  5025. {
  5026. cmsHPROFILE hProfile;
  5027. cmsCIEXYZ Black;
  5028. cmsCIELab Lab;
  5029. hProfile = cmsOpenProfileFromFile(ContextID, "test5.icc", "r");
  5030. cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
  5031. cmsCloseProfile(ContextID, hProfile);
  5032. hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  5033. cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
  5034. cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
  5035. cmsCloseProfile(ContextID, hProfile);
  5036. hProfile = cmsOpenProfileFromFile(ContextID, "lcms2cmyk.icc", "r");
  5037. cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
  5038. cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
  5039. cmsCloseProfile(ContextID, hProfile);
  5040. hProfile = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
  5041. cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
  5042. cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
  5043. cmsCloseProfile(ContextID, hProfile);
  5044. hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  5045. cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_PERCEPTUAL, 0);
  5046. cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
  5047. cmsCloseProfile(ContextID, hProfile);
  5048. return 1;
  5049. }
  5050. static
  5051. cmsInt32Number CheckOneTAC(cmsContext ContextID, cmsFloat64Number InkLimit)
  5052. {
  5053. cmsHPROFILE h;
  5054. cmsFloat64Number d;
  5055. h =CreateFakeCMYK(ContextID, InkLimit, TRUE);
  5056. cmsSaveProfileToFile(ContextID, h, "lcmstac.icc");
  5057. cmsCloseProfile(ContextID, h);
  5058. h = cmsOpenProfileFromFile(ContextID, "lcmstac.icc", "r");
  5059. d = cmsDetectTAC(ContextID, h);
  5060. cmsCloseProfile(ContextID, h);
  5061. remove("lcmstac.icc");
  5062. if (fabs(d - InkLimit) > 5) return 0;
  5063. return 1;
  5064. }
  5065. static
  5066. cmsInt32Number CheckTAC(cmsContext ContextID)
  5067. {
  5068. if (!CheckOneTAC(ContextID, 180)) return 0;
  5069. if (!CheckOneTAC(ContextID, 220)) return 0;
  5070. if (!CheckOneTAC(ContextID, 286)) return 0;
  5071. if (!CheckOneTAC(ContextID, 310)) return 0;
  5072. if (!CheckOneTAC(ContextID, 330)) return 0;
  5073. return 1;
  5074. }
  5075. // -------------------------------------------------------------------------------------------------------
  5076. #define NPOINTS_IT8 10 // (17*17*17*17)
  5077. static
  5078. cmsInt32Number CheckCGATS(cmsContext ContextID)
  5079. {
  5080. cmsHANDLE it8;
  5081. cmsInt32Number i;
  5082. SubTest("IT8 creation");
  5083. it8 = cmsIT8Alloc(ContextID);
  5084. if (it8 == NULL) return 0;
  5085. cmsIT8SetSheetType(ContextID, it8, "LCMS/TESTING");
  5086. cmsIT8SetPropertyStr(ContextID, it8, "ORIGINATOR", "1 2 3 4");
  5087. cmsIT8SetPropertyUncooked(ContextID, it8, "DESCRIPTOR", "1234");
  5088. cmsIT8SetPropertyStr(ContextID, it8, "MANUFACTURER", "3");
  5089. cmsIT8SetPropertyDbl(ContextID, it8, "CREATED", 4);
  5090. cmsIT8SetPropertyDbl(ContextID, it8, "SERIAL", 5);
  5091. cmsIT8SetPropertyHex(ContextID, it8, "MATERIAL", 0x123);
  5092. cmsIT8SetPropertyDbl(ContextID, it8, "NUMBER_OF_SETS", NPOINTS_IT8);
  5093. cmsIT8SetPropertyDbl(ContextID, it8, "NUMBER_OF_FIELDS", 4);
  5094. cmsIT8SetDataFormat(ContextID, it8, 0, "SAMPLE_ID");
  5095. cmsIT8SetDataFormat(ContextID, it8, 1, "RGB_R");
  5096. cmsIT8SetDataFormat(ContextID, it8, 2, "RGB_G");
  5097. cmsIT8SetDataFormat(ContextID, it8, 3, "RGB_B");
  5098. SubTest("Table creation");
  5099. for (i=0; i < NPOINTS_IT8; i++) {
  5100. char Patch[20];
  5101. sprintf(Patch, "P%d", i);
  5102. cmsIT8SetDataRowCol(ContextID, it8, i, 0, Patch);
  5103. cmsIT8SetDataRowColDbl(ContextID, it8, i, 1, i);
  5104. cmsIT8SetDataRowColDbl(ContextID, it8, i, 2, i);
  5105. cmsIT8SetDataRowColDbl(ContextID, it8, i, 3, i);
  5106. }
  5107. SubTest("Save to file");
  5108. cmsIT8SaveToFile(ContextID, it8, "TEST.IT8");
  5109. cmsIT8Free(ContextID, it8);
  5110. SubTest("Load from file");
  5111. it8 = cmsIT8LoadFromFile(ContextID, "TEST.IT8");
  5112. if (it8 == NULL) return 0;
  5113. SubTest("Save again file");
  5114. cmsIT8SaveToFile(ContextID, it8, "TEST.IT8");
  5115. cmsIT8Free(ContextID, it8);
  5116. SubTest("Load from file (II)");
  5117. it8 = cmsIT8LoadFromFile(ContextID, "TEST.IT8");
  5118. if (it8 == NULL) return 0;
  5119. SubTest("Change prop value");
  5120. if (cmsIT8GetPropertyDbl(ContextID, it8, "DESCRIPTOR") != 1234) {
  5121. return 0;
  5122. }
  5123. cmsIT8SetPropertyDbl(ContextID, it8, "DESCRIPTOR", 5678);
  5124. if (cmsIT8GetPropertyDbl(ContextID, it8, "DESCRIPTOR") != 5678) {
  5125. return 0;
  5126. }
  5127. SubTest("Positive numbers");
  5128. if (cmsIT8GetDataDbl(ContextID, it8, "P3", "RGB_G") != 3) {
  5129. return 0;
  5130. }
  5131. SubTest("Positive exponent numbers");
  5132. cmsIT8SetPropertyDbl(ContextID, it8, "DBL_PROP", 123E+12);
  5133. if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_PROP") - 123E+12) > 1 ) {
  5134. return 0;
  5135. }
  5136. SubTest("Negative exponent numbers");
  5137. cmsIT8SetPropertyDbl(ContextID, it8, "DBL_PROP_NEG", 123E-45);
  5138. if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_PROP_NEG") - 123E-45) > 1E-45 ) {
  5139. return 0;
  5140. }
  5141. SubTest("Negative numbers");
  5142. cmsIT8SetPropertyDbl(ContextID, it8, "DBL_NEG_VAL", -123);
  5143. if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_NEG_VAL")) != -123 ) {
  5144. return 0;
  5145. }
  5146. cmsIT8Free(ContextID, it8);
  5147. remove("TEST.IT8");
  5148. return 1;
  5149. }
  5150. static
  5151. cmsInt32Number CheckCGATS2(cmsContext ContextID)
  5152. {
  5153. cmsHANDLE handle;
  5154. const cmsUInt8Number junk[] = { 0x0, 0xd, 0xd, 0xa, 0x20, 0xd, 0x20, 0x20, 0x20, 0x3a, 0x31, 0x3d, 0x3d, 0x3d, 0x3d };
  5155. handle = cmsIT8LoadFromMem(ContextID, (const void*)junk, sizeof(junk));
  5156. if (handle)
  5157. cmsIT8Free(ContextID, handle);
  5158. return 1;
  5159. }
  5160. static
  5161. cmsInt32Number CheckCGATS_Overflow(cmsContext ContextID)
  5162. {
  5163. cmsHANDLE handle;
  5164. const cmsUInt8Number junk[] = { "@\nA 1.e2147483648\n" };
  5165. handle = cmsIT8LoadFromMem(ContextID, (const void*)junk, sizeof(junk));
  5166. if (handle)
  5167. cmsIT8Free(ContextID, handle);
  5168. return 1;
  5169. }
  5170. // Create CSA/CRD
  5171. static
  5172. void GenerateCSA(cmsContext BuffThread, const char* cInProf, const char* FileName)
  5173. {
  5174. cmsHPROFILE hProfile;
  5175. cmsUInt32Number n;
  5176. char* Buffer;
  5177. FILE* o;
  5178. if (cInProf == NULL)
  5179. hProfile = cmsCreateLab4Profile(BuffThread, NULL);
  5180. else
  5181. hProfile = cmsOpenProfileFromFile(BuffThread, cInProf, "r");
  5182. n = cmsGetPostScriptCSA(BuffThread, hProfile, 0, 0, NULL, 0);
  5183. if (n == 0) return;
  5184. Buffer = (char*) _cmsMalloc(BuffThread, n + 1);
  5185. cmsGetPostScriptCSA(BuffThread, hProfile, 0, 0, Buffer, n);
  5186. Buffer[n] = 0;
  5187. if (FileName != NULL) {
  5188. o = fopen(FileName, "wb");
  5189. fwrite(Buffer, n, 1, o);
  5190. fclose(o);
  5191. }
  5192. _cmsFree(BuffThread, Buffer);
  5193. cmsCloseProfile(BuffThread, hProfile);
  5194. if (FileName != NULL)
  5195. remove(FileName);
  5196. }
  5197. static
  5198. void GenerateCRD(cmsContext BuffThread, const char* cOutProf, const char* FileName)
  5199. {
  5200. cmsHPROFILE hProfile;
  5201. cmsUInt32Number n;
  5202. char* Buffer;
  5203. cmsUInt32Number dwFlags = 0;
  5204. if (cOutProf == NULL)
  5205. hProfile = cmsCreateLab4Profile(BuffThread, NULL);
  5206. else
  5207. hProfile = cmsOpenProfileFromFile(BuffThread, cOutProf, "r");
  5208. n = cmsGetPostScriptCRD(BuffThread, hProfile, 0, dwFlags, NULL, 0);
  5209. if (n == 0) return;
  5210. Buffer = (char*) _cmsMalloc(BuffThread, n + 1);
  5211. cmsGetPostScriptCRD(BuffThread, hProfile, 0, dwFlags, Buffer, n);
  5212. Buffer[n] = 0;
  5213. if (FileName != NULL) {
  5214. FILE* o = fopen(FileName, "wb");
  5215. fwrite(Buffer, n, 1, o);
  5216. fclose(o);
  5217. }
  5218. _cmsFree(BuffThread, Buffer);
  5219. cmsCloseProfile(BuffThread, hProfile);
  5220. if (FileName != NULL)
  5221. remove(FileName);
  5222. }
  5223. static
  5224. cmsInt32Number CheckPostScript(cmsContext ContextID)
  5225. {
  5226. GenerateCSA(ContextID, "test5.icc", "sRGB_CSA.ps");
  5227. GenerateCSA(ContextID, "aRGBlcms2.icc", "aRGB_CSA.ps");
  5228. GenerateCSA(ContextID, "test4.icc", "sRGBV4_CSA.ps");
  5229. GenerateCSA(ContextID, "test1.icc", "SWOP_CSA.ps");
  5230. GenerateCSA(ContextID, NULL, "Lab_CSA.ps");
  5231. GenerateCSA(ContextID, "graylcms2.icc", "gray_CSA.ps");
  5232. GenerateCRD(ContextID, "test5.icc", "sRGB_CRD.ps");
  5233. GenerateCRD(ContextID, "aRGBlcms2.icc", "aRGB_CRD.ps");
  5234. GenerateCRD(ContextID, NULL, "Lab_CRD.ps");
  5235. GenerateCRD(ContextID, "test1.icc", "SWOP_CRD.ps");
  5236. GenerateCRD(ContextID, "test4.icc", "sRGBV4_CRD.ps");
  5237. GenerateCRD(ContextID, "graylcms2.icc", "gray_CRD.ps");
  5238. return 1;
  5239. }
  5240. static
  5241. cmsInt32Number CheckGray(cmsContext ContextID, cmsHTRANSFORM xform, cmsUInt8Number g, double L)
  5242. {
  5243. cmsCIELab Lab;
  5244. cmsDoTransform(ContextID, xform, &g, &Lab, 1);
  5245. if (!IsGoodVal("a axis on gray", 0, Lab.a, 0.001)) return 0;
  5246. if (!IsGoodVal("b axis on gray", 0, Lab.b, 0.001)) return 0;
  5247. return IsGoodVal("Gray value", L, Lab.L, 0.01);
  5248. }
  5249. static
  5250. cmsInt32Number CheckInputGray(cmsContext ContextID)
  5251. {
  5252. cmsHPROFILE hGray = Create_Gray22(ContextID);
  5253. cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
  5254. cmsHTRANSFORM xform;
  5255. if (hGray == NULL || hLab == NULL) return 0;
  5256. xform = cmsCreateTransform(ContextID, hGray, TYPE_GRAY_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  5257. cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
  5258. if (!CheckGray(ContextID, xform, 0, 0)) return 0;
  5259. if (!CheckGray(ContextID, xform, 125, 52.768)) return 0;
  5260. if (!CheckGray(ContextID, xform, 200, 81.069)) return 0;
  5261. if (!CheckGray(ContextID, xform, 255, 100.0)) return 0;
  5262. cmsDeleteTransform(ContextID, xform);
  5263. return 1;
  5264. }
  5265. static
  5266. cmsInt32Number CheckLabInputGray(cmsContext ContextID)
  5267. {
  5268. cmsHPROFILE hGray = Create_GrayLab(ContextID);
  5269. cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
  5270. cmsHTRANSFORM xform;
  5271. if (hGray == NULL || hLab == NULL) return 0;
  5272. xform = cmsCreateTransform(ContextID, hGray, TYPE_GRAY_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  5273. cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
  5274. if (!CheckGray(ContextID, xform, 0, 0)) return 0;
  5275. if (!CheckGray(ContextID, xform, 125, 49.019)) return 0;
  5276. if (!CheckGray(ContextID, xform, 200, 78.431)) return 0;
  5277. if (!CheckGray(ContextID, xform, 255, 100.0)) return 0;
  5278. cmsDeleteTransform(ContextID, xform);
  5279. return 1;
  5280. }
  5281. static
  5282. cmsInt32Number CheckOutGray(cmsContext ContextID, cmsHTRANSFORM xform, double L, cmsUInt8Number g)
  5283. {
  5284. cmsCIELab Lab;
  5285. cmsUInt8Number g_out;
  5286. Lab.L = L;
  5287. Lab.a = 0;
  5288. Lab.b = 0;
  5289. cmsDoTransform(ContextID, xform, &Lab, &g_out, 1);
  5290. return IsGoodVal("Gray value", g, (double) g_out, 1);
  5291. }
  5292. static
  5293. cmsInt32Number CheckOutputGray(cmsContext ContextID)
  5294. {
  5295. cmsHPROFILE hGray = Create_Gray22(ContextID);
  5296. cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
  5297. cmsHTRANSFORM xform;
  5298. if (hGray == NULL || hLab == NULL) return 0;
  5299. xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_DBL, hGray, TYPE_GRAY_8, INTENT_RELATIVE_COLORIMETRIC, 0);
  5300. cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
  5301. if (!CheckOutGray(ContextID, xform, 0, 0)) return 0;
  5302. if (!CheckOutGray(ContextID, xform, 100, 255)) return 0;
  5303. if (!CheckOutGray(ContextID, xform, 20, 52)) return 0;
  5304. if (!CheckOutGray(ContextID, xform, 50, 118)) return 0;
  5305. cmsDeleteTransform(ContextID, xform);
  5306. return 1;
  5307. }
  5308. static
  5309. cmsInt32Number CheckLabOutputGray(cmsContext ContextID)
  5310. {
  5311. cmsHPROFILE hGray = Create_GrayLab(ContextID);
  5312. cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
  5313. cmsHTRANSFORM xform;
  5314. cmsInt32Number i;
  5315. if (hGray == NULL || hLab == NULL) return 0;
  5316. xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_DBL, hGray, TYPE_GRAY_8, INTENT_RELATIVE_COLORIMETRIC, 0);
  5317. cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
  5318. if (!CheckOutGray(ContextID, xform, 0, 0)) return 0;
  5319. if (!CheckOutGray(ContextID, xform, 100, 255)) return 0;
  5320. for (i=0; i < 100; i++) {
  5321. cmsUInt8Number g;
  5322. g = (cmsUInt8Number) floor(i * 255.0 / 100.0 + 0.5);
  5323. if (!CheckOutGray(ContextID, xform, i, g)) return 0;
  5324. }
  5325. cmsDeleteTransform(ContextID, xform);
  5326. return 1;
  5327. }
  5328. static
  5329. cmsInt32Number CheckV4gamma(cmsContext ContextID)
  5330. {
  5331. cmsHPROFILE h;
  5332. cmsUInt16Number Lin[] = {0, 0xffff};
  5333. cmsToneCurve*g = cmsBuildTabulatedToneCurve16(ContextID, 2, Lin);
  5334. h = cmsOpenProfileFromFile(ContextID, "v4gamma.icc", "w");
  5335. if (h == NULL) return 0;
  5336. cmsSetProfileVersion(ContextID, h, 4.3);
  5337. if (!cmsWriteTag(ContextID, h, cmsSigGrayTRCTag, g)) return 0;
  5338. cmsCloseProfile(ContextID, h);
  5339. cmsFreeToneCurve(ContextID, g);
  5340. remove("v4gamma.icc");
  5341. return 1;
  5342. }
  5343. // cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname);
  5344. // Gamut descriptor routines
  5345. static
  5346. cmsInt32Number CheckGBD(cmsContext ContextID)
  5347. {
  5348. cmsCIELab Lab;
  5349. cmsHANDLE h;
  5350. cmsInt32Number L, a, b;
  5351. cmsUInt32Number r1, g1, b1;
  5352. cmsHPROFILE hLab, hsRGB;
  5353. cmsHTRANSFORM xform;
  5354. h = cmsGBDAlloc(ContextID);
  5355. if (h == NULL) return 0;
  5356. // Fill all Lab gamut as valid
  5357. SubTest("Filling RAW gamut");
  5358. for (L=0; L <= 100; L += 10)
  5359. for (a = -128; a <= 128; a += 5)
  5360. for (b = -128; b <= 128; b += 5) {
  5361. Lab.L = L;
  5362. Lab.a = a;
  5363. Lab.b = b;
  5364. if (!cmsGDBAddPoint(ContextID, h, &Lab)) return 0;
  5365. }
  5366. // Complete boundaries
  5367. SubTest("computing Lab gamut");
  5368. if (!cmsGDBCompute(ContextID, h, 0)) return 0;
  5369. // All points should be inside gamut
  5370. SubTest("checking Lab gamut");
  5371. for (L=10; L <= 90; L += 25)
  5372. for (a = -120; a <= 120; a += 25)
  5373. for (b = -120; b <= 120; b += 25) {
  5374. Lab.L = L;
  5375. Lab.a = a;
  5376. Lab.b = b;
  5377. if (!cmsGDBCheckPoint(ContextID, h, &Lab)) {
  5378. return 0;
  5379. }
  5380. }
  5381. cmsGBDFree(ContextID, h);
  5382. // Now for sRGB
  5383. SubTest("checking sRGB gamut");
  5384. h = cmsGBDAlloc(ContextID);
  5385. hsRGB = cmsCreate_sRGBProfile(ContextID);
  5386. hLab = cmsCreateLab4Profile(ContextID, NULL);
  5387. xform = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE);
  5388. cmsCloseProfile(ContextID, hsRGB); cmsCloseProfile(ContextID, hLab);
  5389. for (r1=0; r1 < 256; r1 += 5) {
  5390. for (g1=0; g1 < 256; g1 += 5)
  5391. for (b1=0; b1 < 256; b1 += 5) {
  5392. cmsUInt8Number rgb[3];
  5393. rgb[0] = (cmsUInt8Number) r1;
  5394. rgb[1] = (cmsUInt8Number) g1;
  5395. rgb[2] = (cmsUInt8Number) b1;
  5396. cmsDoTransform(ContextID, xform, rgb, &Lab, 1);
  5397. // if (fabs(Lab.b) < 20 && Lab.a > 0) continue;
  5398. if (!cmsGDBAddPoint(ContextID, h, &Lab)) {
  5399. cmsGBDFree(ContextID, h);
  5400. return 0;
  5401. }
  5402. }
  5403. }
  5404. if (!cmsGDBCompute(ContextID, h, 0)) return 0;
  5405. // cmsGBDdumpVRML(h, "c:\\colormaps\\lab.wrl");
  5406. for (r1=10; r1 < 200; r1 += 10) {
  5407. for (g1=10; g1 < 200; g1 += 10)
  5408. for (b1=10; b1 < 200; b1 += 10) {
  5409. cmsUInt8Number rgb[3];
  5410. rgb[0] = (cmsUInt8Number) r1;
  5411. rgb[1] = (cmsUInt8Number) g1;
  5412. rgb[2] = (cmsUInt8Number) b1;
  5413. cmsDoTransform(ContextID, xform, rgb, &Lab, 1);
  5414. if (!cmsGDBCheckPoint(ContextID, h, &Lab)) {
  5415. cmsDeleteTransform(ContextID, xform);
  5416. cmsGBDFree(ContextID, h);
  5417. return 0;
  5418. }
  5419. }
  5420. }
  5421. cmsDeleteTransform(ContextID, xform);
  5422. cmsGBDFree(ContextID, h);
  5423. SubTest("checking LCh chroma ring");
  5424. h = cmsGBDAlloc(ContextID);
  5425. for (r1=0; r1 < 360; r1++) {
  5426. cmsCIELCh LCh;
  5427. LCh.L = 70;
  5428. LCh.C = 60;
  5429. LCh.h = r1;
  5430. cmsLCh2Lab(ContextID, &Lab, &LCh);
  5431. if (!cmsGDBAddPoint(ContextID, h, &Lab)) {
  5432. cmsGBDFree(ContextID, h);
  5433. return 0;
  5434. }
  5435. }
  5436. if (!cmsGDBCompute(ContextID, h, 0)) return 0;
  5437. cmsGBDFree(ContextID, h);
  5438. return 1;
  5439. }
  5440. static
  5441. int CheckMD5(cmsContext ContextID)
  5442. {
  5443. cmsHPROFILE pProfile = cmsOpenProfileFromFile(ContextID, "sRGBlcms2.icc", "r");
  5444. cmsProfileID ProfileID1, ProfileID2, ProfileID3, ProfileID4;
  5445. if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile, ProfileID1.ID8);
  5446. if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile,ProfileID2.ID8);
  5447. cmsCloseProfile(ContextID, pProfile);
  5448. pProfile = cmsOpenProfileFromFile(ContextID, "sRGBlcms2.icc", "r");
  5449. h =(_cmsICCPROFILE*) pProfile;
  5450. if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile, ProfileID3.ID8);
  5451. if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile,ProfileID4.ID8);
  5452. cmsCloseProfile(ContextID, pProfile);
  5453. return ((memcmp(ProfileID1.ID8, ProfileID3.ID8, sizeof(ProfileID1)) == 0) &&
  5454. (memcmp(ProfileID2.ID8, ProfileID4.ID8, sizeof(ProfileID2)) == 0));
  5455. }
  5456. static
  5457. int CheckLinking(cmsContext ContextID)
  5458. {
  5459. cmsHPROFILE h;
  5460. cmsPipeline * pipeline;
  5461. cmsStage *stageBegin, *stageEnd;
  5462. // Create a CLUT based profile
  5463. h = cmsCreateInkLimitingDeviceLink(ContextID, cmsSigCmykData, 150);
  5464. // link a second tag
  5465. cmsLinkTag(ContextID, h, cmsSigAToB1Tag, cmsSigAToB0Tag);
  5466. // Save the linked devicelink
  5467. if (!cmsSaveProfileToFile(ContextID, h, "lcms2link.icc")) return 0;
  5468. cmsCloseProfile(ContextID, h);
  5469. // Now open the profile and read the pipeline
  5470. h = cmsOpenProfileFromFile(ContextID, "lcms2link.icc", "r");
  5471. if (h == NULL) return 0;
  5472. pipeline = (cmsPipeline*) cmsReadTag(ContextID, h, cmsSigAToB1Tag);
  5473. if (pipeline == NULL)
  5474. {
  5475. return 0;
  5476. }
  5477. pipeline = cmsPipelineDup(ContextID, pipeline);
  5478. // extract stage from pipe line
  5479. cmsPipelineUnlinkStage(ContextID, pipeline, cmsAT_BEGIN, &stageBegin);
  5480. cmsPipelineUnlinkStage(ContextID, pipeline, cmsAT_END, &stageEnd);
  5481. cmsPipelineInsertStage(ContextID, pipeline, cmsAT_END, stageEnd);
  5482. cmsPipelineInsertStage(ContextID, pipeline, cmsAT_BEGIN, stageBegin);
  5483. if (cmsTagLinkedTo(ContextID, h, cmsSigAToB1Tag) != cmsSigAToB0Tag) return 0;
  5484. cmsWriteTag(ContextID, h, cmsSigAToB0Tag, pipeline);
  5485. cmsPipelineFree(ContextID, pipeline);
  5486. if (!cmsSaveProfileToFile(ContextID, h, "lcms2link2.icc")) return 0;
  5487. cmsCloseProfile(ContextID, h);
  5488. return 1;
  5489. }
  5490. // TestMPE
  5491. //
  5492. // Created by Paul Miller on 30/08/2016.
  5493. //
  5494. static
  5495. cmsHPROFILE IdentityMatrixProfile(cmsContext ctx, cmsColorSpaceSignature dataSpace)
  5496. {
  5497. cmsVEC3 zero = {{0,0,0}};
  5498. cmsMAT3 identity;
  5499. cmsPipeline* forward;
  5500. cmsPipeline* reverse;
  5501. cmsHPROFILE identityProfile = cmsCreateProfilePlaceholder(ctx);
  5502. cmsSetProfileVersion(ctx, identityProfile, 4.3);
  5503. cmsSetDeviceClass(ctx, identityProfile, cmsSigColorSpaceClass);
  5504. cmsSetColorSpace(ctx, identityProfile, dataSpace);
  5505. cmsSetPCS(ctx, identityProfile, cmsSigXYZData);
  5506. cmsSetHeaderRenderingIntent(ctx, identityProfile, INTENT_RELATIVE_COLORIMETRIC);
  5507. cmsWriteTag(ctx, identityProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ(ctx));
  5508. _cmsMAT3identity(ctx, &identity);
  5509. // build forward transform.... (RGB to PCS)
  5510. forward = cmsPipelineAlloc(ctx, 3, 3);
  5511. cmsPipelineInsertStage(ctx, forward, cmsAT_END, cmsStageAllocMatrix( ctx, 3, 3, (cmsFloat64Number*)&identity, (cmsFloat64Number*)&zero));
  5512. cmsWriteTag(ctx, identityProfile, cmsSigDToB1Tag, forward);
  5513. cmsPipelineFree(ctx, forward);
  5514. reverse = cmsPipelineAlloc(ctx, 3, 3);
  5515. cmsPipelineInsertStage(ctx, reverse, cmsAT_END, cmsStageAllocMatrix( ctx, 3, 3, (cmsFloat64Number*)&identity, (cmsFloat64Number*)&zero));
  5516. cmsWriteTag(ctx, identityProfile, cmsSigBToD1Tag, reverse);
  5517. cmsPipelineFree(ctx, reverse);
  5518. return identityProfile;
  5519. }
  5520. static
  5521. cmsInt32Number CheckFloatXYZ(cmsContext ctx)
  5522. {
  5523. cmsHPROFILE input;
  5524. cmsHPROFILE xyzProfile = cmsCreateXYZProfile(ctx);
  5525. cmsHTRANSFORM xform;
  5526. cmsFloat32Number in[4];
  5527. cmsFloat32Number out[4];
  5528. in[0] = 1.0;
  5529. in[1] = 1.0;
  5530. in[2] = 1.0;
  5531. in[3] = 0.5;
  5532. // RGB to XYZ
  5533. input = IdentityMatrixProfile(ctx, cmsSigRgbData);
  5534. xform = cmsCreateTransform(ctx, input, TYPE_RGB_FLT, xyzProfile, TYPE_XYZ_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  5535. cmsCloseProfile(ctx, input);
  5536. cmsDoTransform(ctx, xform, in, out, 1);
  5537. cmsDeleteTransform(ctx, xform);
  5538. if (!IsGoodVal("Float RGB->XYZ", in[0], out[0], FLOAT_PRECISSION) ||
  5539. !IsGoodVal("Float RGB->XYZ", in[1], out[1], FLOAT_PRECISSION) ||
  5540. !IsGoodVal("Float RGB->XYZ", in[2], out[2], FLOAT_PRECISSION))
  5541. return 0;
  5542. // XYZ to XYZ
  5543. input = IdentityMatrixProfile(ctx, cmsSigXYZData);
  5544. xform = cmsCreateTransform(ctx, input, TYPE_XYZ_FLT, xyzProfile, TYPE_XYZ_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  5545. cmsCloseProfile(ctx, input);
  5546. cmsDoTransform(ctx, xform, in, out, 1);
  5547. cmsDeleteTransform(ctx, xform);
  5548. if (!IsGoodVal("Float XYZ->XYZ", in[0], out[0], FLOAT_PRECISSION) ||
  5549. !IsGoodVal("Float XYZ->XYZ", in[1], out[1], FLOAT_PRECISSION) ||
  5550. !IsGoodVal("Float XYZ->XYZ", in[2], out[2], FLOAT_PRECISSION))
  5551. return 0;
  5552. input = IdentityMatrixProfile(ctx, cmsSigXYZData);
  5553. # define TYPE_XYZA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
  5554. xform = cmsCreateTransform(ctx, input, TYPE_XYZA_FLT, xyzProfile, TYPE_XYZA_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_COPY_ALPHA);
  5555. cmsCloseProfile(ctx, input);
  5556. cmsDoTransform(ctx, xform, in, out, 1);
  5557. cmsDeleteTransform(ctx, xform);
  5558. if (!IsGoodVal("Float XYZA->XYZA", in[0], out[0], FLOAT_PRECISSION) ||
  5559. !IsGoodVal("Float XYZA->XYZA", in[1], out[1], FLOAT_PRECISSION) ||
  5560. !IsGoodVal("Float XYZA->XYZA", in[2], out[2], FLOAT_PRECISSION) ||
  5561. !IsGoodVal("Float XYZA->XYZA", in[3], out[3], FLOAT_PRECISSION))
  5562. return 0;
  5563. // XYZ to RGB
  5564. input = IdentityMatrixProfile(ctx, cmsSigRgbData);
  5565. xform = cmsCreateTransform(ctx, xyzProfile, TYPE_XYZ_FLT, input, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  5566. cmsCloseProfile(ctx, input);
  5567. cmsDoTransform(ctx, xform, in, out, 1);
  5568. cmsDeleteTransform(ctx, xform);
  5569. if (!IsGoodVal("Float XYZ->RGB", in[0], out[0], FLOAT_PRECISSION) ||
  5570. !IsGoodVal("Float XYZ->RGB", in[1], out[1], FLOAT_PRECISSION) ||
  5571. !IsGoodVal("Float XYZ->RGB", in[2], out[2], FLOAT_PRECISSION))
  5572. return 0;
  5573. // Now the optimizer should remove a stage
  5574. // XYZ to RGB
  5575. input = IdentityMatrixProfile(ctx, cmsSigRgbData);
  5576. xform = cmsCreateTransform(ctx, input, TYPE_RGB_FLT, input, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
  5577. cmsCloseProfile(ctx, input);
  5578. cmsDoTransform(ctx, xform, in, out, 1);
  5579. cmsDeleteTransform(ctx, xform);
  5580. if (!IsGoodVal("Float RGB->RGB", in[0], out[0], FLOAT_PRECISSION) ||
  5581. !IsGoodVal("Float RGB->RGB", in[1], out[1], FLOAT_PRECISSION) ||
  5582. !IsGoodVal("Float RGB->RGB", in[2], out[2], FLOAT_PRECISSION))
  5583. return 0;
  5584. cmsCloseProfile(ctx, xyzProfile);
  5585. return 1;
  5586. }
  5587. /*
  5588. Bug reported
  5589. 1)
  5590. sRGB built-in V4.3 -> Lab identity built-in V4.3
  5591. Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
  5592. Input format: TYPE_RGBA_FLT
  5593. Output format: TYPE_LabA_FLT
  5594. 2) and back
  5595. Lab identity built-in V4.3 -> sRGB built-in V4.3
  5596. Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
  5597. Input format: TYPE_LabA_FLT
  5598. Output format: TYPE_RGBA_FLT
  5599. */
  5600. static
  5601. cmsInt32Number ChecksRGB2LabFLT(cmsContext ctx)
  5602. {
  5603. cmsHPROFILE hSRGB = cmsCreate_sRGBProfile(ctx);
  5604. cmsHPROFILE hLab = cmsCreateLab4Profile(ctx, NULL);
  5605. cmsHTRANSFORM xform1 = cmsCreateTransform(ctx, hSRGB, TYPE_RGBA_FLT, hLab, TYPE_LabA_FLT, 0, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
  5606. cmsHTRANSFORM xform2 = cmsCreateTransform(ctx, hLab, TYPE_LabA_FLT, hSRGB, TYPE_RGBA_FLT, 0, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
  5607. cmsFloat32Number RGBA1[4], RGBA2[4], LabA[4];
  5608. int i;
  5609. for (i = 0; i <= 100; i++)
  5610. {
  5611. RGBA1[0] = i / 100.0F;
  5612. RGBA1[1] = i / 100.0F;
  5613. RGBA1[2] = i / 100.0F;
  5614. RGBA1[3] = 0;
  5615. cmsDoTransform(ctx, xform1, RGBA1, LabA, 1);
  5616. cmsDoTransform(ctx, xform2, LabA, RGBA2, 1);
  5617. if (!IsGoodVal("Float RGB->RGB", RGBA1[0], RGBA2[0], FLOAT_PRECISSION) ||
  5618. !IsGoodVal("Float RGB->RGB", RGBA1[1], RGBA2[1], FLOAT_PRECISSION) ||
  5619. !IsGoodVal("Float RGB->RGB", RGBA1[2], RGBA2[2], FLOAT_PRECISSION))
  5620. return 0;
  5621. }
  5622. cmsDeleteTransform(ctx, xform1);
  5623. cmsDeleteTransform(ctx, xform2);
  5624. cmsCloseProfile(ctx, hSRGB);
  5625. cmsCloseProfile(ctx, hLab);
  5626. return 1;
  5627. }
  5628. /*
  5629. * parametric curve for Rec709
  5630. */
  5631. static
  5632. double Rec709(double L)
  5633. {
  5634. if (L <0.018) return 4.5*L;
  5635. else
  5636. {
  5637. double a = 1.099* pow(L, 0.45);
  5638. a = a - 0.099;
  5639. return a;
  5640. }
  5641. }
  5642. static
  5643. cmsInt32Number CheckParametricRec709(cmsContext ContextID)
  5644. {
  5645. cmsFloat64Number params[7];
  5646. cmsToneCurve* t;
  5647. int i;
  5648. params[0] = 0.45; /* y */
  5649. params[1] = pow(1.099, 1.0 / 0.45); /* a */
  5650. params[2] = 0.0; /* b */
  5651. params[3] = 4.5; /* c */
  5652. params[4] = 0.018; /* d */
  5653. params[5] = -0.099; /* e */
  5654. params[6] = 0.0; /* f */
  5655. t = cmsBuildParametricToneCurve (ContextID, 5, params);
  5656. for (i=0; i < 256; i++)
  5657. {
  5658. cmsFloat32Number n = (cmsFloat32Number) i / 255.0F;
  5659. cmsUInt16Number f1 = (cmsUInt16Number) floor(255.0 * cmsEvalToneCurveFloat(ContextID, t, n) + 0.5);
  5660. cmsUInt16Number f2 = (cmsUInt16Number) floor(255.0*Rec709((double) i / 255.0) + 0.5);
  5661. if (f1 != f2)
  5662. {
  5663. cmsFreeToneCurve(ContextID, t);
  5664. return 0;
  5665. }
  5666. }
  5667. cmsFreeToneCurve(ContextID, t);
  5668. return 1;
  5669. }
  5670. #define kNumPoints 10
  5671. typedef cmsFloat32Number(*Function)(cmsFloat32Number x);
  5672. static cmsFloat32Number StraightLine( cmsFloat32Number x)
  5673. {
  5674. return (cmsFloat32Number) (0.1 + 0.9 * x);
  5675. }
  5676. static cmsInt32Number TestCurve(cmsContext ContextID, const char* label, cmsToneCurve* curve, Function fn)
  5677. {
  5678. cmsInt32Number ok = 1;
  5679. int i;
  5680. for (i = 0; i < kNumPoints*3; i++) {
  5681. cmsFloat32Number x = (cmsFloat32Number)i / (kNumPoints*3 - 1);
  5682. cmsFloat32Number expectedY = fn(x);
  5683. cmsFloat32Number out = cmsEvalToneCurveFloat(ContextID, curve, x);
  5684. if (!IsGoodVal(label, expectedY, out, FLOAT_PRECISSION)) {
  5685. ok = 0;
  5686. }
  5687. }
  5688. return ok;
  5689. }
  5690. static
  5691. cmsInt32Number CheckFloatSamples(cmsContext ContextID)
  5692. {
  5693. cmsFloat32Number y[kNumPoints];
  5694. int i;
  5695. cmsToneCurve *curve;
  5696. cmsInt32Number ok;
  5697. for (i = 0; i < kNumPoints; i++) {
  5698. cmsFloat32Number x = (cmsFloat32Number)i / (kNumPoints-1);
  5699. y[i] = StraightLine(x);
  5700. }
  5701. curve = cmsBuildTabulatedToneCurveFloat(ContextID, kNumPoints, y);
  5702. ok = TestCurve(ContextID, "Float Samples", curve, StraightLine);
  5703. cmsFreeToneCurve(ContextID, curve);
  5704. return ok;
  5705. }
  5706. static
  5707. cmsInt32Number CheckFloatSegments(cmsContext ContextID)
  5708. {
  5709. cmsInt32Number ok = 1;
  5710. int i;
  5711. cmsToneCurve *curve;
  5712. cmsFloat32Number y[ kNumPoints];
  5713. // build a segmented curve with a sampled section...
  5714. cmsCurveSegment Seg[3];
  5715. // Initialize segmented curve part up to 0.1
  5716. Seg[0].x0 = -1e22f; // -infinity
  5717. Seg[0].x1 = 0.1f;
  5718. Seg[0].Type = 6; // Y = (a * X + b) ^ Gamma + c
  5719. Seg[0].Params[0] = 1.0f; // gamma
  5720. Seg[0].Params[1] = 0.9f; // a
  5721. Seg[0].Params[2] = 0.0f; // b
  5722. Seg[0].Params[3] = 0.1f; // c
  5723. Seg[0].Params[4] = 0.0f;
  5724. // From zero to 1
  5725. Seg[1].x0 = 0.1f;
  5726. Seg[1].x1 = 0.9f;
  5727. Seg[1].Type = 0;
  5728. Seg[1].nGridPoints = kNumPoints;
  5729. Seg[1].SampledPoints = y;
  5730. for (i = 0; i < kNumPoints; i++) {
  5731. cmsFloat32Number x = (cmsFloat32Number) (0.1 + ((cmsFloat32Number)i / (kNumPoints-1)) * (0.9 - 0.1));
  5732. y[i] = StraightLine(x);
  5733. }
  5734. // from 1 to +infinity
  5735. Seg[2].x0 = 0.9f;
  5736. Seg[2].x1 = 1e22f; // +infinity
  5737. Seg[2].Type = 6;
  5738. Seg[2].Params[0] = 1.0f;
  5739. Seg[2].Params[1] = 0.9f;
  5740. Seg[2].Params[2] = 0.0f;
  5741. Seg[2].Params[3] = 0.1f;
  5742. Seg[2].Params[4] = 0.0f;
  5743. curve = cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
  5744. ok = TestCurve(ContextID, "Float Segmented Curve", curve, StraightLine);
  5745. cmsFreeToneCurve(ContextID, curve);
  5746. return ok;
  5747. }
  5748. static
  5749. cmsInt32Number CheckReadRAW(cmsContext ContextID)
  5750. {
  5751. cmsInt32Number tag_size, tag_size1;
  5752. char buffer[37009];
  5753. cmsHPROFILE hProfile;
  5754. SubTest("RAW read on on-disk");
  5755. hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
  5756. if (hProfile == NULL)
  5757. return 0;
  5758. tag_size1 = cmsReadRawTag(ContextID, hProfile, cmsSigGamutTag, NULL, 0);
  5759. tag_size = cmsReadRawTag(ContextID, hProfile, cmsSigGamutTag, buffer, 37009);
  5760. cmsCloseProfile(ContextID, hProfile);
  5761. if (tag_size != 37009)
  5762. return 0;
  5763. if (tag_size1 != 37009)
  5764. return 0;
  5765. SubTest("RAW read on in-memory created profiles");
  5766. hProfile = cmsCreate_sRGBProfile(ContextID);
  5767. tag_size1 = cmsReadRawTag(ContextID, hProfile, cmsSigGreenColorantTag, NULL, 0);
  5768. tag_size = cmsReadRawTag(ContextID, hProfile, cmsSigGreenColorantTag, buffer, 20);
  5769. cmsCloseProfile(ContextID, hProfile);
  5770. if (tag_size != 20)
  5771. return 0;
  5772. if (tag_size1 != 20)
  5773. return 0;
  5774. return 1;
  5775. }
  5776. static
  5777. cmsInt32Number CheckMeta(cmsContext ContextID)
  5778. {
  5779. char *data;
  5780. cmsHANDLE dict;
  5781. cmsHPROFILE p;
  5782. cmsUInt32Number clen;
  5783. FILE *fp;
  5784. int rc;
  5785. /* open file */
  5786. p = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
  5787. if (p == NULL) return 0;
  5788. /* read dictionary, but don't do anything with the value */
  5789. //COMMENT OUT THE NEXT TWO LINES AND IT WORKS FINE!!!
  5790. dict = cmsReadTag(ContextID, p, cmsSigMetaTag);
  5791. if (dict == NULL) return 0;
  5792. /* serialize profile to memory */
  5793. rc = cmsSaveProfileToMem(ContextID, p, NULL, &clen);
  5794. if (!rc) return 0;
  5795. data = (char*) chknull(malloc(clen));
  5796. rc = cmsSaveProfileToMem(ContextID, p, data, &clen);
  5797. if (!rc) return 0;
  5798. /* write the memory blob to a file */
  5799. //NOTE: The crash does not happen if cmsSaveProfileToFile() is used */
  5800. fp = fopen("new.icc", "wb");
  5801. fwrite(data, 1, clen, fp);
  5802. fclose(fp);
  5803. free(data);
  5804. cmsCloseProfile(ContextID, p);
  5805. /* open newly created file and read metadata */
  5806. p = cmsOpenProfileFromFile(ContextID, "new.icc", "r");
  5807. //ERROR: Bad dictionary Name/Value
  5808. //ERROR: Corrupted tag 'meta'
  5809. //test: test.c:59: main: Assertion `dict' failed.
  5810. dict = cmsReadTag(ContextID, p, cmsSigMetaTag);
  5811. if (dict == NULL) return 0;
  5812. cmsCloseProfile(ContextID, p);
  5813. return 1;
  5814. }
  5815. // Bug on applying null transforms on floating point buffers
  5816. static
  5817. cmsInt32Number CheckFloatNULLxform(cmsContext ContextID)
  5818. {
  5819. int i;
  5820. cmsFloat32Number in[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  5821. cmsFloat32Number out[10];
  5822. cmsHTRANSFORM xform = cmsCreateTransform(ContextID, NULL, TYPE_GRAY_FLT, NULL, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NULLTRANSFORM);
  5823. if (xform == NULL) {
  5824. Fail("Unable to create float null transform");
  5825. return 0;
  5826. }
  5827. cmsDoTransform(ContextID, xform, in, out, 10);
  5828. cmsDeleteTransform(ContextID, xform);
  5829. for (i=0; i < 10; i++) {
  5830. if (!IsGoodVal("float nullxform", in[i], out[i], 0.001)) {
  5831. return 0;
  5832. }
  5833. }
  5834. return 1;
  5835. }
  5836. static
  5837. cmsInt32Number CheckRemoveTag(cmsContext ContextID)
  5838. {
  5839. cmsHPROFILE p;
  5840. cmsMLU *mlu;
  5841. int ret;
  5842. p = cmsCreate_sRGBProfile(ContextID);
  5843. /* set value */
  5844. mlu = cmsMLUalloc (ContextID, 1);
  5845. ret = cmsMLUsetASCII(ContextID, mlu, "en", "US", "bar");
  5846. if (!ret) return 0;
  5847. ret = cmsWriteTag(ContextID, p, cmsSigDeviceMfgDescTag, mlu);
  5848. if (!ret) return 0;
  5849. cmsMLUfree(ContextID, mlu);
  5850. /* remove the tag */
  5851. ret = cmsWriteTag(ContextID, p, cmsSigDeviceMfgDescTag, NULL);
  5852. if (!ret) return 0;
  5853. /* THIS EXPLODES */
  5854. cmsCloseProfile(ContextID, p);
  5855. return 1;
  5856. }
  5857. static
  5858. cmsInt32Number CheckMatrixSimplify(cmsContext ContextID)
  5859. {
  5860. cmsHPROFILE pIn;
  5861. cmsHPROFILE pOut;
  5862. cmsHTRANSFORM t;
  5863. unsigned char buf[3] = { 127, 32, 64 };
  5864. pIn = cmsCreate_sRGBProfile(ContextID);
  5865. pOut = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
  5866. if (pIn == NULL || pOut == NULL)
  5867. return 0;
  5868. t = cmsCreateTransform(ContextID, pIn, TYPE_RGB_8, pOut, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
  5869. cmsDoTransformStride(ContextID, t, buf, buf, 1, 1);
  5870. cmsDeleteTransform(ContextID, t);
  5871. cmsCloseProfile(ContextID, pIn);
  5872. cmsCloseProfile(ContextID, pOut);
  5873. return buf[0] == 144 && buf[1] == 0 && buf[2] == 69;
  5874. }
  5875. static
  5876. cmsInt32Number CheckTransformLineStride(cmsContext ContextID)
  5877. {
  5878. cmsHPROFILE pIn;
  5879. cmsHPROFILE pOut;
  5880. cmsHTRANSFORM t;
  5881. // Our buffer is formed by 4 RGB8 lines, each line is 2 pixels wide plus a padding of one byte
  5882. cmsUInt8Number buf1[]= { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
  5883. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
  5884. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
  5885. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, };
  5886. // Our buffer2 is formed by 4 RGBA lines, each line is 2 pixels wide plus a padding of one byte
  5887. cmsUInt8Number buf2[] = { 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
  5888. 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
  5889. 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
  5890. 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0};
  5891. // Our buffer3 is formed by 4 RGBA16 lines, each line is 2 pixels wide plus a padding of two bytes
  5892. cmsUInt16Number buf3[] = { 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
  5893. 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
  5894. 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
  5895. 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0 };
  5896. cmsUInt8Number out[1024];
  5897. memset(out, 0, sizeof(out));
  5898. pIn = cmsCreate_sRGBProfile(ContextID);
  5899. pOut = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
  5900. if (pIn == NULL || pOut == NULL)
  5901. return 0;
  5902. t = cmsCreateTransform(ContextID, pIn, TYPE_RGB_8, pOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
  5903. cmsDoTransformLineStride(ContextID, t, buf1, out, 2, 4, 7, 7, 0, 0);
  5904. cmsDeleteTransform(ContextID, t);
  5905. if (memcmp(out, buf1, sizeof(buf1)) != 0) {
  5906. Fail("Failed transform line stride on RGB8");
  5907. cmsCloseProfile(ContextID, pIn);
  5908. cmsCloseProfile(ContextID, pOut);
  5909. return 0;
  5910. }
  5911. memset(out, 0, sizeof(out));
  5912. t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_8, pOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
  5913. cmsDoTransformLineStride(ContextID, t, buf2, out, 2, 4, 9, 9, 0, 0);
  5914. cmsDeleteTransform(ContextID, t);
  5915. if (memcmp(out, buf2, sizeof(buf2)) != 0) {
  5916. cmsCloseProfile(ContextID, pIn);
  5917. cmsCloseProfile(ContextID, pOut);
  5918. Fail("Failed transform line stride on RGBA8");
  5919. return 0;
  5920. }
  5921. memset(out, 0, sizeof(out));
  5922. t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_16, pOut, TYPE_RGBA_16, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
  5923. cmsDoTransformLineStride(ContextID, t, buf3, out, 2, 4, 18, 18, 0, 0);
  5924. cmsDeleteTransform(ContextID, t);
  5925. if (memcmp(out, buf3, sizeof(buf3)) != 0) {
  5926. cmsCloseProfile(ContextID, pIn);
  5927. cmsCloseProfile(ContextID, pOut);
  5928. Fail("Failed transform line stride on RGBA16");
  5929. return 0;
  5930. }
  5931. memset(out, 0, sizeof(out));
  5932. // From 8 to 16
  5933. t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_8, pOut, TYPE_RGBA_16, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
  5934. cmsDoTransformLineStride(ContextID, t, buf2, out, 2, 4, 9, 18, 0, 0);
  5935. cmsDeleteTransform(ContextID, t);
  5936. if (memcmp(out, buf3, sizeof(buf3)) != 0) {
  5937. cmsCloseProfile(ContextID, pIn);
  5938. cmsCloseProfile(ContextID, pOut);
  5939. Fail("Failed transform line stride on RGBA16");
  5940. return 0;
  5941. }
  5942. cmsCloseProfile(ContextID, pIn);
  5943. cmsCloseProfile(ContextID, pOut);
  5944. return 1;
  5945. }
  5946. static
  5947. int CheckPlanar8opt(cmsContext ContextID)
  5948. {
  5949. cmsHPROFILE aboveRGB = Create_AboveRGB(ContextID);
  5950. cmsHPROFILE sRGB = cmsCreate_sRGBProfile(ContextID);
  5951. cmsHTRANSFORM transform = cmsCreateTransform(ContextID,
  5952. sRGB, TYPE_RGB_8_PLANAR,
  5953. aboveRGB, TYPE_RGB_8_PLANAR,
  5954. INTENT_PERCEPTUAL, 0);
  5955. cmsDeleteTransform(ContextID, transform);
  5956. cmsCloseProfile(ContextID, aboveRGB);
  5957. cmsCloseProfile(ContextID, sRGB);
  5958. return 1;
  5959. }
  5960. /**
  5961. * Bug reported & fixed. Thanks to Kornel Lesinski for spotting this.
  5962. */
  5963. static
  5964. int CheckSE(cmsContext ContextID)
  5965. {
  5966. cmsHPROFILE input_profile = Create_AboveRGB(ContextID);
  5967. cmsHPROFILE output_profile = cmsCreate_sRGBProfile(ContextID);
  5968. cmsHTRANSFORM tr = cmsCreateTransform(ContextID, input_profile, TYPE_RGBA_8, output_profile, TYPE_RGBA_16_SE, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_COPY_ALPHA);
  5969. cmsUInt8Number rgba[4] = { 40, 41, 41, 0xfa };
  5970. cmsUInt16Number out[4];
  5971. cmsDoTransform(ContextID, tr, rgba, out, 1);
  5972. cmsCloseProfile(ContextID, input_profile);
  5973. cmsCloseProfile(ContextID, output_profile);
  5974. cmsDeleteTransform(ContextID, tr);
  5975. if (out[0] != 0xf622 || out[1] != 0x7f24 || out[2] != 0x7f24)
  5976. return 0;
  5977. return 1;
  5978. }
  5979. /**
  5980. * Bug reported.
  5981. */
  5982. static
  5983. int CheckForgedMPE(cmsContext ContextID)
  5984. {
  5985. cmsUInt32Number i;
  5986. cmsHPROFILE srcProfile;
  5987. cmsHPROFILE dstProfile;
  5988. cmsColorSpaceSignature srcCS;
  5989. cmsUInt32Number nSrcComponents;
  5990. cmsUInt32Number srcFormat;
  5991. cmsUInt32Number intent = 0;
  5992. cmsUInt32Number flags = 0;
  5993. cmsHTRANSFORM hTransform;
  5994. cmsUInt8Number output[4];
  5995. srcProfile = cmsOpenProfileFromFile(ContextID, "bad_mpe.icc", "r");
  5996. if (!srcProfile)
  5997. return 0;
  5998. dstProfile = cmsCreate_sRGBProfile(ContextID);
  5999. if (!dstProfile) {
  6000. cmsCloseProfile(ContextID, srcProfile);
  6001. return 0;
  6002. }
  6003. srcCS = cmsGetColorSpace(ContextID, srcProfile);
  6004. nSrcComponents = cmsChannelsOfColorSpace(ContextID, srcCS);
  6005. if (srcCS == cmsSigLabData) {
  6006. srcFormat =
  6007. COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0);
  6008. }
  6009. else {
  6010. srcFormat =
  6011. COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1);
  6012. }
  6013. cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
  6014. hTransform = cmsCreateTransform(ContextID, srcProfile, srcFormat, dstProfile,
  6015. TYPE_BGR_8, intent, flags);
  6016. cmsCloseProfile(ContextID, srcProfile);
  6017. cmsCloseProfile(ContextID, dstProfile);
  6018. cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
  6019. // Should report error
  6020. if (!TrappedError) return 0;
  6021. TrappedError = FALSE;
  6022. // Transform should NOT be created
  6023. if (!hTransform) return 1;
  6024. // Never should reach here
  6025. if (T_BYTES(srcFormat) == 0) { // 0 means double
  6026. double input[128];
  6027. for (i = 0; i < nSrcComponents; i++)
  6028. input[i] = 0.5f;
  6029. cmsDoTransform(ContextID, hTransform, input, output, 1);
  6030. }
  6031. else {
  6032. cmsUInt8Number input[128];
  6033. for (i = 0; i < nSrcComponents; i++)
  6034. input[i] = 128;
  6035. cmsDoTransform(ContextID, hTransform, input, output, 1);
  6036. }
  6037. cmsDeleteTransform(ContextID, hTransform);
  6038. return 0;
  6039. }
  6040. /**
  6041. * What the self test is trying to do is creating a proofing transform
  6042. * with gamut check, so we can getting the coverage of one profile of
  6043. * another, i.e. to approximate the gamut intersection. e.g.
  6044. * Thanks to Richard Hughes for providing the test
  6045. */
  6046. static
  6047. int CheckProofingIntersection(cmsContext ContextID)
  6048. {
  6049. cmsHPROFILE profile_null, hnd1, hnd2;
  6050. cmsHTRANSFORM transform;
  6051. hnd1 = cmsCreate_sRGBProfile(ContextID);
  6052. hnd2 = Create_AboveRGB(ContextID);
  6053. profile_null = cmsCreateNULLProfile(ContextID);
  6054. transform = cmsCreateProofingTransform(ContextID,
  6055. hnd1,
  6056. TYPE_RGB_FLT,
  6057. profile_null,
  6058. TYPE_GRAY_FLT,
  6059. hnd2,
  6060. INTENT_ABSOLUTE_COLORIMETRIC,
  6061. INTENT_ABSOLUTE_COLORIMETRIC,
  6062. cmsFLAGS_GAMUTCHECK |
  6063. cmsFLAGS_SOFTPROOFING);
  6064. cmsCloseProfile(ContextID, hnd1);
  6065. cmsCloseProfile(ContextID, hnd2);
  6066. cmsCloseProfile(ContextID, profile_null);
  6067. // Failed?
  6068. if (transform == NULL) return 0;
  6069. cmsDeleteTransform(ContextID, transform);
  6070. return 1;
  6071. }
  6072. /**
  6073. * In 2.11: When I create a RGB profile, set the copyright data with an empty string,
  6074. * then call cmsMD5computeID on said profile, the program crashes.
  6075. */
  6076. static
  6077. int CheckEmptyMLUC(cmsContext context)
  6078. {
  6079. cmsCIExyY white = { 0.31271, 0.32902, 1.0 };
  6080. cmsCIExyYTRIPLE primaries =
  6081. {
  6082. .Red = { 0.640, 0.330, 1.0 },
  6083. .Green = { 0.300, 0.600, 1.0 },
  6084. .Blue = { 0.150, 0.060, 1.0 }
  6085. };
  6086. cmsFloat64Number parameters[10] = { 2.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  6087. cmsToneCurve* toneCurve = cmsBuildParametricToneCurve(context, 1, parameters);
  6088. cmsToneCurve* toneCurves[3] = { toneCurve, toneCurve, toneCurve };
  6089. cmsHPROFILE profile = cmsCreateRGBProfile(context, &white, &primaries, toneCurves);
  6090. cmsSetLogErrorHandler(context, FatalErrorQuit);
  6091. cmsFreeToneCurve(context, toneCurve);
  6092. // Set an empty copyright tag. This should log an error.
  6093. cmsMLU* mlu = cmsMLUalloc(context, 1);
  6094. cmsMLUsetASCII(context, mlu, "en", "AU", "");
  6095. cmsMLUsetWide(context, mlu, "en", "EN", L"");
  6096. cmsWriteTag(context, profile, cmsSigCopyrightTag, mlu);
  6097. cmsMLUfree(context, mlu);
  6098. // This will cause a crash after setting an empty copyright tag.
  6099. cmsMD5computeID(context, profile);
  6100. // Cleanup
  6101. cmsCloseProfile(context, profile);
  6102. return 1;
  6103. }
  6104. static
  6105. double distance(const cmsUInt16Number* a, const cmsUInt16Number* b)
  6106. {
  6107. double d1 = a[0] - b[0];
  6108. double d2 = a[1] - b[1];
  6109. double d3 = a[2] - b[2];
  6110. return sqrt(d1 * d1 + d2 * d2 + d3 * d3);
  6111. }
  6112. /**
  6113. * In 2.12, a report suggest that the built-in sRGB has roundtrip errors that makes color to move
  6114. * when roundtripping again and again
  6115. */
  6116. static
  6117. int Check_sRGB_Rountrips(cmsContext contextID)
  6118. {
  6119. cmsUInt16Number rgb[3], seed[3];
  6120. cmsCIELab Lab;
  6121. int i, r, g, b;
  6122. double err, maxErr;
  6123. cmsHPROFILE hsRGB = cmsCreate_sRGBProfile(contextID);
  6124. cmsHPROFILE hLab = cmsCreateLab4Profile(contextID, NULL);
  6125. cmsHTRANSFORM hBack = cmsCreateTransform(contextID, hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6126. cmsHTRANSFORM hForth = cmsCreateTransform(contextID, hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  6127. cmsCloseProfile(contextID, hLab);
  6128. cmsCloseProfile(contextID, hsRGB);
  6129. maxErr = 0.0;
  6130. for (r = 0; r <= 255; r += 16)
  6131. for (g = 0; g <= 255; g += 16)
  6132. for (b = 0; b <= 255; b += 16)
  6133. {
  6134. seed[0] = rgb[0] = (cmsUInt16Number) ((r << 8) | r);
  6135. seed[1] = rgb[1] = (cmsUInt16Number) ((g << 8) | g);
  6136. seed[2] = rgb[2] = (cmsUInt16Number) ((b << 8) | b);
  6137. for (i = 0; i < 50; i++)
  6138. {
  6139. cmsDoTransform(contextID, hForth, rgb, &Lab, 1);
  6140. cmsDoTransform(contextID, hBack, &Lab, rgb, 1);
  6141. }
  6142. err = distance(seed, rgb);
  6143. if (err > maxErr)
  6144. maxErr = err;
  6145. }
  6146. cmsDeleteTransform(contextID, hBack);
  6147. cmsDeleteTransform(contextID, hForth);
  6148. if (maxErr > 20.0)
  6149. {
  6150. printf("Maximum sRGB roundtrip error %f!\n", maxErr);
  6151. return 0;
  6152. }
  6153. return 1;
  6154. }
  6155. /**
  6156. * Check OKLab colorspace
  6157. */
  6158. static
  6159. int Check_OkLab(void)
  6160. {
  6161. cmsHPROFILE hOkLab = cmsCreate_OkLabProfile(NULL);
  6162. cmsHPROFILE hXYZ = cmsCreateXYZProfile();
  6163. cmsCIEXYZ xyz, xyz2;
  6164. cmsCIELab okLab;
  6165. #define TYPE_OKLAB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0))
  6166. cmsHTRANSFORM xform = cmsCreateTransform(hXYZ, TYPE_XYZ_DBL, hOkLab, TYPE_OKLAB_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  6167. cmsHTRANSFORM xform2 = cmsCreateTransform(hOkLab, TYPE_OKLAB_DBL, hXYZ, TYPE_XYZ_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
  6168. /**
  6169. * D50 should be converted to white by PCS definition
  6170. */
  6171. xyz.X = 0.9642; xyz.Y = 1.0000; xyz.Z = 0.8249;
  6172. cmsDoTransform(xform, &xyz, &okLab, 1);
  6173. cmsDoTransform(xform2, &okLab, &xyz2, 1);
  6174. xyz.X = 1.0; xyz.Y = 0.0; xyz.Z = 0.0;
  6175. cmsDoTransform(xform, &xyz, &okLab, 1);
  6176. cmsDoTransform(xform2, &okLab, &xyz2, 1);
  6177. xyz.X = 0.0; xyz.Y = 1.0; xyz.Z = 0.0;
  6178. cmsDoTransform(xform, &xyz, &okLab, 1);
  6179. cmsDoTransform(xform2, &okLab, &xyz2, 1);
  6180. xyz.X = 0.0; xyz.Y = 0.0; xyz.Z = 1.0;
  6181. cmsDoTransform(xform, &xyz, &okLab, 1);
  6182. cmsDoTransform(xform2, &okLab, &xyz2, 1);
  6183. xyz.X = 0.143046; xyz.Y = 0.060610; xyz.Z = 0.713913;
  6184. cmsDoTransform(xform, &xyz, &okLab, 1);
  6185. cmsDoTransform(xform2, &okLab, &xyz2, 1);
  6186. cmsDeleteTransform(xform);
  6187. cmsDeleteTransform(xform2);
  6188. cmsCloseProfile(hOkLab);
  6189. cmsCloseProfile(hXYZ);
  6190. return 1;
  6191. }
  6192. static
  6193. int Check_OkLab2(void)
  6194. {
  6195. #define TYPE_LABA_F32 (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
  6196. cmsUInt16Number rgb[3];
  6197. cmsFloat32Number lab[4];
  6198. cmsHPROFILE labProfile = cmsCreate_OkLabProfile(NULL);
  6199. cmsHPROFILE rgbProfile = cmsCreate_sRGBProfile();
  6200. cmsHTRANSFORM hBack = cmsCreateTransform(labProfile, TYPE_LABA_F32, rgbProfile, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6201. cmsHTRANSFORM hForth = cmsCreateTransform(rgbProfile, TYPE_RGB_16, labProfile, TYPE_LABA_F32, INTENT_RELATIVE_COLORIMETRIC, 0);
  6202. cmsCloseProfile(labProfile);
  6203. cmsCloseProfile(rgbProfile);
  6204. rgb[0] = 0;
  6205. rgb[1] = 0;
  6206. rgb[2] = 65535;
  6207. cmsDoTransform(hForth, rgb, &lab, 1);
  6208. cmsDoTransform(hBack, lab, &rgb, 1);
  6209. cmsDeleteTransform(hBack);
  6210. cmsDeleteTransform(hForth);
  6211. if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 65535) return 0;
  6212. return 1;
  6213. }
  6214. static
  6215. cmsHPROFILE createRgbGamma(cmsContext contextID, cmsFloat64Number g)
  6216. {
  6217. cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
  6218. cmsCIExyYTRIPLE Rec709Primaries = {
  6219. {0.6400, 0.3300, 1.0},
  6220. {0.3000, 0.6000, 1.0},
  6221. {0.1500, 0.0600, 1.0}
  6222. };
  6223. cmsToneCurve* Gamma[3];
  6224. cmsHPROFILE hRGB;
  6225. Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(contextID, g);
  6226. if (Gamma[0] == NULL) return NULL;
  6227. hRGB = cmsCreateRGBProfile(contextID, &D65, &Rec709Primaries, Gamma);
  6228. cmsFreeToneCurve(contextID, Gamma[0]);
  6229. return hRGB;
  6230. }
  6231. static
  6232. int CheckGammaSpaceDetection(cmsContext contextID)
  6233. {
  6234. cmsFloat64Number i;
  6235. for (i = 0.5; i < 3; i += 0.1)
  6236. {
  6237. cmsHPROFILE hProfile = createRgbGamma(contextID, i);
  6238. cmsFloat64Number gamma = cmsDetectRGBProfileGamma(contextID, hProfile, 0.01);
  6239. cmsCloseProfile(contextID, hProfile);
  6240. if (fabs(gamma - i) > 0.1)
  6241. {
  6242. Fail("Failed profile gamma detection of %f (got %f)", i, gamma);
  6243. return 0;
  6244. }
  6245. }
  6246. return 1;
  6247. }
  6248. // Per issue #308. A built-in is corrupted by using write raw tag was causing a segfault
  6249. static
  6250. int CheckInducedCorruption(void)
  6251. {
  6252. cmsHTRANSFORM xform0;
  6253. char garbage[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b";
  6254. cmsHPROFILE hsrgb = cmsCreate_sRGBProfile();
  6255. cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
  6256. cmsSetLogErrorHandler(NULL);
  6257. cmsWriteRawTag(hsrgb, cmsSigBlueColorantTag, &garbage, sizeof(garbage));
  6258. xform0 = cmsCreateTransform(hsrgb, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6259. if (xform0) cmsDeleteTransform(xform0);
  6260. cmsCloseProfile(hsrgb);
  6261. cmsCloseProfile(hLab);
  6262. ResetFatalError();
  6263. return 1;
  6264. }
  6265. #if 0
  6266. // You need to download following profiles to execute this test: sRGB-elle-V4-srgbtrc.icc, sRGB-elle-V4-g10.icc
  6267. // The include this line in the checks list: Check("KInear spaces detection", CheckLinearSpacesOptimization);
  6268. static
  6269. void uint16toFloat(cmsUInt16Number* src, cmsFloat32Number* dst)
  6270. {
  6271. for (int i = 0; i < 3; i++) {
  6272. dst[i] = src[i] / 65535.f;
  6273. }
  6274. }
  6275. static
  6276. int CheckLinearSpacesOptimization(cmsContext contextID)
  6277. {
  6278. cmsHPROFILE lcms_sRGB = cmsCreate_sRGBProfile(contextID);
  6279. cmsHPROFILE elle_sRGB = cmsOpenProfileFromFile(contextID, "sRGB-elle-V4-srgbtrc.icc", "r");
  6280. cmsHPROFILE elle_linear = cmsOpenProfileFromFile(contextID, "sRGB-elle-V4-g10.icc", "r");
  6281. cmsHTRANSFORM transform1 = cmsCreateTransform(contextID, elle_sRGB, TYPE_RGB_16, elle_linear, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6282. cmsHTRANSFORM transform2 = cmsCreateTransform(contextID, elle_linear, TYPE_RGB_16, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6283. cmsHTRANSFORM transform2a = cmsCreateTransform(contextID, elle_linear, TYPE_RGB_FLT, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
  6284. cmsUInt16Number sourceCol[3] = { 43 * 257, 27 * 257, 6 * 257 };
  6285. cmsUInt16Number linearCol[3] = { 0 };
  6286. float linearColF[3] = { 0 };
  6287. cmsUInt16Number finalCol[3] = { 0 };
  6288. int difR, difG, difB;
  6289. int difR2, difG2, difB2;
  6290. cmsDoTransform(contextID, transform1, sourceCol, linearCol, 1);
  6291. cmsDoTransform(contextID, transform2, linearCol, finalCol, 1);
  6292. cmsCloseProfile(contextID, lcms_sRGB); cmsCloseProfile(contextID, elle_sRGB); cmsCloseProfile(contextID, elle_linear);
  6293. difR = (int)sourceCol[0] - finalCol[0];
  6294. difG = (int)sourceCol[1] - finalCol[1];
  6295. difB = (int)sourceCol[2] - finalCol[2];
  6296. uint16toFloat(linearCol, linearColF);
  6297. cmsDoTransform(contextID, transform2a, linearColF, finalCol, 1);
  6298. difR2 = (int)sourceCol[0] - finalCol[0];
  6299. difG2 = (int)sourceCol[1] - finalCol[1];
  6300. difB2 = (int)sourceCol[2] - finalCol[2];
  6301. cmsDeleteTransform(contextID, transform1);
  6302. cmsDeleteTransform(contextID, transform2);
  6303. cmsDeleteTransform(contextID, transform2a);
  6304. if (abs(difR2 - difR) > 5 || abs(difG2 - difG) > 5 || abs(difB2 - difB) > 5)
  6305. {
  6306. Fail("Linear detection failed");
  6307. return 0;
  6308. }
  6309. return 1;
  6310. }
  6311. #endif
  6312. static
  6313. int CheckBadCGATS(void)
  6314. {
  6315. const char* bad_it8 =
  6316. " \"\"\n"
  6317. "NUMBER_OF_FIELDS 4\n"
  6318. "BEGIN_DATA_FORMAT\n"
  6319. "I R G G\n"
  6320. "END_DATA_FORMAT\n"
  6321. "NUMBER_OF_FIELDS 9\n"
  6322. "NUMBER_OF_SETS 2\n"
  6323. "BEGIN_DATA\n"
  6324. "d\n"
  6325. "0 0Bd\n"
  6326. "0Ba $ $ t .";
  6327. cmsHANDLE hIT8;
  6328. cmsSetLogErrorHandler(NULL);
  6329. hIT8 = cmsIT8LoadFromMem(0, bad_it8, (cmsUInt32Number) strlen(bad_it8));
  6330. ResetFatalError();
  6331. if (hIT8 != NULL)
  6332. {
  6333. Fail("Wrong IT8 accepted as ok");
  6334. cmsIT8Free(hIT8);
  6335. }
  6336. return 1;
  6337. }
  6338. static
  6339. int CheckIntToFloatTransform(void)
  6340. {
  6341. cmsHPROFILE hAbove = Create_AboveRGB();
  6342. cmsHPROFILE hsRGB = cmsCreate_sRGBProfile();
  6343. cmsHTRANSFORM xform = cmsCreateTransform(hAbove, TYPE_RGB_8, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL, 0);
  6344. cmsUInt8Number rgb8[3] = { 12, 253, 21 };
  6345. cmsFloat64Number rgbDBL[3] = { 0 };
  6346. cmsCloseProfile(hAbove); cmsCloseProfile(hsRGB);
  6347. cmsDoTransform(xform, rgb8, rgbDBL, 1);
  6348. cmsDeleteTransform(xform);
  6349. if (rgbDBL[0] < 0 && rgbDBL[2] < 0) return 1;
  6350. Fail("Unbounded transforms with integer input failed");
  6351. return 0;
  6352. }
  6353. static
  6354. int CheckSaveLinearizationDevicelink(void)
  6355. {
  6356. const cmsFloat32Number table[] = { 0, 0.5f, 1.0f };
  6357. cmsToneCurve* tone = cmsBuildTabulatedToneCurveFloat(NULL, 3, table);
  6358. cmsToneCurve* rgb_curves[3] = { tone, tone, tone };
  6359. cmsHPROFILE hDeviceLink = cmsCreateLinearizationDeviceLink(cmsSigRgbData, rgb_curves);
  6360. cmsBool result;
  6361. cmsHTRANSFORM xform;
  6362. int i;
  6363. cmsFreeToneCurve(tone);
  6364. result = cmsSaveProfileToFile(hDeviceLink, "lin_rgb.icc");
  6365. cmsCloseProfile(hDeviceLink);
  6366. if (!result)
  6367. {
  6368. remove("lin_rgb.icc");
  6369. Fail("Couldn't save linearization devicelink");
  6370. }
  6371. hDeviceLink = cmsOpenProfileFromFile("lin_rgb.icc", "r");
  6372. if (hDeviceLink == NULL)
  6373. {
  6374. remove("lin_rgb.icc");
  6375. Fail("Could't open devicelink");
  6376. }
  6377. xform = cmsCreateTransform(hDeviceLink, TYPE_RGB_8, NULL, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
  6378. cmsCloseProfile(hDeviceLink);
  6379. for (i = 0; i < 256; i++)
  6380. {
  6381. cmsUInt8Number rgb_in[3] = { i, i, i };
  6382. cmsUInt8Number rgb_out[3];
  6383. cmsDoTransform(xform, rgb_in, rgb_out, 1);
  6384. if (rgb_in[0] != rgb_out[0] ||
  6385. rgb_in[1] != rgb_out[1] ||
  6386. rgb_in[2] != rgb_out[2])
  6387. {
  6388. remove("lin_rgb.icc");
  6389. Fail("Saved devicelink was not working");
  6390. }
  6391. }
  6392. cmsDeleteTransform(xform);
  6393. remove("lin_rgb.icc");
  6394. return 1;
  6395. }
  6396. // --------------------------------------------------------------------------------------------------
  6397. // P E R F O R M A N C E C H E C K S
  6398. // --------------------------------------------------------------------------------------------------
  6399. typedef struct {cmsUInt8Number r, g, b, a;} Scanline_rgba8;
  6400. typedef struct {cmsUInt16Number r, g, b, a;} Scanline_rgba16;
  6401. typedef struct {cmsFloat32Number r, g, b, a;} Scanline_rgba32;
  6402. typedef struct {cmsUInt8Number r, g, b;} Scanline_rgb8;
  6403. typedef struct {cmsUInt16Number r, g, b;} Scanline_rgb16;
  6404. typedef struct {cmsFloat32Number r, g, b;} Scanline_rgb32;
  6405. static
  6406. void TitlePerformance(const char* Txt)
  6407. {
  6408. printf("%-45s: ", Txt); fflush(stdout);
  6409. }
  6410. static
  6411. void PrintPerformance(cmsUInt32Number Bytes, cmsUInt32Number SizeOfPixel, cmsFloat64Number diff)
  6412. {
  6413. cmsFloat64Number seconds = (cmsFloat64Number) diff / CLOCKS_PER_SEC;
  6414. cmsFloat64Number mpix_sec = Bytes / (1024.0*1024.0*seconds*SizeOfPixel);
  6415. printf("%#4.3g MPixel/sec.\n", mpix_sec);
  6416. fflush(stdout);
  6417. }
  6418. static
  6419. void SpeedTest32bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6420. {
  6421. cmsInt32Number r, g, b, j;
  6422. clock_t atime;
  6423. cmsFloat64Number diff;
  6424. cmsHTRANSFORM hlcmsxform;
  6425. Scanline_rgba32 *In;
  6426. cmsUInt32Number Mb;
  6427. cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
  6428. cmsUInt32Number NumPixels;
  6429. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6430. Die("Unable to open profiles");
  6431. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGBA_FLT,
  6432. hlcmsProfileOut, TYPE_RGBA_FLT, Intent, cmsFLAGS_NOCACHE);
  6433. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6434. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6435. NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
  6436. Mb = NumPixels * sizeof(Scanline_rgba32);
  6437. In = (Scanline_rgba32 *) chknull(malloc(Mb));
  6438. j = 0;
  6439. for (r=0; r < 256; r += Interval)
  6440. for (g=0; g < 256; g += Interval)
  6441. for (b=0; b < 256; b += Interval) {
  6442. In[j].r = r / 256.0f;
  6443. In[j].g = g / 256.0f;
  6444. In[j].b = b / 256.0f;
  6445. In[j].a = (In[j].r + In[j].g + In[j].b) / 3;
  6446. j++;
  6447. }
  6448. TitlePerformance(Title);
  6449. atime = clock();
  6450. cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
  6451. diff = clock() - atime;
  6452. free(In);
  6453. PrintPerformance(Mb, sizeof(Scanline_rgba32), diff);
  6454. cmsDeleteTransform(ContextID, hlcmsxform);
  6455. }
  6456. static
  6457. void SpeedTest16bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6458. {
  6459. cmsInt32Number r, g, b, j;
  6460. clock_t atime;
  6461. cmsFloat64Number diff;
  6462. cmsHTRANSFORM hlcmsxform;
  6463. Scanline_rgb16 *In;
  6464. cmsUInt32Number Mb;
  6465. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6466. Die("Unable to open profiles");
  6467. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGB_16,
  6468. hlcmsProfileOut, TYPE_RGB_16, Intent, cmsFLAGS_NOCACHE);
  6469. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6470. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6471. Mb = 256*256*256 * sizeof(Scanline_rgb16);
  6472. In = (Scanline_rgb16*) chknull(malloc(Mb));
  6473. j = 0;
  6474. for (r=0; r < 256; r++)
  6475. for (g=0; g < 256; g++)
  6476. for (b=0; b < 256; b++) {
  6477. In[j].r = (cmsUInt16Number) ((r << 8) | r);
  6478. In[j].g = (cmsUInt16Number) ((g << 8) | g);
  6479. In[j].b = (cmsUInt16Number) ((b << 8) | b);
  6480. j++;
  6481. }
  6482. TitlePerformance(Title);
  6483. atime = clock();
  6484. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6485. diff = clock() - atime;
  6486. free(In);
  6487. PrintPerformance(Mb, sizeof(Scanline_rgb16), diff);
  6488. cmsDeleteTransform(ContextID, hlcmsxform);
  6489. }
  6490. static
  6491. void SpeedTest32bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  6492. {
  6493. cmsInt32Number r, g, b, j;
  6494. clock_t atime;
  6495. cmsFloat64Number diff;
  6496. cmsHTRANSFORM hlcmsxform;
  6497. Scanline_rgba32 *In;
  6498. cmsUInt32Number Mb;
  6499. cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
  6500. cmsUInt32Number NumPixels;
  6501. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6502. Die("Unable to open profiles");
  6503. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_FLT,
  6504. hlcmsProfileOut, TYPE_CMYK_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  6505. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6506. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6507. NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
  6508. Mb = NumPixels * sizeof(Scanline_rgba32);
  6509. In = (Scanline_rgba32 *) chknull(malloc(Mb));
  6510. j = 0;
  6511. for (r=0; r < 256; r += Interval)
  6512. for (g=0; g < 256; g += Interval)
  6513. for (b=0; b < 256; b += Interval) {
  6514. In[j].r = r / 256.0f;
  6515. In[j].g = g / 256.0f;
  6516. In[j].b = b / 256.0f;
  6517. In[j].a = (In[j].r + In[j].g + In[j].b) / 3;
  6518. j++;
  6519. }
  6520. TitlePerformance(Title);
  6521. atime = clock();
  6522. cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
  6523. diff = clock() - atime;
  6524. free(In);
  6525. PrintPerformance(Mb, sizeof(Scanline_rgba32), diff);
  6526. cmsDeleteTransform(ContextID, hlcmsxform);
  6527. }
  6528. static
  6529. void SpeedTest16bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  6530. {
  6531. cmsInt32Number r, g, b, j;
  6532. clock_t atime;
  6533. cmsFloat64Number diff;
  6534. cmsHTRANSFORM hlcmsxform;
  6535. Scanline_rgba16 *In;
  6536. cmsUInt32Number Mb;
  6537. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6538. Die("Unable to open profiles");
  6539. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_16,
  6540. hlcmsProfileOut, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  6541. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6542. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6543. Mb = 256*256*256*sizeof(Scanline_rgba16);
  6544. In = (Scanline_rgba16*) chknull(malloc(Mb));
  6545. j = 0;
  6546. for (r=0; r < 256; r++)
  6547. for (g=0; g < 256; g++)
  6548. for (b=0; b < 256; b++) {
  6549. In[j].r = (cmsUInt16Number) ((r << 8) | r);
  6550. In[j].g = (cmsUInt16Number) ((g << 8) | g);
  6551. In[j].b = (cmsUInt16Number) ((b << 8) | b);
  6552. In[j].a = 0;
  6553. j++;
  6554. }
  6555. TitlePerformance(Title);
  6556. atime = clock();
  6557. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6558. diff = clock() - atime;
  6559. free(In);
  6560. PrintPerformance(Mb, sizeof(Scanline_rgba16), diff);
  6561. cmsDeleteTransform(ContextID, hlcmsxform);
  6562. }
  6563. static
  6564. void SpeedTest8bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6565. {
  6566. cmsInt32Number r, g, b, j;
  6567. clock_t atime;
  6568. cmsFloat64Number diff;
  6569. cmsHTRANSFORM hlcmsxform;
  6570. Scanline_rgb8 *In;
  6571. cmsUInt32Number Mb;
  6572. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6573. Die("Unable to open profiles");
  6574. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGB_8,
  6575. hlcmsProfileOut, TYPE_RGB_8, Intent, cmsFLAGS_NOCACHE);
  6576. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6577. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6578. Mb = 256*256*256*sizeof(Scanline_rgb8);
  6579. In = (Scanline_rgb8*) chknull(malloc(Mb));
  6580. j = 0;
  6581. for (r=0; r < 256; r++)
  6582. for (g=0; g < 256; g++)
  6583. for (b=0; b < 256; b++) {
  6584. In[j].r = (cmsUInt8Number) r;
  6585. In[j].g = (cmsUInt8Number) g;
  6586. In[j].b = (cmsUInt8Number) b;
  6587. j++;
  6588. }
  6589. TitlePerformance(Title);
  6590. atime = clock();
  6591. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6592. diff = clock() - atime;
  6593. free(In);
  6594. PrintPerformance(Mb, sizeof(Scanline_rgb8), diff);
  6595. cmsDeleteTransform(ContextID, hlcmsxform);
  6596. }
  6597. static
  6598. void SpeedTest8bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  6599. {
  6600. cmsInt32Number r, g, b, j;
  6601. clock_t atime;
  6602. cmsFloat64Number diff;
  6603. cmsHTRANSFORM hlcmsxform;
  6604. Scanline_rgba8 *In;
  6605. cmsUInt32Number Mb;
  6606. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6607. Die("Unable to open profiles");
  6608. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_8,
  6609. hlcmsProfileOut, TYPE_CMYK_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  6610. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6611. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6612. Mb = 256*256*256*sizeof(Scanline_rgba8);
  6613. In = (Scanline_rgba8*) chknull(malloc(Mb));
  6614. j = 0;
  6615. for (r=0; r < 256; r++)
  6616. for (g=0; g < 256; g++)
  6617. for (b=0; b < 256; b++) {
  6618. In[j].r = (cmsUInt8Number) r;
  6619. In[j].g = (cmsUInt8Number) g;
  6620. In[j].b = (cmsUInt8Number) b;
  6621. In[j].a = (cmsUInt8Number) 0;
  6622. j++;
  6623. }
  6624. TitlePerformance(Title);
  6625. atime = clock();
  6626. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6627. diff = clock() - atime;
  6628. free(In);
  6629. PrintPerformance(Mb, sizeof(Scanline_rgba8), diff);
  6630. cmsDeleteTransform(ContextID, hlcmsxform);
  6631. }
  6632. static
  6633. void SpeedTest32bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6634. {
  6635. cmsInt32Number r, g, b, j;
  6636. clock_t atime;
  6637. cmsFloat64Number diff;
  6638. cmsHTRANSFORM hlcmsxform;
  6639. cmsFloat32Number *In;
  6640. cmsUInt32Number Mb;
  6641. cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
  6642. cmsUInt32Number NumPixels;
  6643. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6644. Die("Unable to open profiles");
  6645. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
  6646. TYPE_GRAY_FLT, hlcmsProfileOut, TYPE_GRAY_FLT, Intent, cmsFLAGS_NOCACHE);
  6647. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6648. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6649. NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
  6650. Mb = NumPixels * sizeof(cmsFloat32Number);
  6651. In = (cmsFloat32Number*) chknull(malloc(Mb));
  6652. j = 0;
  6653. for (r = 0; r < 256; r += Interval)
  6654. for (g = 0; g < 256; g += Interval)
  6655. for (b = 0; b < 256; b += Interval) {
  6656. In[j] = ((r + g + b) / 768.0f);
  6657. j++;
  6658. }
  6659. TitlePerformance(Title);
  6660. atime = clock();
  6661. cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
  6662. diff = clock() - atime;
  6663. free(In);
  6664. PrintPerformance(Mb, sizeof(cmsFloat32Number), diff);
  6665. cmsDeleteTransform(ContextID, hlcmsxform);
  6666. }
  6667. static
  6668. void SpeedTest16bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6669. {
  6670. cmsInt32Number r, g, b, j;
  6671. clock_t atime;
  6672. cmsFloat64Number diff;
  6673. cmsHTRANSFORM hlcmsxform;
  6674. cmsUInt16Number *In;
  6675. cmsUInt32Number Mb;
  6676. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6677. Die("Unable to open profiles");
  6678. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
  6679. TYPE_GRAY_16, hlcmsProfileOut, TYPE_GRAY_16, Intent, cmsFLAGS_NOCACHE);
  6680. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6681. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6682. Mb = 256*256*256 * sizeof(cmsUInt16Number);
  6683. In = (cmsUInt16Number *) chknull(malloc(Mb));
  6684. j = 0;
  6685. for (r=0; r < 256; r++)
  6686. for (g=0; g < 256; g++)
  6687. for (b=0; b < 256; b++) {
  6688. In[j] = (cmsUInt16Number) ((r + g + b) / 3);
  6689. j++;
  6690. }
  6691. TitlePerformance(Title);
  6692. atime = clock();
  6693. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6694. diff = clock() - atime;
  6695. free(In);
  6696. PrintPerformance(Mb, sizeof(cmsUInt16Number), diff);
  6697. cmsDeleteTransform(ContextID, hlcmsxform);
  6698. }
  6699. static
  6700. void SpeedTest8bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
  6701. {
  6702. cmsInt32Number r, g, b, j;
  6703. clock_t atime;
  6704. cmsFloat64Number diff;
  6705. cmsHTRANSFORM hlcmsxform;
  6706. cmsUInt8Number *In;
  6707. cmsUInt32Number Mb;
  6708. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  6709. Die("Unable to open profiles");
  6710. hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
  6711. TYPE_GRAY_8, hlcmsProfileOut, TYPE_GRAY_8, Intent, cmsFLAGS_NOCACHE);
  6712. cmsCloseProfile(ContextID, hlcmsProfileIn);
  6713. cmsCloseProfile(ContextID, hlcmsProfileOut);
  6714. Mb = 256*256*256;
  6715. In = (cmsUInt8Number*) chknull(malloc(Mb));
  6716. j = 0;
  6717. for (r=0; r < 256; r++)
  6718. for (g=0; g < 256; g++)
  6719. for (b=0; b < 256; b++) {
  6720. In[j] = (cmsUInt8Number) r;
  6721. j++;
  6722. }
  6723. TitlePerformance(Title);
  6724. atime = clock();
  6725. cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
  6726. diff = clock() - atime;
  6727. free(In);
  6728. PrintPerformance(Mb, sizeof(cmsUInt8Number), diff);
  6729. cmsDeleteTransform(ContextID, hlcmsxform);
  6730. }
  6731. static
  6732. cmsHPROFILE CreateCurves(cmsContext ContextID)
  6733. {
  6734. cmsToneCurve* Gamma = cmsBuildGamma(ContextID, 1.1);
  6735. cmsToneCurve* Transfer[3];
  6736. cmsHPROFILE h;
  6737. Transfer[0] = Transfer[1] = Transfer[2] = Gamma;
  6738. h = cmsCreateLinearizationDeviceLink(ContextID, cmsSigRgbData, Transfer);
  6739. cmsFreeToneCurve(ContextID, Gamma);
  6740. return h;
  6741. }
  6742. static
  6743. void SpeedTest(cmsContext ContextID)
  6744. {
  6745. printf("\n\nP E R F O R M A N C E T E S T S\n");
  6746. printf( "=================================\n\n");
  6747. fflush(stdout);
  6748. SpeedTest8bits(ContextID, "8 bits on CLUT profiles",
  6749. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6750. cmsOpenProfileFromFile(ContextID, "test3.icc", "r"),
  6751. INTENT_PERCEPTUAL);
  6752. SpeedTest16bits(ContextID, "16 bits on CLUT profiles",
  6753. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6754. cmsOpenProfileFromFile(ContextID, "test3.icc", "r"), INTENT_PERCEPTUAL);
  6755. SpeedTest32bits(ContextID, "32 bits on CLUT profiles",
  6756. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6757. cmsOpenProfileFromFile(ContextID, "test3.icc", "r"), INTENT_PERCEPTUAL);
  6758. printf("\n");
  6759. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6760. SpeedTest8bits(ContextID, "8 bits on Matrix-Shaper profiles",
  6761. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6762. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6763. INTENT_PERCEPTUAL);
  6764. SpeedTest16bits(ContextID, "16 bits on Matrix-Shaper profiles",
  6765. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6766. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6767. INTENT_PERCEPTUAL);
  6768. SpeedTest32bits(ContextID, "32 bits on Matrix-Shaper profiles",
  6769. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6770. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6771. INTENT_PERCEPTUAL);
  6772. printf("\n");
  6773. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6774. SpeedTest8bits(ContextID, "8 bits on SAME Matrix-Shaper profiles",
  6775. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6776. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6777. INTENT_PERCEPTUAL);
  6778. SpeedTest16bits(ContextID, "16 bits on SAME Matrix-Shaper profiles",
  6779. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6780. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6781. INTENT_PERCEPTUAL);
  6782. SpeedTest32bits(ContextID, "32 bits on SAME Matrix-Shaper profiles",
  6783. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6784. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6785. INTENT_PERCEPTUAL);
  6786. printf("\n");
  6787. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6788. SpeedTest8bits(ContextID, "8 bits on Matrix-Shaper profiles (AbsCol)",
  6789. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6790. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6791. INTENT_ABSOLUTE_COLORIMETRIC);
  6792. SpeedTest16bits(ContextID, "16 bits on Matrix-Shaper profiles (AbsCol)",
  6793. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6794. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6795. INTENT_ABSOLUTE_COLORIMETRIC);
  6796. SpeedTest32bits(ContextID, "32 bits on Matrix-Shaper profiles (AbsCol)",
  6797. cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
  6798. cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
  6799. INTENT_ABSOLUTE_COLORIMETRIC);
  6800. printf("\n");
  6801. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6802. SpeedTest8bits(ContextID, "8 bits on curves",
  6803. CreateCurves(ContextID),
  6804. CreateCurves(ContextID),
  6805. INTENT_PERCEPTUAL);
  6806. SpeedTest16bits(ContextID, "16 bits on curves",
  6807. CreateCurves(ContextID),
  6808. CreateCurves(ContextID),
  6809. INTENT_PERCEPTUAL);
  6810. SpeedTest32bits(ContextID, "32 bits on curves",
  6811. CreateCurves(ContextID),
  6812. CreateCurves(ContextID),
  6813. INTENT_PERCEPTUAL);
  6814. printf("\n");
  6815. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6816. SpeedTest8bitsCMYK(ContextID, "8 bits on CMYK profiles",
  6817. cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
  6818. cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
  6819. SpeedTest16bitsCMYK(ContextID, "16 bits on CMYK profiles",
  6820. cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
  6821. cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
  6822. SpeedTest32bitsCMYK(ContextID, "32 bits on CMYK profiles",
  6823. cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
  6824. cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
  6825. printf("\n");
  6826. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6827. SpeedTest8bitsGray(ContextID, "8 bits on gray-to gray",
  6828. cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
  6829. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6830. SpeedTest16bitsGray(ContextID, "16 bits on gray-to gray",
  6831. cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
  6832. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6833. SpeedTest32bitsGray(ContextID, "32 bits on gray-to gray",
  6834. cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
  6835. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6836. printf("\n");
  6837. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6838. SpeedTest8bitsGray(ContextID, "8 bits on gray-to-lab gray",
  6839. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6840. cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6841. SpeedTest16bitsGray(ContextID, "16 bits on gray-to-lab gray",
  6842. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6843. cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6844. SpeedTest32bitsGray(ContextID, "32 bits on gray-to-lab gray",
  6845. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6846. cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
  6847. printf("\n");
  6848. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6849. SpeedTest8bitsGray(ContextID, "8 bits on SAME gray-to-gray",
  6850. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6851. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
  6852. SpeedTest16bitsGray(ContextID, "16 bits on SAME gray-to-gray",
  6853. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6854. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
  6855. SpeedTest32bitsGray(ContextID, "32 bits on SAME gray-to-gray",
  6856. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
  6857. cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
  6858. printf("\n");
  6859. }
  6860. // -----------------------------------------------------------------------------------------------------
  6861. // Print the supported intents
  6862. static
  6863. void PrintSupportedIntents(void)
  6864. {
  6865. cmsUInt32Number n, i;
  6866. cmsUInt32Number Codes[200];
  6867. char* Descriptions[200];
  6868. n = cmsGetSupportedIntents(DbgThread(), 200, Codes, Descriptions);
  6869. printf("Supported intents:\n");
  6870. for (i=0; i < n; i++) {
  6871. printf("\t%u - %s\n", Codes[i], Descriptions[i]);
  6872. }
  6873. printf("\n");
  6874. }
  6875. // ---------------------------------------------------------------------------------------
  6876. int main(int argc, char* argv[])
  6877. {
  6878. cmsInt32Number Exhaustive = 0;
  6879. cmsInt32Number DoSpeedTests = 1;
  6880. cmsInt32Number DoCheckTests = 1;
  6881. cmsInt32Number DoPluginTests = 1;
  6882. cmsInt32Number DoZooTests = 0;
  6883. cmsContext ctx;
  6884. #ifdef _MSC_VER
  6885. _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
  6886. #endif
  6887. // First of all, check for the right header
  6888. if (cmsGetEncodedCMMversion() != LCMS_VERSION) {
  6889. Die("Oops, you are mixing header and shared lib!\nHeader version reports to be '%d' and shared lib '%d'\n", LCMS_VERSION, cmsGetEncodedCMMversion());
  6890. }
  6891. printf("LittleCMS %2.2f test bed %s %s\n\n", cmsGetEncodedCMMversion() / 1000.0, __DATE__, __TIME__);
  6892. if ((argc == 2) && strcmp(argv[1], "--exhaustive") == 0) {
  6893. Exhaustive = 1;
  6894. printf("Running exhaustive tests (will take a while...)\n\n");
  6895. }
  6896. else
  6897. if ((argc == 3) && strcmp(argv[1], "--chdir") == 0) {
  6898. CHDIR(argv[2]);
  6899. }
  6900. printf("Installing debug memory plug-in ... ");
  6901. cmsPlugin(NULL, &DebugMemHandler);
  6902. printf("done.\n");
  6903. ctx = NULL;//cmsCreateContext(NULL, NULL);
  6904. printf("Installing error logger ... ");
  6905. cmsSetLogErrorHandler(NULL, FatalErrorQuit);
  6906. printf("done.\n");
  6907. PrintSupportedIntents();
  6908. Check(ctx, "Base types", CheckBaseTypes);
  6909. Check(ctx, "endianness", CheckEndianness);
  6910. Check(ctx, "quick floor", CheckQuickFloor);
  6911. Check(ctx, "quick floor word", CheckQuickFloorWord);
  6912. Check(ctx, "Fixed point 15.16 representation", CheckFixedPoint15_16);
  6913. Check(ctx, "Fixed point 8.8 representation", CheckFixedPoint8_8);
  6914. Check(ctx, "D50 roundtrip", CheckD50Roundtrip);
  6915. // Create utility profiles
  6916. if (DoCheckTests || DoSpeedTests)
  6917. Check(ctx, "Creation of test profiles", CreateTestProfiles);
  6918. if (DoCheckTests) {
  6919. // Forward 1D interpolation
  6920. Check(ctx, "1D interpolation in 2pt tables", Check1DLERP2);
  6921. Check(ctx, "1D interpolation in 3pt tables", Check1DLERP3);
  6922. Check(ctx, "1D interpolation in 4pt tables", Check1DLERP4);
  6923. Check(ctx, "1D interpolation in 6pt tables", Check1DLERP6);
  6924. Check(ctx, "1D interpolation in 18pt tables", Check1DLERP18);
  6925. Check(ctx, "1D interpolation in descending 2pt tables", Check1DLERP2Down);
  6926. Check(ctx, "1D interpolation in descending 3pt tables", Check1DLERP3Down);
  6927. Check(ctx, "1D interpolation in descending 6pt tables", Check1DLERP6Down);
  6928. Check(ctx, "1D interpolation in descending 18pt tables", Check1DLERP18Down);
  6929. if (Exhaustive) {
  6930. Check(ctx, "1D interpolation in n tables", ExhaustiveCheck1DLERP);
  6931. Check(ctx, "1D interpolation in descending tables", ExhaustiveCheck1DLERPDown);
  6932. }
  6933. // Forward 3D interpolation
  6934. Check(ctx, "3D interpolation Tetrahedral (float) ", Check3DinterpolationFloatTetrahedral);
  6935. Check(ctx, "3D interpolation Trilinear (float) ", Check3DinterpolationFloatTrilinear);
  6936. Check(ctx, "3D interpolation Tetrahedral (16) ", Check3DinterpolationTetrahedral16);
  6937. Check(ctx, "3D interpolation Trilinear (16) ", Check3DinterpolationTrilinear16);
  6938. if (Exhaustive) {
  6939. Check(ctx, "Exhaustive 3D interpolation Tetrahedral (float) ", ExaustiveCheck3DinterpolationFloatTetrahedral);
  6940. Check(ctx, "Exhaustive 3D interpolation Trilinear (float) ", ExaustiveCheck3DinterpolationFloatTrilinear);
  6941. Check(ctx, "Exhaustive 3D interpolation Tetrahedral (16) ", ExhaustiveCheck3DinterpolationTetrahedral16);
  6942. Check(ctx, "Exhaustive 3D interpolation Trilinear (16) ", ExhaustiveCheck3DinterpolationTrilinear16);
  6943. }
  6944. Check(ctx, "Reverse interpolation 3 -> 3", CheckReverseInterpolation3x3);
  6945. Check(ctx, "Reverse interpolation 4 -> 3", CheckReverseInterpolation4x3);
  6946. // High dimensionality interpolation
  6947. Check(ctx, "3D interpolation", Check3Dinterp);
  6948. Check(ctx, "3D interpolation with granularity", Check3DinterpGranular);
  6949. Check(ctx, "4D interpolation", Check4Dinterp);
  6950. Check(ctx, "4D interpolation with granularity", Check4DinterpGranular);
  6951. Check(ctx, "5D interpolation with granularity", Check5DinterpGranular);
  6952. Check(ctx, "6D interpolation with granularity", Check6DinterpGranular);
  6953. Check(ctx, "7D interpolation with granularity", Check7DinterpGranular);
  6954. Check(ctx, "8D interpolation with granularity", Check8DinterpGranular);
  6955. // Encoding of colorspaces
  6956. Check(ctx, "Lab to LCh and back (float only) ", CheckLab2LCh);
  6957. Check(ctx, "Lab to XYZ and back (float only) ", CheckLab2XYZ);
  6958. Check(ctx, "Lab to xyY and back (float only) ", CheckLab2xyY);
  6959. Check(ctx, "Lab V2 encoding", CheckLabV2encoding);
  6960. Check(ctx, "Lab V4 encoding", CheckLabV4encoding);
  6961. // BlackBody
  6962. Check(ctx, "Blackbody radiator", CheckTemp2CHRM);
  6963. // Tone curves
  6964. Check(ctx, "Linear gamma curves (16 bits)", CheckGammaCreation16);
  6965. Check(ctx, "Linear gamma curves (float)", CheckGammaCreationFlt);
  6966. Check(ctx, "Curve 1.8 (float)", CheckGamma18);
  6967. Check(ctx, "Curve 2.2 (float)", CheckGamma22);
  6968. Check(ctx, "Curve 3.0 (float)", CheckGamma30);
  6969. Check(ctx, "Curve 1.8 (table)", CheckGamma18Table);
  6970. Check(ctx, "Curve 2.2 (table)", CheckGamma22Table);
  6971. Check(ctx, "Curve 3.0 (table)", CheckGamma30Table);
  6972. Check(ctx, "Curve 1.8 (word table)", CheckGamma18TableWord);
  6973. Check(ctx, "Curve 2.2 (word table)", CheckGamma22TableWord);
  6974. Check(ctx, "Curve 3.0 (word table)", CheckGamma30TableWord);
  6975. Check(ctx, "Parametric curves", CheckParametricToneCurves);
  6976. Check(ctx, "Join curves", CheckJointCurves);
  6977. Check(ctx, "Join curves descending", CheckJointCurvesDescending);
  6978. Check(ctx, "Join curves degenerated", CheckReverseDegenerated);
  6979. Check(ctx, "Join curves sRGB (Float)", CheckJointFloatCurves_sRGB);
  6980. Check(ctx, "Join curves sRGB (16 bits)", CheckJoint16Curves_sRGB);
  6981. Check(ctx, "Join curves sigmoidal", CheckJointCurvesSShaped);
  6982. // LUT basics
  6983. Check(ctx, "LUT creation & dup", CheckLUTcreation);
  6984. Check(ctx, "1 Stage LUT ", Check1StageLUT);
  6985. Check(ctx, "2 Stage LUT ", Check2StageLUT);
  6986. Check(ctx, "2 Stage LUT (16 bits)", Check2Stage16LUT);
  6987. Check(ctx, "3 Stage LUT ", Check3StageLUT);
  6988. Check(ctx, "3 Stage LUT (16 bits)", Check3Stage16LUT);
  6989. Check(ctx, "4 Stage LUT ", Check4StageLUT);
  6990. Check(ctx, "4 Stage LUT (16 bits)", Check4Stage16LUT);
  6991. Check(ctx, "5 Stage LUT ", Check5StageLUT);
  6992. Check(ctx, "5 Stage LUT (16 bits) ", Check5Stage16LUT);
  6993. Check(ctx, "6 Stage LUT ", Check6StageLUT);
  6994. Check(ctx, "6 Stage LUT (16 bits) ", Check6Stage16LUT);
  6995. // LUT operation
  6996. Check(ctx, "Lab to Lab LUT (float only) ", CheckLab2LabLUT);
  6997. Check(ctx, "XYZ to XYZ LUT (float only) ", CheckXYZ2XYZLUT);
  6998. Check(ctx, "Lab to Lab MAT LUT (float only) ", CheckLab2LabMatLUT);
  6999. Check(ctx, "Named Color LUT", CheckNamedColorLUT);
  7000. Check(ctx, "Usual formatters", CheckFormatters16);
  7001. Check(ctx, "Floating point formatters", CheckFormattersFloat);
  7002. #ifndef CMS_NO_HALF_SUPPORT
  7003. Check(ctx, "HALF formatters", CheckFormattersHalf);
  7004. #endif
  7005. // ChangeBuffersFormat
  7006. Check(ctx, "ChangeBuffersFormat", CheckChangeBufferFormat);
  7007. // MLU
  7008. Check(ctx, "Multilocalized Unicode", CheckMLU);
  7009. Check(ctx, "Multilocalized Unicode (II)", CheckMLU_UTF8);
  7010. // Named color
  7011. Check(ctx, "Named color lists", CheckNamedColorList);
  7012. Check(ctx, "Create named color profile", CreateNamedColorProfile);
  7013. // Profile I/O (this one is huge!)
  7014. Check(ctx, "Profile creation", CheckProfileCreation);
  7015. Check(ctx, "Header version", CheckVersionHeaderWriting);
  7016. Check(ctx, "Multilocalized profile", CheckMultilocalizedProfile);
  7017. // Error reporting
  7018. Check(ctx, "Error reporting on bad profiles", CheckErrReportingOnBadProfiles);
  7019. Check(ctx, "Error reporting on bad transforms", CheckErrReportingOnBadTransforms);
  7020. // Transforms
  7021. Check(ctx, "Curves only transforms", CheckCurvesOnlyTransforms);
  7022. Check(ctx, "Float Lab->Lab transforms", CheckFloatLabTransforms);
  7023. Check(ctx, "Encoded Lab->Lab transforms", CheckEncodedLabTransforms);
  7024. Check(ctx, "Stored identities", CheckStoredIdentities);
  7025. Check(ctx, "Matrix-shaper transform (float)", CheckMatrixShaperXFORMFloat);
  7026. Check(ctx, "Matrix-shaper transform (16 bits)", CheckMatrixShaperXFORM16);
  7027. Check(ctx, "Matrix-shaper transform (8 bits)", CheckMatrixShaperXFORM8);
  7028. Check(ctx, "Primaries of sRGB", CheckRGBPrimaries);
  7029. // Known values
  7030. Check(ctx, "Known values across matrix-shaper", Chack_sRGB_Float);
  7031. Check(ctx, "Gray input profile", CheckInputGray);
  7032. Check(ctx, "Gray Lab input profile", CheckLabInputGray);
  7033. Check(ctx, "Gray output profile", CheckOutputGray);
  7034. Check(ctx, "Gray Lab output profile", CheckLabOutputGray);
  7035. Check(ctx, "Matrix-shaper proofing transform (float)", CheckProofingXFORMFloat);
  7036. Check(ctx, "Matrix-shaper proofing transform (16 bits)", CheckProofingXFORM16);
  7037. Check(ctx, "Gamut check", CheckGamutCheck);
  7038. Check(ctx, "CMYK roundtrip on perceptual transform", CheckCMYKRoundtrip);
  7039. Check(ctx, "CMYK perceptual transform", CheckCMYKPerceptual);
  7040. // Check("CMYK rel.col. transform", CheckCMYKRelCol);
  7041. Check(ctx, "Black ink only preservation", CheckKOnlyBlackPreserving);
  7042. Check(ctx, "Black plane preservation", CheckKPlaneBlackPreserving);
  7043. Check(ctx, "Deciding curve types", CheckV4gamma);
  7044. Check(ctx, "Black point detection", CheckBlackPoint);
  7045. Check(ctx, "TAC detection", CheckTAC);
  7046. Check(ctx, "CGATS parser", CheckCGATS);
  7047. Check(ctx, "CGATS parser on junk", CheckCGATS2);
  7048. Check(ctx, "CGATS parser on overflow", CheckCGATS_Overflow);
  7049. Check(ctx, "PostScript generator", CheckPostScript);
  7050. Check(ctx, "Segment maxima GBD", CheckGBD);
  7051. Check(ctx, "MD5 digest", CheckMD5);
  7052. Check(ctx, "Linking", CheckLinking);
  7053. Check(ctx, "floating point tags on XYZ", CheckFloatXYZ);
  7054. Check(ctx, "RGB->Lab->RGB with alpha on FLT", ChecksRGB2LabFLT);
  7055. Check(ctx, "Parametric curve on Rec709", CheckParametricRec709);
  7056. Check(ctx, "Floating Point sampled curve with non-zero start", CheckFloatSamples);
  7057. Check(ctx, "Floating Point segmented curve with short sampled segment", CheckFloatSegments);
  7058. Check(ctx, "Read RAW tags", CheckReadRAW);
  7059. Check(ctx, "Check MetaTag", CheckMeta);
  7060. Check(ctx, "Null transform on floats", CheckFloatNULLxform);
  7061. Check(ctx, "Set free a tag", CheckRemoveTag);
  7062. Check(ctx, "Matrix simplification", CheckMatrixSimplify);
  7063. Check(ctx, "Planar 8 optimization", CheckPlanar8opt);
  7064. Check(ctx, "Swap endian feature", CheckSE);
  7065. Check(ctx, "Transform line stride RGB", CheckTransformLineStride);
  7066. Check(ctx, "Forged MPE profile", CheckForgedMPE);
  7067. Check(ctx, "Proofing intersection", CheckProofingIntersection);
  7068. Check(ctx, "Empty MLUC", CheckEmptyMLUC);
  7069. Check(ctx, "sRGB round-trips", Check_sRGB_Rountrips);
  7070. Check(ctx, "OkLab color space", Check_OkLab);
  7071. Check(ctx, "OkLab color space (2)", Check_OkLab2);
  7072. Check(ctx, "Gamma space detection", CheckGammaSpaceDetection);
  7073. Check(ctx, "Unbounded mode w/ integer output", CheckIntToFloatTransform);
  7074. Check(ctx, "Corrupted built-in by using cmsWriteRawTag", CheckInducedCorruption);
  7075. Check(ctx, "Bad CGATS file", CheckBadCGATS);
  7076. Check(ctx, "Saving linearization devicelink", CheckSaveLinearizationDevicelink);
  7077. }
  7078. if (DoPluginTests)
  7079. {
  7080. Check(ctx, "Context memory handling", CheckAllocContext);
  7081. Check(ctx, "Simple context functionality", CheckSimpleContext);
  7082. Check(ctx, "Alarm codes context", CheckAlarmColorsContext);
  7083. Check(ctx, "Adaptation state context", CheckAdaptationStateContext);
  7084. Check(ctx, "1D interpolation plugin", CheckInterp1DPlugin);
  7085. Check(ctx, "3D interpolation plugin", CheckInterp3DPlugin);
  7086. Check(ctx, "Parametric curve plugin", CheckParametricCurvePlugin);
  7087. Check(ctx, "Formatters plugin", CheckFormattersPlugin);
  7088. Check(ctx, "Tag type plugin", CheckTagTypePlugin);
  7089. Check(ctx, "MPE type plugin", CheckMPEPlugin);
  7090. Check(ctx, "Optimization plugin", CheckOptimizationPlugin);
  7091. Check(ctx, "Rendering intent plugin", CheckIntentPlugin);
  7092. Check(ctx, "Full transform plugin", CheckTransformPlugin);
  7093. Check(ctx, "Mutex plugin", CheckMutexPlugin);
  7094. }
  7095. if (DoSpeedTests)
  7096. SpeedTest(ctx);
  7097. #ifdef CMS_IS_WINDOWS_
  7098. if (DoZooTests)
  7099. CheckProfileZOO(ctx);
  7100. #endif
  7101. DebugMemPrintTotals();
  7102. cmsUnregisterPlugins(NULL);
  7103. // Cleanup
  7104. if (DoCheckTests || DoSpeedTests)
  7105. RemoveTestProfiles();
  7106. return TotalFail;
  7107. }