| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799 |
- //---------------------------------------------------------------------------------
- //
- // Little Color Management System
- // Copyright (c) 1998-2023 Marti Maria Saguer
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the Software
- // is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- //---------------------------------------------------------------------------------
- //
- #include "testcms2.h"
- // A single check. Returns 1 if success, 0 if failed
- typedef cmsInt32Number (*TestFn)(cmsContext);
- // A parametric Tone curve test function
- typedef cmsFloat32Number (* dblfnptr)(cmsFloat32Number x, const cmsFloat64Number Params[]);
- // Some globals to keep track of error
- #define TEXT_ERROR_BUFFER_SIZE 4096
- static char ReasonToFailBuffer[TEXT_ERROR_BUFFER_SIZE];
- static char SubTestBuffer[TEXT_ERROR_BUFFER_SIZE];
- static cmsInt32Number TotalTests = 0, TotalFail = 0;
- static cmsBool TrappedError;
- static cmsInt32Number SimultaneousErrors;
- #define cmsmin(a, b) (((a) < (b)) ? (a) : (b))
- // Die, a fatal unexpected error is detected!
- void Die(const char* Reason, ...)
- {
- va_list args;
- va_start(args, Reason);
- vsprintf(ReasonToFailBuffer, Reason, args);
- va_end(args);
- printf("\n%s\n", ReasonToFailBuffer);
- fflush(stdout);
- exit(1);
- }
- static
- void* chknull(void* mem)
- {
- if (mem == NULL)
- Die("Memory may be corrupted");
- return mem;
- }
- // Memory management replacement -----------------------------------------------------------------------------
- // This is just a simple plug-in for malloc, free and realloc to keep track of memory allocated,
- // maximum requested as a single block and maximum allocated at a given time. Results are printed at the end
- static cmsUInt32Number SingleHit, MaxAllocated=0, TotalMemory=0;
- // I'm hiding the size before the block. This is a well-known technique and probably the blocks coming from
- // malloc are built in a way similar to that, but I do on my own to be portable.
- typedef struct {
- cmsUInt32Number KeepSize;
- cmsContext WhoAllocated;
- cmsUInt32Number DontCheck;
- union {
- cmsUInt64Number HiSparc;
- // '_cmsMemoryBlock' block is prepended by the
- // allocator for any requested size. Thus, union holds
- // "widest" type to guarantee proper '_cmsMemoryBlock'
- // alignment for any requested size.
- } alignment;
- } _cmsMemoryBlock;
- #define SIZE_OF_MEM_HEADER (sizeof(_cmsMemoryBlock))
- // This is a fake thread descriptor used to check thread integrity.
- // Basically it returns a different threadID each time it is called.
- // Then the memory management replacement functions does check if each
- // free() is being called with same ContextID used on malloc()
- static
- cmsContext DbgThread(void)
- {
- static cmsUInt32Number n = 1;
- return (cmsContext) (void*) ((cmsUInt8Number*) NULL + (n++ % 0xff0));
- }
- // The allocate routine
- static
- void* DebugMalloc(cmsContext ContextID, cmsUInt32Number size)
- {
- _cmsMemoryBlock* blk;
- if (size <= 0) {
- Die("malloc requested with zero bytes");
- }
- TotalMemory += size;
- if (TotalMemory > MaxAllocated)
- MaxAllocated = TotalMemory;
- if (size > SingleHit)
- SingleHit = size;
- blk = (_cmsMemoryBlock*) chknull(malloc(size + SIZE_OF_MEM_HEADER));
- if (blk == NULL) return NULL;
- blk ->KeepSize = size;
- blk ->WhoAllocated = ContextID;
- blk ->DontCheck = 0;
- return (void*) ((cmsUInt8Number*) blk + SIZE_OF_MEM_HEADER);
- }
- // The free routine
- static
- void DebugFree(cmsContext ContextID, void *Ptr)
- {
- _cmsMemoryBlock* blk;
- if (Ptr == NULL) {
- Die("NULL free (which is a no-op in C, but may be an clue of something going wrong)");
- }
- blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
- TotalMemory -= blk ->KeepSize;
- if (blk ->WhoAllocated != ContextID && !blk->DontCheck) {
- Die("Trying to free memory allocated by a different thread");
- }
- free(blk);
- }
- // Reallocate, just a malloc, a copy and a free in this case.
- static
- void * DebugRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize)
- {
- _cmsMemoryBlock* blk;
- void* NewPtr;
- cmsUInt32Number max_sz;
- NewPtr = DebugMalloc(ContextID, NewSize);
- if (Ptr == NULL) return NewPtr;
- blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
- max_sz = blk -> KeepSize > NewSize ? NewSize : blk ->KeepSize;
- memmove(NewPtr, Ptr, max_sz);
- DebugFree(ContextID, Ptr);
- return NewPtr;
- }
- // Let's know the totals
- static
- void DebugMemPrintTotals(void)
- {
- printf("[Memory statistics]\n");
- printf("Allocated = %u MaxAlloc = %u Single block hit = %u\n", TotalMemory, MaxAllocated, SingleHit);
- }
- void DebugMemDontCheckThis(void *Ptr)
- {
- _cmsMemoryBlock* blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER);
- blk ->DontCheck = 1;
- }
- // Memory string
- static
- const char* MemStr(cmsUInt32Number size)
- {
- static char Buffer[1024];
- if (size > 1024*1024) {
- sprintf(Buffer, "%g Mb", (cmsFloat64Number) size / (1024.0*1024.0));
- }
- else
- if (size > 1024) {
- sprintf(Buffer, "%g Kb", (cmsFloat64Number) size / 1024.0);
- }
- else
- sprintf(Buffer, "%g bytes", (cmsFloat64Number) size);
- return Buffer;
- }
- void TestMemoryLeaks(cmsBool ok)
- {
- if (TotalMemory > 0)
- printf("Ok, but %s are left!\n", MemStr(TotalMemory));
- else {
- if (ok) printf("Ok.\n");
- }
- }
- // Here we go with the plug-in declaration
- static cmsPluginMemHandler DebugMemHandler = {{ cmsPluginMagicNumber, 2060-2000, cmsPluginMemHandlerSig, NULL },
- DebugMalloc, DebugFree, DebugRealloc, NULL, NULL, NULL };
- // Returns a pointer to the memhandler plugin
- void* PluginMemHandler(void)
- {
- return (void*) &DebugMemHandler;
- }
- cmsContext WatchDogContext(void* usr)
- {
- cmsContext ctx;
- ctx = cmsCreateContext(&DebugMemHandler, usr);
- if (ctx == NULL)
- Die("Unable to create memory managed context");
- DebugMemDontCheckThis(ctx);
- return ctx;
- }
- static
- void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
- {
- Die(Text);
- cmsUNUSED_PARAMETER(ContextID);
- cmsUNUSED_PARAMETER(ErrorCode);
- }
- void ResetFatalError(cmsContext ContextID)
- {
- cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
- }
- // Print a dot for gauging
- void Dot(void)
- {
- fprintf(stdout, "."); fflush(stdout);
- }
- void Say(const char* str)
- {
- fprintf(stdout, "%s", str); fflush(stdout);
- }
- // Keep track of the reason to fail
- void Fail(const char* frm, ...)
- {
- va_list args;
- va_start(args, frm);
- vsprintf(ReasonToFailBuffer, frm, args);
- va_end(args);
- }
- // Keep track of subtest
- void SubTest(const char* frm, ...)
- {
- va_list args;
- Dot();
- va_start(args, frm);
- vsprintf(SubTestBuffer, frm, args);
- va_end(args);
- }
- // The check framework
- static
- void Check(cmsContext ContextID, const char* Title, TestFn Fn)
- {
- cmsContext ctx = DbgThread();
- printf("Checking %s ...", Title);
- fflush(stdout);
- ReasonToFailBuffer[0] = 0;
- SubTestBuffer[0] = 0;
- TrappedError = FALSE;
- SimultaneousErrors = 0;
- TotalTests++;
- if (Fn(ctx) && !TrappedError) {
- // It is a good place to check memory
- TestMemoryLeaks(TRUE);
- }
- else {
- printf("FAIL!\n");
- if (SubTestBuffer[0])
- printf("%s: [%s]\n\t%s\n", Title, SubTestBuffer, ReasonToFailBuffer);
- else
- printf("%s:\n\t%s\n", Title, ReasonToFailBuffer);
- if (SimultaneousErrors > 1)
- printf("\tMore than one (%d) errors were reported\n", SimultaneousErrors);
- TotalFail++;
- }
- fflush(stdout);
- }
- // Dump a tone curve, for easy diagnostic
- void DumpToneCurve(cmsContext ContextID, cmsToneCurve* gamma, const char* FileName)
- {
- cmsHANDLE hIT8;
- cmsUInt32Number i;
- hIT8 = cmsIT8Alloc(ContextID);
- cmsIT8SetPropertyDbl(ContextID, hIT8, "NUMBER_OF_FIELDS", 2);
- cmsIT8SetPropertyDbl(ContextID, hIT8, "NUMBER_OF_SETS", gamma ->nEntries);
- cmsIT8SetDataFormat(ContextID, hIT8, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8, 1, "VALUE");
- for (i=0; i < gamma ->nEntries; i++) {
- char Val[30];
- sprintf(Val, "%u", i);
- cmsIT8SetDataRowCol(ContextID, hIT8, i, 0, Val);
- sprintf(Val, "0x%x", gamma ->Table16[i]);
- cmsIT8SetDataRowCol(ContextID, hIT8, i, 1, Val);
- }
- cmsIT8SaveToFile(ContextID, hIT8, FileName);
- cmsIT8Free(ContextID, hIT8);
- }
- // -------------------------------------------------------------------------------------------------
- // Used to perform several checks.
- // The space used is a clone of a well-known commercial
- // color space which I will name "Above RGB"
- static
- cmsHPROFILE Create_AboveRGB(cmsContext ctx)
- {
- cmsToneCurve* Curve[3];
- cmsHPROFILE hProfile;
- cmsCIExyY D65;
- cmsCIExyYTRIPLE Primaries = {{0.64, 0.33, 1 },
- {0.21, 0.71, 1 },
- {0.15, 0.06, 1 }};
- Curve[0] = Curve[1] = Curve[2] = cmsBuildGamma(ctx, 2.19921875);
- cmsWhitePointFromTemp(ctx, &D65, 6504);
- hProfile = cmsCreateRGBProfile(ctx, &D65, &Primaries, Curve);
- cmsFreeToneCurve(ctx, Curve[0]);
- return hProfile;
- }
- // A gamma-2.2 gray space
- static
- cmsHPROFILE Create_Gray22(cmsContext ctx)
- {
- cmsHPROFILE hProfile;
- cmsToneCurve* Curve = cmsBuildGamma(ctx, 2.2);
- if (Curve == NULL) return NULL;
- hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
- cmsFreeToneCurve(ctx, Curve);
- return hProfile;
- }
- // A gamma-3.0 gray space
- static
- cmsHPROFILE Create_Gray30(cmsContext ctx)
- {
- cmsHPROFILE hProfile;
- cmsToneCurve* Curve = cmsBuildGamma(ctx, 3.0);
- if (Curve == NULL) return NULL;
- hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
- cmsFreeToneCurve(ctx, Curve);
- return hProfile;
- }
- static
- cmsHPROFILE Create_GrayLab(cmsContext ctx)
- {
- cmsHPROFILE hProfile;
- cmsToneCurve* Curve = cmsBuildGamma(ctx, 1.0);
- if (Curve == NULL) return NULL;
- hProfile = cmsCreateGrayProfile(ctx, cmsD50_xyY(ctx), Curve);
- cmsFreeToneCurve(ctx, Curve);
- cmsSetPCS(ctx, hProfile, cmsSigLabData);
- return hProfile;
- }
- // A CMYK devicelink that adds gamma 3.0 to each channel
- static
- cmsHPROFILE Create_CMYK_DeviceLink(cmsContext ctx)
- {
- cmsHPROFILE hProfile;
- cmsToneCurve* Tab[4];
- cmsToneCurve* Curve = cmsBuildGamma(ctx, 3.0);
- if (Curve == NULL) return NULL;
- Tab[0] = Curve;
- Tab[1] = Curve;
- Tab[2] = Curve;
- Tab[3] = Curve;
- hProfile = cmsCreateLinearizationDeviceLink(ctx, cmsSigCmykData, Tab);
- if (hProfile == NULL) return NULL;
- cmsFreeToneCurve(ctx, Curve);
- return hProfile;
- }
- // Create a fake CMYK profile, without any other requirement that being coarse CMYK.
- // DON'T USE THIS PROFILE FOR ANYTHING, IT IS USELESS BUT FOR TESTING PURPOSES.
- typedef struct {
- cmsHTRANSFORM hLab2sRGB;
- cmsHTRANSFORM sRGB2Lab;
- cmsHTRANSFORM hIlimit;
- } FakeCMYKParams;
- static
- cmsFloat64Number Clip(cmsFloat64Number v)
- {
- if (v < 0) return 0;
- if (v > 1) return 1;
- return v;
- }
- static
- cmsInt32Number ForwardSampler(cmsContext ContextID, CMSREGISTER const cmsUInt16Number In[], cmsUInt16Number Out[], void* Cargo)
- {
- FakeCMYKParams* p = (FakeCMYKParams*) Cargo;
- cmsFloat64Number rgb[3], cmyk[4];
- cmsFloat64Number c, m, y, k;
- cmsDoTransform(ContextID, p ->hLab2sRGB, In, rgb, 1);
- c = 1 - rgb[0];
- m = 1 - rgb[1];
- y = 1 - rgb[2];
- k = (c < m ? cmsmin(c, y) : cmsmin(m, y));
- // NONSENSE WARNING!: I'm doing this just because this is a test
- // profile that may have ink limit up to 400%. There is no UCR here
- // so the profile is basically useless for anything but testing.
- cmyk[0] = c;
- cmyk[1] = m;
- cmyk[2] = y;
- cmyk[3] = k;
- cmsDoTransform(ContextID, p ->hIlimit, cmyk, Out, 1);
- return 1;
- }
- static
- cmsInt32Number ReverseSampler(cmsContext ContextID, CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
- {
- FakeCMYKParams* p = (FakeCMYKParams*) Cargo;
- cmsFloat64Number c, m, y, k, rgb[3];
- c = In[0] / 65535.0;
- m = In[1] / 65535.0;
- y = In[2] / 65535.0;
- k = In[3] / 65535.0;
- if (k == 0) {
- rgb[0] = Clip(1 - c);
- rgb[1] = Clip(1 - m);
- rgb[2] = Clip(1 - y);
- }
- else
- if (k == 1) {
- rgb[0] = rgb[1] = rgb[2] = 0;
- }
- else {
- rgb[0] = Clip((1 - c) * (1 - k));
- rgb[1] = Clip((1 - m) * (1 - k));
- rgb[2] = Clip((1 - y) * (1 - k));
- }
- cmsDoTransform(ContextID, p ->sRGB2Lab, rgb, Out, 1);
- return 1;
- }
- static
- cmsHPROFILE CreateFakeCMYK(cmsContext ContextID, cmsFloat64Number InkLimit, cmsBool lUseAboveRGB)
- {
- cmsHPROFILE hICC;
- cmsPipeline* AToB0, *BToA0;
- cmsStage* CLUT;
- FakeCMYKParams p;
- cmsHPROFILE hLab, hsRGB, hLimit;
- cmsUInt32Number cmykfrm;
- if (lUseAboveRGB)
- hsRGB = Create_AboveRGB(ContextID);
- else
- hsRGB = cmsCreate_sRGBProfile(ContextID);
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- hLimit = cmsCreateInkLimitingDeviceLink(ContextID, cmsSigCmykData, InkLimit);
- cmykfrm = FLOAT_SH(1) | BYTES_SH(0)|CHANNELS_SH(4);
- p.hLab2sRGB = cmsCreateTransform(ContextID, hLab, TYPE_Lab_16, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
- p.sRGB2Lab = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_DBL, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
- p.hIlimit = cmsCreateTransform(ContextID, hLimit, cmykfrm, NULL, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hLab); cmsCloseProfile(ContextID, hsRGB); cmsCloseProfile(ContextID, hLimit);
- hICC = cmsCreateProfilePlaceholder(ContextID);
- if (!hICC) return NULL;
- cmsSetProfileVersion(ContextID, hICC, 4.3);
- cmsSetDeviceClass(ContextID, hICC, cmsSigOutputClass);
- cmsSetColorSpace(ContextID, hICC, cmsSigCmykData);
- cmsSetPCS(ContextID, hICC, cmsSigLabData);
- BToA0 = cmsPipelineAlloc(ContextID, 3, 4);
- if (BToA0 == NULL) return 0;
- CLUT = cmsStageAllocCLut16bit(ContextID, 17, 3, 4, NULL);
- if (CLUT == NULL) return 0;
- if (!cmsStageSampleCLut16bit(ContextID, CLUT, ForwardSampler, &p, 0)) return 0;
- cmsPipelineInsertStage(ContextID, BToA0, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
- cmsPipelineInsertStage(ContextID, BToA0, cmsAT_END, CLUT);
- cmsPipelineInsertStage(ContextID, BToA0, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 4));
- if (!cmsWriteTag(ContextID, hICC, cmsSigBToA0Tag, (void*) BToA0)) return 0;
- cmsPipelineFree(ContextID, BToA0);
- AToB0 = cmsPipelineAlloc(ContextID, 4, 3);
- if (AToB0 == NULL) return 0;
- CLUT = cmsStageAllocCLut16bit(ContextID, 17, 4, 3, NULL);
- if (CLUT == NULL) return 0;
- if (!cmsStageSampleCLut16bit(ContextID, CLUT, ReverseSampler, &p, 0)) return 0;
- cmsPipelineInsertStage(ContextID, AToB0, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 4));
- cmsPipelineInsertStage(ContextID, AToB0, cmsAT_END, CLUT);
- cmsPipelineInsertStage(ContextID, AToB0, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 3));
- if (!cmsWriteTag(ContextID, hICC, cmsSigAToB0Tag, (void*) AToB0)) return 0;
- cmsPipelineFree(ContextID, AToB0);
- cmsDeleteTransform(ContextID, p.hLab2sRGB);
- cmsDeleteTransform(ContextID, p.sRGB2Lab);
- cmsDeleteTransform(ContextID, p.hIlimit);
- cmsLinkTag(ContextID, hICC, cmsSigAToB1Tag, cmsSigAToB0Tag);
- cmsLinkTag(ContextID, hICC, cmsSigAToB2Tag, cmsSigAToB0Tag);
- cmsLinkTag(ContextID, hICC, cmsSigBToA1Tag, cmsSigBToA0Tag);
- cmsLinkTag(ContextID, hICC, cmsSigBToA2Tag, cmsSigBToA0Tag);
- return hICC;
- }
- // Does create several profiles for latter use------------------------------------------------------------------------------------------------
- static
- cmsInt32Number OneVirtual(cmsContext ctx, cmsHPROFILE h, const char* SubTestTxt, const char* FileName)
- {
- SubTest(SubTestTxt);
- if (h == NULL) return 0;
- if (!cmsSaveProfileToFile(ctx, h, FileName)) return 0;
- cmsCloseProfile(ctx, h);
- h = cmsOpenProfileFromFile(ctx, FileName, "r");
- if (h == NULL) return 0;
- cmsCloseProfile(ctx, h);
- return 1;
- }
- // This test checks the ability of lcms2 to save its built-ins as valid profiles.
- // It does not check the functionality of such profiles
- static
- cmsInt32Number CreateTestProfiles(cmsContext ctx)
- {
- cmsHPROFILE h;
- h = cmsCreate_sRGBProfile(ctx);
- if (!OneVirtual(ctx, h, "sRGB profile", "sRGBlcms2.icc")) return 0;
- // ----
- h = Create_AboveRGB(ctx);
- if (!OneVirtual(ctx, h, "aRGB profile", "aRGBlcms2.icc")) return 0;
- // ----
- h = Create_Gray22(ctx);
- if (!OneVirtual(ctx, h, "Gray profile", "graylcms2.icc")) return 0;
- // ----
- h = Create_Gray30(ctx);
- if (!OneVirtual(ctx, h, "Gray 3.0 profile", "gray3lcms2.icc")) return 0;
- // ----
- h = Create_GrayLab(ctx);
- if (!OneVirtual(ctx, h, "Gray Lab profile", "glablcms2.icc")) return 0;
- // ----
- h = Create_CMYK_DeviceLink(ctx);
- if (!OneVirtual(ctx, h, "Linearization profile", "linlcms2.icc")) return 0;
- // -------
- h = cmsCreateInkLimitingDeviceLink(ctx, cmsSigCmykData, 150);
- if (h == NULL) return 0;
- if (!OneVirtual(ctx, h, "Ink-limiting profile", "limitlcms2.icc")) return 0;
- // ------
- h = cmsCreateLab2Profile(ctx, NULL);
- if (!OneVirtual(ctx, h, "Lab 2 identity profile", "labv2lcms2.icc")) return 0;
- // ----
- h = cmsCreateLab4Profile(ctx, NULL);
- if (!OneVirtual(ctx, h, "Lab 4 identity profile", "labv4lcms2.icc")) return 0;
- // ----
- h = cmsCreateXYZProfile(ctx);
- if (!OneVirtual(ctx, h, "XYZ identity profile", "xyzlcms2.icc")) return 0;
- // ----
- h = cmsCreateNULLProfile(ctx);
- if (!OneVirtual(ctx, h, "NULL profile", "nullcms2.icc")) return 0;
- // ---
- h = cmsCreateBCHSWabstractProfile(ctx, 17, 0, 0, 0, 0, 5000, 6000);
- if (!OneVirtual(ctx, h, "BCHS profile", "bchslcms2.icc")) return 0;
- // ---
- h = CreateFakeCMYK(ctx, 300, FALSE);
- if (!OneVirtual(ctx, h, "Fake CMYK profile", "lcms2cmyk.icc")) return 0;
- // ---
- h = cmsCreateBCHSWabstractProfile(ctx, 17, 0, 1.2, 0, 3, 5000, 5000);
- if (!OneVirtual(ctx, h, "Brightness", "brightness.icc")) return 0;
- return 1;
- }
- static
- void RemoveTestProfiles(void)
- {
- remove("sRGBlcms2.icc");
- remove("aRGBlcms2.icc");
- remove("graylcms2.icc");
- remove("gray3lcms2.icc");
- remove("linlcms2.icc");
- remove("limitlcms2.icc");
- remove("labv2lcms2.icc");
- remove("labv4lcms2.icc");
- remove("xyzlcms2.icc");
- remove("nullcms2.icc");
- remove("bchslcms2.icc");
- remove("lcms2cmyk.icc");
- remove("glablcms2.icc");
- remove("lcms2link.icc");
- remove("lcms2link2.icc");
- remove("brightness.icc");
- }
- // -------------------------------------------------------------------------------------------------
- // Check the size of basic types. If this test fails, nothing is going to work anyway
- static
- cmsInt32Number CheckBaseTypes(cmsContext ContextID)
- {
- // Ignore warnings about conditional expression
- #ifdef _MSC_VER
- #pragma warning(disable: 4127)
- #endif
- if (sizeof(cmsUInt8Number) != 1) return 0;
- if (sizeof(cmsInt8Number) != 1) return 0;
- if (sizeof(cmsUInt16Number) != 2) return 0;
- if (sizeof(cmsInt16Number) != 2) return 0;
- if (sizeof(cmsUInt32Number) != 4) return 0;
- if (sizeof(cmsInt32Number) != 4) return 0;
- if (sizeof(cmsUInt64Number) != 8) return 0;
- if (sizeof(cmsInt64Number) != 8) return 0;
- if (sizeof(cmsFloat32Number) != 4) return 0;
- if (sizeof(cmsFloat64Number) != 8) return 0;
- if (sizeof(cmsSignature) != 4) return 0;
- if (sizeof(cmsU8Fixed8Number) != 2) return 0;
- if (sizeof(cmsS15Fixed16Number) != 4) return 0;
- if (sizeof(cmsU16Fixed16Number) != 4) return 0;
- return 1;
- }
- // -------------------------------------------------------------------------------------------------
- // Are we little or big endian? From Harbison&Steele.
- static
- cmsInt32Number CheckEndianness(cmsContext ContextID)
- {
- cmsInt32Number BigEndian, IsOk;
- union {
- long l;
- char c[sizeof (long)];
- } u;
- u.l = 1;
- BigEndian = (u.c[sizeof (long) - 1] == 1);
- #ifdef CMS_USE_BIG_ENDIAN
- IsOk = BigEndian;
- #else
- IsOk = !BigEndian;
- #endif
- if (!IsOk) {
- Die("\nOOOPPSS! You have CMS_USE_BIG_ENDIAN toggle misconfigured!\n\n"
- "Please, edit lcms2mt.h and %s the CMS_USE_BIG_ENDIAN toggle.\n", BigEndian? "uncomment" : "comment");
- return 0;
- }
- return 1;
- }
- // Check quick floor
- static
- cmsInt32Number CheckQuickFloor(cmsContext ContextID)
- {
- if ((_cmsQuickFloor(1.234) != 1) ||
- (_cmsQuickFloor(32767.234) != 32767) ||
- (_cmsQuickFloor(-1.234) != -2) ||
- (_cmsQuickFloor(-32767.1) != -32768)) {
- Die("\nOOOPPSS! _cmsQuickFloor() does not work as expected in your machine!\n\n"
- "Please, edit lcms2mt.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
- return 0;
- }
- return 1;
- }
- // Quick floor restricted to word
- static
- cmsInt32Number CheckQuickFloorWord(cmsContext ContextID)
- {
- cmsUInt32Number i;
- for (i=0; i < 65535; i++) {
- if (_cmsQuickFloorWord((cmsFloat64Number) i + 0.1234) != i) {
- Die("\nOOOPPSS! _cmsQuickFloorWord() does not work as expected in your machine!\n\n"
- "Please, edit lcms2mt.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
- return 0;
- }
- }
- return 1;
- }
- // -------------------------------------------------------------------------------------------------
- // Precision stuff.
- // On 15.16 fixed point, this is the maximum we can obtain. Remember ICC profiles have storage limits on this number
- #define FIXED_PRECISION_15_16 (1.0 / 65535.0)
- // On 8.8 fixed point, that is the max we can obtain.
- #define FIXED_PRECISION_8_8 (1.0 / 255.0)
- // On cmsFloat32Number type, this is the precision we expect
- #define FLOAT_PRECISSION (0.00001)
- static cmsFloat64Number MaxErr;
- cmsBool IsGoodVal(const char *title, cmsFloat64Number in, cmsFloat64Number out, cmsFloat64Number max)
- {
- cmsFloat64Number Err = fabs(in - out);
- if (Err > MaxErr) MaxErr = Err;
- if ((Err > max )) {
- Fail("(%s): Must be %f, But is %f ", title, in, out);
- return FALSE;
- }
- return TRUE;
- }
- cmsBool IsGoodFixed15_16(const char *title, cmsFloat64Number in, cmsFloat64Number out)
- {
- return IsGoodVal(title, in, out, FIXED_PRECISION_15_16);
- }
- cmsBool IsGoodFixed8_8(const char *title, cmsFloat64Number in, cmsFloat64Number out)
- {
- return IsGoodVal(title, in, out, FIXED_PRECISION_8_8);
- }
- cmsBool IsGoodWord(const char *title, cmsUInt16Number in, cmsUInt16Number out)
- {
- if ((abs(in - out) > 0 )) {
- Fail("(%s): Must be %x, But is %x ", title, in, out);
- return FALSE;
- }
- return TRUE;
- }
- cmsBool IsGoodWordPrec(const char *title, cmsUInt16Number in, cmsUInt16Number out, cmsUInt16Number maxErr)
- {
- if ((abs(in - out) > maxErr )) {
- Fail("(%s): Must be %x, But is %x ", title, in, out);
- return FALSE;
- }
- return TRUE;
- }
- // Fixed point ----------------------------------------------------------------------------------------------
- static
- cmsInt32Number TestSingleFixed15_16(cmsContext ContextID, cmsFloat64Number d)
- {
- cmsS15Fixed16Number f = _cmsDoubleTo15Fixed16(ContextID, d);
- cmsFloat64Number RoundTrip = _cms15Fixed16toDouble(ContextID, f);
- cmsFloat64Number Error = fabs(d - RoundTrip);
- return ( Error <= FIXED_PRECISION_15_16);
- }
- static
- cmsInt32Number CheckFixedPoint15_16(cmsContext ContextID)
- {
- if (!TestSingleFixed15_16(ContextID, 1.0)) return 0;
- if (!TestSingleFixed15_16(ContextID, 2.0)) return 0;
- if (!TestSingleFixed15_16(ContextID, 1.23456)) return 0;
- if (!TestSingleFixed15_16(ContextID, 0.99999)) return 0;
- if (!TestSingleFixed15_16(ContextID, 0.1234567890123456789099999)) return 0;
- if (!TestSingleFixed15_16(ContextID, -1.0)) return 0;
- if (!TestSingleFixed15_16(ContextID, -2.0)) return 0;
- if (!TestSingleFixed15_16(ContextID, -1.23456)) return 0;
- if (!TestSingleFixed15_16(ContextID, -1.1234567890123456789099999)) return 0;
- if (!TestSingleFixed15_16(ContextID, +32767.1234567890123456789099999)) return 0;
- if (!TestSingleFixed15_16(ContextID, -32767.1234567890123456789099999)) return 0;
- return 1;
- }
- static
- cmsInt32Number TestSingleFixed8_8(cmsContext ContextID, cmsFloat64Number d)
- {
- cmsS15Fixed16Number f = _cmsDoubleTo8Fixed8(ContextID, d);
- cmsFloat64Number RoundTrip = _cms8Fixed8toDouble(ContextID, (cmsUInt16Number) f);
- cmsFloat64Number Error = fabs(d - RoundTrip);
- return ( Error <= FIXED_PRECISION_8_8);
- }
- static
- cmsInt32Number CheckFixedPoint8_8(cmsContext ContextID)
- {
- if (!TestSingleFixed8_8(ContextID, 1.0)) return 0;
- if (!TestSingleFixed8_8(ContextID, 2.0)) return 0;
- if (!TestSingleFixed8_8(ContextID, 1.23456)) return 0;
- if (!TestSingleFixed8_8(ContextID, 0.99999)) return 0;
- if (!TestSingleFixed8_8(ContextID, 0.1234567890123456789099999)) return 0;
- if (!TestSingleFixed8_8(ContextID, +255.1234567890123456789099999)) return 0;
- return 1;
- }
- // D50 constant --------------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckD50Roundtrip(cmsContext ContextID)
- {
- cmsFloat64Number cmsD50X_2 = 0.96420288;
- cmsFloat64Number cmsD50Y_2 = 1.0;
- cmsFloat64Number cmsD50Z_2 = 0.82490540;
- cmsS15Fixed16Number xe = _cmsDoubleTo15Fixed16(ContextID, cmsD50X);
- cmsS15Fixed16Number ye = _cmsDoubleTo15Fixed16(ContextID, cmsD50Y);
- cmsS15Fixed16Number ze = _cmsDoubleTo15Fixed16(ContextID, cmsD50Z);
- cmsFloat64Number x = _cms15Fixed16toDouble(ContextID, xe);
- cmsFloat64Number y = _cms15Fixed16toDouble(ContextID, ye);
- cmsFloat64Number z = _cms15Fixed16toDouble(ContextID, ze);
- double dx = fabs(cmsD50X - x);
- double dy = fabs(cmsD50Y - y);
- double dz = fabs(cmsD50Z - z);
- double euc = sqrt(dx*dx + dy*dy + dz* dz);
- if (euc > 1E-5) {
- Fail("D50 roundtrip |err| > (%f) ", euc);
- return 0;
- }
- xe = _cmsDoubleTo15Fixed16(ContextID, cmsD50X_2);
- ye = _cmsDoubleTo15Fixed16(ContextID, cmsD50Y_2);
- ze = _cmsDoubleTo15Fixed16(ContextID, cmsD50Z_2);
- x = _cms15Fixed16toDouble(ContextID, xe);
- y = _cms15Fixed16toDouble(ContextID, ye);
- z = _cms15Fixed16toDouble(ContextID, ze);
- dx = fabs(cmsD50X_2 - x);
- dy = fabs(cmsD50Y_2 - y);
- dz = fabs(cmsD50Z_2 - z);
- euc = sqrt(dx*dx + dy*dy + dz* dz);
- if (euc > 1E-5) {
- Fail("D50 roundtrip |err| > (%f) ", euc);
- return 0;
- }
- return 1;
- }
- // Linear interpolation -----------------------------------------------------------------------------------------------
- // Since prime factors of 65535 (FFFF) are,
- //
- // 0xFFFF = 3 * 5 * 17 * 257
- //
- // I test tables of 2, 4, 6, and 18 points, that will be exact.
- static
- void BuildTable(cmsInt32Number n, cmsUInt16Number Tab[], cmsBool Descending)
- {
- cmsInt32Number i;
- for (i=0; i < n; i++) {
- cmsFloat64Number v = (cmsFloat64Number) ((cmsFloat64Number) 65535.0 * i ) / (n-1);
- Tab[Descending ? (n - i - 1) : i ] = (cmsUInt16Number) floor(v + 0.5);
- }
- }
- // A single function that does check 1D interpolation
- // nNodesToCheck = number on nodes to check
- // Down = Create decreasing tables
- // Reverse = Check reverse interpolation
- // max_err = max allowed error
- static
- cmsInt32Number Check1D(cmsContext ContextID, cmsInt32Number nNodesToCheck, cmsBool Down, cmsInt32Number max_err)
- {
- cmsUInt32Number i;
- cmsUInt16Number in, out;
- cmsInterpParams* p;
- cmsUInt16Number* Tab;
- Tab = (cmsUInt16Number*) chknull(malloc(sizeof(cmsUInt16Number)* nNodesToCheck));
- if (Tab == NULL) return 0;
- p = _cmsComputeInterpParams(ContextID, nNodesToCheck, 1, 1, Tab, CMS_LERP_FLAGS_16BITS);
- if (p == NULL) return 0;
- BuildTable(nNodesToCheck, Tab, Down);
- for (i=0; i <= 0xffff; i++) {
- in = (cmsUInt16Number) i;
- out = 0;
- p ->Interpolation.Lerp16(ContextID, &in, &out, p);
- if (Down) out = 0xffff - out;
- if (abs(out - in) > max_err) {
- Fail("(%dp): Must be %x, But is %x : ", nNodesToCheck, in, out);
- _cmsFreeInterpParams(ContextID, p);
- free(Tab);
- return 0;
- }
- }
- _cmsFreeInterpParams(ContextID, p);
- free(Tab);
- return 1;
- }
- static
- cmsInt32Number Check1DLERP2(cmsContext ContextID)
- {
- return Check1D(ContextID, 2, FALSE, 0);
- }
- static
- cmsInt32Number Check1DLERP3(cmsContext ContextID)
- {
- return Check1D(ContextID, 3, FALSE, 1);
- }
- static
- cmsInt32Number Check1DLERP4(cmsContext ContextID)
- {
- return Check1D(ContextID, 4, FALSE, 0);
- }
- static
- cmsInt32Number Check1DLERP6(cmsContext ContextID)
- {
- return Check1D(ContextID, 6, FALSE, 0);
- }
- static
- cmsInt32Number Check1DLERP18(cmsContext ContextID)
- {
- return Check1D(ContextID, 18, FALSE, 0);
- }
- static
- cmsInt32Number Check1DLERP2Down(cmsContext ContextID)
- {
- return Check1D(ContextID, 2, TRUE, 0);
- }
- static
- cmsInt32Number Check1DLERP3Down(cmsContext ContextID)
- {
- return Check1D(ContextID, 3, TRUE, 1);
- }
- static
- cmsInt32Number Check1DLERP6Down(cmsContext ContextID)
- {
- return Check1D(ContextID, 6, TRUE, 0);
- }
- static
- cmsInt32Number Check1DLERP18Down(cmsContext ContextID)
- {
- return Check1D(ContextID, 18, TRUE, 0);
- }
- static
- cmsInt32Number ExhaustiveCheck1DLERP(cmsContext ContextID)
- {
- cmsUInt32Number j;
- printf("\n");
- for (j=10; j <= 4096; j++) {
- if ((j % 10) == 0) printf("%u \r", j);
- if (!Check1D(ContextID, j, FALSE, 1)) return 0;
- }
- printf("\rResult is ");
- return 1;
- }
- static
- cmsInt32Number ExhaustiveCheck1DLERPDown(cmsContext ContextID)
- {
- cmsUInt32Number j;
- printf("\n");
- for (j=10; j <= 4096; j++) {
- if ((j % 10) == 0) printf("%u \r", j);
- if (!Check1D(ContextID, j, TRUE, 1)) return 0;
- }
- printf("\rResult is ");
- return 1;
- }
- // 3D interpolation -------------------------------------------------------------------------------------------------
- static
- cmsInt32Number Check3DinterpolationFloatTetrahedral(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number i;
- cmsFloat32Number In[3], Out[3];
- cmsFloat32Number FloatTable[] = { //R G B
- 0, 0, 0, // B=0,G=0,R=0
- 0, 0, .25, // B=1,G=0,R=0
- 0, .5, 0, // B=0,G=1,R=0
- 0, .5, .25, // B=1,G=1,R=0
- 1, 0, 0, // B=0,G=0,R=1
- 1, 0, .25, // B=1,G=0,R=1
- 1, .5, 0, // B=0,G=1,R=1
- 1, .5, .25 // B=1,G=1,R=1
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT);
- MaxErr = 0.0;
- for (i=0; i < 0xffff; i++) {
- In[0] = In[1] = In[2] = (cmsFloat32Number) ( (cmsFloat32Number) i / 65535.0F);
- p ->Interpolation.LerpFloat(ContextID, In, Out, p);
- if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
- if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number Check3DinterpolationFloatTrilinear(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number i;
- cmsFloat32Number In[3], Out[3];
- cmsFloat32Number FloatTable[] = { //R G B
- 0, 0, 0, // B=0,G=0,R=0
- 0, 0, .25, // B=1,G=0,R=0
- 0, .5, 0, // B=0,G=1,R=0
- 0, .5, .25, // B=1,G=1,R=0
- 1, 0, 0, // B=0,G=0,R=1
- 1, 0, .25, // B=1,G=0,R=1
- 1, .5, 0, // B=0,G=1,R=1
- 1, .5, .25 // B=1,G=1,R=1
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT|CMS_LERP_FLAGS_TRILINEAR);
- MaxErr = 0.0;
- for (i=0; i < 0xffff; i++) {
- In[0] = In[1] = In[2] = (cmsFloat32Number) ( (cmsFloat32Number) i / 65535.0F);
- p ->Interpolation.LerpFloat(ContextID, In, Out, p);
- if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
- if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number Check3DinterpolationTetrahedral16(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number i;
- cmsUInt16Number In[3], Out[3];
- cmsUInt16Number Table[] = {
- 0, 0, 0,
- 0, 0, 0xffff,
- 0, 0xffff, 0,
- 0, 0xffff, 0xffff,
- 0xffff, 0, 0,
- 0xffff, 0, 0xffff,
- 0xffff, 0xffff, 0,
- 0xffff, 0xffff, 0xffff
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_16BITS);
- MaxErr = 0.0;
- for (i=0; i < 0xffff; i++) {
- In[0] = In[1] = In[2] = (cmsUInt16Number) i;
- p ->Interpolation.Lerp16(ContextID, In, Out, p);
- if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
- if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number Check3DinterpolationTrilinear16(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number i;
- cmsUInt16Number In[3], Out[3];
- cmsUInt16Number Table[] = {
- 0, 0, 0,
- 0, 0, 0xffff,
- 0, 0xffff, 0,
- 0, 0xffff, 0xffff,
- 0xffff, 0, 0,
- 0xffff, 0, 0xffff,
- 0xffff, 0xffff, 0,
- 0xffff, 0xffff, 0xffff
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_TRILINEAR);
- MaxErr = 0.0;
- for (i=0; i < 0xffff; i++) {
- In[0] = In[1] = In[2] = (cmsUInt16Number) i;
- p ->Interpolation.Lerp16(ContextID, In, Out, p);
- if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
- if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number ExaustiveCheck3DinterpolationFloatTetrahedral(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number r, g, b;
- cmsFloat32Number In[3], Out[3];
- cmsFloat32Number FloatTable[] = { //R G B
- 0, 0, 0, // B=0,G=0,R=0
- 0, 0, .25, // B=1,G=0,R=0
- 0, .5, 0, // B=0,G=1,R=0
- 0, .5, .25, // B=1,G=1,R=0
- 1, 0, 0, // B=0,G=0,R=1
- 1, 0, .25, // B=1,G=0,R=1
- 1, .5, 0, // B=0,G=1,R=1
- 1, .5, .25 // B=1,G=1,R=1
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT);
- MaxErr = 0.0;
- for (r=0; r < 0xff; r++)
- for (g=0; g < 0xff; g++)
- for (b=0; b < 0xff; b++)
- {
- In[0] = (cmsFloat32Number) r / 255.0F;
- In[1] = (cmsFloat32Number) g / 255.0F;
- In[2] = (cmsFloat32Number) b / 255.0F;
- p ->Interpolation.LerpFloat(ContextID, In, Out, p);
- if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
- if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number ExaustiveCheck3DinterpolationFloatTrilinear(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number r, g, b;
- cmsFloat32Number In[3], Out[3];
- cmsFloat32Number FloatTable[] = { //R G B
- 0, 0, 0, // B=0,G=0,R=0
- 0, 0, .25, // B=1,G=0,R=0
- 0, .5, 0, // B=0,G=1,R=0
- 0, .5, .25, // B=1,G=1,R=0
- 1, 0, 0, // B=0,G=0,R=1
- 1, 0, .25, // B=1,G=0,R=1
- 1, .5, 0, // B=0,G=1,R=1
- 1, .5, .25 // B=1,G=1,R=1
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, FloatTable, CMS_LERP_FLAGS_FLOAT|CMS_LERP_FLAGS_TRILINEAR);
- MaxErr = 0.0;
- for (r=0; r < 0xff; r++)
- for (g=0; g < 0xff; g++)
- for (b=0; b < 0xff; b++)
- {
- In[0] = (cmsFloat32Number) r / 255.0F;
- In[1] = (cmsFloat32Number) g / 255.0F;
- In[2] = (cmsFloat32Number) b / 255.0F;
- p ->Interpolation.LerpFloat(ContextID, In, Out, p);
- if (!IsGoodFixed15_16("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodFixed15_16("Channel 2", Out[1], (cmsFloat32Number) In[1] / 2.F)) goto Error;
- if (!IsGoodFixed15_16("Channel 3", Out[2], (cmsFloat32Number) In[2] / 4.F)) goto Error;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr);
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number ExhaustiveCheck3DinterpolationTetrahedral16(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number r, g, b;
- cmsUInt16Number In[3], Out[3];
- cmsUInt16Number Table[] = {
- 0, 0, 0,
- 0, 0, 0xffff,
- 0, 0xffff, 0,
- 0, 0xffff, 0xffff,
- 0xffff, 0, 0,
- 0xffff, 0, 0xffff,
- 0xffff, 0xffff, 0,
- 0xffff, 0xffff, 0xffff
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_16BITS);
- for (r=0; r < 0xff; r++)
- for (g=0; g < 0xff; g++)
- for (b=0; b < 0xff; b++)
- {
- In[0] = (cmsUInt16Number) r ;
- In[1] = (cmsUInt16Number) g ;
- In[2] = (cmsUInt16Number) b ;
- p ->Interpolation.Lerp16(ContextID, In, Out, p);
- if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
- if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
- }
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- static
- cmsInt32Number ExhaustiveCheck3DinterpolationTrilinear16(cmsContext ContextID)
- {
- cmsInterpParams* p;
- cmsInt32Number r, g, b;
- cmsUInt16Number In[3], Out[3];
- cmsUInt16Number Table[] = {
- 0, 0, 0,
- 0, 0, 0xffff,
- 0, 0xffff, 0,
- 0, 0xffff, 0xffff,
- 0xffff, 0, 0,
- 0xffff, 0, 0xffff,
- 0xffff, 0xffff, 0,
- 0xffff, 0xffff, 0xffff
- };
- p = _cmsComputeInterpParams(ContextID, 2, 3, 3, Table, CMS_LERP_FLAGS_TRILINEAR);
- for (r=0; r < 0xff; r++)
- for (g=0; g < 0xff; g++)
- for (b=0; b < 0xff; b++)
- {
- In[0] = (cmsUInt16Number) r ;
- In[1] = (cmsUInt16Number)g ;
- In[2] = (cmsUInt16Number)b ;
- p ->Interpolation.Lerp16(ContextID, In, Out, p);
- if (!IsGoodWord("Channel 1", Out[0], In[0])) goto Error;
- if (!IsGoodWord("Channel 2", Out[1], In[1])) goto Error;
- if (!IsGoodWord("Channel 3", Out[2], In[2])) goto Error;
- }
- _cmsFreeInterpParams(ContextID, p);
- return 1;
- Error:
- _cmsFreeInterpParams(ContextID, p);
- return 0;
- }
- // Check reverse interpolation on LUTS. This is right now exclusively used by K preservation algorithm
- static
- cmsInt32Number CheckReverseInterpolation3x3(cmsContext ContextID)
- {
- cmsPipeline* Lut;
- cmsStage* clut;
- cmsFloat32Number Target[4], Result[4], Hint[4];
- cmsFloat32Number err, max;
- cmsInt32Number i;
- cmsUInt16Number Table[] = {
- 0, 0, 0, // 0 0 0
- 0, 0, 0xffff, // 0 0 1
- 0, 0xffff, 0, // 0 1 0
- 0, 0xffff, 0xffff, // 0 1 1
- 0xffff, 0, 0, // 1 0 0
- 0xffff, 0, 0xffff, // 1 0 1
- 0xffff, 0xffff, 0, // 1 1 0
- 0xffff, 0xffff, 0xffff, // 1 1 1
- };
- Lut = cmsPipelineAlloc(ContextID, 3, 3);
- clut = cmsStageAllocCLut16bit(ContextID, 2, 3, 3, Table);
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, clut);
- Target[0] = 0; Target[1] = 0; Target[2] = 0;
- Hint[0] = 0; Hint[1] = 0; Hint[2] = 0;
- cmsPipelineEvalReverseFloat(ContextID, Target, Result, NULL, Lut);
- if (Result[0] != 0 || Result[1] != 0 || Result[2] != 0){
- Fail("Reverse interpolation didn't find zero");
- goto Error;
- }
- // Transverse identity
- max = 0;
- for (i=0; i <= 100; i++) {
- cmsFloat32Number in = i / 100.0F;
- Target[0] = in; Target[1] = 0; Target[2] = 0;
- cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
- err = fabsf(in - Result[0]);
- if (err > max) max = err;
- memcpy(Hint, Result, sizeof(Hint));
- }
- cmsPipelineFree(ContextID, Lut);
- return (max <= FLOAT_PRECISSION);
- Error:
- cmsPipelineFree(ContextID, Lut);
- return 0;
- }
- static
- cmsInt32Number CheckReverseInterpolation4x3(cmsContext ContextID)
- {
- cmsPipeline* Lut;
- cmsStage* clut;
- cmsFloat32Number Target[4], Result[4], Hint[4];
- cmsFloat32Number err, max;
- cmsInt32Number i;
- // 4 -> 3, output gets 3 first channels copied
- cmsUInt16Number Table[] = {
- 0, 0, 0, // 0 0 0 0 = ( 0, 0, 0)
- 0, 0, 0, // 0 0 0 1 = ( 0, 0, 0)
- 0, 0, 0xffff, // 0 0 1 0 = ( 0, 0, 1)
- 0, 0, 0xffff, // 0 0 1 1 = ( 0, 0, 1)
- 0, 0xffff, 0, // 0 1 0 0 = ( 0, 1, 0)
- 0, 0xffff, 0, // 0 1 0 1 = ( 0, 1, 0)
- 0, 0xffff, 0xffff, // 0 1 1 0 = ( 0, 1, 1)
- 0, 0xffff, 0xffff, // 0 1 1 1 = ( 0, 1, 1)
- 0xffff, 0, 0, // 1 0 0 0 = ( 1, 0, 0)
- 0xffff, 0, 0, // 1 0 0 1 = ( 1, 0, 0)
- 0xffff, 0, 0xffff, // 1 0 1 0 = ( 1, 0, 1)
- 0xffff, 0, 0xffff, // 1 0 1 1 = ( 1, 0, 1)
- 0xffff, 0xffff, 0, // 1 1 0 0 = ( 1, 1, 0)
- 0xffff, 0xffff, 0, // 1 1 0 1 = ( 1, 1, 0)
- 0xffff, 0xffff, 0xffff, // 1 1 1 0 = ( 1, 1, 1)
- 0xffff, 0xffff, 0xffff, // 1 1 1 1 = ( 1, 1, 1)
- };
- Lut = cmsPipelineAlloc(ContextID, 4, 3);
- clut = cmsStageAllocCLut16bit(ContextID, 2, 4, 3, Table);
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, clut);
- // Check if the LUT is behaving as expected
- SubTest("4->3 feasibility");
- for (i=0; i <= 100; i++) {
- Target[0] = i / 100.0F;
- Target[1] = Target[0];
- Target[2] = 0;
- Target[3] = 12;
- cmsPipelineEvalFloat(ContextID, Target, Result, Lut);
- if (!IsGoodFixed15_16("0", Target[0], Result[0])) goto Error;
- if (!IsGoodFixed15_16("1", Target[1], Result[1])) goto Error;
- if (!IsGoodFixed15_16("2", Target[2], Result[2])) goto Error;
- }
- SubTest("4->3 zero");
- Target[0] = 0;
- Target[1] = 0;
- Target[2] = 0;
- // This one holds the fixed K
- Target[3] = 0;
- // This is our hint (which is a big lie in this case)
- Hint[0] = 0.1F; Hint[1] = 0.1F; Hint[2] = 0.1F;
- cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
- if (Result[0] != 0 || Result[1] != 0 || Result[2] != 0 || Result[3] != 0){
- Fail("Reverse interpolation didn't find zero");
- goto Error;
- }
- SubTest("4->3 find CMY");
- max = 0;
- for (i=0; i <= 100; i++) {
- cmsFloat32Number in = i / 100.0F;
- Target[0] = in; Target[1] = 0; Target[2] = 0;
- cmsPipelineEvalReverseFloat(ContextID, Target, Result, Hint, Lut);
- err = fabsf(in - Result[0]);
- if (err > max) max = err;
- memcpy(Hint, Result, sizeof(Hint));
- }
- cmsPipelineFree(ContextID, Lut);
- return (max <= FLOAT_PRECISSION);
- Error:
- cmsPipelineFree(ContextID, Lut);
- return 0;
- }
- // Check all interpolation.
- static
- cmsUInt16Number Fn8D1(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
- cmsUInt32Number m)
- {
- return (cmsUInt16Number) ((a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8) / m);
- }
- static
- cmsUInt16Number Fn8D2(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
- cmsUInt32Number m)
- {
- return (cmsUInt16Number) ((a1 + 3* a2 + 3* a3 + a4 + a5 + a6 + a7 + a8 ) / (m + 4));
- }
- static
- cmsUInt16Number Fn8D3(cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6, cmsUInt16Number a7, cmsUInt16Number a8,
- cmsUInt32Number m)
- {
- return (cmsUInt16Number) ((3*a1 + 2*a2 + 3*a3 + a4 + a5 + a6 + a7 + a8) / (m + 5));
- }
- static
- cmsInt32Number Sampler3D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
- Out[1] = Fn8D2(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
- Out[2] = Fn8D3(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsInt32Number Sampler4D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
- Out[1] = Fn8D2(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
- Out[2] = Fn8D3(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsInt32Number Sampler5D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
- Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
- Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsInt32Number Sampler6D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
- Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
- Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsInt32Number Sampler7D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
- Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
- Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsInt32Number Sampler8D(cmsContext ContextID,
- CMSREGISTER const cmsUInt16Number In[],
- CMSREGISTER cmsUInt16Number Out[],
- CMSREGISTER void * Cargo)
- {
- Out[0] = Fn8D1(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
- Out[1] = Fn8D2(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
- Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
- return 1;
- cmsUNUSED_PARAMETER(Cargo);
- }
- static
- cmsBool CheckOne3D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3)
- {
- cmsUInt16Number In[3], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler3D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsBool CheckOne4D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2, cmsUInt16Number a3, cmsUInt16Number a4)
- {
- cmsUInt16Number In[4], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler4D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsBool CheckOne5D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
- cmsUInt16Number a3, cmsUInt16Number a4, cmsUInt16Number a5)
- {
- cmsUInt16Number In[5], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler5D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsBool CheckOne6D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
- cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6)
- {
- cmsUInt16Number In[6], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler6D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsBool CheckOne7D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
- cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6,
- cmsUInt16Number a7)
- {
- cmsUInt16Number In[7], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6; In[6] = a7;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler7D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsBool CheckOne8D(cmsContext ContextID, cmsPipeline* lut, cmsUInt16Number a1, cmsUInt16Number a2,
- cmsUInt16Number a3, cmsUInt16Number a4,
- cmsUInt16Number a5, cmsUInt16Number a6,
- cmsUInt16Number a7, cmsUInt16Number a8)
- {
- cmsUInt16Number In[8], Out1[3], Out2[3];
- In[0] = a1; In[1] = a2; In[2] = a3; In[3] = a4; In[4] = a5; In[5] = a6; In[6] = a7; In[7] = a8;
- // This is the interpolated value
- cmsPipelineEval16(ContextID, In, Out1, lut);
- // This is the real value
- Sampler8D(ContextID, In, Out2, NULL);
- // Let's see the difference
- if (!IsGoodWordPrec("Channel 1", Out1[0], Out2[0], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 2", Out1[1], Out2[1], 2)) return FALSE;
- if (!IsGoodWordPrec("Channel 3", Out1[2], Out2[2], 2)) return FALSE;
- return TRUE;
- }
- static
- cmsInt32Number Check3Dinterp(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- lut = cmsPipelineAlloc(ContextID, 3, 3);
- mpe = cmsStageAllocCLut16bit(ContextID, 9, 3, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler3D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne3D(ContextID, lut, 0, 0, 0)) return 0;
- if (!CheckOne3D(ContextID, lut, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x8080, 0x8080, 0x8080)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x0000, 0xFE00, 0x80FF)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x1111, 0x2222, 0x3333)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x0000, 0x0012, 0x0013)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x3141, 0x1415, 0x1592)) return 0;
- if (!CheckOne3D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check3DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 7, 8, 9 };
- lut = cmsPipelineAlloc(ContextID, 3, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler3D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne3D(ContextID, lut, 0, 0, 0)) return 0;
- if (!CheckOne3D(ContextID, lut, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x8080, 0x8080, 0x8080)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x0000, 0xFE00, 0x80FF)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x1111, 0x2222, 0x3333)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x0000, 0x0012, 0x0013)) return 0;
- if (!CheckOne3D(ContextID, lut, 0x3141, 0x1415, 0x1592)) return 0;
- if (!CheckOne3D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check4Dinterp(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- lut = cmsPipelineAlloc(ContextID, 4, 3);
- mpe = cmsStageAllocCLut16bit(ContextID, 9, 4, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler4D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne4D(ContextID, lut, 0, 0, 0, 0)) return 0;
- if (!CheckOne4D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
- if (!CheckOne4D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check4DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 9, 8, 7, 6 };
- lut = cmsPipelineAlloc(ContextID, 4, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 4, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler4D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne4D(ContextID, lut, 0, 0, 0, 0)) return 0;
- if (!CheckOne4D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
- if (!CheckOne4D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
- if (!CheckOne4D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check5DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 3, 2, 2, 2, 2 };
- lut = cmsPipelineAlloc(ContextID, 5, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 5, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler5D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne5D(ContextID, lut, 0, 0, 0, 0, 0)) return 0;
- if (!CheckOne5D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne5D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234)) return 0;
- if (!CheckOne5D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078)) return 0;
- if (!CheckOne5D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455)) return 0;
- if (!CheckOne5D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333)) return 0;
- if (!CheckOne5D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567)) return 0;
- if (!CheckOne5D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check6DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2 };
- lut = cmsPipelineAlloc(ContextID, 6, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 6, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler6D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne6D(ContextID, lut, 0, 0, 0, 0, 0, 0)) return 0;
- if (!CheckOne6D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne6D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122)) return 0;
- if (!CheckOne6D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233)) return 0;
- if (!CheckOne6D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344)) return 0;
- if (!CheckOne6D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455)) return 0;
- if (!CheckOne6D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566)) return 0;
- if (!CheckOne6D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check7DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2, 2 };
- lut = cmsPipelineAlloc(ContextID, 7, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 7, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler7D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne7D(ContextID, lut, 0, 0, 0, 0, 0, 0, 0)) return 0;
- if (!CheckOne7D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne7D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056)) return 0;
- if (!CheckOne7D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088)) return 0;
- if (!CheckOne7D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987)) return 0;
- if (!CheckOne7D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988)) return 0;
- if (!CheckOne7D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56)) return 0;
- if (!CheckOne7D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- static
- cmsInt32Number Check8DinterpGranular(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsStage* mpe;
- cmsUInt32Number Dimensions[] = { 4, 3, 3, 2, 2, 2, 2, 2 };
- lut = cmsPipelineAlloc(ContextID, 8, 3);
- mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 8, 3, NULL);
- cmsStageSampleCLut16bit(ContextID, mpe, Sampler8D, NULL, 0);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_BEGIN, mpe);
- // Check accuracy
- if (!CheckOne8D(ContextID, lut, 0, 0, 0, 0, 0, 0, 0, 0)) return 0;
- if (!CheckOne8D(ContextID, lut, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
- if (!CheckOne8D(ContextID, lut, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056, 0x0011)) return 0;
- if (!CheckOne8D(ContextID, lut, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088, 0x2020)) return 0;
- if (!CheckOne8D(ContextID, lut, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987, 0x4532)) return 0;
- if (!CheckOne8D(ContextID, lut, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988, 0x1200)) return 0;
- if (!CheckOne8D(ContextID, lut, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56, 0x6666)) return 0;
- if (!CheckOne8D(ContextID, lut, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe, 0xface)) return 0;
- cmsPipelineFree(ContextID, lut);
- return 1;
- }
- // Colorimetric conversions -------------------------------------------------------------------------------------------------
- // Lab to LCh and back should be performed at 1E-12 accuracy at least
- static
- cmsInt32Number CheckLab2LCh(cmsContext ContextID)
- {
- cmsInt32Number l, a, b;
- cmsFloat64Number dist, Max = 0;
- cmsCIELab Lab, Lab2;
- cmsCIELCh LCh;
- for (l=0; l <= 100; l += 10) {
- for (a=-128; a <= +128; a += 8) {
- for (b=-128; b <= 128; b += 8) {
- Lab.L = l;
- Lab.a = a;
- Lab.b = b;
- cmsLab2LCh(ContextID, &LCh, &Lab);
- cmsLCh2Lab(ContextID, &Lab2, &LCh);
- dist = cmsDeltaE(ContextID, &Lab, &Lab2);
- if (dist > Max) Max = dist;
- }
- }
- }
- return Max < 1E-12;
- }
- // Lab to LCh and back should be performed at 1E-12 accuracy at least
- static
- cmsInt32Number CheckLab2XYZ(cmsContext ContextID)
- {
- cmsInt32Number l, a, b;
- cmsFloat64Number dist, Max = 0;
- cmsCIELab Lab, Lab2;
- cmsCIEXYZ XYZ;
- for (l=0; l <= 100; l += 10) {
- for (a=-128; a <= +128; a += 8) {
- for (b=-128; b <= 128; b += 8) {
- Lab.L = l;
- Lab.a = a;
- Lab.b = b;
- cmsLab2XYZ(ContextID, NULL, &XYZ, &Lab);
- cmsXYZ2Lab(ContextID, NULL, &Lab2, &XYZ);
- dist = cmsDeltaE(ContextID, &Lab, &Lab2);
- if (dist > Max) Max = dist;
- }
- }
- }
- return Max < 1E-12;
- }
- // Lab to xyY and back should be performed at 1E-12 accuracy at least
- static
- cmsInt32Number CheckLab2xyY(cmsContext ContextID)
- {
- cmsInt32Number l, a, b;
- cmsFloat64Number dist, Max = 0;
- cmsCIELab Lab, Lab2;
- cmsCIEXYZ XYZ;
- cmsCIExyY xyY;
- for (l=0; l <= 100; l += 10) {
- for (a=-128; a <= +128; a += 8) {
- for (b=-128; b <= 128; b += 8) {
- Lab.L = l;
- Lab.a = a;
- Lab.b = b;
- cmsLab2XYZ(ContextID, NULL, &XYZ, &Lab);
- cmsXYZ2xyY(ContextID, &xyY, &XYZ);
- cmsxyY2XYZ(ContextID, &XYZ, &xyY);
- cmsXYZ2Lab(ContextID, NULL, &Lab2, &XYZ);
- dist = cmsDeltaE(ContextID, &Lab, &Lab2);
- if (dist > Max) Max = dist;
- }
- }
- }
- return Max < 1E-12;
- }
- static
- cmsInt32Number CheckLabV2encoding(cmsContext ContextID)
- {
- cmsInt32Number n2, i, j;
- cmsUInt16Number Inw[3], aw[3];
- cmsCIELab Lab;
- n2=0;
- for (j=0; j < 65535; j++) {
- Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
- cmsLabEncoded2FloatV2(ContextID, &Lab, Inw);
- cmsFloat2LabEncodedV2(ContextID, aw, &Lab);
- for (i=0; i < 3; i++) {
- if (aw[i] != j) {
- n2++;
- }
- }
- }
- return (n2 == 0);
- }
- static
- cmsInt32Number CheckLabV4encoding(cmsContext ContextID)
- {
- cmsInt32Number n2, i, j;
- cmsUInt16Number Inw[3], aw[3];
- cmsCIELab Lab;
- n2=0;
- for (j=0; j < 65535; j++) {
- Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
- cmsLabEncoded2Float(ContextID, &Lab, Inw);
- cmsFloat2LabEncoded(ContextID, aw, &Lab);
- for (i=0; i < 3; i++) {
- if (aw[i] != j) {
- n2++;
- }
- }
- }
- return (n2 == 0);
- }
- // BlackBody -----------------------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckTemp2CHRM(cmsContext ContextID)
- {
- cmsInt32Number j;
- cmsFloat64Number d, v, Max = 0;
- cmsCIExyY White;
- for (j=4000; j < 25000; j++) {
- cmsWhitePointFromTemp(ContextID, &White, j);
- if (!cmsTempFromWhitePoint(ContextID, &v, &White)) return 0;
- d = fabs(v - j);
- if (d > Max) Max = d;
- }
- // 100 degree is the actual resolution
- return (Max < 100);
- }
- // Tone curves -----------------------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckGammaEstimation(cmsContext ContextID, cmsToneCurve* c, cmsFloat64Number g)
- {
- cmsFloat64Number est = cmsEstimateGamma(ContextID, c, 0.001);
- SubTest("Gamma estimation");
- if (fabs(est - g) > 0.001) return 0;
- return 1;
- }
- static
- cmsInt32Number CheckGammaCreation16(cmsContext ContextID)
- {
- cmsToneCurve* LinGamma = cmsBuildGamma(ContextID, 1.0);
- cmsInt32Number i;
- cmsUInt16Number in, out;
- for (i=0; i < 0xffff; i++) {
- in = (cmsUInt16Number) i;
- out = cmsEvalToneCurve16(ContextID, LinGamma, in);
- if (in != out) {
- Fail("(lin gamma): Must be %x, But is %x : ", in, out);
- cmsFreeToneCurve(ContextID, LinGamma);
- return 0;
- }
- }
- if (!CheckGammaEstimation(ContextID, LinGamma, 1.0)) return 0;
- cmsFreeToneCurve(ContextID, LinGamma);
- return 1;
- }
- static
- cmsInt32Number CheckGammaCreationFlt(cmsContext ContextID)
- {
- cmsToneCurve* LinGamma = cmsBuildGamma(ContextID, 1.0);
- cmsInt32Number i;
- cmsFloat32Number in, out;
- for (i=0; i < 0xffff; i++) {
- in = (cmsFloat32Number) (i / 65535.0);
- out = cmsEvalToneCurveFloat(ContextID, LinGamma, in);
- if (fabs(in - out) > (1/65535.0)) {
- Fail("(lin gamma): Must be %f, But is %f : ", in, out);
- cmsFreeToneCurve(ContextID, LinGamma);
- return 0;
- }
- }
- if (!CheckGammaEstimation(ContextID, LinGamma, 1.0)) return 0;
- cmsFreeToneCurve(ContextID, LinGamma);
- return 1;
- }
- // Curve curves using a single power function
- // Error is given in 0..ffff counts
- static
- cmsInt32Number CheckGammaFloat(cmsContext ContextID, cmsFloat64Number g)
- {
- cmsToneCurve* Curve = cmsBuildGamma(ContextID, g);
- cmsInt32Number i;
- cmsFloat32Number in, out;
- cmsFloat64Number val, Err;
- MaxErr = 0.0;
- for (i=0; i < 0xffff; i++) {
- in = (cmsFloat32Number) (i / 65535.0);
- out = cmsEvalToneCurveFloat(ContextID, Curve, in);
- val = pow((cmsFloat64Number) in, g);
- Err = fabs( val - out);
- if (Err > MaxErr) MaxErr = Err;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
- if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
- cmsFreeToneCurve(ContextID, Curve);
- return 1;
- }
- static cmsInt32Number CheckGamma18(cmsContext ContextID)
- {
- return CheckGammaFloat(ContextID, 1.8);
- }
- static cmsInt32Number CheckGamma22(cmsContext ContextID)
- {
- return CheckGammaFloat(ContextID, 2.2);
- }
- static cmsInt32Number CheckGamma30(cmsContext ContextID)
- {
- return CheckGammaFloat(ContextID, 3.0);
- }
- // Check table-based gamma functions
- static
- cmsInt32Number CheckGammaFloatTable(cmsContext ContextID, cmsFloat64Number g)
- {
- cmsFloat32Number Values[1025];
- cmsToneCurve* Curve;
- cmsInt32Number i;
- cmsFloat32Number in, out;
- cmsFloat64Number val, Err;
- for (i=0; i <= 1024; i++) {
- in = (cmsFloat32Number) (i / 1024.0);
- Values[i] = powf(in, (float) g);
- }
- Curve = cmsBuildTabulatedToneCurveFloat(ContextID, 1025, Values);
- MaxErr = 0.0;
- for (i=0; i <= 0xffff; i++) {
- in = (cmsFloat32Number) (i / 65535.0);
- out = cmsEvalToneCurveFloat(ContextID, Curve, in);
- val = pow(in, g);
- Err = fabs(val - out);
- if (Err > MaxErr) MaxErr = Err;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
- if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
- cmsFreeToneCurve(ContextID, Curve);
- return 1;
- }
- static cmsInt32Number CheckGamma18Table(cmsContext ContextID)
- {
- return CheckGammaFloatTable(ContextID, 1.8);
- }
- static cmsInt32Number CheckGamma22Table(cmsContext ContextID)
- {
- return CheckGammaFloatTable(ContextID, 2.2);
- }
- static cmsInt32Number CheckGamma30Table(cmsContext ContextID)
- {
- return CheckGammaFloatTable(ContextID, 3.0);
- }
- // Create a curve from a table (which is a pure gamma function) and check it against the pow function.
- static
- cmsInt32Number CheckGammaWordTable(cmsContext ContextID, cmsFloat64Number g)
- {
- cmsUInt16Number Values[1025];
- cmsToneCurve* Curve;
- cmsInt32Number i;
- cmsFloat32Number in, out;
- cmsFloat64Number val, Err;
- for (i=0; i <= 1024; i++) {
- in = (cmsFloat32Number) (i / 1024.0);
- Values[i] = (cmsUInt16Number) floor(pow(in, g) * 65535.0 + 0.5);
- }
- Curve = cmsBuildTabulatedToneCurve16(ContextID, 1025, Values);
- MaxErr = 0.0;
- for (i=0; i <= 0xffff; i++) {
- in = (cmsFloat32Number) (i / 65535.0);
- out = cmsEvalToneCurveFloat(ContextID, Curve, in);
- val = pow(in, g);
- Err = fabs(val - out);
- if (Err > MaxErr) MaxErr = Err;
- }
- if (MaxErr > 0) printf("|Err|<%lf ", MaxErr * 65535.0);
- if (!CheckGammaEstimation(ContextID, Curve, g)) return 0;
- cmsFreeToneCurve(ContextID, Curve);
- return 1;
- }
- static cmsInt32Number CheckGamma18TableWord(cmsContext ContextID)
- {
- return CheckGammaWordTable(ContextID, 1.8);
- }
- static cmsInt32Number CheckGamma22TableWord(cmsContext ContextID)
- {
- return CheckGammaWordTable(ContextID, 2.2);
- }
- static cmsInt32Number CheckGamma30TableWord(cmsContext ContextID)
- {
- return CheckGammaWordTable(ContextID, 3.0);
- }
- // Curve joining test. Joining two high-gamma of 3.0 curves should
- // give something like linear
- static
- cmsInt32Number CheckJointCurves(cmsContext ContextID)
- {
- cmsToneCurve *Forward, *Reverse, *Result;
- cmsBool rc;
- Forward = cmsBuildGamma(ContextID, 3.0);
- Reverse = cmsBuildGamma(ContextID, 3.0);
- Result = cmsJoinToneCurve(ContextID, Forward, Reverse, 256);
- cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
- rc = cmsIsToneCurveLinear(ContextID, Result);
- cmsFreeToneCurve(ContextID, Result);
- if (!rc)
- Fail("Joining same curve twice does not result in a linear ramp");
- return rc;
- }
- #if 0
- // Create a gamma curve by cheating the table
- static
- cmsToneCurve* GammaTableLinear(cmsContext ContextID, cmsInt32Number nEntries, cmsBool Dir)
- {
- cmsInt32Number i;
- cmsToneCurve* g = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
- for (i=0; i < nEntries; i++) {
- cmsInt32Number v = _cmsQuantizeVal(i, nEntries);
- if (Dir)
- g->Table16[i] = (cmsUInt16Number) v;
- else
- g->Table16[i] = (cmsUInt16Number) (0xFFFF - v);
- }
- return g;
- }
- #endif
- static
- cmsInt32Number CheckJointCurvesDescending(cmsContext ContextID)
- {
- cmsToneCurve *Forward, *Reverse, *Result;
- cmsInt32Number i, rc;
- Forward = cmsBuildGamma(ContextID, 2.2);
- // Fake the curve to be table-based
- for (i=0; i < 4096; i++)
- Forward ->Table16[i] = 0xffff - Forward->Table16[i];
- Forward ->Segments[0].Type = 0;
- Reverse = cmsReverseToneCurve(ContextID, Forward);
- Result = cmsJoinToneCurve(ContextID, Reverse, Reverse, 256);
- cmsFreeToneCurve(ContextID, Forward);
- cmsFreeToneCurve(ContextID, Reverse);
- rc = cmsIsToneCurveLinear(ContextID, Result);
- cmsFreeToneCurve(ContextID, Result);
- return rc;
- }
- static
- cmsInt32Number CheckFToneCurvePoint(cmsContext ContextID, cmsToneCurve* c, cmsUInt16Number Point, cmsInt32Number Value)
- {
- cmsInt32Number Result;
- Result = cmsEvalToneCurve16(ContextID, c, Point);
- return (abs(Value - Result) < 2);
- }
- static
- cmsInt32Number CheckReverseDegenerated(cmsContext ContextID)
- {
- cmsToneCurve* p, *g;
- cmsUInt16Number Tab[16];
- Tab[0] = 0;
- Tab[1] = 0;
- Tab[2] = 0;
- Tab[3] = 0;
- Tab[4] = 0;
- Tab[5] = 0x5555;
- Tab[6] = 0x6666;
- Tab[7] = 0x7777;
- Tab[8] = 0x8888;
- Tab[9] = 0x9999;
- Tab[10]= 0xffff;
- Tab[11]= 0xffff;
- Tab[12]= 0xffff;
- Tab[13]= 0xffff;
- Tab[14]= 0xffff;
- Tab[15]= 0xffff;
- p = cmsBuildTabulatedToneCurve16(ContextID, 16, Tab);
- g = cmsReverseToneCurve(ContextID, p);
- // Now let's check some points
- if (!CheckFToneCurvePoint(ContextID, g, 0x5555, 0x5555)) return 0;
- if (!CheckFToneCurvePoint(ContextID, g, 0x7777, 0x7777)) return 0;
- // First point for zero
- if (!CheckFToneCurvePoint(ContextID, g, 0x0000, 0x4444)) return 0;
- // Last point
- if (!CheckFToneCurvePoint(ContextID, g, 0xFFFF, 0xFFFF)) return 0;
- cmsFreeToneCurve(ContextID, p);
- cmsFreeToneCurve(ContextID, g);
- return 1;
- }
- // Build a parametric sRGB-like curve
- static
- cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
- {
- cmsFloat64Number Parameters[5];
- Parameters[0] = 2.4;
- Parameters[1] = 1. / 1.055;
- Parameters[2] = 0.055 / 1.055;
- Parameters[3] = 1. / 12.92;
- Parameters[4] = 0.04045; // d
- return cmsBuildParametricToneCurve(ContextID, 4, Parameters);
- }
- // Join two gamma tables in floating point format. Result should be a straight line
- static
- cmsToneCurve* CombineGammaFloat(cmsContext ContextID, cmsToneCurve* g1, cmsToneCurve* g2)
- {
- cmsUInt16Number Tab[256];
- cmsFloat32Number f;
- cmsInt32Number i;
- for (i=0; i < 256; i++) {
- f = (cmsFloat32Number) i / 255.0F;
- f = cmsEvalToneCurveFloat(ContextID, g2, cmsEvalToneCurveFloat(ContextID, g1, f));
- Tab[i] = (cmsUInt16Number) floor(f * 65535.0 + 0.5);
- }
- return cmsBuildTabulatedToneCurve16(ContextID, 256, Tab);
- }
- // Same of anterior, but using quantized tables
- static
- cmsToneCurve* CombineGamma16(cmsContext ContextID, cmsToneCurve* g1, cmsToneCurve* g2)
- {
- cmsUInt16Number Tab[256];
- cmsInt32Number i;
- for (i=0; i < 256; i++) {
- cmsUInt16Number wValIn;
- wValIn = _cmsQuantizeVal(i, 256);
- Tab[i] = cmsEvalToneCurve16(ContextID, g2, cmsEvalToneCurve16(ContextID, g1, wValIn));
- }
- return cmsBuildTabulatedToneCurve16(ContextID, 256, Tab);
- }
- static
- cmsInt32Number CheckJointFloatCurves_sRGB(cmsContext ContextID)
- {
- cmsToneCurve *Forward, *Reverse, *Result;
- cmsBool rc;
- Forward = Build_sRGBGamma(ContextID);
- Reverse = cmsReverseToneCurve(ContextID, Forward);
- Result = CombineGammaFloat(ContextID, Forward, Reverse);
- cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
- rc = cmsIsToneCurveLinear(ContextID, Result);
- cmsFreeToneCurve(ContextID, Result);
- return rc;
- }
- static
- cmsInt32Number CheckJoint16Curves_sRGB(cmsContext ContextID)
- {
- cmsToneCurve *Forward, *Reverse, *Result;
- cmsBool rc;
- Forward = Build_sRGBGamma(ContextID);
- Reverse = cmsReverseToneCurve(ContextID, Forward);
- Result = CombineGamma16(ContextID, Forward, Reverse);
- cmsFreeToneCurve(ContextID, Forward); cmsFreeToneCurve(ContextID, Reverse);
- rc = cmsIsToneCurveLinear(ContextID, Result);
- cmsFreeToneCurve(ContextID, Result);
- return rc;
- }
- // sigmoidal curve f(x) = (1-x^g) ^(1/g)
- static
- cmsInt32Number CheckJointCurvesSShaped(cmsContext ContextID)
- {
- cmsFloat64Number p = 3.2;
- cmsToneCurve *Forward, *Reverse, *Result;
- cmsInt32Number rc;
- Forward = cmsBuildParametricToneCurve(ContextID, 108, &p);
- Reverse = cmsReverseToneCurve(ContextID, Forward);
- Result = cmsJoinToneCurve(ContextID, Forward, Forward, 4096);
- cmsFreeToneCurve(ContextID, Forward);
- cmsFreeToneCurve(ContextID, Reverse);
- rc = cmsIsToneCurveLinear(ContextID, Result);
- cmsFreeToneCurve(ContextID, Result);
- return rc;
- }
- // --------------------------------------------------------------------------------------------------------
- // Implementation of some tone curve functions
- static
- cmsFloat32Number Gamma(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- return (cmsFloat32Number) pow(x, Params[0]);
- }
- static
- cmsFloat32Number CIE122(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number e, Val;
- if (x >= -Params[2] / Params[1]) {
- e = Params[1]*x + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]);
- else
- Val = 0;
- }
- else
- Val = 0;
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number IEC61966_3(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number e, Val;
- if (x >= -Params[2] / Params[1]) {
- e = Params[1]*x + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]) + Params[3];
- else
- Val = 0;
- }
- else
- Val = Params[3];
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number IEC61966_21(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number e, Val;
- if (x >= Params[4]) {
- e = Params[1]*x + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]);
- else
- Val = 0;
- }
- else
- Val = x * Params[3];
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number param_5(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number e, Val;
- // Y = (aX + b)^Gamma + e | X >= d
- // Y = cX + f | else
- if (x >= Params[4]) {
- e = Params[1]*x + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]) + Params[5];
- else
- Val = 0;
- }
- else
- Val = x*Params[3] + Params[6];
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number param_6(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number e, Val;
- e = Params[1]*x + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]) + Params[3];
- else
- Val = 0;
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number param_7(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number Val;
- Val = Params[1]*log10(Params[2] * pow(x, Params[0]) + Params[3]) + Params[4];
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number param_8(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number Val;
- Val = (Params[0] * pow(Params[1], Params[2] * x + Params[3]) + Params[4]);
- return (cmsFloat32Number) Val;
- }
- static
- cmsFloat32Number sigmoidal(cmsFloat32Number x, const cmsFloat64Number Params[])
- {
- cmsFloat64Number Val;
- Val = pow(1.0 - pow(1 - x, 1/Params[0]), 1/Params[0]);
- return (cmsFloat32Number) Val;
- }
- static
- cmsBool CheckSingleParametric(cmsContext ContextID, const char* Name, dblfnptr fn, cmsInt32Number Type, const cmsFloat64Number Params[])
- {
- cmsInt32Number i;
- cmsToneCurve* tc;
- cmsToneCurve* tc_1;
- char InverseText[256];
- tc = cmsBuildParametricToneCurve(ContextID, Type, Params);
- tc_1 = cmsBuildParametricToneCurve(ContextID, -Type, Params);
- for (i=0; i <= 1000; i++) {
- cmsFloat32Number x = (cmsFloat32Number) i / 1000;
- cmsFloat32Number y_fn, y_param, x_param, y_param2;
- y_fn = fn(x, Params);
- y_param = cmsEvalToneCurveFloat(ContextID, tc, x);
- x_param = cmsEvalToneCurveFloat(ContextID, tc_1, y_param);
- y_param2 = fn(x_param, Params);
- if (!IsGoodVal(Name, y_fn, y_param, FIXED_PRECISION_15_16))
- goto Error;
- sprintf(InverseText, "Inverse %s", Name);
- if (!IsGoodVal(InverseText, y_fn, y_param2, FIXED_PRECISION_15_16))
- goto Error;
- }
- cmsFreeToneCurve(ContextID, tc);
- cmsFreeToneCurve(ContextID, tc_1);
- return TRUE;
- Error:
- cmsFreeToneCurve(ContextID, tc);
- cmsFreeToneCurve(ContextID, tc_1);
- return FALSE;
- }
- // Check against some known values
- static
- cmsInt32Number CheckParametricToneCurves(cmsContext ContextID)
- {
- cmsFloat64Number Params[10];
- // 1) X = Y ^ Gamma
- Params[0] = 2.2;
- if (!CheckSingleParametric(ContextID, "Gamma", Gamma, 1, Params)) return 0;
- // 2) CIE 122-1966
- // Y = (aX + b)^Gamma | X >= -b/a
- // Y = 0 | else
- Params[0] = 2.2;
- Params[1] = 1.5;
- Params[2] = -0.5;
- if (!CheckSingleParametric(ContextID, "CIE122-1966", CIE122, 2, Params)) return 0;
- // 3) IEC 61966-3
- // Y = (aX + b)^Gamma | X <= -b/a
- // Y = c | else
- Params[0] = 2.2;
- Params[1] = 1.5;
- Params[2] = -0.5;
- Params[3] = 0.3;
- if (!CheckSingleParametric(ContextID, "IEC 61966-3", IEC61966_3, 3, Params)) return 0;
- // 4) IEC 61966-2.1 (sRGB)
- // Y = (aX + b)^Gamma | X >= d
- // Y = cX | X < d
- Params[0] = 2.4;
- Params[1] = 1. / 1.055;
- Params[2] = 0.055 / 1.055;
- Params[3] = 1. / 12.92;
- Params[4] = 0.04045;
- if (!CheckSingleParametric(ContextID, "IEC 61966-2.1", IEC61966_21, 4, Params)) return 0;
- // 5) Y = (aX + b)^Gamma + e | X >= d
- // Y = cX + f | else
- Params[0] = 2.2;
- Params[1] = 0.7;
- Params[2] = 0.2;
- Params[3] = 0.3;
- Params[4] = 0.1;
- Params[5] = 0.5;
- Params[6] = 0.2;
- if (!CheckSingleParametric(ContextID, "param_5", param_5, 5, Params)) return 0;
- // 6) Y = (aX + b) ^ Gamma + c
- Params[0] = 2.2;
- Params[1] = 0.7;
- Params[2] = 0.2;
- Params[3] = 0.3;
- if (!CheckSingleParametric(ContextID, "param_6", param_6, 6, Params)) return 0;
- // 7) Y = a * log (b * X^Gamma + c) + d
- Params[0] = 2.2;
- Params[1] = 0.9;
- Params[2] = 0.9;
- Params[3] = 0.02;
- Params[4] = 0.1;
- if (!CheckSingleParametric(ContextID, "param_7", param_7, 7, Params)) return 0;
- // 8) Y = a * b ^ (c*X+d) + e
- Params[0] = 0.9;
- Params[1] = 0.9;
- Params[2] = 1.02;
- Params[3] = 0.1;
- Params[4] = 0.2;
- if (!CheckSingleParametric(ContextID, "param_8", param_8, 8, Params)) return 0;
- // 108: S-Shaped: (1 - (1-x)^1/g)^1/g
- Params[0] = 1.9;
- if (!CheckSingleParametric(ContextID, "sigmoidal", sigmoidal, 108, Params)) return 0;
- // All OK
- return 1;
- }
- // LUT checks ------------------------------------------------------------------------------
- static
- cmsInt32Number CheckLUTcreation(cmsContext ContextID)
- {
- cmsPipeline* lut;
- cmsPipeline* lut2;
- cmsInt32Number n1, n2;
- lut = cmsPipelineAlloc(ContextID, 1, 1);
- n1 = cmsPipelineStageCount(ContextID, lut);
- lut2 = cmsPipelineDup(ContextID, lut);
- n2 = cmsPipelineStageCount(ContextID, lut2);
- cmsPipelineFree(ContextID, lut);
- cmsPipelineFree(ContextID, lut2);
- return (n1 == 0) && (n2 == 0);
- }
- // Create a MPE for a identity matrix
- static
- void AddIdentityMatrix(cmsContext ContextID, cmsPipeline* lut)
- {
- const cmsFloat64Number Identity[] = { 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1,
- 0, 0, 0 };
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, Identity, NULL));
- }
- // Create a MPE for identity cmsFloat32Number CLUT
- static
- void AddIdentityCLUTfloat(cmsContext ContextID, cmsPipeline* lut)
- {
- const cmsFloat32Number Table[] = {
- 0, 0, 0,
- 0, 0, 1.0,
- 0, 1.0, 0,
- 0, 1.0, 1.0,
- 1.0, 0, 0,
- 1.0, 0, 1.0,
- 1.0, 1.0, 0,
- 1.0, 1.0, 1.0
- };
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocCLutFloat(ContextID, 2, 3, 3, Table));
- }
- // Create a MPE for identity cmsFloat32Number CLUT
- static
- void AddIdentityCLUT16(cmsContext ContextID, cmsPipeline* lut)
- {
- const cmsUInt16Number Table[] = {
- 0, 0, 0,
- 0, 0, 0xffff,
- 0, 0xffff, 0,
- 0, 0xffff, 0xffff,
- 0xffff, 0, 0,
- 0xffff, 0, 0xffff,
- 0xffff, 0xffff, 0,
- 0xffff, 0xffff, 0xffff
- };
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocCLut16bit(ContextID, 2, 3, 3, Table));
- }
- // Create a 3 fn identity curves
- static
- void Add3GammaCurves(cmsContext ContextID, cmsPipeline* lut, cmsFloat64Number Curve)
- {
- cmsToneCurve* id = cmsBuildGamma(ContextID, Curve);
- cmsToneCurve* id3[3];
- id3[0] = id;
- id3[1] = id;
- id3[2] = id;
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, id3));
- cmsFreeToneCurve(ContextID, id);
- }
- static
- cmsInt32Number CheckFloatLUT(cmsContext ContextID, cmsPipeline* lut)
- {
- cmsInt32Number n1, i, j;
- cmsFloat32Number Inf[3], Outf[3];
- n1=0;
- for (j=0; j < 65535; j++) {
- cmsInt32Number af[3];
- Inf[0] = Inf[1] = Inf[2] = (cmsFloat32Number) j / 65535.0F;
- cmsPipelineEvalFloat(ContextID, Inf, Outf, lut);
- af[0] = (cmsInt32Number) floor(Outf[0]*65535.0 + 0.5);
- af[1] = (cmsInt32Number) floor(Outf[1]*65535.0 + 0.5);
- af[2] = (cmsInt32Number) floor(Outf[2]*65535.0 + 0.5);
- for (i=0; i < 3; i++) {
- if (af[i] != j) {
- n1++;
- }
- }
- }
- return (n1 == 0);
- }
- static
- cmsInt32Number Check16LUT(cmsContext ContextID, cmsPipeline* lut)
- {
- cmsInt32Number n2, i, j;
- cmsUInt16Number Inw[3], Outw[3];
- n2=0;
- for (j=0; j < 65535; j++) {
- cmsInt32Number aw[3];
- Inw[0] = Inw[1] = Inw[2] = (cmsUInt16Number) j;
- cmsPipelineEval16(ContextID, Inw, Outw, lut);
- aw[0] = Outw[0];
- aw[1] = Outw[1];
- aw[2] = Outw[2];
- for (i=0; i < 3; i++) {
- if (aw[i] != j) {
- n2++;
- }
- }
- }
- return (n2 == 0);
- }
- // Check any LUT that is linear
- static
- cmsInt32Number CheckStagesLUT(cmsContext ContextID, cmsPipeline* lut, cmsInt32Number ExpectedStages)
- {
- cmsInt32Number nInpChans, nOutpChans, nStages;
- nInpChans = cmsPipelineInputChannels(ContextID, lut);
- nOutpChans = cmsPipelineOutputChannels(ContextID, lut);
- nStages = cmsPipelineStageCount(ContextID, lut);
- return (nInpChans == 3) && (nOutpChans == 3) && (nStages == ExpectedStages);
- }
- static
- cmsInt32Number CheckFullLUT(cmsContext ContextID, cmsPipeline* lut, cmsInt32Number ExpectedStages)
- {
- cmsInt32Number rc = CheckStagesLUT(ContextID, lut, ExpectedStages) && Check16LUT(ContextID, lut) && CheckFloatLUT(ContextID, lut);
- cmsPipelineFree(ContextID, lut);
- return rc;
- }
- static
- cmsInt32Number Check1StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- return CheckFullLUT(ContextID, lut, 1);
- }
- static
- cmsInt32Number Check2StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUTfloat(ContextID, lut);
- return CheckFullLUT(ContextID, lut, 2);
- }
- static
- cmsInt32Number Check2Stage16LUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUT16(ContextID, lut);
- return CheckFullLUT(ContextID, lut, 2);
- }
- static
- cmsInt32Number Check3StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUTfloat(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 3);
- }
- static
- cmsInt32Number Check3Stage16LUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUT16(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 3);
- }
- static
- cmsInt32Number Check4StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUTfloat(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- return CheckFullLUT(ContextID, lut, 4);
- }
- static
- cmsInt32Number Check4Stage16LUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUT16(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- return CheckFullLUT(ContextID, lut, 4);
- }
- static
- cmsInt32Number Check5StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUTfloat(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 5);
- }
- static
- cmsInt32Number Check5Stage16LUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- AddIdentityCLUT16(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 5);
- }
- static
- cmsInt32Number Check6StageLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityCLUTfloat(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 6);
- }
- static
- cmsInt32Number Check6Stage16LUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityCLUT16(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- AddIdentityMatrix(ContextID, lut);
- Add3GammaCurves(ContextID, lut, 1.0);
- return CheckFullLUT(ContextID, lut, 6);
- }
- static
- cmsInt32Number CheckLab2LabLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- cmsInt32Number rc;
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
- rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 2);
- cmsPipelineFree(ContextID, lut);
- return rc;
- }
- static
- cmsInt32Number CheckXYZ2XYZLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- cmsInt32Number rc;
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
- rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 2);
- cmsPipelineFree(ContextID, lut);
- return rc;
- }
- static
- cmsInt32Number CheckLab2LabMatLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- cmsInt32Number rc;
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID));
- AddIdentityMatrix(ContextID, lut);
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID));
- rc = CheckFloatLUT(ContextID, lut) && CheckStagesLUT(ContextID, lut, 3);
- cmsPipelineFree(ContextID, lut);
- return rc;
- }
- static
- cmsInt32Number CheckNamedColorLUT(cmsContext ContextID)
- {
- cmsPipeline* lut = cmsPipelineAlloc(ContextID, 3, 3);
- cmsNAMEDCOLORLIST* nc;
- cmsInt32Number i,j, rc = 1, n2;
- cmsUInt16Number PCS[3];
- cmsUInt16Number Colorant[cmsMAXCHANNELS];
- char Name[255];
- cmsUInt16Number Inw[3], Outw[3];
- nc = cmsAllocNamedColorList(ContextID, 256, 3, "pre", "post");
- if (nc == NULL) return 0;
- for (i=0; i < 256; i++) {
- PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
- Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) i;
- sprintf(Name, "#%d", i);
- if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { rc = 0; break; }
- }
- cmsPipelineInsertStage(ContextID, lut, cmsAT_END, _cmsStageAllocNamedColor(ContextID, nc, FALSE));
- cmsFreeNamedColorList(ContextID, nc);
- if (rc == 0) return 0;
- n2=0;
- for (j=0; j < 256; j++) {
- Inw[0] = (cmsUInt16Number) j;
- cmsPipelineEval16(ContextID, Inw, Outw, lut);
- for (i=0; i < 3; i++) {
- if (Outw[i] != j) {
- n2++;
- }
- }
- }
- cmsPipelineFree(ContextID, lut);
- return (n2 == 0);
- }
- // --------------------------------------------------------------------------------------------
- // A lightweight test of multilocalized unicode structures.
- static
- cmsInt32Number CheckMLU(cmsContext ContextID)
- {
- cmsMLU* mlu, *mlu2, *mlu3;
- char Buffer[256], Buffer2[256];
- cmsInt32Number rc = 1;
- cmsInt32Number i;
- cmsHPROFILE h= NULL;
- // Allocate a MLU structure, no preferred size
- mlu = cmsMLUalloc(ContextID, 0);
- // Add some localizations
- cmsMLUsetWide(ContextID, mlu, "en", "US", L"Hello, world");
- cmsMLUsetWide(ContextID, mlu, "es", "ES", L"Hola, mundo");
- cmsMLUsetWide(ContextID, mlu, "fr", "FR", L"Bonjour, le monde");
- cmsMLUsetWide(ContextID, mlu, "ca", "CA", L"Hola, mon");
- // Check the returned string for each language
- cmsMLUgetASCII(ContextID, mlu, "en", "US", Buffer, 256);
- if (strcmp(Buffer, "Hello, world") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, mlu, "es", "ES", Buffer, 256);
- if (strcmp(Buffer, "Hola, mundo") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, mlu, "fr", "FR", Buffer, 256);
- if (strcmp(Buffer, "Bonjour, le monde") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, mlu, "ca", "CA", Buffer, 256);
- if (strcmp(Buffer, "Hola, mon") != 0) rc = 0;
- if (rc == 0)
- Fail("Unexpected string '%s'", Buffer);
- // So far, so good.
- cmsMLUfree(ContextID, mlu);
- // Now for performance, allocate an empty struct
- mlu = cmsMLUalloc(ContextID, 0);
- // Fill it with several thousands of different lenguages
- for (i=0; i < 4096; i++) {
- char Lang[3];
- Lang[0] = (char) (i % 255);
- Lang[1] = (char) (i / 255);
- Lang[2] = 0;
- sprintf(Buffer, "String #%i", i);
- cmsMLUsetASCII(ContextID, mlu, Lang, Lang, Buffer);
- }
- // Duplicate it
- mlu2 = cmsMLUdup(ContextID, mlu);
- // Get rid of original
- cmsMLUfree(ContextID, mlu);
- // Check all is still in place
- for (i=0; i < 4096; i++) {
- char Lang[3];
- Lang[0] = (char)(i % 255);
- Lang[1] = (char)(i / 255);
- Lang[2] = 0;
- cmsMLUgetASCII(ContextID, mlu2, Lang, Lang, Buffer2, 256);
- sprintf(Buffer, "String #%i", i);
- if (strcmp(Buffer, Buffer2) != 0) { rc = 0; break; }
- }
- if (rc == 0)
- Fail("Unexpected string '%s'", Buffer2);
- // Check profile IO
- h = cmsOpenProfileFromFile(ContextID, "mlucheck.icc", "w");
- cmsSetProfileVersion(ContextID, h, 4.3);
- cmsWriteTag(ContextID, h, cmsSigProfileDescriptionTag, mlu2);
- cmsCloseProfile(ContextID, h);
- cmsMLUfree(ContextID, mlu2);
- h = cmsOpenProfileFromFile(ContextID, "mlucheck.icc", "r");
- mlu3 = (cmsMLU *) cmsReadTag(ContextID, h, cmsSigProfileDescriptionTag);
- if (mlu3 == NULL) { Fail("Profile didn't get the MLU\n"); rc = 0; goto Error; }
- // Check all is still in place
- for (i=0; i < 4096; i++) {
- char Lang[3];
- Lang[0] = (char) (i % 255);
- Lang[1] = (char) (i / 255);
- Lang[2] = 0;
- cmsMLUgetASCII(ContextID, mlu3, Lang, Lang, Buffer2, 256);
- sprintf(Buffer, "String #%i", i);
- if (strcmp(Buffer, Buffer2) != 0) { rc = 0; break; }
- }
- if (rc == 0) Fail("Unexpected string '%s'", Buffer2);
- Error:
- if (h != NULL) cmsCloseProfile(ContextID, h);
- remove("mlucheck.icc");
- return rc;
- }
- // Check UTF8 encoding
- static
- cmsInt32Number CheckMLU_UTF8(void)
- {
- cmsMLU* mlu;
- char Buffer[256];
- cmsInt32Number rc = 1;
-
- mlu = cmsMLUalloc(DbgThread(), 0);
-
- cmsMLUsetWide(mlu, "en", "US", L"\x3b2\x14b");
- cmsMLUgetUTF8(mlu, "en", "US", Buffer, 256);
- if (strcmp(Buffer, "\xce\xb2\xc5\x8b") != 0) rc = 0;
- if (rc == 0)
- Fail("Unexpected string '%s'", Buffer);
- cmsMLUfree(mlu);
- return rc;
- }
- // A lightweight test of named color structures.
- static
- cmsInt32Number CheckNamedColorList(cmsContext ContextID)
- {
- cmsNAMEDCOLORLIST* nc = NULL, *nc2;
- cmsInt32Number i, j, rc=1;
- char Name[cmsMAX_PATH];
- cmsUInt16Number PCS[3];
- cmsUInt16Number Colorant[cmsMAXCHANNELS];
- char CheckName[cmsMAX_PATH];
- cmsUInt16Number CheckPCS[3];
- cmsUInt16Number CheckColorant[cmsMAXCHANNELS];
- cmsHPROFILE h;
- nc = cmsAllocNamedColorList(ContextID, 0, 4, "prefix", "suffix");
- if (nc == NULL) return 0;
- for (i=0; i < 4096; i++) {
- PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
- Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) (4096 - i);
- sprintf(Name, "#%d", i);
- if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { rc = 0; break; }
- }
- for (i=0; i < 4096; i++) {
- CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
- CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (4096 - i);
- sprintf(CheckName, "#%d", i);
- if (!cmsNamedColorInfo(ContextID, nc, i, Name, NULL, NULL, PCS, Colorant)) { rc = 0; goto Error; }
- for (j=0; j < 3; j++) {
- if (CheckPCS[j] != PCS[j]) { rc = 0; Fail("Invalid PCS"); goto Error; }
- }
- for (j=0; j < 4; j++) {
- if (CheckColorant[j] != Colorant[j]) { rc = 0; Fail("Invalid Colorant"); goto Error; };
- }
- if (strcmp(Name, CheckName) != 0) {rc = 0; Fail("Invalid Name"); goto Error; };
- }
- h = cmsOpenProfileFromFile(ContextID, "namedcol.icc", "w");
- if (h == NULL) return 0;
- if (!cmsWriteTag(ContextID, h, cmsSigNamedColor2Tag, nc)) return 0;
- cmsCloseProfile(ContextID, h);
- cmsFreeNamedColorList(ContextID, nc);
- nc = NULL;
- h = cmsOpenProfileFromFile(ContextID, "namedcol.icc", "r");
- nc2 = (cmsNAMEDCOLORLIST *) cmsReadTag(ContextID, h, cmsSigNamedColor2Tag);
- if (cmsNamedColorCount(ContextID, nc2) != 4096) { rc = 0; Fail("Invalid count"); goto Error; }
- i = cmsNamedColorIndex(ContextID, nc2, "#123");
- if (i != 123) { rc = 0; Fail("Invalid index"); goto Error; }
- for (i=0; i < 4096; i++) {
- CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
- CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (4096 - i);
- sprintf(CheckName, "#%d", i);
- if (!cmsNamedColorInfo(ContextID, nc2, i, Name, NULL, NULL, PCS, Colorant)) { rc = 0; goto Error; }
- for (j=0; j < 3; j++) {
- if (CheckPCS[j] != PCS[j]) { rc = 0; Fail("Invalid PCS"); goto Error; }
- }
- for (j=0; j < 4; j++) {
- if (CheckColorant[j] != Colorant[j]) { rc = 0; Fail("Invalid Colorant"); goto Error; };
- }
- if (strcmp(Name, CheckName) != 0) {rc = 0; Fail("Invalid Name"); goto Error; };
- }
- cmsCloseProfile(ContextID, h);
- remove("namedcol.icc");
- Error:
- if (nc != NULL) cmsFreeNamedColorList(ContextID, nc);
- return rc;
- }
- // For educational purposes ONLY. No error checking is performed!
- static
- cmsInt32Number CreateNamedColorProfile(cmsContext ContextID)
- {
- // Color list database
- cmsNAMEDCOLORLIST* colors = cmsAllocNamedColorList(ContextID, 10, 4, "PANTONE", "TCX");
- // Containers for names
- cmsMLU* DescriptionMLU, *CopyrightMLU;
- // Create n empty profile
- cmsHPROFILE hProfile = cmsOpenProfileFromFile(ContextID, "named.icc", "w");
- // Values
- cmsCIELab Lab;
- cmsUInt16Number PCS[3], Colorant[cmsMAXCHANNELS];
- // Set profile class
- cmsSetProfileVersion(ContextID, hProfile, 4.3);
- cmsSetDeviceClass(ContextID, hProfile, cmsSigNamedColorClass);
- cmsSetColorSpace(ContextID, hProfile, cmsSigCmykData);
- cmsSetPCS(ContextID, hProfile, cmsSigLabData);
- cmsSetHeaderRenderingIntent(ContextID, hProfile, INTENT_PERCEPTUAL);
- // Add description and copyright only in english/US
- DescriptionMLU = cmsMLUalloc(ContextID, 1);
- CopyrightMLU = cmsMLUalloc(ContextID, 1);
- cmsMLUsetWide(ContextID, DescriptionMLU, "en", "US", L"Profile description");
- cmsMLUsetWide(ContextID, CopyrightMLU, "en", "US", L"Profile copyright");
- cmsWriteTag(ContextID, hProfile, cmsSigProfileDescriptionTag, DescriptionMLU);
- cmsWriteTag(ContextID, hProfile, cmsSigCopyrightTag, CopyrightMLU);
- // Set the media white point
- cmsWriteTag(ContextID, hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ(ContextID));
- // Populate one value, Colorant = CMYK values in 16 bits, PCS[] = Encoded Lab values (in V2 format!!)
- Lab.L = 50; Lab.a = 10; Lab.b = -10;
- cmsFloat2LabEncodedV2(ContextID, PCS, &Lab);
- Colorant[0] = 10 * 257; Colorant[1] = 20 * 257; Colorant[2] = 30 * 257; Colorant[3] = 40 * 257;
- cmsAppendNamedColor(ContextID, colors, "Hazelnut 14-1315", PCS, Colorant);
- // Another one. Consider to write a routine for that
- Lab.L = 40; Lab.a = -5; Lab.b = 8;
- cmsFloat2LabEncodedV2(ContextID, PCS, &Lab);
- Colorant[0] = 10 * 257; Colorant[1] = 20 * 257; Colorant[2] = 30 * 257; Colorant[3] = 40 * 257;
- cmsAppendNamedColor(ContextID, colors, "Kale 18-0107", PCS, Colorant);
- // Write the colors database
- cmsWriteTag(ContextID, hProfile, cmsSigNamedColor2Tag, colors);
- // That will create the file
- cmsCloseProfile(ContextID, hProfile);
- // Free resources
- cmsFreeNamedColorList(ContextID, colors);
- cmsMLUfree(ContextID, DescriptionMLU);
- cmsMLUfree(ContextID, CopyrightMLU);
- remove("named.icc");
- return 1;
- }
- // ----------------------------------------------------------------------------------------------------------
- // Formatters
- static cmsBool FormatterFailed;
- static
- void CheckSingleFormatter16(cmsContext id, cmsUInt32Number Type, const char* Text)
- {
- cmsUInt16Number Values[cmsMAXCHANNELS];
- cmsUInt8Number Buffer[1024];
- cmsFormatter f, b;
- cmsInt32Number i, j, nChannels, bytes;
- _cmsTRANSFORM info;
- // Already failed?
- if (FormatterFailed) return;
- memset(&info, 0, sizeof(info));
- info.OutputFormat = info.InputFormat = Type;
- // Go forth and back
- f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
- b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
- if (f.Fmt16 == NULL || b.Fmt16 == NULL) {
- Fail("no formatter for %s", Text);
- FormatterFailed = TRUE;
- // Useful for debug
- f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
- b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
- return;
- }
- nChannels = T_CHANNELS(Type);
- bytes = T_BYTES(Type);
- for (j=0; j < 5; j++) {
- for (i=0; i < nChannels; i++) {
- Values[i] = (cmsUInt16Number) (i+j);
- // For 8-bit
- if (bytes == 1)
- Values[i] <<= 8;
- }
- b.Fmt16(id, &info, Values, Buffer, 2);
- memset(Values, 0, sizeof(Values));
- f.Fmt16(id, &info, Values, Buffer, 2);
- for (i=0; i < nChannels; i++) {
- if (bytes == 1)
- Values[i] >>= 8;
- if (Values[i] != i+j) {
- Fail("%s failed", Text);
- FormatterFailed = TRUE;
- // Useful for debug
- for (i=0; i < nChannels; i++) {
- Values[i] = (cmsUInt16Number) (i+j);
- // For 8-bit
- if (bytes == 1)
- Values[i] <<= 8;
- }
- b.Fmt16(id, &info, Values, Buffer, 1);
- f.Fmt16(id, &info, Values, Buffer, 1);
- return;
- }
- }
- }
- }
- #define C(a) CheckSingleFormatter16(0, a, #a)
- // Check all formatters
- static
- cmsInt32Number CheckFormatters16(cmsContext ContextID)
- {
- FormatterFailed = FALSE;
- C( TYPE_GRAY_8 );
- C( TYPE_GRAY_8_REV );
- C( TYPE_GRAY_16 );
- C( TYPE_GRAY_16_REV );
- C( TYPE_GRAY_16_SE );
- C( TYPE_GRAYA_8 );
- C( TYPE_GRAYA_16 );
- C( TYPE_GRAYA_16_SE );
- C( TYPE_GRAYA_8_PLANAR );
- C( TYPE_GRAYA_16_PLANAR );
- C( TYPE_RGB_8 );
- C( TYPE_RGB_8_PLANAR );
- C( TYPE_BGR_8 );
- C( TYPE_BGR_8_PLANAR );
- C( TYPE_RGB_16 );
- C( TYPE_RGB_16_PLANAR );
- C( TYPE_RGB_16_SE );
- C( TYPE_BGR_16 );
- C( TYPE_BGR_16_PLANAR );
- C( TYPE_BGR_16_SE );
- C( TYPE_RGBA_8 );
- C( TYPE_RGBA_8_PLANAR );
- C( TYPE_RGBA_16 );
- C( TYPE_RGBA_16_PLANAR );
- C( TYPE_RGBA_16_SE );
- C( TYPE_ARGB_8 );
- C( TYPE_ARGB_8_PLANAR );
- C( TYPE_ARGB_16 );
- C( TYPE_ABGR_8 );
- C( TYPE_ABGR_8_PLANAR );
- C( TYPE_ABGR_16 );
- C( TYPE_ABGR_16_PLANAR );
- C( TYPE_ABGR_16_SE );
- C( TYPE_BGRA_8 );
- C( TYPE_BGRA_8_PLANAR );
- C( TYPE_BGRA_16 );
- C( TYPE_BGRA_16_SE );
- C( TYPE_CMY_8 );
- C( TYPE_CMY_8_PLANAR );
- C( TYPE_CMY_16 );
- C( TYPE_CMY_16_PLANAR );
- C( TYPE_CMY_16_SE );
- C( TYPE_CMYK_8 );
- C( TYPE_CMYKA_8 );
- C( TYPE_CMYK_8_REV );
- C( TYPE_YUVK_8 );
- C( TYPE_CMYK_8_PLANAR );
- C( TYPE_CMYK_16 );
- C( TYPE_CMYK_16_REV );
- C( TYPE_YUVK_16 );
- C( TYPE_CMYK_16_PLANAR );
- C( TYPE_CMYK_16_SE );
- C( TYPE_KYMC_8 );
- C( TYPE_KYMC_16 );
- C( TYPE_KYMC_16_SE );
- C( TYPE_KCMY_8 );
- C( TYPE_KCMY_8_REV );
- C( TYPE_KCMY_16 );
- C( TYPE_KCMY_16_REV );
- C( TYPE_KCMY_16_SE );
- C( TYPE_CMYK5_8 );
- C( TYPE_CMYK5_16 );
- C( TYPE_CMYK5_16_SE );
- C( TYPE_KYMC5_8 );
- C( TYPE_KYMC5_16 );
- C( TYPE_KYMC5_16_SE );
- C( TYPE_CMYK6_8 );
- C( TYPE_CMYK6_8_PLANAR );
- C( TYPE_CMYK6_16 );
- C( TYPE_CMYK6_16_PLANAR );
- C( TYPE_CMYK6_16_SE );
- C( TYPE_CMYK7_8 );
- C( TYPE_CMYK7_16 );
- C( TYPE_CMYK7_16_SE );
- C( TYPE_KYMC7_8 );
- C( TYPE_KYMC7_16 );
- C( TYPE_KYMC7_16_SE );
- C( TYPE_CMYK8_8 );
- C( TYPE_CMYK8_16 );
- C( TYPE_CMYK8_16_SE );
- C( TYPE_KYMC8_8 );
- C( TYPE_KYMC8_16 );
- C( TYPE_KYMC8_16_SE );
- C( TYPE_CMYK9_8 );
- C( TYPE_CMYK9_16 );
- C( TYPE_CMYK9_16_SE );
- C( TYPE_KYMC9_8 );
- C( TYPE_KYMC9_16 );
- C( TYPE_KYMC9_16_SE );
- C( TYPE_CMYK10_8 );
- C( TYPE_CMYK10_16 );
- C( TYPE_CMYK10_16_SE );
- C( TYPE_KYMC10_8 );
- C( TYPE_KYMC10_16 );
- C( TYPE_KYMC10_16_SE );
- C( TYPE_CMYK11_8 );
- C( TYPE_CMYK11_16 );
- C( TYPE_CMYK11_16_SE );
- C( TYPE_KYMC11_8 );
- C( TYPE_KYMC11_16 );
- C( TYPE_KYMC11_16_SE );
- C( TYPE_CMYK12_8 );
- C( TYPE_CMYK12_16 );
- C( TYPE_CMYK12_16_SE );
- C( TYPE_KYMC12_8 );
- C( TYPE_KYMC12_16 );
- C( TYPE_KYMC12_16_SE );
- C( TYPE_XYZ_16 );
- C( TYPE_Lab_8 );
- C( TYPE_ALab_8 );
- C( TYPE_Lab_16 );
- C( TYPE_Yxy_16 );
- C( TYPE_YCbCr_8 );
- C( TYPE_YCbCr_8_PLANAR );
- C( TYPE_YCbCr_16 );
- C( TYPE_YCbCr_16_PLANAR );
- C( TYPE_YCbCr_16_SE );
- C( TYPE_YUV_8 );
- C( TYPE_YUV_8_PLANAR );
- C( TYPE_YUV_16 );
- C( TYPE_YUV_16_PLANAR );
- C( TYPE_YUV_16_SE );
- C( TYPE_HLS_8 );
- C( TYPE_HLS_8_PLANAR );
- C( TYPE_HLS_16 );
- C( TYPE_HLS_16_PLANAR );
- C( TYPE_HLS_16_SE );
- C( TYPE_HSV_8 );
- C( TYPE_HSV_8_PLANAR );
- C( TYPE_HSV_16 );
- C( TYPE_HSV_16_PLANAR );
- C( TYPE_HSV_16_SE );
- C( TYPE_XYZ_FLT );
- C( TYPE_Lab_FLT );
- C( TYPE_GRAY_FLT );
- C( TYPE_RGB_FLT );
- C( TYPE_BGR_FLT );
- C( TYPE_CMYK_FLT );
- C( TYPE_LabA_FLT );
- C( TYPE_RGBA_FLT );
- C( TYPE_ARGB_FLT );
- C( TYPE_BGRA_FLT );
- C( TYPE_ABGR_FLT );
- C( TYPE_XYZ_DBL );
- C( TYPE_Lab_DBL );
- C( TYPE_GRAY_DBL );
- C( TYPE_RGB_DBL );
- C( TYPE_BGR_DBL );
- C( TYPE_CMYK_DBL );
- C( TYPE_LabV2_8 );
- C( TYPE_ALabV2_8 );
- C( TYPE_LabV2_16 );
- #ifndef CMS_NO_HALF_SUPPORT
- C( TYPE_GRAY_HALF_FLT );
- C( TYPE_RGB_HALF_FLT );
- C( TYPE_CMYK_HALF_FLT );
- C( TYPE_RGBA_HALF_FLT );
- C( TYPE_RGBA_HALF_FLT );
- C( TYPE_ARGB_HALF_FLT );
- C( TYPE_BGR_HALF_FLT );
- C( TYPE_BGRA_HALF_FLT );
- C( TYPE_ABGR_HALF_FLT );
- #endif
- return FormatterFailed == 0 ? 1 : 0;
- }
- #undef C
- static
- void CheckSingleFormatterFloat(cmsContext ContextID, cmsUInt32Number Type, const char* Text)
- {
- cmsFloat32Number Values[cmsMAXCHANNELS];
- cmsUInt8Number Buffer[1024];
- cmsFormatter f, b;
- cmsInt32Number i, j, nChannels;
- _cmsTRANSFORM info;
- // Already failed?
- if (FormatterFailed) return;
- memset(&info, 0, sizeof(info));
- info.OutputFormat = info.InputFormat = Type;
- // Go forth and back
- f = _cmsGetFormatter(ContextID, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT);
- b = _cmsGetFormatter(ContextID, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT);
- if (f.FmtFloat == NULL || b.FmtFloat == NULL) {
- Fail("no formatter for %s", Text);
- FormatterFailed = TRUE;
- // Useful for debug
- f = _cmsGetFormatter(ContextID, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT);
- b = _cmsGetFormatter(ContextID, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT);
- return;
- }
- nChannels = T_CHANNELS(Type);
- for (j=0; j < 5; j++) {
- for (i=0; i < nChannels; i++) {
- Values[i] = (cmsFloat32Number) (i+j);
- }
- b.FmtFloat(ContextID, &info, Values, Buffer, 1);
- memset(Values, 0, sizeof(Values));
- f.FmtFloat(ContextID, &info, Values, Buffer, 1);
- for (i=0; i < nChannels; i++) {
- cmsFloat64Number delta = fabs(Values[i] - ( i+j));
- if (delta > 0.000000001) {
- Fail("%s failed", Text);
- FormatterFailed = TRUE;
- // Useful for debug
- for (i=0; i < nChannels; i++) {
- Values[i] = (cmsFloat32Number) (i+j);
- }
- b.FmtFloat(ContextID, &info, Values, Buffer, 1);
- f.FmtFloat(ContextID, &info, Values, Buffer, 1);
- return;
- }
- }
- }
- }
- #define C(a) CheckSingleFormatterFloat(ContextID, a, #a)
- static
- cmsInt32Number CheckFormattersFloat(cmsContext ContextID)
- {
- FormatterFailed = FALSE;
- C( TYPE_XYZ_FLT );
- C( TYPE_Lab_FLT );
- C( TYPE_GRAY_FLT );
- C( TYPE_RGB_FLT );
- C( TYPE_BGR_FLT );
- C( TYPE_CMYK_FLT );
- C( TYPE_LabA_FLT );
- C( TYPE_RGBA_FLT );
- C( TYPE_ARGB_FLT );
- C( TYPE_BGRA_FLT );
- C( TYPE_ABGR_FLT );
- C( TYPE_XYZ_DBL );
- C( TYPE_Lab_DBL );
- C( TYPE_GRAY_DBL );
- C( TYPE_RGB_DBL );
- C( TYPE_BGR_DBL );
- C( TYPE_CMYK_DBL );
- C( TYPE_XYZ_FLT );
- #ifndef CMS_NO_HALF_SUPPORT
- C( TYPE_GRAY_HALF_FLT );
- C( TYPE_RGB_HALF_FLT );
- C( TYPE_CMYK_HALF_FLT );
- C( TYPE_RGBA_HALF_FLT );
- C( TYPE_RGBA_HALF_FLT );
- C( TYPE_ARGB_HALF_FLT );
- C( TYPE_BGR_HALF_FLT );
- C( TYPE_BGRA_HALF_FLT );
- C( TYPE_ABGR_HALF_FLT );
- #endif
- return FormatterFailed == 0 ? 1 : 0;
- }
- #undef C
- #ifndef CMS_NO_HALF_SUPPORT
- // Check half float
- #define my_isfinite(x) ((x) != (x))
- static
- cmsInt32Number CheckFormattersHalf(cmsContext ContextID)
- {
- int i, j;
- for (i=0; i < 0xffff; i++) {
- cmsFloat32Number f = _cmsHalf2Float((cmsUInt16Number) i);
- if (!my_isfinite(f)) {
- j = _cmsFloat2Half(f);
- if (i != j) {
- Fail("%d != %d in Half float support!\n", i, j);
- return 0;
- }
- }
- }
- return 1;
- }
- #endif
- static
- cmsInt32Number CheckOneRGB(cmsContext ContextID, cmsHTRANSFORM xform, cmsUInt16Number R, cmsUInt16Number G, cmsUInt16Number B, cmsUInt16Number Ro, cmsUInt16Number Go, cmsUInt16Number Bo)
- {
- cmsUInt16Number RGB[3];
- cmsUInt16Number Out[3];
- RGB[0] = R;
- RGB[1] = G;
- RGB[2] = B;
- cmsDoTransform(ContextID, xform, RGB, Out, 1);
- return IsGoodWord("R", Ro , Out[0]) &&
- IsGoodWord("G", Go , Out[1]) &&
- IsGoodWord("B", Bo , Out[2]);
- }
- // Check known values going from sRGB to XYZ
- static
- cmsInt32Number CheckOneRGB_double(cmsContext ContextID, cmsHTRANSFORM xform, cmsFloat64Number R, cmsFloat64Number G, cmsFloat64Number B, cmsFloat64Number Ro, cmsFloat64Number Go, cmsFloat64Number Bo)
- {
- cmsFloat64Number RGB[3];
- cmsFloat64Number Out[3];
- RGB[0] = R;
- RGB[1] = G;
- RGB[2] = B;
- cmsDoTransform(ContextID, xform, RGB, Out, 1);
- return IsGoodVal("R", Ro , Out[0], 0.01) &&
- IsGoodVal("G", Go , Out[1], 0.01) &&
- IsGoodVal("B", Bo , Out[2], 0.01);
- }
- static
- cmsInt32Number CheckChangeBufferFormat(cmsContext ContextID)
- {
- cmsHPROFILE hsRGB = cmsCreate_sRGBProfile(ContextID);
- cmsHTRANSFORM xform;
- cmsHTRANSFORM xform2;
- xform = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_16, hsRGB, TYPE_RGB_16, INTENT_PERCEPTUAL, 0);
- cmsCloseProfile(ContextID, hsRGB);
- if (xform == NULL) return 0;
- if (!CheckOneRGB(ContextID, xform, 0, 0, 0, 0, 0, 0)) return 0;
- if (!CheckOneRGB(ContextID, xform, 120, 0, 0, 120, 0, 0)) return 0;
- if (!CheckOneRGB(ContextID, xform, 0, 222, 255, 0, 222, 255)) return 0;
- xform2 = cmsCloneTransformChangingFormats(ContextID, xform, TYPE_BGR_16, TYPE_RGB_16);
- if (!xform2) return 0;
- if (!CheckOneRGB(ContextID, xform2, 0, 0, 123, 123, 0, 0)) return 0;
- if (!CheckOneRGB(ContextID, xform2, 154, 234, 0, 0, 234, 154)) return 0;
- cmsDeleteTransform(ContextID,xform2);
- xform2 = cmsCloneTransformChangingFormats(ContextID, xform, TYPE_RGB_DBL, TYPE_RGB_DBL);
- if (!xform2) return 0;
- if (!CheckOneRGB_double(ContextID, xform2, 0.20, 0, 0, 0.20, 0, 0)) return 0;
- if (!CheckOneRGB_double(ContextID, xform2, 0, 0.9, 1, 0, 0.9, 1)) return 0;
- cmsDeleteTransform(ContextID,xform2);
- cmsDeleteTransform(ContextID,xform);
- return 1;
- }
- // Write tag testbed ----------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckXYZ(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsCIEXYZ XYZ, *Pt;
- switch (Pass) {
- case 1:
- XYZ.X = 1.0; XYZ.Y = 1.1; XYZ.Z = 1.2;
- return cmsWriteTag(ContextID, hProfile, tag, &XYZ);
- case 2:
- Pt = (cmsCIEXYZ *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return IsGoodFixed15_16("X", 1.0, Pt ->X) &&
- IsGoodFixed15_16("Y", 1.1, Pt->Y) &&
- IsGoodFixed15_16("Z", 1.2, Pt -> Z);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckGamma(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsToneCurve *g, *Pt;
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- g = cmsBuildGamma(ContextID, 1.0);
- rc = cmsWriteTag(ContextID, hProfile, tag, g);
- cmsFreeToneCurve(ContextID, g);
- return rc;
- case 2:
- Pt = (cmsToneCurve *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return cmsIsToneCurveLinear(ContextID, Pt);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckTextSingle(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsMLU *m, *Pt;
- cmsInt32Number rc;
- char Buffer[256];
- switch (Pass) {
- case 1:
- m = cmsMLUalloc(ContextID, 0);
- cmsMLUsetASCII(ContextID, m, cmsNoLanguage, cmsNoCountry, "Test test");
- rc = cmsWriteTag(ContextID, hProfile, tag, m);
- cmsMLUfree(ContextID, m);
- return rc;
- case 2:
- Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- cmsMLUgetASCII(ContextID, Pt, cmsNoLanguage, cmsNoCountry, Buffer, 256);
- if (strcmp(Buffer, "Test test") != 0) return FALSE;
- return TRUE;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckText(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsMLU *m, *Pt;
- cmsInt32Number rc;
- char Buffer[256];
- switch (Pass) {
- case 1:
- m = cmsMLUalloc(ContextID, 0);
- cmsMLUsetASCII(ContextID, m, cmsNoLanguage, cmsNoCountry, "Test test");
- cmsMLUsetASCII(ContextID, m, "en", "US", "1 1 1 1");
- cmsMLUsetASCII(ContextID, m, "es", "ES", "2 2 2 2");
- cmsMLUsetASCII(ContextID, m, "ct", "ES", "3 3 3 3");
- cmsMLUsetASCII(ContextID, m, "en", "GB", "444444444");
- rc = cmsWriteTag(ContextID, hProfile, tag, m);
- cmsMLUfree(ContextID, m);
- return rc;
- case 2:
- Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- cmsMLUgetASCII(ContextID, Pt, cmsNoLanguage, cmsNoCountry, Buffer, 256);
- if (strcmp(Buffer, "Test test") != 0) return FALSE;
- cmsMLUgetASCII(ContextID, Pt, "en", "US", Buffer, 256);
- if (strcmp(Buffer, "1 1 1 1") != 0) return FALSE;
- cmsMLUgetASCII(ContextID, Pt, "es", "ES", Buffer, 256);
- if (strcmp(Buffer, "2 2 2 2") != 0) return FALSE;
- cmsMLUgetASCII(ContextID, Pt, "ct", "ES", Buffer, 256);
- if (strcmp(Buffer, "3 3 3 3") != 0) return FALSE;
- cmsMLUgetASCII(ContextID, Pt, "en", "GB", Buffer, 256);
- if (strcmp(Buffer, "444444444") != 0) return FALSE;
- return TRUE;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckData(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsICCData *Pt;
- cmsICCData d = { 1, 0, { '?' }};
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- rc = cmsWriteTag(ContextID, hProfile, tag, &d);
- return rc;
- case 2:
- Pt = (cmsICCData *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return (Pt ->data[0] == '?') && (Pt ->flag == 0) && (Pt ->len == 1);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckSignature(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsTagSignature *Pt, Holder;
- switch (Pass) {
- case 1:
- Holder = (cmsTagSignature) cmsSigPerceptualReferenceMediumGamut;
- return cmsWriteTag(ContextID, hProfile, tag, &Holder);
- case 2:
- Pt = (cmsTagSignature *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return *Pt == cmsSigPerceptualReferenceMediumGamut;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckDateTime(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- struct tm *Pt, Holder;
- switch (Pass) {
- case 1:
- Holder.tm_hour = 1;
- Holder.tm_min = 2;
- Holder.tm_sec = 3;
- Holder.tm_mday = 4;
- Holder.tm_mon = 5;
- Holder.tm_year = 2009 - 1900;
- return cmsWriteTag(ContextID, hProfile, tag, &Holder);
- case 2:
- Pt = (struct tm *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return (Pt ->tm_hour == 1 &&
- Pt ->tm_min == 2 &&
- Pt ->tm_sec == 3 &&
- Pt ->tm_mday == 4 &&
- Pt ->tm_mon == 5 &&
- Pt ->tm_year == 2009 - 1900);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckNamedColor(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag, cmsInt32Number max_check, cmsBool colorant_check)
- {
- cmsNAMEDCOLORLIST* nc;
- cmsInt32Number i, j, rc;
- char Name[255];
- cmsUInt16Number PCS[3];
- cmsUInt16Number Colorant[cmsMAXCHANNELS];
- char CheckName[255];
- cmsUInt16Number CheckPCS[3];
- cmsUInt16Number CheckColorant[cmsMAXCHANNELS];
- switch (Pass) {
- case 1:
- nc = cmsAllocNamedColorList(ContextID, 0, 4, "prefix", "suffix");
- if (nc == NULL) return 0;
- for (i=0; i < max_check; i++) {
- PCS[0] = PCS[1] = PCS[2] = (cmsUInt16Number) i;
- Colorant[0] = Colorant[1] = Colorant[2] = Colorant[3] = (cmsUInt16Number) (max_check - i);
- sprintf(Name, "#%d", i);
- if (!cmsAppendNamedColor(ContextID, nc, Name, PCS, Colorant)) { Fail("Couldn't append named color"); return 0; }
- }
- rc = cmsWriteTag(ContextID, hProfile, tag, nc);
- cmsFreeNamedColorList(ContextID, nc);
- return rc;
- case 2:
- nc = (cmsNAMEDCOLORLIST *) cmsReadTag(ContextID, hProfile, tag);
- if (nc == NULL) return 0;
- for (i=0; i < max_check; i++) {
- CheckPCS[0] = CheckPCS[1] = CheckPCS[2] = (cmsUInt16Number) i;
- CheckColorant[0] = CheckColorant[1] = CheckColorant[2] = CheckColorant[3] = (cmsUInt16Number) (max_check - i);
- sprintf(CheckName, "#%d", i);
- if (!cmsNamedColorInfo(ContextID, nc, i, Name, NULL, NULL, PCS, Colorant)) { Fail("Invalid string"); return 0; }
- for (j=0; j < 3; j++) {
- if (CheckPCS[j] != PCS[j]) { Fail("Invalid PCS"); return 0; }
- }
- // This is only used on named color list
- if (colorant_check) {
- for (j=0; j < 4; j++) {
- if (CheckColorant[j] != Colorant[j]) { Fail("Invalid Colorant"); return 0; };
- }
- }
- if (strcmp(Name, CheckName) != 0) { Fail("Invalid Name"); return 0; };
- }
- return 1;
- default: return 0;
- }
- }
- static
- cmsInt32Number CheckLUT(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsPipeline* Lut, *Pt;
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- Lut = cmsPipelineAlloc(ContextID, 3, 3);
- if (Lut == NULL) return 0;
- // Create an identity LUT
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocIdentityCLut(ContextID, 3));
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, 3));
- rc = cmsWriteTag(ContextID, hProfile, tag, Lut);
- cmsPipelineFree(ContextID, Lut);
- return rc;
- case 2:
- Pt = (cmsPipeline *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- // Transform values, check for identity
- return Check16LUT(ContextID, Pt);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckCHAD(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsFloat64Number *Pt;
- cmsFloat64Number CHAD[] = { 0, .1, .2, .3, .4, .5, .6, .7, .8 };
- cmsInt32Number i;
- switch (Pass) {
- case 1:
- return cmsWriteTag(ContextID, hProfile, tag, CHAD);
- case 2:
- Pt = (cmsFloat64Number *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- for (i=0; i < 9; i++) {
- if (!IsGoodFixed15_16("CHAD", Pt[i], CHAD[i])) return 0;
- }
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckChromaticity(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsCIExyYTRIPLE *Pt, c = { {0, .1, 1 }, { .3, .4, 1 }, { .6, .7, 1 }};
- switch (Pass) {
- case 1:
- return cmsWriteTag(ContextID, hProfile, tag, &c);
- case 2:
- Pt = (cmsCIExyYTRIPLE *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Red.x, c.Red.x)) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Red.y, c.Red.y)) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Green.x, c.Green.x)) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Green.y, c.Green.y)) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Blue.x, c.Blue.x)) return 0;
- if (!IsGoodFixed15_16("xyY", Pt ->Blue.y, c.Blue.y)) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckColorantOrder(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsUInt8Number *Pt, c[cmsMAXCHANNELS];
- cmsInt32Number i;
- switch (Pass) {
- case 1:
- for (i=0; i < cmsMAXCHANNELS; i++) c[i] = (cmsUInt8Number) (cmsMAXCHANNELS - i - 1);
- return cmsWriteTag(ContextID, hProfile, tag, c);
- case 2:
- Pt = (cmsUInt8Number *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- for (i=0; i < cmsMAXCHANNELS; i++) {
- if (Pt[i] != ( cmsMAXCHANNELS - i - 1 )) return 0;
- }
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckMeasurement(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsICCMeasurementConditions *Pt, m;
- switch (Pass) {
- case 1:
- m.Backing.X = 0.1;
- m.Backing.Y = 0.2;
- m.Backing.Z = 0.3;
- m.Flare = 1.0;
- m.Geometry = 1;
- m.IlluminantType = cmsILLUMINANT_TYPE_D50;
- m.Observer = 1;
- return cmsWriteTag(ContextID, hProfile, tag, &m);
- case 2:
- Pt = (cmsICCMeasurementConditions *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- if (!IsGoodFixed15_16("Backing", Pt ->Backing.X, 0.1)) return 0;
- if (!IsGoodFixed15_16("Backing", Pt ->Backing.Y, 0.2)) return 0;
- if (!IsGoodFixed15_16("Backing", Pt ->Backing.Z, 0.3)) return 0;
- if (!IsGoodFixed15_16("Flare", Pt ->Flare, 1.0)) return 0;
- if (Pt ->Geometry != 1) return 0;
- if (Pt ->IlluminantType != cmsILLUMINANT_TYPE_D50) return 0;
- if (Pt ->Observer != 1) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckUcrBg(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsUcrBg *Pt, m;
- cmsInt32Number rc;
- char Buffer[256];
- switch (Pass) {
- case 1:
- m.Ucr = cmsBuildGamma(ContextID, 2.4);
- m.Bg = cmsBuildGamma(ContextID, -2.2);
- m.Desc = cmsMLUalloc(ContextID, 1);
- cmsMLUsetASCII(ContextID, m.Desc, cmsNoLanguage, cmsNoCountry, "test UCR/BG");
- rc = cmsWriteTag(ContextID, hProfile, tag, &m);
- cmsMLUfree(ContextID, m.Desc);
- cmsFreeToneCurve(ContextID, m.Bg);
- cmsFreeToneCurve(ContextID, m.Ucr);
- return rc;
- case 2:
- Pt = (cmsUcrBg *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- cmsMLUgetASCII(ContextID, Pt ->Desc, cmsNoLanguage, cmsNoCountry, Buffer, 256);
- if (strcmp(Buffer, "test UCR/BG") != 0) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckCRDinfo(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsMLU *mlu;
- char Buffer[256];
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- mlu = cmsMLUalloc(ContextID, 5);
- cmsMLUsetWide(ContextID, mlu, "PS", "nm", L"test postscript");
- cmsMLUsetWide(ContextID, mlu, "PS", "#0", L"perceptual");
- cmsMLUsetWide(ContextID, mlu, "PS", "#1", L"relative_colorimetric");
- cmsMLUsetWide(ContextID, mlu, "PS", "#2", L"saturation");
- cmsMLUsetWide(ContextID, mlu, "PS", "#3", L"absolute_colorimetric");
- rc = cmsWriteTag(ContextID, hProfile, tag, mlu);
- cmsMLUfree(ContextID, mlu);
- return rc;
- case 2:
- mlu = (cmsMLU*) cmsReadTag(ContextID, hProfile, tag);
- if (mlu == NULL) return 0;
- cmsMLUgetASCII(ContextID, mlu, "PS", "nm", Buffer, 256);
- if (strcmp(Buffer, "test postscript") != 0) return 0;
- cmsMLUgetASCII(ContextID, mlu, "PS", "#0", Buffer, 256);
- if (strcmp(Buffer, "perceptual") != 0) return 0;
- cmsMLUgetASCII(ContextID, mlu, "PS", "#1", Buffer, 256);
- if (strcmp(Buffer, "relative_colorimetric") != 0) return 0;
- cmsMLUgetASCII(ContextID, mlu, "PS", "#2", Buffer, 256);
- if (strcmp(Buffer, "saturation") != 0) return 0;
- cmsMLUgetASCII(ContextID, mlu, "PS", "#3", Buffer, 256);
- if (strcmp(Buffer, "absolute_colorimetric") != 0) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsToneCurve *CreateSegmentedCurve(cmsContext ContextID)
- {
- cmsCurveSegment Seg[3];
- cmsFloat32Number Sampled[2] = { 0, 1};
- Seg[0].Type = 6;
- Seg[0].Params[0] = 1;
- Seg[0].Params[1] = 0;
- Seg[0].Params[2] = 0;
- Seg[0].Params[3] = 0;
- Seg[0].x0 = -1E22F;
- Seg[0].x1 = 0;
- Seg[1].Type = 0;
- Seg[1].nGridPoints = 2;
- Seg[1].SampledPoints = Sampled;
- Seg[1].x0 = 0;
- Seg[1].x1 = 1;
- Seg[2].Type = 6;
- Seg[2].Params[0] = 1;
- Seg[2].Params[1] = 0;
- Seg[2].Params[2] = 0;
- Seg[2].Params[3] = 0;
- Seg[2].x0 = 1;
- Seg[2].x1 = 1E22F;
- return cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
- }
- static
- cmsInt32Number CheckMPE(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsPipeline* Lut, *Pt;
- cmsToneCurve* G[3];
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- Lut = cmsPipelineAlloc(ContextID, 3, 3);
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4(ContextID));
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID));
- AddIdentityCLUTfloat(ContextID, Lut);
- G[0] = G[1] = G[2] = CreateSegmentedCurve(ContextID);
- cmsPipelineInsertStage(ContextID, Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, G));
- cmsFreeToneCurve(ContextID, G[0]);
- rc = cmsWriteTag(ContextID, hProfile, tag, Lut);
- cmsPipelineFree(ContextID, Lut);
- return rc;
- case 2:
- Pt = (cmsPipeline *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- return CheckFloatLUT(ContextID, Pt);
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckScreening(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile, cmsTagSignature tag)
- {
- cmsScreening *Pt, sc;
- cmsInt32Number rc;
- switch (Pass) {
- case 1:
- sc.Flag = 0;
- sc.nChannels = 1;
- sc.Channels[0].Frequency = 2.0;
- sc.Channels[0].ScreenAngle = 3.0;
- sc.Channels[0].SpotShape = cmsSPOT_ELLIPSE;
- rc = cmsWriteTag(ContextID, hProfile, tag, &sc);
- return rc;
- case 2:
- Pt = (cmsScreening *) cmsReadTag(ContextID, hProfile, tag);
- if (Pt == NULL) return 0;
- if (Pt ->nChannels != 1) return 0;
- if (Pt ->Flag != 0) return 0;
- if (!IsGoodFixed15_16("Freq", Pt ->Channels[0].Frequency, 2.0)) return 0;
- if (!IsGoodFixed15_16("Angle", Pt ->Channels[0].ScreenAngle, 3.0)) return 0;
- if (Pt ->Channels[0].SpotShape != cmsSPOT_ELLIPSE) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsBool CheckOneStr(cmsContext ContextID, cmsMLU* mlu, cmsInt32Number n)
- {
- char Buffer[256], Buffer2[256];
- cmsMLUgetASCII(ContextID, mlu, "en", "US", Buffer, 255);
- sprintf(Buffer2, "Hello, world %d", n);
- if (strcmp(Buffer, Buffer2) != 0) return FALSE;
- cmsMLUgetASCII(ContextID, mlu, "es", "ES", Buffer, 255);
- sprintf(Buffer2, "Hola, mundo %d", n);
- if (strcmp(Buffer, Buffer2) != 0) return FALSE;
- return TRUE;
- }
- static
- void SetOneStr(cmsContext ContextID, cmsMLU** mlu, const wchar_t* s1, const wchar_t* s2)
- {
- *mlu = cmsMLUalloc(ContextID, 0);
- cmsMLUsetWide(ContextID, *mlu, "en", "US", s1);
- cmsMLUsetWide(ContextID, *mlu, "es", "ES", s2);
- }
- static
- cmsInt32Number CheckProfileSequenceTag(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsSEQ* s;
- cmsInt32Number i;
- switch (Pass) {
- case 1:
- s = cmsAllocProfileSequenceDescription(ContextID, 3);
- if (s == NULL) return 0;
- SetOneStr(ContextID, &s -> seq[0].Manufacturer, L"Hello, world 0", L"Hola, mundo 0");
- SetOneStr(ContextID, &s -> seq[0].Model, L"Hello, world 0", L"Hola, mundo 0");
- SetOneStr(ContextID, &s -> seq[1].Manufacturer, L"Hello, world 1", L"Hola, mundo 1");
- SetOneStr(ContextID, &s -> seq[1].Model, L"Hello, world 1", L"Hola, mundo 1");
- SetOneStr(ContextID, &s -> seq[2].Manufacturer, L"Hello, world 2", L"Hola, mundo 2");
- SetOneStr(ContextID, &s -> seq[2].Model, L"Hello, world 2", L"Hola, mundo 2");
- #ifdef CMS_DONT_USE_INT64
- s ->seq[0].attributes[0] = cmsTransparency|cmsMatte;
- s ->seq[0].attributes[1] = 0;
- #else
- s ->seq[0].attributes = cmsTransparency|cmsMatte;
- #endif
- #ifdef CMS_DONT_USE_INT64
- s ->seq[1].attributes[0] = cmsReflective|cmsMatte;
- s ->seq[1].attributes[1] = 0;
- #else
- s ->seq[1].attributes = cmsReflective|cmsMatte;
- #endif
- #ifdef CMS_DONT_USE_INT64
- s ->seq[2].attributes[0] = cmsTransparency|cmsGlossy;
- s ->seq[2].attributes[1] = 0;
- #else
- s ->seq[2].attributes = cmsTransparency|cmsGlossy;
- #endif
- if (!cmsWriteTag(ContextID, hProfile, cmsSigProfileSequenceDescTag, s)) return 0;
- cmsFreeProfileSequenceDescription(ContextID, s);
- return 1;
- case 2:
- s = (cmsSEQ *) cmsReadTag(ContextID, hProfile, cmsSigProfileSequenceDescTag);
- if (s == NULL) return 0;
- if (s ->n != 3) return 0;
- #ifdef CMS_DONT_USE_INT64
- if (s ->seq[0].attributes[0] != (cmsTransparency|cmsMatte)) return 0;
- if (s ->seq[0].attributes[1] != 0) return 0;
- #else
- if (s ->seq[0].attributes != (cmsTransparency|cmsMatte)) return 0;
- #endif
- #ifdef CMS_DONT_USE_INT64
- if (s ->seq[1].attributes[0] != (cmsReflective|cmsMatte)) return 0;
- if (s ->seq[1].attributes[1] != 0) return 0;
- #else
- if (s ->seq[1].attributes != (cmsReflective|cmsMatte)) return 0;
- #endif
- #ifdef CMS_DONT_USE_INT64
- if (s ->seq[2].attributes[0] != (cmsTransparency|cmsGlossy)) return 0;
- if (s ->seq[2].attributes[1] != 0) return 0;
- #else
- if (s ->seq[2].attributes != (cmsTransparency|cmsGlossy)) return 0;
- #endif
- // Check MLU
- for (i=0; i < 3; i++) {
- if (!CheckOneStr(ContextID, s -> seq[i].Manufacturer, i)) return 0;
- if (!CheckOneStr(ContextID, s -> seq[i].Model, i)) return 0;
- }
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckProfileSequenceIDTag(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsSEQ* s;
- cmsInt32Number i;
- switch (Pass) {
- case 1:
- s = cmsAllocProfileSequenceDescription(ContextID, 3);
- if (s == NULL) return 0;
- memcpy(s ->seq[0].ProfileID.ID8, "0123456789ABCDEF", 16);
- memcpy(s ->seq[1].ProfileID.ID8, "1111111111111111", 16);
- memcpy(s ->seq[2].ProfileID.ID8, "2222222222222222", 16);
- SetOneStr(ContextID, &s -> seq[0].Description, L"Hello, world 0", L"Hola, mundo 0");
- SetOneStr(ContextID, &s -> seq[1].Description, L"Hello, world 1", L"Hola, mundo 1");
- SetOneStr(ContextID, &s -> seq[2].Description, L"Hello, world 2", L"Hola, mundo 2");
- if (!cmsWriteTag(ContextID, hProfile, cmsSigProfileSequenceIdTag, s)) return 0;
- cmsFreeProfileSequenceDescription(ContextID, s);
- return 1;
- case 2:
- s = (cmsSEQ *) cmsReadTag(ContextID, hProfile, cmsSigProfileSequenceIdTag);
- if (s == NULL) return 0;
- if (s ->n != 3) return 0;
- if (memcmp(s ->seq[0].ProfileID.ID8, "0123456789ABCDEF", 16) != 0) return 0;
- if (memcmp(s ->seq[1].ProfileID.ID8, "1111111111111111", 16) != 0) return 0;
- if (memcmp(s ->seq[2].ProfileID.ID8, "2222222222222222", 16) != 0) return 0;
- for (i=0; i < 3; i++) {
- if (!CheckOneStr(ContextID, s -> seq[i].Description, i)) return 0;
- }
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckICCViewingConditions(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsICCViewingConditions* v;
- cmsICCViewingConditions s;
- switch (Pass) {
- case 1:
- s.IlluminantType = 1;
- s.IlluminantXYZ.X = 0.1;
- s.IlluminantXYZ.Y = 0.2;
- s.IlluminantXYZ.Z = 0.3;
- s.SurroundXYZ.X = 0.4;
- s.SurroundXYZ.Y = 0.5;
- s.SurroundXYZ.Z = 0.6;
- if (!cmsWriteTag(ContextID, hProfile, cmsSigViewingConditionsTag, &s)) return 0;
- return 1;
- case 2:
- v = (cmsICCViewingConditions *) cmsReadTag(ContextID, hProfile, cmsSigViewingConditionsTag);
- if (v == NULL) return 0;
- if (v ->IlluminantType != 1) return 0;
- if (!IsGoodVal("IlluminantXYZ.X", v ->IlluminantXYZ.X, 0.1, 0.001)) return 0;
- if (!IsGoodVal("IlluminantXYZ.Y", v ->IlluminantXYZ.Y, 0.2, 0.001)) return 0;
- if (!IsGoodVal("IlluminantXYZ.Z", v ->IlluminantXYZ.Z, 0.3, 0.001)) return 0;
- if (!IsGoodVal("SurroundXYZ.X", v ->SurroundXYZ.X, 0.4, 0.001)) return 0;
- if (!IsGoodVal("SurroundXYZ.Y", v ->SurroundXYZ.Y, 0.5, 0.001)) return 0;
- if (!IsGoodVal("SurroundXYZ.Z", v ->SurroundXYZ.Z, 0.6, 0.001)) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number CheckVCGT(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsToneCurve* Curves[3];
- cmsToneCurve** PtrCurve;
- switch (Pass) {
- case 1:
- Curves[0] = cmsBuildGamma(ContextID, 1.1);
- Curves[1] = cmsBuildGamma(ContextID, 2.2);
- Curves[2] = cmsBuildGamma(ContextID, 3.4);
- if (!cmsWriteTag(ContextID, hProfile, cmsSigVcgtTag, Curves)) return 0;
- cmsFreeToneCurveTriple(ContextID, Curves);
- return 1;
- case 2:
- PtrCurve = (cmsToneCurve **) cmsReadTag(ContextID, hProfile, cmsSigVcgtTag);
- if (PtrCurve == NULL) return 0;
- if (!IsGoodVal("VCGT R", cmsEstimateGamma(ContextID, PtrCurve[0], 0.01), 1.1, 0.001)) return 0;
- if (!IsGoodVal("VCGT G", cmsEstimateGamma(ContextID, PtrCurve[1], 0.01), 2.2, 0.001)) return 0;
- if (!IsGoodVal("VCGT B", cmsEstimateGamma(ContextID, PtrCurve[2], 0.01), 3.4, 0.001)) return 0;
- return 1;
- default:;
- }
- return 0;
- }
- // Only one of the two following may be used, as they share the same tag
- static
- cmsInt32Number CheckDictionary16(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsHANDLE hDict;
- const cmsDICTentry* e;
- switch (Pass) {
- case 1:
- hDict = cmsDictAlloc(ContextID);
- cmsDictAddEntry(ContextID, hDict, L"Name0", NULL, NULL, NULL);
- cmsDictAddEntry(ContextID, hDict, L"Name1", L"", NULL, NULL);
- cmsDictAddEntry(ContextID, hDict, L"Name", L"String", NULL, NULL);
- cmsDictAddEntry(ContextID, hDict, L"Name2", L"12", NULL, NULL);
- if (!cmsWriteTag(ContextID, hProfile, cmsSigMetaTag, hDict)) return 0;
- cmsDictFree(ContextID, hDict);
- return 1;
- case 2:
- hDict = cmsReadTag(ContextID, hProfile, cmsSigMetaTag);
- if (hDict == NULL) return 0;
- e = cmsDictGetEntryList(ContextID, hDict);
- if (memcmp(e ->Name, L"Name2", sizeof(wchar_t) * 5) != 0) return 0;
- if (memcmp(e ->Value, L"12", sizeof(wchar_t) * 2) != 0) return 0;
- e = cmsDictNextEntry(ContextID, e);
- if (memcmp(e ->Name, L"Name", sizeof(wchar_t) * 4) != 0) return 0;
- if (memcmp(e ->Value, L"String", sizeof(wchar_t) * 5) != 0) return 0;
- e = cmsDictNextEntry(ContextID, e);
- if (memcmp(e ->Name, L"Name1", sizeof(wchar_t) *5) != 0) return 0;
- if (e ->Value == NULL) return 0;
- if (*e->Value != 0) return 0;
- e = cmsDictNextEntry(ContextID, e);
- if (memcmp(e ->Name, L"Name0", sizeof(wchar_t) * 5) != 0) return 0;
- if (e ->Value != NULL) return 0;
- return 1;
- default:;
- }
- return 0;
- }
- static
- cmsInt32Number CheckDictionary24(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsHANDLE hDict;
- const cmsDICTentry* e;
- cmsMLU* DisplayName;
- char Buffer[256];
- cmsInt32Number rc = 1;
- switch (Pass) {
- case 1:
- hDict = cmsDictAlloc(ContextID);
- DisplayName = cmsMLUalloc(ContextID, 0);
- cmsMLUsetWide(ContextID, DisplayName, "en", "US", L"Hello, world");
- cmsMLUsetWide(ContextID, DisplayName, "es", "ES", L"Hola, mundo");
- cmsMLUsetWide(ContextID, DisplayName, "fr", "FR", L"Bonjour, le monde");
- cmsMLUsetWide(ContextID, DisplayName, "ca", "CA", L"Hola, mon");
- cmsDictAddEntry(ContextID, hDict, L"Name", L"String", DisplayName, NULL);
- cmsMLUfree(ContextID, DisplayName);
- cmsDictAddEntry(ContextID, hDict, L"Name2", L"12", NULL, NULL);
- if (!cmsWriteTag(ContextID, hProfile, cmsSigMetaTag, hDict)) return 0;
- cmsDictFree(ContextID, hDict);
- return 1;
- case 2:
- hDict = cmsReadTag(ContextID, hProfile, cmsSigMetaTag);
- if (hDict == NULL) return 0;
- e = cmsDictGetEntryList(ContextID, hDict);
- if (memcmp(e ->Name, L"Name2", sizeof(wchar_t) * 5) != 0) return 0;
- if (memcmp(e ->Value, L"12", sizeof(wchar_t) * 2) != 0) return 0;
- e = cmsDictNextEntry(ContextID, e);
- if (memcmp(e ->Name, L"Name", sizeof(wchar_t) * 4) != 0) return 0;
- if (memcmp(e ->Value, L"String", sizeof(wchar_t) * 5) != 0) return 0;
- cmsMLUgetASCII(ContextID, e->DisplayName, "en", "US", Buffer, 256);
- if (strcmp(Buffer, "Hello, world") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, e->DisplayName, "es", "ES", Buffer, 256);
- if (strcmp(Buffer, "Hola, mundo") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, e->DisplayName, "fr", "FR", Buffer, 256);
- if (strcmp(Buffer, "Bonjour, le monde") != 0) rc = 0;
- cmsMLUgetASCII(ContextID, e->DisplayName, "ca", "CA", Buffer, 256);
- if (strcmp(Buffer, "Hola, mon") != 0) rc = 0;
- if (rc == 0)
- Fail("Unexpected string '%s'", Buffer);
- return 1;
- default:;
- }
- return 0;
- }
- static
- cmsInt32Number CheckRAWtags(cmsContext ContextID, cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- char Buffer[7];
- switch (Pass) {
- case 1:
- return cmsWriteRawTag(ContextID, hProfile, (cmsTagSignature) 0x31323334, "data123", 7);
- case 2:
- if (!cmsReadRawTag(ContextID, hProfile, (cmsTagSignature) 0x31323334, Buffer, 7)) return 0;
- if (memcmp(Buffer, "data123", 7) != 0) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- cmsInt32Number Check_cicp(cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsVideoSignalType* v;
- cmsVideoSignalType s;
- switch (Pass) {
- case 1:
- s.ColourPrimaries = 1;
- s.TransferCharacteristics = 13;
- s.MatrixCoefficients = 0;
- s.VideoFullRangeFlag = 1;
- if (!cmsWriteTag(hProfile, cmsSigcicpTag, &s)) return 0;
- return 1;
- case 2:
- v = (cmsVideoSignalType*)cmsReadTag(hProfile, cmsSigcicpTag);
- if (v == NULL) return 0;
- if (v->ColourPrimaries != 1) return 0;
- if (v->TransferCharacteristics != 13) return 0;
- if (v->MatrixCoefficients != 0) return 0;
- if (v->VideoFullRangeFlag != 1) return 0;
- return 1;
- default:
- return 0;
- }
- }
- static
- void SetMHC2Matrix(cmsFloat64Number XYZ2XYZmatrix[3][4])
- {
- XYZ2XYZmatrix[0][0] = 0.5; XYZ2XYZmatrix[0][1] = 0.1; XYZ2XYZmatrix[0][2] = 0.1; XYZ2XYZmatrix[0][3] = 0.0;
- XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0;
- XYZ2XYZmatrix[2][0] = 0.3; XYZ2XYZmatrix[2][1] = 0.2; XYZ2XYZmatrix[2][2] = 0.4; XYZ2XYZmatrix[2][3] = 0.0;
- }
- static
- cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
- {
- return fabs(b - a) < (1.0 / 65535.0);
- }
- cmsBool IsOriginalMHC2Matrix(cmsFloat64Number XYZ2XYZmatrix[3][4])
- {
- cmsFloat64Number m[3][4];
- int i, j;
- SetMHC2Matrix(m);
- for (i = 0; i < 3; i++)
- for (j = 0; j < 4; j++)
- if (!CloseEnough(XYZ2XYZmatrix[i][j], m[i][j])) return FALSE;
- return TRUE;
- }
- static
- cmsInt32Number Check_MHC2(cmsInt32Number Pass, cmsHPROFILE hProfile)
- {
- cmsMHC2Type* v;
- cmsMHC2Type s;
- double curve[] = { 0, 0.5, 1.0 };
- switch (Pass) {
- case 1:
- SetMHC2Matrix(s.XYZ2XYZmatrix);
- s.CurveEntries = 3;
- s.GreenCurve = curve;
- s.RedCurve = curve;
- s.BlueCurve = curve;
- s.MinLuminance = 0.1;
- s.PeakLuminance = 100.0;
-
- if (!cmsWriteTag(hProfile, cmsSigMHC2Tag, &s)) return 0;
- return 1;
- case 2:
- v = (cmsMHC2Type*)cmsReadTag(hProfile, cmsSigMHC2Tag);
- if (v == NULL) return 0;
- if (!IsOriginalMHC2Matrix(v->XYZ2XYZmatrix)) return 0;
- if (v->CurveEntries != 3) return 0;
- return 1;
- default:
- return 0;
- }
- }
- // This is a very big test that checks every single tag
- static
- cmsInt32Number CheckProfileCreation(cmsContext ContextID)
- {
- cmsHPROFILE h;
- cmsInt32Number Pass;
- h = cmsCreateProfilePlaceholder(ContextID);
- if (h == NULL) return 0;
- cmsSetProfileVersion(ContextID, h, 4.3);
- if (cmsGetTagCount(ContextID, h) != 0) { Fail("Empty profile with nonzero number of tags"); goto Error; }
- if (cmsIsTag(ContextID, h, cmsSigAToB0Tag)) { Fail("Found a tag in an empty profile"); goto Error; }
- cmsSetColorSpace(ContextID, h, cmsSigRgbData);
- if (cmsGetColorSpace(ContextID, h) != cmsSigRgbData) { Fail("Unable to set colorspace"); goto Error; }
- cmsSetPCS(ContextID, h, cmsSigLabData);
- if (cmsGetPCS(ContextID, h) != cmsSigLabData) { Fail("Unable to set colorspace"); goto Error; }
- cmsSetDeviceClass(ContextID, h, cmsSigDisplayClass);
- if (cmsGetDeviceClass(ContextID, h) != cmsSigDisplayClass) { Fail("Unable to set deviceclass"); goto Error; }
- cmsSetHeaderRenderingIntent(ContextID, h, INTENT_SATURATION);
- if (cmsGetHeaderRenderingIntent(ContextID, h) != INTENT_SATURATION) { Fail("Unable to set rendering intent"); goto Error; }
- for (Pass = 1; Pass <= 2; Pass++) {
- SubTest("Tags holding XYZ");
- if (!CheckXYZ(ContextID, Pass, h, cmsSigBlueColorantTag)) goto Error;
- if (!CheckXYZ(ContextID, Pass, h, cmsSigGreenColorantTag)) goto Error;
- if (!CheckXYZ(ContextID, Pass, h, cmsSigRedColorantTag)) goto Error;
- if (!CheckXYZ(ContextID, Pass, h, cmsSigMediaBlackPointTag)) goto Error;
- if (!CheckXYZ(ContextID, Pass, h, cmsSigMediaWhitePointTag)) goto Error;
- if (!CheckXYZ(ContextID, Pass, h, cmsSigLuminanceTag)) goto Error;
- SubTest("Tags holding curves");
- if (!CheckGamma(ContextID, Pass, h, cmsSigBlueTRCTag)) goto Error;
- if (!CheckGamma(ContextID, Pass, h, cmsSigGrayTRCTag)) goto Error;
- if (!CheckGamma(ContextID, Pass, h, cmsSigGreenTRCTag)) goto Error;
- if (!CheckGamma(ContextID, Pass, h, cmsSigRedTRCTag)) goto Error;
- SubTest("Tags holding text");
- if (!CheckTextSingle(ContextID, Pass, h, cmsSigCharTargetTag)) goto Error;
- if (!CheckTextSingle(ContextID, Pass, h, cmsSigScreeningDescTag)) goto Error;
- if (!CheckText(ContextID, Pass, h, cmsSigCopyrightTag)) goto Error;
- if (!CheckText(ContextID, Pass, h, cmsSigProfileDescriptionTag)) goto Error;
- if (!CheckText(ContextID, Pass, h, cmsSigDeviceMfgDescTag)) goto Error;
- if (!CheckText(ContextID, Pass, h, cmsSigDeviceModelDescTag)) goto Error;
- if (!CheckText(ContextID, Pass, h, cmsSigViewingCondDescTag)) goto Error;
- SubTest("Tags holding cmsICCData");
- if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD0Tag)) goto Error;
- if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD1Tag)) goto Error;
- if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD2Tag)) goto Error;
- if (!CheckData(ContextID, Pass, h, cmsSigPs2CRD3Tag)) goto Error;
- if (!CheckData(ContextID, Pass, h, cmsSigPs2CSATag)) goto Error;
- if (!CheckData(ContextID, Pass, h, cmsSigPs2RenderingIntentTag)) goto Error;
- SubTest("Tags holding signatures");
- if (!CheckSignature(ContextID, Pass, h, cmsSigColorimetricIntentImageStateTag)) goto Error;
- if (!CheckSignature(ContextID, Pass, h, cmsSigPerceptualRenderingIntentGamutTag)) goto Error;
- if (!CheckSignature(ContextID, Pass, h, cmsSigSaturationRenderingIntentGamutTag)) goto Error;
- if (!CheckSignature(ContextID, Pass, h, cmsSigTechnologyTag)) goto Error;
- SubTest("Tags holding date_time");
- if (!CheckDateTime(ContextID, Pass, h, cmsSigCalibrationDateTimeTag)) goto Error;
- if (!CheckDateTime(ContextID, Pass, h, cmsSigDateTimeTag)) goto Error;
- SubTest("Tags holding named color lists");
- if (!CheckNamedColor(ContextID, Pass, h, cmsSigColorantTableTag, 15, FALSE)) goto Error;
- if (!CheckNamedColor(ContextID, Pass, h, cmsSigColorantTableOutTag, 15, FALSE)) goto Error;
- if (!CheckNamedColor(ContextID, Pass, h, cmsSigNamedColor2Tag, 4096, TRUE)) goto Error;
- SubTest("Tags holding LUTs");
- if (!CheckLUT(ContextID, Pass, h, cmsSigAToB0Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigAToB1Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigAToB2Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigBToA0Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigBToA1Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigBToA2Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigPreview0Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigPreview1Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigPreview2Tag)) goto Error;
- if (!CheckLUT(ContextID, Pass, h, cmsSigGamutTag)) goto Error;
- SubTest("Tags holding CHAD");
- if (!CheckCHAD(ContextID, Pass, h, cmsSigChromaticAdaptationTag)) goto Error;
- SubTest("Tags holding Chromaticity");
- if (!CheckChromaticity(ContextID, Pass, h, cmsSigChromaticityTag)) goto Error;
- SubTest("Tags holding colorant order");
- if (!CheckColorantOrder(ContextID, Pass, h, cmsSigColorantOrderTag)) goto Error;
- SubTest("Tags holding measurement");
- if (!CheckMeasurement(ContextID, Pass, h, cmsSigMeasurementTag)) goto Error;
- SubTest("Tags holding CRD info");
- if (!CheckCRDinfo(ContextID, Pass, h, cmsSigCrdInfoTag)) goto Error;
- SubTest("Tags holding UCR/BG");
- if (!CheckUcrBg(ContextID, Pass, h, cmsSigUcrBgTag)) goto Error;
- SubTest("Tags holding MPE");
- if (!CheckMPE(ContextID, Pass, h, cmsSigDToB0Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigDToB1Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigDToB2Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigDToB3Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigBToD0Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigBToD1Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigBToD2Tag)) goto Error;
- if (!CheckMPE(ContextID, Pass, h, cmsSigBToD3Tag)) goto Error;
- SubTest("Tags using screening");
- if (!CheckScreening(ContextID, Pass, h, cmsSigScreeningTag)) goto Error;
- SubTest("Tags holding profile sequence description");
- if (!CheckProfileSequenceTag(ContextID, Pass, h)) goto Error;
- if (!CheckProfileSequenceIDTag(ContextID, Pass, h)) goto Error;
- SubTest("Tags holding ICC viewing conditions");
- if (!CheckICCViewingConditions(ContextID, Pass, h)) goto Error;
- SubTest("VCGT tags");
- if (!CheckVCGT(ContextID, Pass, h)) goto Error;
- SubTest("RAW tags");
- if (!CheckRAWtags(ContextID, Pass, h)) goto Error;
- SubTest("Dictionary meta tags");
- // if (!CheckDictionary16(ContextID, Pass, h)) goto Error;
- if (!CheckDictionary24(ContextID, Pass, h)) goto Error;
- SubTest("cicp Video Signal Type");
- if (!Check_cicp(Pass, h)) goto Error;
- SubTest("Microsoft MHC2 tag");
- if (!Check_MHC2(Pass, h)) goto Error;
- if (Pass == 1) {
- cmsSaveProfileToFile(ContextID, h, "alltags.icc");
- cmsCloseProfile(ContextID, h);
- h = cmsOpenProfileFromFile(ContextID, "alltags.icc", "r");
- }
- }
- /*
- Not implemented (by design):
- cmsSigDataTag = 0x64617461, // 'data' -- Unused
- cmsSigDeviceSettingsTag = 0x64657673, // 'devs' -- Unused
- cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' -- Don't use this one, deprecated by ICC
- cmsSigOutputResponseTag = 0x72657370, // 'resp' -- Possible patent on this
- */
- cmsCloseProfile(ContextID, h);
- remove("alltags.icc");
- return 1;
- Error:
- cmsCloseProfile(ContextID, h);
- remove("alltags.icc");
- return 0;
- }
- // Thanks to Christopher James Halse Rogers for the bugfixing and providing this test
- static
- cmsInt32Number CheckVersionHeaderWriting(cmsContext ContextID)
- {
- cmsHPROFILE h;
- int index;
- float test_versions[] = {
- 2.3f,
- 4.08f,
- 4.09f,
- 4.3f
- };
- for (index = 0; index < sizeof(test_versions)/sizeof(test_versions[0]); index++) {
- h = cmsCreateProfilePlaceholder(ContextID);
- if (h == NULL) return 0;
- cmsSetProfileVersion(ContextID, h, test_versions[index]);
- cmsSaveProfileToFile(ContextID, h, "versions.icc");
- cmsCloseProfile(ContextID, h);
- h = cmsOpenProfileFromFile(ContextID, "versions.icc", "r");
- // Only the first 3 digits are significant
- if (fabs(cmsGetProfileVersion(ContextID, h) - test_versions[index]) > 0.005) {
- Fail("Version failed to round-trip: wrote %.2f, read %.2f",
- test_versions[index], cmsGetProfileVersion(ContextID, h));
- return 0;
- }
- cmsCloseProfile(ContextID, h);
- remove("versions.icc");
- }
- return 1;
- }
- // Test on Richard Hughes "crayons.icc"
- static
- cmsInt32Number CheckMultilocalizedProfile(cmsContext ContextID)
- {
- cmsHPROFILE hProfile;
- cmsMLU *Pt;
- char Buffer[256];
- hProfile = cmsOpenProfileFromFile(ContextID, "crayons.icc", "r");
- Pt = (cmsMLU *) cmsReadTag(ContextID, hProfile, cmsSigProfileDescriptionTag);
- cmsMLUgetASCII(ContextID, Pt, "en", "GB", Buffer, 256);
- if (strcmp(Buffer, "Crayon Colours") != 0) return FALSE;
- cmsMLUgetASCII(ContextID, Pt, "en", "US", Buffer, 256);
- if (strcmp(Buffer, "Crayon Colors") != 0) return FALSE;
- cmsCloseProfile(ContextID, hProfile);
- return TRUE;
- }
- // Error reporting -------------------------------------------------------------------------------------------------------
- static
- void ErrorReportingFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
- {
- TrappedError = TRUE;
- SimultaneousErrors++;
- strncpy(ReasonToFailBuffer, Text, TEXT_ERROR_BUFFER_SIZE-1);
- cmsUNUSED_PARAMETER(ContextID);
- cmsUNUSED_PARAMETER(ErrorCode);
- }
- static
- cmsInt32Number CheckBadProfiles(cmsContext ContextID)
- {
- cmsHPROFILE h;
- h = cmsOpenProfileFromFile(ContextID, "IDoNotExist.icc", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromFile(ContextID, "IAmIllFormed*.icc", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- // No profile name given
- h = cmsOpenProfileFromFile(ContextID, "", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromFile(ContextID, "..", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromFile(ContextID, "IHaveBadAccessMode.icc", "@");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromFile(ContextID, "bad.icc", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromFile(ContextID, "toosmall.icc", "r");
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromMem(ContextID, NULL, 3);
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- h = cmsOpenProfileFromMem(ContextID, "123", 3);
- if (h != NULL) {
- cmsCloseProfile(ContextID, h);
- return 0;
- }
- if (SimultaneousErrors != 9) return 0;
- return 1;
- }
- static
- cmsInt32Number CheckErrReportingOnBadProfiles(cmsContext ContextID)
- {
- cmsInt32Number rc;
- cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
- rc = CheckBadProfiles(ContextID);
- cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
- // Reset the error state
- TrappedError = FALSE;
- return rc;
- }
- static
- cmsInt32Number CheckBadTransforms(cmsContext ContextID)
- {
- cmsHPROFILE h1 = cmsCreate_sRGBProfile(ContextID);
- cmsHTRANSFORM x1;
- x1 = cmsCreateTransform(ContextID, NULL, 0, NULL, 0, 0, 0);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, h1, TYPE_RGB_8, 12345, 0);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- x1 = cmsCreateTransform(ContextID, h1, TYPE_CMYK_8, h1, TYPE_RGB_8, 0, 0);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, h1, TYPE_CMYK_8, 1, 0);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- // sRGB does its output as XYZ!
- x1 = cmsCreateTransform(ContextID, h1, TYPE_RGB_8, NULL, TYPE_Lab_8, 1, 0);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- cmsCloseProfile(ContextID, h1);
- {
- cmsHPROFILE hp1 = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- cmsHPROFILE hp2 = cmsCreate_sRGBProfile(ContextID);
- x1 = cmsCreateTransform(ContextID, hp1, TYPE_BGR_8, hp2, TYPE_BGR_8, INTENT_PERCEPTUAL, 0);
- cmsCloseProfile(ContextID, hp1); cmsCloseProfile(ContextID, hp2);
- if (x1 != NULL) {
- cmsDeleteTransform(ContextID, x1);
- return 0;
- }
- }
- return 1;
- }
- static
- cmsInt32Number CheckErrReportingOnBadTransforms(cmsContext ContextID)
- {
- cmsInt32Number rc;
- cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
- rc = CheckBadTransforms(ContextID);
- cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
- // Reset the error state
- TrappedError = FALSE;
- return rc;
- }
- // ---------------------------------------------------------------------------------------------------------
- // Check a linear xform
- static
- cmsInt32Number Check8linearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
- {
- cmsInt32Number n2, i, j;
- cmsUInt8Number Inw[cmsMAXCHANNELS], Outw[cmsMAXCHANNELS];
- n2=0;
- for (j=0; j < 0xFF; j++) {
- memset(Inw, j, sizeof(Inw));
- cmsDoTransform(ContextID, xform, Inw, Outw, 1);
- for (i=0; i < nChan; i++) {
- cmsInt32Number dif = abs(Outw[i] - j);
- if (dif > n2) n2 = dif;
- }
- }
- // We allow 2 contone of difference on 8 bits
- if (n2 > 2) {
- Fail("Differences too big (%x)", n2);
- return 0;
- }
- return 1;
- }
- static
- cmsInt32Number Compare8bitXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
- {
- cmsInt32Number n2, i, j;
- cmsUInt8Number Inw[cmsMAXCHANNELS], Outw1[cmsMAXCHANNELS], Outw2[cmsMAXCHANNELS];;
- n2=0;
- for (j=0; j < 0xFF; j++) {
- memset(Inw, j, sizeof(Inw));
- cmsDoTransform(ContextID, xform1, Inw, Outw1, 1);
- cmsDoTransform(ContextID, xform2, Inw, Outw2, 1);
- for (i=0; i < nChan; i++) {
- cmsInt32Number dif = abs(Outw2[i] - Outw1[i]);
- if (dif > n2) n2 = dif;
- }
- }
- // We allow 2 contone of difference on 8 bits
- if (n2 > 2) {
- Fail("Differences too big (%x)", n2);
- return 0;
- }
- return 1;
- }
- // Check a linear xform
- static
- cmsInt32Number Check16linearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
- {
- cmsInt32Number n2, i, j;
- cmsUInt16Number Inw[cmsMAXCHANNELS], Outw[cmsMAXCHANNELS];
- n2=0;
- for (j=0; j < 0xFFFF; j++) {
- for (i=0; i < nChan; i++) Inw[i] = (cmsUInt16Number) j;
- cmsDoTransform(ContextID, xform, Inw, Outw, 1);
- for (i=0; i < nChan; i++) {
- cmsInt32Number dif = abs(Outw[i] - j);
- if (dif > n2) n2 = dif;
- }
- // We allow 2 contone of difference on 16 bits
- if (n2 > 0x200) {
- Fail("Differences too big (%x)", n2);
- return 0;
- }
- }
- return 1;
- }
- static
- cmsInt32Number Compare16bitXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
- {
- cmsInt32Number n2, i, j;
- cmsUInt16Number Inw[cmsMAXCHANNELS], Outw1[cmsMAXCHANNELS], Outw2[cmsMAXCHANNELS];;
- n2=0;
- for (j=0; j < 0xFFFF; j++) {
- for (i=0; i < nChan; i++) Inw[i] = (cmsUInt16Number) j;
- cmsDoTransform(ContextID, xform1, Inw, Outw1, 1);
- cmsDoTransform(ContextID, xform2, Inw, Outw2, 1);
- for (i=0; i < nChan; i++) {
- cmsInt32Number dif = abs(Outw2[i] - Outw1[i]);
- if (dif > n2) n2 = dif;
- }
- }
- // We allow 2 contone of difference on 16 bits
- if (n2 > 0x200) {
- Fail("Differences too big (%x)", n2);
- return 0;
- }
- return 1;
- }
- // Check a linear xform
- static
- cmsInt32Number CheckFloatlinearXFORM(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number nChan)
- {
- cmsInt32Number i, j;
- cmsFloat32Number In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS];
- for (j=0; j < 0xFFFF; j++) {
- for (i=0; i < nChan; i++) In[i] = (cmsFloat32Number) (j / 65535.0);;
- cmsDoTransform(ContextID, xform, In, Out, 1);
- for (i=0; i < nChan; i++) {
- // We allow no difference in floating point
- if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out[i], (cmsFloat32Number) (j / 65535.0)))
- return 0;
- }
- }
- return 1;
- }
- // Check a linear xform
- static
- cmsInt32Number CompareFloatXFORM(cmsContext ContextID, cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, cmsInt32Number nChan)
- {
- cmsInt32Number i, j;
- cmsFloat32Number In[cmsMAXCHANNELS], Out1[cmsMAXCHANNELS], Out2[cmsMAXCHANNELS];
- for (j=0; j < 0xFFFF; j++) {
- for (i=0; i < nChan; i++) In[i] = (cmsFloat32Number) (j / 65535.0);;
- cmsDoTransform(ContextID, xform1, In, Out1, 1);
- cmsDoTransform(ContextID, xform2, In, Out2, 1);
- for (i=0; i < nChan; i++) {
- // We allow no difference in floating point
- if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out1[i], Out2[i]))
- return 0;
- }
- }
- return 1;
- }
- // Curves only transforms ----------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckCurvesOnlyTransforms(cmsContext ContextID)
- {
- cmsHTRANSFORM xform1, xform2;
- cmsHPROFILE h1, h2, h3;
- cmsToneCurve* c1, *c2, *c3;
- cmsInt32Number rc = 1;
- c1 = cmsBuildGamma(ContextID, 2.2);
- c2 = cmsBuildGamma(ContextID, 1/2.2);
- c3 = cmsBuildGamma(ContextID, 4.84);
- h1 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c1);
- h2 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c2);
- h3 = cmsCreateLinearizationDeviceLink(ContextID, cmsSigGrayData, &c3);
- SubTest("Gray float optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_FLT, h2, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
- rc &= CheckFloatlinearXFORM(ContextID, xform1, 1);
- cmsDeleteTransform(ContextID, xform1);
- if (rc == 0) goto Error;
- SubTest("Gray 8 optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_8, h2, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
- rc &= Check8linearXFORM(ContextID, xform1, 1);
- cmsDeleteTransform(ContextID, xform1);
- if (rc == 0) goto Error;
- SubTest("Gray 16 optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_16, h2, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
- rc &= Check16linearXFORM(ContextID, xform1, 1);
- cmsDeleteTransform(ContextID, xform1);
- if (rc == 0) goto Error;
- SubTest("Gray float non-optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_FLT, h1, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
- xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_FLT, NULL, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0);
- rc &= CompareFloatXFORM(ContextID, xform1, xform2, 1);
- cmsDeleteTransform(ContextID, xform1);
- cmsDeleteTransform(ContextID, xform2);
- if (rc == 0) goto Error;
- SubTest("Gray 8 non-optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_8, h1, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
- xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_8, NULL, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0);
- rc &= Compare8bitXFORM(ContextID, xform1, xform2, 1);
- cmsDeleteTransform(ContextID, xform1);
- cmsDeleteTransform(ContextID, xform2);
- if (rc == 0) goto Error;
- SubTest("Gray 16 non-optimizeable transform");
- xform1 = cmsCreateTransform(ContextID, h1, TYPE_GRAY_16, h1, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
- xform2 = cmsCreateTransform(ContextID, h3, TYPE_GRAY_16, NULL, TYPE_GRAY_16, INTENT_PERCEPTUAL, 0);
- rc &= Compare16bitXFORM(ContextID, xform1, xform2, 1);
- cmsDeleteTransform(ContextID, xform1);
- cmsDeleteTransform(ContextID, xform2);
- if (rc == 0) goto Error;
- Error:
- cmsCloseProfile(ContextID, h1); cmsCloseProfile(ContextID, h2); cmsCloseProfile(ContextID, h3);
- cmsFreeToneCurve(ContextID, c1); cmsFreeToneCurve(ContextID, c2); cmsFreeToneCurve(ContextID, c3);
- return rc;
- }
- // Lab to Lab trivial transforms ----------------------------------------------------------------------------------------
- static cmsFloat64Number MaxDE;
- static
- cmsInt32Number CheckOneLab(cmsContext ContextID, cmsHTRANSFORM xform, cmsFloat64Number L, cmsFloat64Number a, cmsFloat64Number b)
- {
- cmsCIELab In, Out;
- cmsFloat64Number dE;
- In.L = L; In.a = a; In.b = b;
- cmsDoTransform(ContextID, xform, &In, &Out, 1);
- dE = cmsDeltaE(ContextID, &In, &Out);
- if (dE > MaxDE) MaxDE = dE;
- if (MaxDE > 0.003) {
- 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);
- cmsDoTransform(ContextID, xform, &In, &Out, 1);
- return 0;
- }
- return 1;
- }
- // Check several Lab, slicing at non-exact values. Precision should be 16 bits. 50x50x50 checks aprox.
- static
- cmsInt32Number CheckSeveralLab(cmsContext ContextID, cmsHTRANSFORM xform)
- {
- cmsInt32Number L, a, b;
- MaxDE = 0;
- for (L=0; L < 65536; L += 1311) {
- for (a = 0; a < 65536; a += 1232) {
- for (b = 0; b < 65536; b += 1111) {
- if (!CheckOneLab(ContextID, xform, (L * 100.0) / 65535.0,
- (a / 257.0) - 128, (b / 257.0) - 128))
- return 0;
- }
- }
- }
- return 1;
- }
- static
- cmsInt32Number OneTrivialLab(cmsContext ContextID, cmsHPROFILE hLab1, cmsHPROFILE hLab2, const char* txt)
- {
- cmsHTRANSFORM xform;
- cmsInt32Number rc;
- SubTest(txt);
- xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
- rc = CheckSeveralLab(ContextID, xform);
- cmsDeleteTransform(ContextID, xform);
- return rc;
- }
- static
- cmsInt32Number CheckFloatLabTransforms(cmsContext ContextID)
- {
- return OneTrivialLab(ContextID, cmsCreateLab4Profile(ContextID, NULL), cmsCreateLab4Profile(ContextID, NULL), "Lab4/Lab4") &&
- OneTrivialLab(ContextID, cmsCreateLab2Profile(ContextID, NULL), cmsCreateLab2Profile(ContextID, NULL), "Lab2/Lab2") &&
- OneTrivialLab(ContextID, cmsCreateLab4Profile(ContextID, NULL), cmsCreateLab2Profile(ContextID, NULL), "Lab4/Lab2") &&
- OneTrivialLab(ContextID, cmsCreateLab2Profile(ContextID, NULL), cmsCreateLab4Profile(ContextID, NULL), "Lab2/Lab4");
- }
- static
- cmsInt32Number CheckEncodedLabTransforms(cmsContext ContextID)
- {
- cmsHTRANSFORM xform;
- cmsUInt16Number In[3];
- cmsUInt16Number wLab[3];
- cmsCIELab Lab;
- cmsCIELab White = { 100, 0, 0 };
- cmsCIELab Color = { 7.11070, -76, 26 };
- cmsHPROFILE hLab1 = cmsCreateLab4Profile(ContextID, NULL);
- cmsHPROFILE hLab2 = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_16, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
- In[0] = 0xFFFF;
- In[1] = 0x8080;
- In[2] = 0x8080;
- cmsDoTransform(ContextID, xform, In, &Lab, 1);
- if (cmsDeltaE(ContextID, &Lab, &White) > 0.0001) return 0;
- In[0] = 0x1234;
- In[1] = 0x3434;
- In[2] = 0x9A9A;
- cmsDoTransform(xform, In, &Lab, 1);
- cmsFloat2LabEncoded(wLab, &Lab);
- if (memcmp(In, wLab, sizeof(wLab)) != 0) return 0;
- if (cmsDeltaE(&Lab, &Color) > 0.0001) return 0;
- cmsDeleteTransform(ContextID, xform);
- hLab1 = cmsCreateLab2Profile(ContextID, NULL);
- hLab2 = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hLab1, TYPE_LabV2_16, hLab2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
- In[0] = 0xFF00;
- In[1] = 0x8000;
- In[2] = 0x8000;
- cmsDoTransform(ContextID, xform, In, &Lab, 1);
- if (cmsDeltaE(ContextID, &Lab, &White) > 0.0001) return 0;
- cmsDeleteTransform(ContextID, xform);
- hLab2 = cmsCreateLab2Profile(ContextID, NULL);
- hLab1 = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_LabV2_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
- Lab.L = 100;
- Lab.a = 0;
- Lab.b = 0;
- cmsDoTransform(ContextID, xform, &Lab, In, 1);
- if (In[0] != 0xFF00 ||
- In[1] != 0x8000 ||
- In[2] != 0x8000) return 0;
- cmsDeleteTransform(ContextID, xform);
- hLab1 = cmsCreateLab4Profile(ContextID, NULL);
- hLab2 = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hLab1, TYPE_Lab_DBL, hLab2, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hLab1); cmsCloseProfile(ContextID, hLab2);
- Lab.L = 100;
- Lab.a = 0;
- Lab.b = 0;
- cmsDoTransform(ContextID, xform, &Lab, In, 1);
- if (In[0] != 0xFFFF ||
- In[1] != 0x8080 ||
- In[2] != 0x8080) return 0;
- cmsDeleteTransform(ContextID, xform);
- return 1;
- }
- static
- cmsInt32Number CheckStoredIdentities(cmsContext ContextID)
- {
- cmsHPROFILE hLab, hLink, h4, h2;
- cmsHTRANSFORM xform;
- cmsInt32Number rc = 1;
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_8, hLab, TYPE_Lab_8, 0, 0);
- hLink = cmsTransform2DeviceLink(ContextID, xform, 3.4, 0);
- cmsSaveProfileToFile(ContextID, hLink, "abstractv2.icc");
- cmsCloseProfile(ContextID, hLink);
- hLink = cmsTransform2DeviceLink(ContextID, xform, 4.3, 0);
- cmsSaveProfileToFile(ContextID, hLink, "abstractv4.icc");
- cmsCloseProfile(ContextID, hLink);
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, hLab);
- h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
- xform = cmsCreateTransform(ContextID, h4, TYPE_Lab_DBL, h4, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- SubTest("V4");
- rc &= CheckSeveralLab(ContextID, xform);
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, h4);
- if (!rc) goto Error;
- SubTest("V2");
- h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
- xform = cmsCreateTransform(ContextID, h2, TYPE_Lab_DBL, h2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- rc &= CheckSeveralLab(ContextID, xform);
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, h2);
- if (!rc) goto Error;
- SubTest("V2 -> V4");
- h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
- h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
- xform = cmsCreateTransform(ContextID, h4, TYPE_Lab_DBL, h2, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- rc &= CheckSeveralLab(ContextID, xform);
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, h2);
- cmsCloseProfile(ContextID, h4);
- SubTest("V4 -> V2");
- h2 = cmsOpenProfileFromFile(ContextID, "abstractv2.icc", "r");
- h4 = cmsOpenProfileFromFile(ContextID, "abstractv4.icc", "r");
- xform = cmsCreateTransform(ContextID, h2, TYPE_Lab_DBL, h4, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- rc &= CheckSeveralLab(ContextID, xform);
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, h2);
- cmsCloseProfile(ContextID, h4);
- Error:
- remove("abstractv2.icc");
- remove("abstractv4.icc");
- return rc;
- }
- // Check a simple xform from a matrix profile to itself. Test floating point accuracy.
- static
- cmsInt32Number CheckMatrixShaperXFORMFloat(cmsContext ContextID)
- {
- cmsHPROFILE hAbove, hSRGB;
- cmsHTRANSFORM xform;
- cmsInt32Number rc1, rc2;
- hAbove = Create_AboveRGB(ContextID);
- xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hAbove);
- rc1 = CheckFloatlinearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- hSRGB = cmsCreate_sRGBProfile(ContextID);
- xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_FLT, hSRGB, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hSRGB);
- rc2 = CheckFloatlinearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc1 && rc2;
- }
- // Check a simple xform from a matrix profile to itself. Test 16 bits accuracy.
- static
- cmsInt32Number CheckMatrixShaperXFORM16(cmsContext ContextID)
- {
- cmsHPROFILE hAbove, hSRGB;
- cmsHTRANSFORM xform;
- cmsInt32Number rc1, rc2;
- hAbove = Create_AboveRGB(ContextID);
- xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hAbove);
- rc1 = Check16linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- hSRGB = cmsCreate_sRGBProfile(ContextID);
- xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_16, hSRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hSRGB);
- rc2 = Check16linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc1 && rc2;
- }
- // Check a simple xform from a matrix profile to itself. Test 8 bits accuracy.
- static
- cmsInt32Number CheckMatrixShaperXFORM8(cmsContext ContextID)
- {
- cmsHPROFILE hAbove, hSRGB;
- cmsHTRANSFORM xform;
- cmsInt32Number rc1, rc2;
- hAbove = Create_AboveRGB(ContextID);
- xform = cmsCreateTransform(ContextID, hAbove, TYPE_RGB_8, hAbove, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hAbove);
- rc1 = Check8linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- hSRGB = cmsCreate_sRGBProfile(ContextID);
- xform = cmsCreateTransform(ContextID, hSRGB, TYPE_RGB_8, hSRGB, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hSRGB);
- rc2 = Check8linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc1 && rc2;
- }
- // TODO: Check LUT based to LUT based transforms for CMYK
- // -----------------------------------------------------------------------------------------------------------------
- // Check known values going from sRGB to XYZ
- static
- cmsInt32Number CheckOneRGB_f(cmsContext ContextID, cmsHTRANSFORM xform, cmsInt32Number R, cmsInt32Number G, cmsInt32Number B, cmsFloat64Number X, cmsFloat64Number Y, cmsFloat64Number Z, cmsFloat64Number err)
- {
- cmsFloat32Number RGB[3];
- cmsFloat64Number Out[3];
- RGB[0] = (cmsFloat32Number) (R / 255.0);
- RGB[1] = (cmsFloat32Number) (G / 255.0);
- RGB[2] = (cmsFloat32Number) (B / 255.0);
- cmsDoTransform(ContextID, xform, RGB, Out, 1);
- return IsGoodVal("X", X , Out[0], err) &&
- IsGoodVal("Y", Y , Out[1], err) &&
- IsGoodVal("Z", Z , Out[2], err);
- }
- static
- cmsInt32Number Chack_sRGB_Float(cmsContext ContextID)
- {
- cmsHPROFILE hsRGB, hXYZ, hLab;
- cmsHTRANSFORM xform1, xform2;
- cmsInt32Number rc;
- hsRGB = cmsCreate_sRGBProfile(ContextID);
- hXYZ = cmsCreateXYZProfile(ContextID);
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform1 = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_FLT, hXYZ, TYPE_XYZ_DBL,
- INTENT_RELATIVE_COLORIMETRIC, 0);
- xform2 = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_FLT, hLab, TYPE_Lab_DBL,
- INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hsRGB);
- cmsCloseProfile(ContextID, hXYZ);
- cmsCloseProfile(ContextID, hLab);
- MaxErr = 0;
- // Xform 1 goes from 8 bits to XYZ,
- rc = CheckOneRGB_f(ContextID, xform1, 1, 1, 1, 0.0002927, 0.0003035, 0.000250, 0.0001);
- rc &= CheckOneRGB_f(ContextID, xform1, 127, 127, 127, 0.2046329, 0.212230, 0.175069, 0.0001);
- rc &= CheckOneRGB_f(ContextID, xform1, 12, 13, 15, 0.0038364, 0.0039928, 0.003853, 0.0001);
- rc &= CheckOneRGB_f(ContextID, xform1, 128, 0, 0, 0.0941240, 0.0480256, 0.003005, 0.0001);
- rc &= CheckOneRGB_f(ContextID, xform1, 190, 25, 210, 0.3204592, 0.1605926, 0.468213, 0.0001);
- // Xform 2 goes from 8 bits to Lab, we allow 0.01 error max
- rc &= CheckOneRGB_f(ContextID, xform2, 1, 1, 1, 0.2741748, 0, 0, 0.01);
- rc &= CheckOneRGB_f(ContextID, xform2, 127, 127, 127, 53.192776, 0, 0, 0.01);
- rc &= CheckOneRGB_f(ContextID, xform2, 190, 25, 210, 47.052136, 74.565610, -56.883274, 0.01);
- rc &= CheckOneRGB_f(ContextID, xform2, 128, 0, 0, 26.164701, 48.478171, 39.4384713, 0.01);
- cmsDeleteTransform(ContextID, xform1);
- cmsDeleteTransform(ContextID, xform2);
- return rc;
- }
- // ---------------------------------------------------
- static
- cmsBool GetProfileRGBPrimaries(cmsContext ContextID,
- cmsHPROFILE hProfile,
- cmsCIEXYZTRIPLE *result,
- cmsUInt32Number intent)
- {
- cmsHPROFILE hXYZ;
- cmsHTRANSFORM hTransform;
- cmsFloat64Number rgb[3][3] = {{1., 0., 0.},
- {0., 1., 0.},
- {0., 0., 1.}};
- hXYZ = cmsCreateXYZProfile(ContextID);
- if (hXYZ == NULL) return FALSE;
- hTransform = cmsCreateTransform(ContextID, hProfile, TYPE_RGB_DBL, hXYZ, TYPE_XYZ_DBL,
- intent, cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
- cmsCloseProfile(ContextID, hXYZ);
- if (hTransform == NULL) return FALSE;
- cmsDoTransform(ContextID, hTransform, rgb, result, 3);
- cmsDeleteTransform(ContextID, hTransform);
- return TRUE;
- }
- static
- int CheckRGBPrimaries(cmsContext ContextID)
- {
- cmsHPROFILE hsRGB;
- cmsCIEXYZTRIPLE tripXYZ;
- cmsCIExyYTRIPLE tripxyY;
- cmsBool result;
- cmsSetAdaptationState(ContextID, 0);
- hsRGB = cmsCreate_sRGBProfile(ContextID);
- if (!hsRGB) return 0;
- result = GetProfileRGBPrimaries(ContextID, hsRGB, &tripXYZ,
- INTENT_ABSOLUTE_COLORIMETRIC);
- cmsCloseProfile(ContextID, hsRGB);
- if (!result) return 0;
- cmsXYZ2xyY(ContextID, &tripxyY.Red, &tripXYZ.Red);
- cmsXYZ2xyY(ContextID, &tripxyY.Green, &tripXYZ.Green);
- cmsXYZ2xyY(ContextID, &tripxyY.Blue, &tripXYZ.Blue);
- /* valus were taken from
- http://en.wikipedia.org/wiki/RGB_color_spaces#Specifications */
- if (!IsGoodFixed15_16("xRed", tripxyY.Red.x, 0.64) ||
- !IsGoodFixed15_16("yRed", tripxyY.Red.y, 0.33) ||
- !IsGoodFixed15_16("xGreen", tripxyY.Green.x, 0.30) ||
- !IsGoodFixed15_16("yGreen", tripxyY.Green.y, 0.60) ||
- !IsGoodFixed15_16("xBlue", tripxyY.Blue.x, 0.15) ||
- !IsGoodFixed15_16("yBlue", tripxyY.Blue.y, 0.06)) {
- Fail("One or more primaries are wrong.");
- return FALSE;
- }
- return TRUE;
- }
- // -----------------------------------------------------------------------------------------------------------------
- // This function will check CMYK -> CMYK transforms. It uses FOGRA29 and SWOP ICC profiles
- static
- cmsInt32Number CheckCMYK(cmsContext ContextID, cmsInt32Number Intent, const char *Profile1, const char* Profile2)
- {
- cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, Profile1, "r");
- cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, Profile2, "r");
- cmsHTRANSFORM xform, swop_lab, fogra_lab;
- cmsFloat32Number CMYK1[4], CMYK2[4];
- cmsCIELab Lab1, Lab2;
- cmsHPROFILE hLab;
- cmsFloat64Number DeltaL, Max;
- cmsInt32Number i;
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, Intent, 0);
- swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, Intent, 0);
- fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, Intent, 0);
- Max = 0;
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 10;
- CMYK1[1] = 20;
- CMYK1[2] = 30;
- CMYK1[3] = (cmsFloat32Number) i;
- cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
- DeltaL = fabs(Lab1.L - Lab2.L);
- if (DeltaL > Max) Max = DeltaL;
- }
- cmsDeleteTransform(ContextID, xform);
- xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, Intent, 0);
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 10;
- CMYK1[1] = 20;
- CMYK1[2] = 30;
- CMYK1[3] = (cmsFloat32Number) i;
- cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
- DeltaL = fabs(Lab1.L - Lab2.L);
- if (DeltaL > Max) Max = DeltaL;
- }
- cmsCloseProfile(ContextID, hSWOP);
- cmsCloseProfile(ContextID, hFOGRA);
- cmsCloseProfile(ContextID, hLab);
- cmsDeleteTransform(ContextID, xform);
- cmsDeleteTransform(ContextID, swop_lab);
- cmsDeleteTransform(ContextID, fogra_lab);
- return Max < 3.0;
- }
- static
- cmsInt32Number CheckCMYKRoundtrip(cmsContext ContextID)
- {
- return CheckCMYK(ContextID, INTENT_RELATIVE_COLORIMETRIC, "test1.icc", "test1.icc");
- }
- static
- cmsInt32Number CheckCMYKPerceptual(cmsContext ContextID)
- {
- return CheckCMYK(ContextID, INTENT_PERCEPTUAL, "test1.icc", "test2.icc");
- }
- #if 0
- static
- cmsInt32Number CheckCMYKRelCol(cmsContext ContextID)
- {
- return CheckCMYK(ContextID, INTENT_RELATIVE_COLORIMETRIC, "test1.icc", "test2.icc");
- }
- #endif
- static
- cmsInt32Number CheckKOnlyBlackPreserving(cmsContext ContextID)
- {
- cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
- cmsHTRANSFORM xform, swop_lab, fogra_lab;
- cmsFloat32Number CMYK1[4], CMYK2[4];
- cmsCIELab Lab1, Lab2;
- cmsHPROFILE hLab;
- cmsFloat64Number DeltaL, Max;
- cmsInt32Number i;
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, INTENT_PRESERVE_K_ONLY_PERCEPTUAL, 0);
- swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
- fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
- Max = 0;
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 0;
- CMYK1[1] = 0;
- CMYK1[2] = 0;
- CMYK1[3] = (cmsFloat32Number) i;
- // SWOP CMYK to Lab1
- cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
- // SWOP To FOGRA using black preservation
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- // Obtained FOGRA CMYK to Lab2
- cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
- // We care only on L*
- DeltaL = fabs(Lab1.L - Lab2.L);
- if (DeltaL > Max) Max = DeltaL;
- }
- cmsDeleteTransform(ContextID, xform);
- // dL should be below 3.0
- // Same, but FOGRA to SWOP
- xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, INTENT_PRESERVE_K_ONLY_PERCEPTUAL, 0);
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 0;
- CMYK1[1] = 0;
- CMYK1[2] = 0;
- CMYK1[3] = (cmsFloat32Number) i;
- cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
- DeltaL = fabs(Lab1.L - Lab2.L);
- if (DeltaL > Max) Max = DeltaL;
- }
- cmsCloseProfile(ContextID, hSWOP);
- cmsCloseProfile(ContextID, hFOGRA);
- cmsCloseProfile(ContextID, hLab);
- cmsDeleteTransform(ContextID, xform);
- cmsDeleteTransform(ContextID, swop_lab);
- cmsDeleteTransform(ContextID, fogra_lab);
- return Max < 3.0;
- }
- static
- cmsInt32Number CheckKPlaneBlackPreserving(cmsContext ContextID)
- {
- cmsHPROFILE hSWOP = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- cmsHPROFILE hFOGRA = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
- cmsHTRANSFORM xform, swop_lab, fogra_lab;
- cmsFloat32Number CMYK1[4], CMYK2[4];
- cmsCIELab Lab1, Lab2;
- cmsHPROFILE hLab;
- cmsFloat64Number DeltaE, Max;
- cmsInt32Number i;
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hFOGRA, TYPE_CMYK_FLT, INTENT_PERCEPTUAL, 0);
- swop_lab = cmsCreateTransform(ContextID, hSWOP, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
- fogra_lab = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hLab, TYPE_Lab_DBL, INTENT_PERCEPTUAL, 0);
- Max = 0;
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 0;
- CMYK1[1] = 0;
- CMYK1[2] = 0;
- CMYK1[3] = (cmsFloat32Number) i;
- cmsDoTransform(ContextID, swop_lab, CMYK1, &Lab1, 1);
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- cmsDoTransform(ContextID, fogra_lab, CMYK2, &Lab2, 1);
- DeltaE = cmsDeltaE(ContextID, &Lab1, &Lab2);
- if (DeltaE > Max) Max = DeltaE;
- }
- cmsDeleteTransform(ContextID, xform);
- xform = cmsCreateTransform(ContextID, hFOGRA, TYPE_CMYK_FLT, hSWOP, TYPE_CMYK_FLT, INTENT_PRESERVE_K_PLANE_PERCEPTUAL, 0);
- for (i=0; i <= 100; i++) {
- CMYK1[0] = 30;
- CMYK1[1] = 20;
- CMYK1[2] = 10;
- CMYK1[3] = (cmsFloat32Number) i;
- cmsDoTransform(ContextID, fogra_lab, CMYK1, &Lab1, 1);
- cmsDoTransform(ContextID, xform, CMYK1, CMYK2, 1);
- cmsDoTransform(ContextID, swop_lab, CMYK2, &Lab2, 1);
- DeltaE = cmsDeltaE(ContextID, &Lab1, &Lab2);
- if (DeltaE > Max) Max = DeltaE;
- }
- cmsDeleteTransform(ContextID, xform);
- cmsCloseProfile(ContextID, hSWOP);
- cmsCloseProfile(ContextID, hFOGRA);
- cmsCloseProfile(ContextID, hLab);
- cmsDeleteTransform(ContextID, swop_lab);
- cmsDeleteTransform(ContextID, fogra_lab);
- return Max < 30.0;
- }
- // ------------------------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckProofingXFORMFloat(cmsContext ContextID)
- {
- cmsHPROFILE hAbove;
- cmsHTRANSFORM xform;
- cmsInt32Number rc;
- hAbove = Create_AboveRGB(ContextID);
- xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, hAbove,
- INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_SOFTPROOFING);
- cmsCloseProfile(ContextID, hAbove);
- rc = CheckFloatlinearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc;
- }
- static
- cmsInt32Number CheckProofingXFORM16(cmsContext ContextID)
- {
- cmsHPROFILE hAbove;
- cmsHTRANSFORM xform;
- cmsInt32Number rc;
- hAbove = Create_AboveRGB(ContextID);
- xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hAbove,
- INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_SOFTPROOFING|cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hAbove);
- rc = Check16linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc;
- }
- static
- cmsInt32Number CheckGamutCheck(cmsContext ContextID)
- {
- cmsHPROFILE hSRGB, hAbove;
- cmsHTRANSFORM xform;
- cmsInt32Number rc;
- cmsUInt16Number Alarm[16] = { 0xDEAD, 0xBABE, 0xFACE };
- // Set alarm codes to fancy values so we could check the out of gamut condition
- cmsSetAlarmCodes(ContextID, Alarm);
- // Create the profiles
- hSRGB = cmsCreate_sRGBProfile(ContextID);
- hAbove = Create_AboveRGB(ContextID);
- if (hSRGB == NULL || hAbove == NULL) return 0; // Failed
- SubTest("Gamut check on floating point");
- // Create a gamut checker in the same space. No value should be out of gamut
- xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_FLT, hAbove, TYPE_RGB_FLT, hAbove,
- INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK);
- if (!CheckFloatlinearXFORM(ContextID, xform, 3)) {
- cmsCloseProfile(ContextID, hSRGB);
- cmsCloseProfile(ContextID, hAbove);
- cmsDeleteTransform(ContextID, xform);
- Fail("Gamut check on same profile failed");
- return 0;
- }
- cmsDeleteTransform(ContextID, xform);
- SubTest("Gamut check on 16 bits");
- xform = cmsCreateProofingTransform(ContextID, hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hSRGB,
- INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK);
- cmsCloseProfile(ContextID, hSRGB);
- cmsCloseProfile(ContextID, hAbove);
- rc = Check16linearXFORM(ContextID, xform, 3);
- cmsDeleteTransform(ContextID, xform);
- return rc;
- }
- // -------------------------------------------------------------------------------------------------------------------
- static
- cmsInt32Number CheckBlackPoint(cmsContext ContextID)
- {
- cmsHPROFILE hProfile;
- cmsCIEXYZ Black;
- cmsCIELab Lab;
- hProfile = cmsOpenProfileFromFile(ContextID, "test5.icc", "r");
- cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hProfile);
- hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
- cmsCloseProfile(ContextID, hProfile);
- hProfile = cmsOpenProfileFromFile(ContextID, "lcms2cmyk.icc", "r");
- cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
- cmsCloseProfile(ContextID, hProfile);
- hProfile = cmsOpenProfileFromFile(ContextID, "test2.icc", "r");
- cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
- cmsCloseProfile(ContextID, hProfile);
- hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- cmsDetectDestinationBlackPoint(ContextID, &Black, hProfile, INTENT_PERCEPTUAL, 0);
- cmsXYZ2Lab(ContextID, NULL, &Lab, &Black);
- cmsCloseProfile(ContextID, hProfile);
- return 1;
- }
- static
- cmsInt32Number CheckOneTAC(cmsContext ContextID, cmsFloat64Number InkLimit)
- {
- cmsHPROFILE h;
- cmsFloat64Number d;
- h =CreateFakeCMYK(ContextID, InkLimit, TRUE);
- cmsSaveProfileToFile(ContextID, h, "lcmstac.icc");
- cmsCloseProfile(ContextID, h);
- h = cmsOpenProfileFromFile(ContextID, "lcmstac.icc", "r");
- d = cmsDetectTAC(ContextID, h);
- cmsCloseProfile(ContextID, h);
- remove("lcmstac.icc");
- if (fabs(d - InkLimit) > 5) return 0;
- return 1;
- }
- static
- cmsInt32Number CheckTAC(cmsContext ContextID)
- {
- if (!CheckOneTAC(ContextID, 180)) return 0;
- if (!CheckOneTAC(ContextID, 220)) return 0;
- if (!CheckOneTAC(ContextID, 286)) return 0;
- if (!CheckOneTAC(ContextID, 310)) return 0;
- if (!CheckOneTAC(ContextID, 330)) return 0;
- return 1;
- }
- // -------------------------------------------------------------------------------------------------------
- #define NPOINTS_IT8 10 // (17*17*17*17)
- static
- cmsInt32Number CheckCGATS(cmsContext ContextID)
- {
- cmsHANDLE it8;
- cmsInt32Number i;
- SubTest("IT8 creation");
- it8 = cmsIT8Alloc(ContextID);
- if (it8 == NULL) return 0;
- cmsIT8SetSheetType(ContextID, it8, "LCMS/TESTING");
- cmsIT8SetPropertyStr(ContextID, it8, "ORIGINATOR", "1 2 3 4");
- cmsIT8SetPropertyUncooked(ContextID, it8, "DESCRIPTOR", "1234");
- cmsIT8SetPropertyStr(ContextID, it8, "MANUFACTURER", "3");
- cmsIT8SetPropertyDbl(ContextID, it8, "CREATED", 4);
- cmsIT8SetPropertyDbl(ContextID, it8, "SERIAL", 5);
- cmsIT8SetPropertyHex(ContextID, it8, "MATERIAL", 0x123);
- cmsIT8SetPropertyDbl(ContextID, it8, "NUMBER_OF_SETS", NPOINTS_IT8);
- cmsIT8SetPropertyDbl(ContextID, it8, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetDataFormat(ContextID, it8, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, it8, 1, "RGB_R");
- cmsIT8SetDataFormat(ContextID, it8, 2, "RGB_G");
- cmsIT8SetDataFormat(ContextID, it8, 3, "RGB_B");
- SubTest("Table creation");
- for (i=0; i < NPOINTS_IT8; i++) {
- char Patch[20];
- sprintf(Patch, "P%d", i);
- cmsIT8SetDataRowCol(ContextID, it8, i, 0, Patch);
- cmsIT8SetDataRowColDbl(ContextID, it8, i, 1, i);
- cmsIT8SetDataRowColDbl(ContextID, it8, i, 2, i);
- cmsIT8SetDataRowColDbl(ContextID, it8, i, 3, i);
- }
- SubTest("Save to file");
- cmsIT8SaveToFile(ContextID, it8, "TEST.IT8");
- cmsIT8Free(ContextID, it8);
- SubTest("Load from file");
- it8 = cmsIT8LoadFromFile(ContextID, "TEST.IT8");
- if (it8 == NULL) return 0;
- SubTest("Save again file");
- cmsIT8SaveToFile(ContextID, it8, "TEST.IT8");
- cmsIT8Free(ContextID, it8);
- SubTest("Load from file (II)");
- it8 = cmsIT8LoadFromFile(ContextID, "TEST.IT8");
- if (it8 == NULL) return 0;
- SubTest("Change prop value");
- if (cmsIT8GetPropertyDbl(ContextID, it8, "DESCRIPTOR") != 1234) {
- return 0;
- }
- cmsIT8SetPropertyDbl(ContextID, it8, "DESCRIPTOR", 5678);
- if (cmsIT8GetPropertyDbl(ContextID, it8, "DESCRIPTOR") != 5678) {
- return 0;
- }
- SubTest("Positive numbers");
- if (cmsIT8GetDataDbl(ContextID, it8, "P3", "RGB_G") != 3) {
- return 0;
- }
- SubTest("Positive exponent numbers");
- cmsIT8SetPropertyDbl(ContextID, it8, "DBL_PROP", 123E+12);
- if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_PROP") - 123E+12) > 1 ) {
- return 0;
- }
- SubTest("Negative exponent numbers");
- cmsIT8SetPropertyDbl(ContextID, it8, "DBL_PROP_NEG", 123E-45);
- if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_PROP_NEG") - 123E-45) > 1E-45 ) {
- return 0;
- }
- SubTest("Negative numbers");
- cmsIT8SetPropertyDbl(ContextID, it8, "DBL_NEG_VAL", -123);
- if ((cmsIT8GetPropertyDbl(ContextID, it8, "DBL_NEG_VAL")) != -123 ) {
- return 0;
- }
- cmsIT8Free(ContextID, it8);
- remove("TEST.IT8");
- return 1;
- }
- static
- cmsInt32Number CheckCGATS2(cmsContext ContextID)
- {
- cmsHANDLE handle;
- const cmsUInt8Number junk[] = { 0x0, 0xd, 0xd, 0xa, 0x20, 0xd, 0x20, 0x20, 0x20, 0x3a, 0x31, 0x3d, 0x3d, 0x3d, 0x3d };
- handle = cmsIT8LoadFromMem(ContextID, (const void*)junk, sizeof(junk));
- if (handle)
- cmsIT8Free(ContextID, handle);
- return 1;
- }
- static
- cmsInt32Number CheckCGATS_Overflow(cmsContext ContextID)
- {
- cmsHANDLE handle;
- const cmsUInt8Number junk[] = { "@\nA 1.e2147483648\n" };
- handle = cmsIT8LoadFromMem(ContextID, (const void*)junk, sizeof(junk));
- if (handle)
- cmsIT8Free(ContextID, handle);
- return 1;
- }
- // Create CSA/CRD
- static
- void GenerateCSA(cmsContext BuffThread, const char* cInProf, const char* FileName)
- {
- cmsHPROFILE hProfile;
- cmsUInt32Number n;
- char* Buffer;
- FILE* o;
- if (cInProf == NULL)
- hProfile = cmsCreateLab4Profile(BuffThread, NULL);
- else
- hProfile = cmsOpenProfileFromFile(BuffThread, cInProf, "r");
- n = cmsGetPostScriptCSA(BuffThread, hProfile, 0, 0, NULL, 0);
- if (n == 0) return;
- Buffer = (char*) _cmsMalloc(BuffThread, n + 1);
- cmsGetPostScriptCSA(BuffThread, hProfile, 0, 0, Buffer, n);
- Buffer[n] = 0;
- if (FileName != NULL) {
- o = fopen(FileName, "wb");
- fwrite(Buffer, n, 1, o);
- fclose(o);
- }
- _cmsFree(BuffThread, Buffer);
- cmsCloseProfile(BuffThread, hProfile);
- if (FileName != NULL)
- remove(FileName);
- }
- static
- void GenerateCRD(cmsContext BuffThread, const char* cOutProf, const char* FileName)
- {
- cmsHPROFILE hProfile;
- cmsUInt32Number n;
- char* Buffer;
- cmsUInt32Number dwFlags = 0;
- if (cOutProf == NULL)
- hProfile = cmsCreateLab4Profile(BuffThread, NULL);
- else
- hProfile = cmsOpenProfileFromFile(BuffThread, cOutProf, "r");
- n = cmsGetPostScriptCRD(BuffThread, hProfile, 0, dwFlags, NULL, 0);
- if (n == 0) return;
- Buffer = (char*) _cmsMalloc(BuffThread, n + 1);
- cmsGetPostScriptCRD(BuffThread, hProfile, 0, dwFlags, Buffer, n);
- Buffer[n] = 0;
- if (FileName != NULL) {
- FILE* o = fopen(FileName, "wb");
- fwrite(Buffer, n, 1, o);
- fclose(o);
- }
- _cmsFree(BuffThread, Buffer);
- cmsCloseProfile(BuffThread, hProfile);
- if (FileName != NULL)
- remove(FileName);
- }
- static
- cmsInt32Number CheckPostScript(cmsContext ContextID)
- {
- GenerateCSA(ContextID, "test5.icc", "sRGB_CSA.ps");
- GenerateCSA(ContextID, "aRGBlcms2.icc", "aRGB_CSA.ps");
- GenerateCSA(ContextID, "test4.icc", "sRGBV4_CSA.ps");
- GenerateCSA(ContextID, "test1.icc", "SWOP_CSA.ps");
- GenerateCSA(ContextID, NULL, "Lab_CSA.ps");
- GenerateCSA(ContextID, "graylcms2.icc", "gray_CSA.ps");
- GenerateCRD(ContextID, "test5.icc", "sRGB_CRD.ps");
- GenerateCRD(ContextID, "aRGBlcms2.icc", "aRGB_CRD.ps");
- GenerateCRD(ContextID, NULL, "Lab_CRD.ps");
- GenerateCRD(ContextID, "test1.icc", "SWOP_CRD.ps");
- GenerateCRD(ContextID, "test4.icc", "sRGBV4_CRD.ps");
- GenerateCRD(ContextID, "graylcms2.icc", "gray_CRD.ps");
- return 1;
- }
- static
- cmsInt32Number CheckGray(cmsContext ContextID, cmsHTRANSFORM xform, cmsUInt8Number g, double L)
- {
- cmsCIELab Lab;
- cmsDoTransform(ContextID, xform, &g, &Lab, 1);
- if (!IsGoodVal("a axis on gray", 0, Lab.a, 0.001)) return 0;
- if (!IsGoodVal("b axis on gray", 0, Lab.b, 0.001)) return 0;
- return IsGoodVal("Gray value", L, Lab.L, 0.01);
- }
- static
- cmsInt32Number CheckInputGray(cmsContext ContextID)
- {
- cmsHPROFILE hGray = Create_Gray22(ContextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
- cmsHTRANSFORM xform;
- if (hGray == NULL || hLab == NULL) return 0;
- xform = cmsCreateTransform(ContextID, hGray, TYPE_GRAY_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
- if (!CheckGray(ContextID, xform, 0, 0)) return 0;
- if (!CheckGray(ContextID, xform, 125, 52.768)) return 0;
- if (!CheckGray(ContextID, xform, 200, 81.069)) return 0;
- if (!CheckGray(ContextID, xform, 255, 100.0)) return 0;
- cmsDeleteTransform(ContextID, xform);
- return 1;
- }
- static
- cmsInt32Number CheckLabInputGray(cmsContext ContextID)
- {
- cmsHPROFILE hGray = Create_GrayLab(ContextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
- cmsHTRANSFORM xform;
- if (hGray == NULL || hLab == NULL) return 0;
- xform = cmsCreateTransform(ContextID, hGray, TYPE_GRAY_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
- if (!CheckGray(ContextID, xform, 0, 0)) return 0;
- if (!CheckGray(ContextID, xform, 125, 49.019)) return 0;
- if (!CheckGray(ContextID, xform, 200, 78.431)) return 0;
- if (!CheckGray(ContextID, xform, 255, 100.0)) return 0;
- cmsDeleteTransform(ContextID, xform);
- return 1;
- }
- static
- cmsInt32Number CheckOutGray(cmsContext ContextID, cmsHTRANSFORM xform, double L, cmsUInt8Number g)
- {
- cmsCIELab Lab;
- cmsUInt8Number g_out;
- Lab.L = L;
- Lab.a = 0;
- Lab.b = 0;
- cmsDoTransform(ContextID, xform, &Lab, &g_out, 1);
- return IsGoodVal("Gray value", g, (double) g_out, 1);
- }
- static
- cmsInt32Number CheckOutputGray(cmsContext ContextID)
- {
- cmsHPROFILE hGray = Create_Gray22(ContextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
- cmsHTRANSFORM xform;
- if (hGray == NULL || hLab == NULL) return 0;
- xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_DBL, hGray, TYPE_GRAY_8, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
- if (!CheckOutGray(ContextID, xform, 0, 0)) return 0;
- if (!CheckOutGray(ContextID, xform, 100, 255)) return 0;
- if (!CheckOutGray(ContextID, xform, 20, 52)) return 0;
- if (!CheckOutGray(ContextID, xform, 50, 118)) return 0;
- cmsDeleteTransform(ContextID, xform);
- return 1;
- }
- static
- cmsInt32Number CheckLabOutputGray(cmsContext ContextID)
- {
- cmsHPROFILE hGray = Create_GrayLab(ContextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
- cmsHTRANSFORM xform;
- cmsInt32Number i;
- if (hGray == NULL || hLab == NULL) return 0;
- xform = cmsCreateTransform(ContextID, hLab, TYPE_Lab_DBL, hGray, TYPE_GRAY_8, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ContextID, hGray); cmsCloseProfile(ContextID, hLab);
- if (!CheckOutGray(ContextID, xform, 0, 0)) return 0;
- if (!CheckOutGray(ContextID, xform, 100, 255)) return 0;
- for (i=0; i < 100; i++) {
- cmsUInt8Number g;
- g = (cmsUInt8Number) floor(i * 255.0 / 100.0 + 0.5);
- if (!CheckOutGray(ContextID, xform, i, g)) return 0;
- }
- cmsDeleteTransform(ContextID, xform);
- return 1;
- }
- static
- cmsInt32Number CheckV4gamma(cmsContext ContextID)
- {
- cmsHPROFILE h;
- cmsUInt16Number Lin[] = {0, 0xffff};
- cmsToneCurve*g = cmsBuildTabulatedToneCurve16(ContextID, 2, Lin);
- h = cmsOpenProfileFromFile(ContextID, "v4gamma.icc", "w");
- if (h == NULL) return 0;
- cmsSetProfileVersion(ContextID, h, 4.3);
- if (!cmsWriteTag(ContextID, h, cmsSigGrayTRCTag, g)) return 0;
- cmsCloseProfile(ContextID, h);
- cmsFreeToneCurve(ContextID, g);
- remove("v4gamma.icc");
- return 1;
- }
- // cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname);
- // Gamut descriptor routines
- static
- cmsInt32Number CheckGBD(cmsContext ContextID)
- {
- cmsCIELab Lab;
- cmsHANDLE h;
- cmsInt32Number L, a, b;
- cmsUInt32Number r1, g1, b1;
- cmsHPROFILE hLab, hsRGB;
- cmsHTRANSFORM xform;
- h = cmsGBDAlloc(ContextID);
- if (h == NULL) return 0;
- // Fill all Lab gamut as valid
- SubTest("Filling RAW gamut");
- for (L=0; L <= 100; L += 10)
- for (a = -128; a <= 128; a += 5)
- for (b = -128; b <= 128; b += 5) {
- Lab.L = L;
- Lab.a = a;
- Lab.b = b;
- if (!cmsGDBAddPoint(ContextID, h, &Lab)) return 0;
- }
- // Complete boundaries
- SubTest("computing Lab gamut");
- if (!cmsGDBCompute(ContextID, h, 0)) return 0;
- // All points should be inside gamut
- SubTest("checking Lab gamut");
- for (L=10; L <= 90; L += 25)
- for (a = -120; a <= 120; a += 25)
- for (b = -120; b <= 120; b += 25) {
- Lab.L = L;
- Lab.a = a;
- Lab.b = b;
- if (!cmsGDBCheckPoint(ContextID, h, &Lab)) {
- return 0;
- }
- }
- cmsGBDFree(ContextID, h);
- // Now for sRGB
- SubTest("checking sRGB gamut");
- h = cmsGBDAlloc(ContextID);
- hsRGB = cmsCreate_sRGBProfile(ContextID);
- hLab = cmsCreateLab4Profile(ContextID, NULL);
- xform = cmsCreateTransform(ContextID, hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hsRGB); cmsCloseProfile(ContextID, hLab);
- for (r1=0; r1 < 256; r1 += 5) {
- for (g1=0; g1 < 256; g1 += 5)
- for (b1=0; b1 < 256; b1 += 5) {
- cmsUInt8Number rgb[3];
- rgb[0] = (cmsUInt8Number) r1;
- rgb[1] = (cmsUInt8Number) g1;
- rgb[2] = (cmsUInt8Number) b1;
- cmsDoTransform(ContextID, xform, rgb, &Lab, 1);
- // if (fabs(Lab.b) < 20 && Lab.a > 0) continue;
- if (!cmsGDBAddPoint(ContextID, h, &Lab)) {
- cmsGBDFree(ContextID, h);
- return 0;
- }
- }
- }
- if (!cmsGDBCompute(ContextID, h, 0)) return 0;
- // cmsGBDdumpVRML(h, "c:\\colormaps\\lab.wrl");
- for (r1=10; r1 < 200; r1 += 10) {
- for (g1=10; g1 < 200; g1 += 10)
- for (b1=10; b1 < 200; b1 += 10) {
- cmsUInt8Number rgb[3];
- rgb[0] = (cmsUInt8Number) r1;
- rgb[1] = (cmsUInt8Number) g1;
- rgb[2] = (cmsUInt8Number) b1;
- cmsDoTransform(ContextID, xform, rgb, &Lab, 1);
- if (!cmsGDBCheckPoint(ContextID, h, &Lab)) {
- cmsDeleteTransform(ContextID, xform);
- cmsGBDFree(ContextID, h);
- return 0;
- }
- }
- }
- cmsDeleteTransform(ContextID, xform);
- cmsGBDFree(ContextID, h);
- SubTest("checking LCh chroma ring");
- h = cmsGBDAlloc(ContextID);
- for (r1=0; r1 < 360; r1++) {
- cmsCIELCh LCh;
- LCh.L = 70;
- LCh.C = 60;
- LCh.h = r1;
- cmsLCh2Lab(ContextID, &Lab, &LCh);
- if (!cmsGDBAddPoint(ContextID, h, &Lab)) {
- cmsGBDFree(ContextID, h);
- return 0;
- }
- }
- if (!cmsGDBCompute(ContextID, h, 0)) return 0;
- cmsGBDFree(ContextID, h);
- return 1;
- }
- static
- int CheckMD5(cmsContext ContextID)
- {
- cmsHPROFILE pProfile = cmsOpenProfileFromFile(ContextID, "sRGBlcms2.icc", "r");
- cmsProfileID ProfileID1, ProfileID2, ProfileID3, ProfileID4;
- if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile, ProfileID1.ID8);
- if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile,ProfileID2.ID8);
- cmsCloseProfile(ContextID, pProfile);
- pProfile = cmsOpenProfileFromFile(ContextID, "sRGBlcms2.icc", "r");
- h =(_cmsICCPROFILE*) pProfile;
- if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile, ProfileID3.ID8);
- if (cmsMD5computeID(ContextID, pProfile)) cmsGetHeaderProfileID(ContextID, pProfile,ProfileID4.ID8);
- cmsCloseProfile(ContextID, pProfile);
- return ((memcmp(ProfileID1.ID8, ProfileID3.ID8, sizeof(ProfileID1)) == 0) &&
- (memcmp(ProfileID2.ID8, ProfileID4.ID8, sizeof(ProfileID2)) == 0));
- }
- static
- int CheckLinking(cmsContext ContextID)
- {
- cmsHPROFILE h;
- cmsPipeline * pipeline;
- cmsStage *stageBegin, *stageEnd;
- // Create a CLUT based profile
- h = cmsCreateInkLimitingDeviceLink(ContextID, cmsSigCmykData, 150);
- // link a second tag
- cmsLinkTag(ContextID, h, cmsSigAToB1Tag, cmsSigAToB0Tag);
- // Save the linked devicelink
- if (!cmsSaveProfileToFile(ContextID, h, "lcms2link.icc")) return 0;
- cmsCloseProfile(ContextID, h);
- // Now open the profile and read the pipeline
- h = cmsOpenProfileFromFile(ContextID, "lcms2link.icc", "r");
- if (h == NULL) return 0;
- pipeline = (cmsPipeline*) cmsReadTag(ContextID, h, cmsSigAToB1Tag);
- if (pipeline == NULL)
- {
- return 0;
- }
- pipeline = cmsPipelineDup(ContextID, pipeline);
- // extract stage from pipe line
- cmsPipelineUnlinkStage(ContextID, pipeline, cmsAT_BEGIN, &stageBegin);
- cmsPipelineUnlinkStage(ContextID, pipeline, cmsAT_END, &stageEnd);
- cmsPipelineInsertStage(ContextID, pipeline, cmsAT_END, stageEnd);
- cmsPipelineInsertStage(ContextID, pipeline, cmsAT_BEGIN, stageBegin);
- if (cmsTagLinkedTo(ContextID, h, cmsSigAToB1Tag) != cmsSigAToB0Tag) return 0;
- cmsWriteTag(ContextID, h, cmsSigAToB0Tag, pipeline);
- cmsPipelineFree(ContextID, pipeline);
- if (!cmsSaveProfileToFile(ContextID, h, "lcms2link2.icc")) return 0;
- cmsCloseProfile(ContextID, h);
- return 1;
- }
- // TestMPE
- //
- // Created by Paul Miller on 30/08/2016.
- //
- static
- cmsHPROFILE IdentityMatrixProfile(cmsContext ctx, cmsColorSpaceSignature dataSpace)
- {
- cmsVEC3 zero = {{0,0,0}};
- cmsMAT3 identity;
- cmsPipeline* forward;
- cmsPipeline* reverse;
- cmsHPROFILE identityProfile = cmsCreateProfilePlaceholder(ctx);
- cmsSetProfileVersion(ctx, identityProfile, 4.3);
- cmsSetDeviceClass(ctx, identityProfile, cmsSigColorSpaceClass);
- cmsSetColorSpace(ctx, identityProfile, dataSpace);
- cmsSetPCS(ctx, identityProfile, cmsSigXYZData);
- cmsSetHeaderRenderingIntent(ctx, identityProfile, INTENT_RELATIVE_COLORIMETRIC);
- cmsWriteTag(ctx, identityProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ(ctx));
- _cmsMAT3identity(ctx, &identity);
- // build forward transform.... (RGB to PCS)
- forward = cmsPipelineAlloc(ctx, 3, 3);
- cmsPipelineInsertStage(ctx, forward, cmsAT_END, cmsStageAllocMatrix( ctx, 3, 3, (cmsFloat64Number*)&identity, (cmsFloat64Number*)&zero));
- cmsWriteTag(ctx, identityProfile, cmsSigDToB1Tag, forward);
- cmsPipelineFree(ctx, forward);
- reverse = cmsPipelineAlloc(ctx, 3, 3);
- cmsPipelineInsertStage(ctx, reverse, cmsAT_END, cmsStageAllocMatrix( ctx, 3, 3, (cmsFloat64Number*)&identity, (cmsFloat64Number*)&zero));
- cmsWriteTag(ctx, identityProfile, cmsSigBToD1Tag, reverse);
- cmsPipelineFree(ctx, reverse);
- return identityProfile;
- }
- static
- cmsInt32Number CheckFloatXYZ(cmsContext ctx)
- {
- cmsHPROFILE input;
- cmsHPROFILE xyzProfile = cmsCreateXYZProfile(ctx);
- cmsHTRANSFORM xform;
- cmsFloat32Number in[4];
- cmsFloat32Number out[4];
- in[0] = 1.0;
- in[1] = 1.0;
- in[2] = 1.0;
- in[3] = 0.5;
- // RGB to XYZ
- input = IdentityMatrixProfile(ctx, cmsSigRgbData);
- xform = cmsCreateTransform(ctx, input, TYPE_RGB_FLT, xyzProfile, TYPE_XYZ_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ctx, input);
- cmsDoTransform(ctx, xform, in, out, 1);
- cmsDeleteTransform(ctx, xform);
- if (!IsGoodVal("Float RGB->XYZ", in[0], out[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->XYZ", in[1], out[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->XYZ", in[2], out[2], FLOAT_PRECISSION))
- return 0;
- // XYZ to XYZ
- input = IdentityMatrixProfile(ctx, cmsSigXYZData);
- xform = cmsCreateTransform(ctx, input, TYPE_XYZ_FLT, xyzProfile, TYPE_XYZ_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ctx, input);
- cmsDoTransform(ctx, xform, in, out, 1);
- cmsDeleteTransform(ctx, xform);
- if (!IsGoodVal("Float XYZ->XYZ", in[0], out[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZ->XYZ", in[1], out[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZ->XYZ", in[2], out[2], FLOAT_PRECISSION))
- return 0;
- input = IdentityMatrixProfile(ctx, cmsSigXYZData);
- # define TYPE_XYZA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
- xform = cmsCreateTransform(ctx, input, TYPE_XYZA_FLT, xyzProfile, TYPE_XYZA_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_COPY_ALPHA);
- cmsCloseProfile(ctx, input);
- cmsDoTransform(ctx, xform, in, out, 1);
- cmsDeleteTransform(ctx, xform);
- if (!IsGoodVal("Float XYZA->XYZA", in[0], out[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZA->XYZA", in[1], out[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZA->XYZA", in[2], out[2], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZA->XYZA", in[3], out[3], FLOAT_PRECISSION))
- return 0;
- // XYZ to RGB
- input = IdentityMatrixProfile(ctx, cmsSigRgbData);
- xform = cmsCreateTransform(ctx, xyzProfile, TYPE_XYZ_FLT, input, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ctx, input);
- cmsDoTransform(ctx, xform, in, out, 1);
- cmsDeleteTransform(ctx, xform);
- if (!IsGoodVal("Float XYZ->RGB", in[0], out[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZ->RGB", in[1], out[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float XYZ->RGB", in[2], out[2], FLOAT_PRECISSION))
- return 0;
- // Now the optimizer should remove a stage
- // XYZ to RGB
- input = IdentityMatrixProfile(ctx, cmsSigRgbData);
- xform = cmsCreateTransform(ctx, input, TYPE_RGB_FLT, input, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(ctx, input);
- cmsDoTransform(ctx, xform, in, out, 1);
- cmsDeleteTransform(ctx, xform);
- if (!IsGoodVal("Float RGB->RGB", in[0], out[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->RGB", in[1], out[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->RGB", in[2], out[2], FLOAT_PRECISSION))
- return 0;
- cmsCloseProfile(ctx, xyzProfile);
- return 1;
- }
- /*
- Bug reported
- 1)
- sRGB built-in V4.3 -> Lab identity built-in V4.3
- Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
- Input format: TYPE_RGBA_FLT
- Output format: TYPE_LabA_FLT
- 2) and back
- Lab identity built-in V4.3 -> sRGB built-in V4.3
- Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
- Input format: TYPE_LabA_FLT
- Output format: TYPE_RGBA_FLT
- */
- static
- cmsInt32Number ChecksRGB2LabFLT(cmsContext ctx)
- {
- cmsHPROFILE hSRGB = cmsCreate_sRGBProfile(ctx);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ctx, NULL);
- cmsHTRANSFORM xform1 = cmsCreateTransform(ctx, hSRGB, TYPE_RGBA_FLT, hLab, TYPE_LabA_FLT, 0, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
- cmsHTRANSFORM xform2 = cmsCreateTransform(ctx, hLab, TYPE_LabA_FLT, hSRGB, TYPE_RGBA_FLT, 0, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
- cmsFloat32Number RGBA1[4], RGBA2[4], LabA[4];
- int i;
- for (i = 0; i <= 100; i++)
- {
- RGBA1[0] = i / 100.0F;
- RGBA1[1] = i / 100.0F;
- RGBA1[2] = i / 100.0F;
- RGBA1[3] = 0;
- cmsDoTransform(ctx, xform1, RGBA1, LabA, 1);
- cmsDoTransform(ctx, xform2, LabA, RGBA2, 1);
- if (!IsGoodVal("Float RGB->RGB", RGBA1[0], RGBA2[0], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->RGB", RGBA1[1], RGBA2[1], FLOAT_PRECISSION) ||
- !IsGoodVal("Float RGB->RGB", RGBA1[2], RGBA2[2], FLOAT_PRECISSION))
- return 0;
- }
- cmsDeleteTransform(ctx, xform1);
- cmsDeleteTransform(ctx, xform2);
- cmsCloseProfile(ctx, hSRGB);
- cmsCloseProfile(ctx, hLab);
- return 1;
- }
- /*
- * parametric curve for Rec709
- */
- static
- double Rec709(double L)
- {
- if (L <0.018) return 4.5*L;
- else
- {
- double a = 1.099* pow(L, 0.45);
- a = a - 0.099;
- return a;
- }
- }
- static
- cmsInt32Number CheckParametricRec709(cmsContext ContextID)
- {
- cmsFloat64Number params[7];
- cmsToneCurve* t;
- int i;
- params[0] = 0.45; /* y */
- params[1] = pow(1.099, 1.0 / 0.45); /* a */
- params[2] = 0.0; /* b */
- params[3] = 4.5; /* c */
- params[4] = 0.018; /* d */
- params[5] = -0.099; /* e */
- params[6] = 0.0; /* f */
- t = cmsBuildParametricToneCurve (ContextID, 5, params);
- for (i=0; i < 256; i++)
- {
- cmsFloat32Number n = (cmsFloat32Number) i / 255.0F;
- cmsUInt16Number f1 = (cmsUInt16Number) floor(255.0 * cmsEvalToneCurveFloat(ContextID, t, n) + 0.5);
- cmsUInt16Number f2 = (cmsUInt16Number) floor(255.0*Rec709((double) i / 255.0) + 0.5);
- if (f1 != f2)
- {
- cmsFreeToneCurve(ContextID, t);
- return 0;
- }
- }
- cmsFreeToneCurve(ContextID, t);
- return 1;
- }
- #define kNumPoints 10
- typedef cmsFloat32Number(*Function)(cmsFloat32Number x);
- static cmsFloat32Number StraightLine( cmsFloat32Number x)
- {
- return (cmsFloat32Number) (0.1 + 0.9 * x);
- }
- static cmsInt32Number TestCurve(cmsContext ContextID, const char* label, cmsToneCurve* curve, Function fn)
- {
- cmsInt32Number ok = 1;
- int i;
- for (i = 0; i < kNumPoints*3; i++) {
- cmsFloat32Number x = (cmsFloat32Number)i / (kNumPoints*3 - 1);
- cmsFloat32Number expectedY = fn(x);
- cmsFloat32Number out = cmsEvalToneCurveFloat(ContextID, curve, x);
- if (!IsGoodVal(label, expectedY, out, FLOAT_PRECISSION)) {
- ok = 0;
- }
- }
- return ok;
- }
- static
- cmsInt32Number CheckFloatSamples(cmsContext ContextID)
- {
- cmsFloat32Number y[kNumPoints];
- int i;
- cmsToneCurve *curve;
- cmsInt32Number ok;
- for (i = 0; i < kNumPoints; i++) {
- cmsFloat32Number x = (cmsFloat32Number)i / (kNumPoints-1);
- y[i] = StraightLine(x);
- }
- curve = cmsBuildTabulatedToneCurveFloat(ContextID, kNumPoints, y);
- ok = TestCurve(ContextID, "Float Samples", curve, StraightLine);
- cmsFreeToneCurve(ContextID, curve);
- return ok;
- }
- static
- cmsInt32Number CheckFloatSegments(cmsContext ContextID)
- {
- cmsInt32Number ok = 1;
- int i;
- cmsToneCurve *curve;
- cmsFloat32Number y[ kNumPoints];
- // build a segmented curve with a sampled section...
- cmsCurveSegment Seg[3];
- // Initialize segmented curve part up to 0.1
- Seg[0].x0 = -1e22f; // -infinity
- Seg[0].x1 = 0.1f;
- Seg[0].Type = 6; // Y = (a * X + b) ^ Gamma + c
- Seg[0].Params[0] = 1.0f; // gamma
- Seg[0].Params[1] = 0.9f; // a
- Seg[0].Params[2] = 0.0f; // b
- Seg[0].Params[3] = 0.1f; // c
- Seg[0].Params[4] = 0.0f;
- // From zero to 1
- Seg[1].x0 = 0.1f;
- Seg[1].x1 = 0.9f;
- Seg[1].Type = 0;
- Seg[1].nGridPoints = kNumPoints;
- Seg[1].SampledPoints = y;
- for (i = 0; i < kNumPoints; i++) {
- cmsFloat32Number x = (cmsFloat32Number) (0.1 + ((cmsFloat32Number)i / (kNumPoints-1)) * (0.9 - 0.1));
- y[i] = StraightLine(x);
- }
- // from 1 to +infinity
- Seg[2].x0 = 0.9f;
- Seg[2].x1 = 1e22f; // +infinity
- Seg[2].Type = 6;
- Seg[2].Params[0] = 1.0f;
- Seg[2].Params[1] = 0.9f;
- Seg[2].Params[2] = 0.0f;
- Seg[2].Params[3] = 0.1f;
- Seg[2].Params[4] = 0.0f;
- curve = cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
- ok = TestCurve(ContextID, "Float Segmented Curve", curve, StraightLine);
- cmsFreeToneCurve(ContextID, curve);
- return ok;
- }
- static
- cmsInt32Number CheckReadRAW(cmsContext ContextID)
- {
- cmsInt32Number tag_size, tag_size1;
- char buffer[37009];
- cmsHPROFILE hProfile;
- SubTest("RAW read on on-disk");
- hProfile = cmsOpenProfileFromFile(ContextID, "test1.icc", "r");
- if (hProfile == NULL)
- return 0;
- tag_size1 = cmsReadRawTag(ContextID, hProfile, cmsSigGamutTag, NULL, 0);
- tag_size = cmsReadRawTag(ContextID, hProfile, cmsSigGamutTag, buffer, 37009);
- cmsCloseProfile(ContextID, hProfile);
- if (tag_size != 37009)
- return 0;
- if (tag_size1 != 37009)
- return 0;
- SubTest("RAW read on in-memory created profiles");
- hProfile = cmsCreate_sRGBProfile(ContextID);
- tag_size1 = cmsReadRawTag(ContextID, hProfile, cmsSigGreenColorantTag, NULL, 0);
- tag_size = cmsReadRawTag(ContextID, hProfile, cmsSigGreenColorantTag, buffer, 20);
- cmsCloseProfile(ContextID, hProfile);
- if (tag_size != 20)
- return 0;
- if (tag_size1 != 20)
- return 0;
- return 1;
- }
- static
- cmsInt32Number CheckMeta(cmsContext ContextID)
- {
- char *data;
- cmsHANDLE dict;
- cmsHPROFILE p;
- cmsUInt32Number clen;
- FILE *fp;
- int rc;
- /* open file */
- p = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
- if (p == NULL) return 0;
- /* read dictionary, but don't do anything with the value */
- //COMMENT OUT THE NEXT TWO LINES AND IT WORKS FINE!!!
- dict = cmsReadTag(ContextID, p, cmsSigMetaTag);
- if (dict == NULL) return 0;
- /* serialize profile to memory */
- rc = cmsSaveProfileToMem(ContextID, p, NULL, &clen);
- if (!rc) return 0;
- data = (char*) chknull(malloc(clen));
- rc = cmsSaveProfileToMem(ContextID, p, data, &clen);
- if (!rc) return 0;
- /* write the memory blob to a file */
- //NOTE: The crash does not happen if cmsSaveProfileToFile() is used */
- fp = fopen("new.icc", "wb");
- fwrite(data, 1, clen, fp);
- fclose(fp);
- free(data);
- cmsCloseProfile(ContextID, p);
- /* open newly created file and read metadata */
- p = cmsOpenProfileFromFile(ContextID, "new.icc", "r");
- //ERROR: Bad dictionary Name/Value
- //ERROR: Corrupted tag 'meta'
- //test: test.c:59: main: Assertion `dict' failed.
- dict = cmsReadTag(ContextID, p, cmsSigMetaTag);
- if (dict == NULL) return 0;
- cmsCloseProfile(ContextID, p);
- return 1;
- }
- // Bug on applying null transforms on floating point buffers
- static
- cmsInt32Number CheckFloatNULLxform(cmsContext ContextID)
- {
- int i;
- cmsFloat32Number in[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- cmsFloat32Number out[10];
- cmsHTRANSFORM xform = cmsCreateTransform(ContextID, NULL, TYPE_GRAY_FLT, NULL, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NULLTRANSFORM);
- if (xform == NULL) {
- Fail("Unable to create float null transform");
- return 0;
- }
- cmsDoTransform(ContextID, xform, in, out, 10);
- cmsDeleteTransform(ContextID, xform);
- for (i=0; i < 10; i++) {
- if (!IsGoodVal("float nullxform", in[i], out[i], 0.001)) {
- return 0;
- }
- }
- return 1;
- }
- static
- cmsInt32Number CheckRemoveTag(cmsContext ContextID)
- {
- cmsHPROFILE p;
- cmsMLU *mlu;
- int ret;
- p = cmsCreate_sRGBProfile(ContextID);
- /* set value */
- mlu = cmsMLUalloc (ContextID, 1);
- ret = cmsMLUsetASCII(ContextID, mlu, "en", "US", "bar");
- if (!ret) return 0;
- ret = cmsWriteTag(ContextID, p, cmsSigDeviceMfgDescTag, mlu);
- if (!ret) return 0;
- cmsMLUfree(ContextID, mlu);
- /* remove the tag */
- ret = cmsWriteTag(ContextID, p, cmsSigDeviceMfgDescTag, NULL);
- if (!ret) return 0;
- /* THIS EXPLODES */
- cmsCloseProfile(ContextID, p);
- return 1;
- }
- static
- cmsInt32Number CheckMatrixSimplify(cmsContext ContextID)
- {
- cmsHPROFILE pIn;
- cmsHPROFILE pOut;
- cmsHTRANSFORM t;
- unsigned char buf[3] = { 127, 32, 64 };
- pIn = cmsCreate_sRGBProfile(ContextID);
- pOut = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
- if (pIn == NULL || pOut == NULL)
- return 0;
- t = cmsCreateTransform(ContextID, pIn, TYPE_RGB_8, pOut, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
- cmsDoTransformStride(ContextID, t, buf, buf, 1, 1);
- cmsDeleteTransform(ContextID, t);
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- return buf[0] == 144 && buf[1] == 0 && buf[2] == 69;
- }
- static
- cmsInt32Number CheckTransformLineStride(cmsContext ContextID)
- {
- cmsHPROFILE pIn;
- cmsHPROFILE pOut;
- cmsHTRANSFORM t;
- // Our buffer is formed by 4 RGB8 lines, each line is 2 pixels wide plus a padding of one byte
- cmsUInt8Number buf1[]= { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, };
- // Our buffer2 is formed by 4 RGBA lines, each line is 2 pixels wide plus a padding of one byte
- cmsUInt8Number buf2[] = { 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
- 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
- 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0,
- 0xff, 0xff, 0xff, 1, 0xff, 0xff, 0xff, 1, 0};
- // Our buffer3 is formed by 4 RGBA16 lines, each line is 2 pixels wide plus a padding of two bytes
- cmsUInt16Number buf3[] = { 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
- 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
- 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0,
- 0xffff, 0xffff, 0xffff, 0x0101, 0xffff, 0xffff, 0xffff, 0x0101, 0 };
- cmsUInt8Number out[1024];
- memset(out, 0, sizeof(out));
- pIn = cmsCreate_sRGBProfile(ContextID);
- pOut = cmsOpenProfileFromFile(ContextID, "ibm-t61.icc", "r");
- if (pIn == NULL || pOut == NULL)
- return 0;
- t = cmsCreateTransform(ContextID, pIn, TYPE_RGB_8, pOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
- cmsDoTransformLineStride(ContextID, t, buf1, out, 2, 4, 7, 7, 0, 0);
- cmsDeleteTransform(ContextID, t);
- if (memcmp(out, buf1, sizeof(buf1)) != 0) {
- Fail("Failed transform line stride on RGB8");
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- return 0;
- }
- memset(out, 0, sizeof(out));
- t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_8, pOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
- cmsDoTransformLineStride(ContextID, t, buf2, out, 2, 4, 9, 9, 0, 0);
- cmsDeleteTransform(ContextID, t);
- if (memcmp(out, buf2, sizeof(buf2)) != 0) {
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- Fail("Failed transform line stride on RGBA8");
- return 0;
- }
- memset(out, 0, sizeof(out));
- t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_16, pOut, TYPE_RGBA_16, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
- cmsDoTransformLineStride(ContextID, t, buf3, out, 2, 4, 18, 18, 0, 0);
- cmsDeleteTransform(ContextID, t);
- if (memcmp(out, buf3, sizeof(buf3)) != 0) {
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- Fail("Failed transform line stride on RGBA16");
- return 0;
- }
- memset(out, 0, sizeof(out));
- // From 8 to 16
- t = cmsCreateTransform(ContextID, pIn, TYPE_RGBA_8, pOut, TYPE_RGBA_16, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
- cmsDoTransformLineStride(ContextID, t, buf2, out, 2, 4, 9, 18, 0, 0);
- cmsDeleteTransform(ContextID, t);
- if (memcmp(out, buf3, sizeof(buf3)) != 0) {
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- Fail("Failed transform line stride on RGBA16");
- return 0;
- }
- cmsCloseProfile(ContextID, pIn);
- cmsCloseProfile(ContextID, pOut);
- return 1;
- }
- static
- int CheckPlanar8opt(cmsContext ContextID)
- {
- cmsHPROFILE aboveRGB = Create_AboveRGB(ContextID);
- cmsHPROFILE sRGB = cmsCreate_sRGBProfile(ContextID);
- cmsHTRANSFORM transform = cmsCreateTransform(ContextID,
- sRGB, TYPE_RGB_8_PLANAR,
- aboveRGB, TYPE_RGB_8_PLANAR,
- INTENT_PERCEPTUAL, 0);
- cmsDeleteTransform(ContextID, transform);
- cmsCloseProfile(ContextID, aboveRGB);
- cmsCloseProfile(ContextID, sRGB);
- return 1;
- }
- /**
- * Bug reported & fixed. Thanks to Kornel Lesinski for spotting this.
- */
- static
- int CheckSE(cmsContext ContextID)
- {
- cmsHPROFILE input_profile = Create_AboveRGB(ContextID);
- cmsHPROFILE output_profile = cmsCreate_sRGBProfile(ContextID);
- cmsHTRANSFORM tr = cmsCreateTransform(ContextID, input_profile, TYPE_RGBA_8, output_profile, TYPE_RGBA_16_SE, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_COPY_ALPHA);
- cmsUInt8Number rgba[4] = { 40, 41, 41, 0xfa };
- cmsUInt16Number out[4];
- cmsDoTransform(ContextID, tr, rgba, out, 1);
- cmsCloseProfile(ContextID, input_profile);
- cmsCloseProfile(ContextID, output_profile);
- cmsDeleteTransform(ContextID, tr);
- if (out[0] != 0xf622 || out[1] != 0x7f24 || out[2] != 0x7f24)
- return 0;
- return 1;
- }
- /**
- * Bug reported.
- */
- static
- int CheckForgedMPE(cmsContext ContextID)
- {
- cmsUInt32Number i;
- cmsHPROFILE srcProfile;
- cmsHPROFILE dstProfile;
- cmsColorSpaceSignature srcCS;
- cmsUInt32Number nSrcComponents;
- cmsUInt32Number srcFormat;
- cmsUInt32Number intent = 0;
- cmsUInt32Number flags = 0;
- cmsHTRANSFORM hTransform;
- cmsUInt8Number output[4];
- srcProfile = cmsOpenProfileFromFile(ContextID, "bad_mpe.icc", "r");
- if (!srcProfile)
- return 0;
- dstProfile = cmsCreate_sRGBProfile(ContextID);
- if (!dstProfile) {
- cmsCloseProfile(ContextID, srcProfile);
- return 0;
- }
- srcCS = cmsGetColorSpace(ContextID, srcProfile);
- nSrcComponents = cmsChannelsOfColorSpace(ContextID, srcCS);
- if (srcCS == cmsSigLabData) {
- srcFormat =
- COLORSPACE_SH(PT_Lab) | CHANNELS_SH(nSrcComponents) | BYTES_SH(0);
- }
- else {
- srcFormat =
- COLORSPACE_SH(PT_ANY) | CHANNELS_SH(nSrcComponents) | BYTES_SH(1);
- }
- cmsSetLogErrorHandler(ContextID, ErrorReportingFunction);
- hTransform = cmsCreateTransform(ContextID, srcProfile, srcFormat, dstProfile,
- TYPE_BGR_8, intent, flags);
- cmsCloseProfile(ContextID, srcProfile);
- cmsCloseProfile(ContextID, dstProfile);
- cmsSetLogErrorHandler(ContextID, FatalErrorQuit);
- // Should report error
- if (!TrappedError) return 0;
- TrappedError = FALSE;
- // Transform should NOT be created
- if (!hTransform) return 1;
- // Never should reach here
- if (T_BYTES(srcFormat) == 0) { // 0 means double
- double input[128];
- for (i = 0; i < nSrcComponents; i++)
- input[i] = 0.5f;
- cmsDoTransform(ContextID, hTransform, input, output, 1);
- }
- else {
- cmsUInt8Number input[128];
- for (i = 0; i < nSrcComponents; i++)
- input[i] = 128;
- cmsDoTransform(ContextID, hTransform, input, output, 1);
- }
- cmsDeleteTransform(ContextID, hTransform);
- return 0;
- }
- /**
- * What the self test is trying to do is creating a proofing transform
- * with gamut check, so we can getting the coverage of one profile of
- * another, i.e. to approximate the gamut intersection. e.g.
- * Thanks to Richard Hughes for providing the test
- */
- static
- int CheckProofingIntersection(cmsContext ContextID)
- {
- cmsHPROFILE profile_null, hnd1, hnd2;
- cmsHTRANSFORM transform;
- hnd1 = cmsCreate_sRGBProfile(ContextID);
- hnd2 = Create_AboveRGB(ContextID);
- profile_null = cmsCreateNULLProfile(ContextID);
- transform = cmsCreateProofingTransform(ContextID,
- hnd1,
- TYPE_RGB_FLT,
- profile_null,
- TYPE_GRAY_FLT,
- hnd2,
- INTENT_ABSOLUTE_COLORIMETRIC,
- INTENT_ABSOLUTE_COLORIMETRIC,
- cmsFLAGS_GAMUTCHECK |
- cmsFLAGS_SOFTPROOFING);
- cmsCloseProfile(ContextID, hnd1);
- cmsCloseProfile(ContextID, hnd2);
- cmsCloseProfile(ContextID, profile_null);
- // Failed?
- if (transform == NULL) return 0;
- cmsDeleteTransform(ContextID, transform);
- return 1;
- }
- /**
- * In 2.11: When I create a RGB profile, set the copyright data with an empty string,
- * then call cmsMD5computeID on said profile, the program crashes.
- */
- static
- int CheckEmptyMLUC(cmsContext context)
- {
- cmsCIExyY white = { 0.31271, 0.32902, 1.0 };
- cmsCIExyYTRIPLE primaries =
- {
- .Red = { 0.640, 0.330, 1.0 },
- .Green = { 0.300, 0.600, 1.0 },
- .Blue = { 0.150, 0.060, 1.0 }
- };
- cmsFloat64Number parameters[10] = { 2.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
- cmsToneCurve* toneCurve = cmsBuildParametricToneCurve(context, 1, parameters);
- cmsToneCurve* toneCurves[3] = { toneCurve, toneCurve, toneCurve };
- cmsHPROFILE profile = cmsCreateRGBProfile(context, &white, &primaries, toneCurves);
- cmsSetLogErrorHandler(context, FatalErrorQuit);
- cmsFreeToneCurve(context, toneCurve);
- // Set an empty copyright tag. This should log an error.
- cmsMLU* mlu = cmsMLUalloc(context, 1);
- cmsMLUsetASCII(context, mlu, "en", "AU", "");
- cmsMLUsetWide(context, mlu, "en", "EN", L"");
- cmsWriteTag(context, profile, cmsSigCopyrightTag, mlu);
- cmsMLUfree(context, mlu);
- // This will cause a crash after setting an empty copyright tag.
- cmsMD5computeID(context, profile);
- // Cleanup
- cmsCloseProfile(context, profile);
- return 1;
- }
- static
- double distance(const cmsUInt16Number* a, const cmsUInt16Number* b)
- {
- double d1 = a[0] - b[0];
- double d2 = a[1] - b[1];
- double d3 = a[2] - b[2];
- return sqrt(d1 * d1 + d2 * d2 + d3 * d3);
- }
- /**
- * In 2.12, a report suggest that the built-in sRGB has roundtrip errors that makes color to move
- * when roundtripping again and again
- */
- static
- int Check_sRGB_Rountrips(cmsContext contextID)
- {
- cmsUInt16Number rgb[3], seed[3];
- cmsCIELab Lab;
- int i, r, g, b;
- double err, maxErr;
- cmsHPROFILE hsRGB = cmsCreate_sRGBProfile(contextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(contextID, NULL);
- cmsHTRANSFORM hBack = cmsCreateTransform(contextID, hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsHTRANSFORM hForth = cmsCreateTransform(contextID, hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(contextID, hLab);
- cmsCloseProfile(contextID, hsRGB);
- maxErr = 0.0;
- for (r = 0; r <= 255; r += 16)
- for (g = 0; g <= 255; g += 16)
- for (b = 0; b <= 255; b += 16)
- {
- seed[0] = rgb[0] = (cmsUInt16Number) ((r << 8) | r);
- seed[1] = rgb[1] = (cmsUInt16Number) ((g << 8) | g);
- seed[2] = rgb[2] = (cmsUInt16Number) ((b << 8) | b);
- for (i = 0; i < 50; i++)
- {
- cmsDoTransform(contextID, hForth, rgb, &Lab, 1);
- cmsDoTransform(contextID, hBack, &Lab, rgb, 1);
- }
- err = distance(seed, rgb);
- if (err > maxErr)
- maxErr = err;
- }
- cmsDeleteTransform(contextID, hBack);
- cmsDeleteTransform(contextID, hForth);
- if (maxErr > 20.0)
- {
- printf("Maximum sRGB roundtrip error %f!\n", maxErr);
- return 0;
- }
- return 1;
- }
- /**
- * Check OKLab colorspace
- */
- static
- int Check_OkLab(void)
- {
- cmsHPROFILE hOkLab = cmsCreate_OkLabProfile(NULL);
- cmsHPROFILE hXYZ = cmsCreateXYZProfile();
- cmsCIEXYZ xyz, xyz2;
- cmsCIELab okLab;
- #define TYPE_OKLAB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0))
- cmsHTRANSFORM xform = cmsCreateTransform(hXYZ, TYPE_XYZ_DBL, hOkLab, TYPE_OKLAB_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsHTRANSFORM xform2 = cmsCreateTransform(hOkLab, TYPE_OKLAB_DBL, hXYZ, TYPE_XYZ_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
- /**
- * D50 should be converted to white by PCS definition
- */
- xyz.X = 0.9642; xyz.Y = 1.0000; xyz.Z = 0.8249;
- cmsDoTransform(xform, &xyz, &okLab, 1);
- cmsDoTransform(xform2, &okLab, &xyz2, 1);
- xyz.X = 1.0; xyz.Y = 0.0; xyz.Z = 0.0;
- cmsDoTransform(xform, &xyz, &okLab, 1);
- cmsDoTransform(xform2, &okLab, &xyz2, 1);
- xyz.X = 0.0; xyz.Y = 1.0; xyz.Z = 0.0;
- cmsDoTransform(xform, &xyz, &okLab, 1);
- cmsDoTransform(xform2, &okLab, &xyz2, 1);
- xyz.X = 0.0; xyz.Y = 0.0; xyz.Z = 1.0;
- cmsDoTransform(xform, &xyz, &okLab, 1);
- cmsDoTransform(xform2, &okLab, &xyz2, 1);
- xyz.X = 0.143046; xyz.Y = 0.060610; xyz.Z = 0.713913;
- cmsDoTransform(xform, &xyz, &okLab, 1);
- cmsDoTransform(xform2, &okLab, &xyz2, 1);
-
- cmsDeleteTransform(xform);
- cmsDeleteTransform(xform2);
- cmsCloseProfile(hOkLab);
- cmsCloseProfile(hXYZ);
- return 1;
- }
- static
- int Check_OkLab2(void)
- {
- #define TYPE_LABA_F32 (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
- cmsUInt16Number rgb[3];
- cmsFloat32Number lab[4];
- cmsHPROFILE labProfile = cmsCreate_OkLabProfile(NULL);
- cmsHPROFILE rgbProfile = cmsCreate_sRGBProfile();
- cmsHTRANSFORM hBack = cmsCreateTransform(labProfile, TYPE_LABA_F32, rgbProfile, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsHTRANSFORM hForth = cmsCreateTransform(rgbProfile, TYPE_RGB_16, labProfile, TYPE_LABA_F32, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsCloseProfile(labProfile);
- cmsCloseProfile(rgbProfile);
- rgb[0] = 0;
- rgb[1] = 0;
- rgb[2] = 65535;
- cmsDoTransform(hForth, rgb, &lab, 1);
- cmsDoTransform(hBack, lab, &rgb, 1);
- cmsDeleteTransform(hBack);
- cmsDeleteTransform(hForth);
- if (rgb[0] != 0 || rgb[1] != 0 || rgb[2] != 65535) return 0;
- return 1;
- }
- static
- cmsHPROFILE createRgbGamma(cmsContext contextID, cmsFloat64Number g)
- {
- cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
- cmsCIExyYTRIPLE Rec709Primaries = {
- {0.6400, 0.3300, 1.0},
- {0.3000, 0.6000, 1.0},
- {0.1500, 0.0600, 1.0}
- };
- cmsToneCurve* Gamma[3];
- cmsHPROFILE hRGB;
- Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(contextID, g);
- if (Gamma[0] == NULL) return NULL;
- hRGB = cmsCreateRGBProfile(contextID, &D65, &Rec709Primaries, Gamma);
- cmsFreeToneCurve(contextID, Gamma[0]);
- return hRGB;
- }
- static
- int CheckGammaSpaceDetection(cmsContext contextID)
- {
- cmsFloat64Number i;
- for (i = 0.5; i < 3; i += 0.1)
- {
- cmsHPROFILE hProfile = createRgbGamma(contextID, i);
- cmsFloat64Number gamma = cmsDetectRGBProfileGamma(contextID, hProfile, 0.01);
- cmsCloseProfile(contextID, hProfile);
- if (fabs(gamma - i) > 0.1)
- {
- Fail("Failed profile gamma detection of %f (got %f)", i, gamma);
- return 0;
- }
- }
- return 1;
- }
- // Per issue #308. A built-in is corrupted by using write raw tag was causing a segfault
- static
- int CheckInducedCorruption(void)
- {
- cmsHTRANSFORM xform0;
- char garbage[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b";
- cmsHPROFILE hsrgb = cmsCreate_sRGBProfile();
- cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
- cmsSetLogErrorHandler(NULL);
- cmsWriteRawTag(hsrgb, cmsSigBlueColorantTag, &garbage, sizeof(garbage));
- xform0 = cmsCreateTransform(hsrgb, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- if (xform0) cmsDeleteTransform(xform0);
- cmsCloseProfile(hsrgb);
- cmsCloseProfile(hLab);
- ResetFatalError();
- return 1;
- }
- #if 0
- // You need to download following profiles to execute this test: sRGB-elle-V4-srgbtrc.icc, sRGB-elle-V4-g10.icc
- // The include this line in the checks list: Check("KInear spaces detection", CheckLinearSpacesOptimization);
- static
- void uint16toFloat(cmsUInt16Number* src, cmsFloat32Number* dst)
- {
- for (int i = 0; i < 3; i++) {
- dst[i] = src[i] / 65535.f;
- }
- }
- static
- int CheckLinearSpacesOptimization(cmsContext contextID)
- {
- cmsHPROFILE lcms_sRGB = cmsCreate_sRGBProfile(contextID);
- cmsHPROFILE elle_sRGB = cmsOpenProfileFromFile(contextID, "sRGB-elle-V4-srgbtrc.icc", "r");
- cmsHPROFILE elle_linear = cmsOpenProfileFromFile(contextID, "sRGB-elle-V4-g10.icc", "r");
- cmsHTRANSFORM transform1 = cmsCreateTransform(contextID, elle_sRGB, TYPE_RGB_16, elle_linear, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsHTRANSFORM transform2 = cmsCreateTransform(contextID, elle_linear, TYPE_RGB_16, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsHTRANSFORM transform2a = cmsCreateTransform(contextID, elle_linear, TYPE_RGB_FLT, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsUInt16Number sourceCol[3] = { 43 * 257, 27 * 257, 6 * 257 };
- cmsUInt16Number linearCol[3] = { 0 };
- float linearColF[3] = { 0 };
- cmsUInt16Number finalCol[3] = { 0 };
- int difR, difG, difB;
- int difR2, difG2, difB2;
- cmsDoTransform(contextID, transform1, sourceCol, linearCol, 1);
- cmsDoTransform(contextID, transform2, linearCol, finalCol, 1);
- cmsCloseProfile(contextID, lcms_sRGB); cmsCloseProfile(contextID, elle_sRGB); cmsCloseProfile(contextID, elle_linear);
- difR = (int)sourceCol[0] - finalCol[0];
- difG = (int)sourceCol[1] - finalCol[1];
- difB = (int)sourceCol[2] - finalCol[2];
- uint16toFloat(linearCol, linearColF);
- cmsDoTransform(contextID, transform2a, linearColF, finalCol, 1);
- difR2 = (int)sourceCol[0] - finalCol[0];
- difG2 = (int)sourceCol[1] - finalCol[1];
- difB2 = (int)sourceCol[2] - finalCol[2];
- cmsDeleteTransform(contextID, transform1);
- cmsDeleteTransform(contextID, transform2);
- cmsDeleteTransform(contextID, transform2a);
- if (abs(difR2 - difR) > 5 || abs(difG2 - difG) > 5 || abs(difB2 - difB) > 5)
- {
- Fail("Linear detection failed");
- return 0;
- }
- return 1;
- }
- #endif
- static
- int CheckBadCGATS(void)
- {
- const char* bad_it8 =
- " \"\"\n"
- "NUMBER_OF_FIELDS 4\n"
- "BEGIN_DATA_FORMAT\n"
- "I R G G\n"
- "END_DATA_FORMAT\n"
- "NUMBER_OF_FIELDS 9\n"
- "NUMBER_OF_SETS 2\n"
- "BEGIN_DATA\n"
- "d\n"
- "0 0Bd\n"
- "0Ba $ $ t .";
- cmsHANDLE hIT8;
-
- cmsSetLogErrorHandler(NULL);
- hIT8 = cmsIT8LoadFromMem(0, bad_it8, (cmsUInt32Number) strlen(bad_it8));
-
- ResetFatalError();
- if (hIT8 != NULL)
- {
- Fail("Wrong IT8 accepted as ok");
- cmsIT8Free(hIT8);
- }
- return 1;
- }
- static
- int CheckIntToFloatTransform(void)
- {
- cmsHPROFILE hAbove = Create_AboveRGB();
- cmsHPROFILE hsRGB = cmsCreate_sRGBProfile();
- cmsHTRANSFORM xform = cmsCreateTransform(hAbove, TYPE_RGB_8, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL, 0);
- cmsUInt8Number rgb8[3] = { 12, 253, 21 };
- cmsFloat64Number rgbDBL[3] = { 0 };
- cmsCloseProfile(hAbove); cmsCloseProfile(hsRGB);
- cmsDoTransform(xform, rgb8, rgbDBL, 1);
- cmsDeleteTransform(xform);
- if (rgbDBL[0] < 0 && rgbDBL[2] < 0) return 1;
- Fail("Unbounded transforms with integer input failed");
- return 0;
- }
- static
- int CheckSaveLinearizationDevicelink(void)
- {
- const cmsFloat32Number table[] = { 0, 0.5f, 1.0f };
- cmsToneCurve* tone = cmsBuildTabulatedToneCurveFloat(NULL, 3, table);
- cmsToneCurve* rgb_curves[3] = { tone, tone, tone };
- cmsHPROFILE hDeviceLink = cmsCreateLinearizationDeviceLink(cmsSigRgbData, rgb_curves);
- cmsBool result;
- cmsHTRANSFORM xform;
- int i;
-
- cmsFreeToneCurve(tone);
- result = cmsSaveProfileToFile(hDeviceLink, "lin_rgb.icc");
- cmsCloseProfile(hDeviceLink);
- if (!result)
- {
- remove("lin_rgb.icc");
- Fail("Couldn't save linearization devicelink");
- }
- hDeviceLink = cmsOpenProfileFromFile("lin_rgb.icc", "r");
- if (hDeviceLink == NULL)
- {
- remove("lin_rgb.icc");
- Fail("Could't open devicelink");
- }
- xform = cmsCreateTransform(hDeviceLink, TYPE_RGB_8, NULL, TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
- cmsCloseProfile(hDeviceLink);
- for (i = 0; i < 256; i++)
- {
- cmsUInt8Number rgb_in[3] = { i, i, i };
- cmsUInt8Number rgb_out[3];
- cmsDoTransform(xform, rgb_in, rgb_out, 1);
- if (rgb_in[0] != rgb_out[0] ||
- rgb_in[1] != rgb_out[1] ||
- rgb_in[2] != rgb_out[2])
- {
- remove("lin_rgb.icc");
- Fail("Saved devicelink was not working");
- }
- }
- cmsDeleteTransform(xform);
- remove("lin_rgb.icc");
- return 1;
- }
- // --------------------------------------------------------------------------------------------------
- // P E R F O R M A N C E C H E C K S
- // --------------------------------------------------------------------------------------------------
- typedef struct {cmsUInt8Number r, g, b, a;} Scanline_rgba8;
- typedef struct {cmsUInt16Number r, g, b, a;} Scanline_rgba16;
- typedef struct {cmsFloat32Number r, g, b, a;} Scanline_rgba32;
- typedef struct {cmsUInt8Number r, g, b;} Scanline_rgb8;
- typedef struct {cmsUInt16Number r, g, b;} Scanline_rgb16;
- typedef struct {cmsFloat32Number r, g, b;} Scanline_rgb32;
- static
- void TitlePerformance(const char* Txt)
- {
- printf("%-45s: ", Txt); fflush(stdout);
- }
- static
- void PrintPerformance(cmsUInt32Number Bytes, cmsUInt32Number SizeOfPixel, cmsFloat64Number diff)
- {
- cmsFloat64Number seconds = (cmsFloat64Number) diff / CLOCKS_PER_SEC;
- cmsFloat64Number mpix_sec = Bytes / (1024.0*1024.0*seconds*SizeOfPixel);
- printf("%#4.3g MPixel/sec.\n", mpix_sec);
- fflush(stdout);
- }
- static
- void SpeedTest32bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgba32 *In;
- cmsUInt32Number Mb;
- cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
- cmsUInt32Number NumPixels;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGBA_FLT,
- hlcmsProfileOut, TYPE_RGBA_FLT, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
- Mb = NumPixels * sizeof(Scanline_rgba32);
- In = (Scanline_rgba32 *) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r += Interval)
- for (g=0; g < 256; g += Interval)
- for (b=0; b < 256; b += Interval) {
- In[j].r = r / 256.0f;
- In[j].g = g / 256.0f;
- In[j].b = b / 256.0f;
- In[j].a = (In[j].r + In[j].g + In[j].b) / 3;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgba32), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest16bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgb16 *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGB_16,
- hlcmsProfileOut, TYPE_RGB_16, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256 * sizeof(Scanline_rgb16);
- In = (Scanline_rgb16*) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j].r = (cmsUInt16Number) ((r << 8) | r);
- In[j].g = (cmsUInt16Number) ((g << 8) | g);
- In[j].b = (cmsUInt16Number) ((b << 8) | b);
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgb16), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest32bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgba32 *In;
- cmsUInt32Number Mb;
- cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
- cmsUInt32Number NumPixels;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_FLT,
- hlcmsProfileOut, TYPE_CMYK_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
- Mb = NumPixels * sizeof(Scanline_rgba32);
- In = (Scanline_rgba32 *) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r += Interval)
- for (g=0; g < 256; g += Interval)
- for (b=0; b < 256; b += Interval) {
- In[j].r = r / 256.0f;
- In[j].g = g / 256.0f;
- In[j].b = b / 256.0f;
- In[j].a = (In[j].r + In[j].g + In[j].b) / 3;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgba32), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest16bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgba16 *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_16,
- hlcmsProfileOut, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256*sizeof(Scanline_rgba16);
- In = (Scanline_rgba16*) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j].r = (cmsUInt16Number) ((r << 8) | r);
- In[j].g = (cmsUInt16Number) ((g << 8) | g);
- In[j].b = (cmsUInt16Number) ((b << 8) | b);
- In[j].a = 0;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgba16), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest8bits(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgb8 *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_RGB_8,
- hlcmsProfileOut, TYPE_RGB_8, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256*sizeof(Scanline_rgb8);
- In = (Scanline_rgb8*) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j].r = (cmsUInt8Number) r;
- In[j].g = (cmsUInt8Number) g;
- In[j].b = (cmsUInt8Number) b;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgb8), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest8bitsCMYK(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- Scanline_rgba8 *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn, TYPE_CMYK_8,
- hlcmsProfileOut, TYPE_CMYK_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256*sizeof(Scanline_rgba8);
- In = (Scanline_rgba8*) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j].r = (cmsUInt8Number) r;
- In[j].g = (cmsUInt8Number) g;
- In[j].b = (cmsUInt8Number) b;
- In[j].a = (cmsUInt8Number) 0;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(Scanline_rgba8), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest32bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- cmsFloat32Number *In;
- cmsUInt32Number Mb;
- cmsUInt32Number Interval = 4; // Power of 2 number to increment r,g,b values by in the loops to keep the test duration practically short
- cmsUInt32Number NumPixels;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
- TYPE_GRAY_FLT, hlcmsProfileOut, TYPE_GRAY_FLT, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- NumPixels = 256 / Interval * 256 / Interval * 256 / Interval;
- Mb = NumPixels * sizeof(cmsFloat32Number);
- In = (cmsFloat32Number*) chknull(malloc(Mb));
- j = 0;
- for (r = 0; r < 256; r += Interval)
- for (g = 0; g < 256; g += Interval)
- for (b = 0; b < 256; b += Interval) {
- In[j] = ((r + g + b) / 768.0f);
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, NumPixels);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(cmsFloat32Number), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest16bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- cmsUInt16Number *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
- TYPE_GRAY_16, hlcmsProfileOut, TYPE_GRAY_16, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256 * sizeof(cmsUInt16Number);
- In = (cmsUInt16Number *) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j] = (cmsUInt16Number) ((r + g + b) / 3);
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(cmsUInt16Number), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- void SpeedTest8bitsGray(cmsContext ContextID, const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent)
- {
- cmsInt32Number r, g, b, j;
- clock_t atime;
- cmsFloat64Number diff;
- cmsHTRANSFORM hlcmsxform;
- cmsUInt8Number *In;
- cmsUInt32Number Mb;
- if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
- Die("Unable to open profiles");
- hlcmsxform = cmsCreateTransform(ContextID, hlcmsProfileIn,
- TYPE_GRAY_8, hlcmsProfileOut, TYPE_GRAY_8, Intent, cmsFLAGS_NOCACHE);
- cmsCloseProfile(ContextID, hlcmsProfileIn);
- cmsCloseProfile(ContextID, hlcmsProfileOut);
- Mb = 256*256*256;
- In = (cmsUInt8Number*) chknull(malloc(Mb));
- j = 0;
- for (r=0; r < 256; r++)
- for (g=0; g < 256; g++)
- for (b=0; b < 256; b++) {
- In[j] = (cmsUInt8Number) r;
- j++;
- }
- TitlePerformance(Title);
- atime = clock();
- cmsDoTransform(ContextID, hlcmsxform, In, In, 256*256*256);
- diff = clock() - atime;
- free(In);
- PrintPerformance(Mb, sizeof(cmsUInt8Number), diff);
- cmsDeleteTransform(ContextID, hlcmsxform);
- }
- static
- cmsHPROFILE CreateCurves(cmsContext ContextID)
- {
- cmsToneCurve* Gamma = cmsBuildGamma(ContextID, 1.1);
- cmsToneCurve* Transfer[3];
- cmsHPROFILE h;
- Transfer[0] = Transfer[1] = Transfer[2] = Gamma;
- h = cmsCreateLinearizationDeviceLink(ContextID, cmsSigRgbData, Transfer);
- cmsFreeToneCurve(ContextID, Gamma);
- return h;
- }
- static
- void SpeedTest(cmsContext ContextID)
- {
- printf("\n\nP E R F O R M A N C E T E S T S\n");
- printf( "=================================\n\n");
- fflush(stdout);
- SpeedTest8bits(ContextID, "8 bits on CLUT profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test3.icc", "r"),
- INTENT_PERCEPTUAL);
- SpeedTest16bits(ContextID, "16 bits on CLUT profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test3.icc", "r"), INTENT_PERCEPTUAL);
- SpeedTest32bits(ContextID, "32 bits on CLUT profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test3.icc", "r"), INTENT_PERCEPTUAL);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bits(ContextID, "8 bits on Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_PERCEPTUAL);
- SpeedTest16bits(ContextID, "16 bits on Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_PERCEPTUAL);
- SpeedTest32bits(ContextID, "32 bits on Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_PERCEPTUAL);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bits(ContextID, "8 bits on SAME Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- INTENT_PERCEPTUAL);
- SpeedTest16bits(ContextID, "16 bits on SAME Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_PERCEPTUAL);
- SpeedTest32bits(ContextID, "32 bits on SAME Matrix-Shaper profiles",
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_PERCEPTUAL);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bits(ContextID, "8 bits on Matrix-Shaper profiles (AbsCol)",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_ABSOLUTE_COLORIMETRIC);
- SpeedTest16bits(ContextID, "16 bits on Matrix-Shaper profiles (AbsCol)",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_ABSOLUTE_COLORIMETRIC);
- SpeedTest32bits(ContextID, "32 bits on Matrix-Shaper profiles (AbsCol)",
- cmsOpenProfileFromFile(ContextID, "test5.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "aRGBlcms2.icc", "r"),
- INTENT_ABSOLUTE_COLORIMETRIC);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bits(ContextID, "8 bits on curves",
- CreateCurves(ContextID),
- CreateCurves(ContextID),
- INTENT_PERCEPTUAL);
- SpeedTest16bits(ContextID, "16 bits on curves",
- CreateCurves(ContextID),
- CreateCurves(ContextID),
- INTENT_PERCEPTUAL);
- SpeedTest32bits(ContextID, "32 bits on curves",
- CreateCurves(ContextID),
- CreateCurves(ContextID),
- INTENT_PERCEPTUAL);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bitsCMYK(ContextID, "8 bits on CMYK profiles",
- cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
- SpeedTest16bitsCMYK(ContextID, "16 bits on CMYK profiles",
- cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
- SpeedTest32bitsCMYK(ContextID, "32 bits on CMYK profiles",
- cmsOpenProfileFromFile(ContextID, "test1.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "test2.icc", "r"));
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bitsGray(ContextID, "8 bits on gray-to gray",
- cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- SpeedTest16bitsGray(ContextID, "16 bits on gray-to gray",
- cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- SpeedTest32bitsGray(ContextID, "32 bits on gray-to gray",
- cmsOpenProfileFromFile(ContextID, "gray3lcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bitsGray(ContextID, "8 bits on gray-to-lab gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- SpeedTest16bitsGray(ContextID, "16 bits on gray-to-lab gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- SpeedTest32bitsGray(ContextID, "32 bits on gray-to-lab gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
- printf("\n");
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SpeedTest8bitsGray(ContextID, "8 bits on SAME gray-to-gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
- SpeedTest16bitsGray(ContextID, "16 bits on SAME gray-to-gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
- SpeedTest32bitsGray(ContextID, "32 bits on SAME gray-to-gray",
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"),
- cmsOpenProfileFromFile(ContextID, "graylcms2.icc", "r"), INTENT_PERCEPTUAL);
- printf("\n");
- }
- // -----------------------------------------------------------------------------------------------------
- // Print the supported intents
- static
- void PrintSupportedIntents(void)
- {
- cmsUInt32Number n, i;
- cmsUInt32Number Codes[200];
- char* Descriptions[200];
- n = cmsGetSupportedIntents(DbgThread(), 200, Codes, Descriptions);
- printf("Supported intents:\n");
- for (i=0; i < n; i++) {
- printf("\t%u - %s\n", Codes[i], Descriptions[i]);
- }
- printf("\n");
- }
- // ---------------------------------------------------------------------------------------
- int main(int argc, char* argv[])
- {
- cmsInt32Number Exhaustive = 0;
- cmsInt32Number DoSpeedTests = 1;
- cmsInt32Number DoCheckTests = 1;
- cmsInt32Number DoPluginTests = 1;
- cmsInt32Number DoZooTests = 0;
- cmsContext ctx;
- #ifdef _MSC_VER
- _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
- #endif
- // First of all, check for the right header
- if (cmsGetEncodedCMMversion() != LCMS_VERSION) {
- Die("Oops, you are mixing header and shared lib!\nHeader version reports to be '%d' and shared lib '%d'\n", LCMS_VERSION, cmsGetEncodedCMMversion());
- }
- printf("LittleCMS %2.2f test bed %s %s\n\n", cmsGetEncodedCMMversion() / 1000.0, __DATE__, __TIME__);
- if ((argc == 2) && strcmp(argv[1], "--exhaustive") == 0) {
- Exhaustive = 1;
- printf("Running exhaustive tests (will take a while...)\n\n");
- }
- else
- if ((argc == 3) && strcmp(argv[1], "--chdir") == 0) {
- CHDIR(argv[2]);
- }
- printf("Installing debug memory plug-in ... ");
- cmsPlugin(NULL, &DebugMemHandler);
- printf("done.\n");
- ctx = NULL;//cmsCreateContext(NULL, NULL);
- printf("Installing error logger ... ");
- cmsSetLogErrorHandler(NULL, FatalErrorQuit);
- printf("done.\n");
- PrintSupportedIntents();
- Check(ctx, "Base types", CheckBaseTypes);
- Check(ctx, "endianness", CheckEndianness);
- Check(ctx, "quick floor", CheckQuickFloor);
- Check(ctx, "quick floor word", CheckQuickFloorWord);
- Check(ctx, "Fixed point 15.16 representation", CheckFixedPoint15_16);
- Check(ctx, "Fixed point 8.8 representation", CheckFixedPoint8_8);
- Check(ctx, "D50 roundtrip", CheckD50Roundtrip);
- // Create utility profiles
- if (DoCheckTests || DoSpeedTests)
- Check(ctx, "Creation of test profiles", CreateTestProfiles);
- if (DoCheckTests) {
- // Forward 1D interpolation
- Check(ctx, "1D interpolation in 2pt tables", Check1DLERP2);
- Check(ctx, "1D interpolation in 3pt tables", Check1DLERP3);
- Check(ctx, "1D interpolation in 4pt tables", Check1DLERP4);
- Check(ctx, "1D interpolation in 6pt tables", Check1DLERP6);
- Check(ctx, "1D interpolation in 18pt tables", Check1DLERP18);
- Check(ctx, "1D interpolation in descending 2pt tables", Check1DLERP2Down);
- Check(ctx, "1D interpolation in descending 3pt tables", Check1DLERP3Down);
- Check(ctx, "1D interpolation in descending 6pt tables", Check1DLERP6Down);
- Check(ctx, "1D interpolation in descending 18pt tables", Check1DLERP18Down);
- if (Exhaustive) {
- Check(ctx, "1D interpolation in n tables", ExhaustiveCheck1DLERP);
- Check(ctx, "1D interpolation in descending tables", ExhaustiveCheck1DLERPDown);
- }
- // Forward 3D interpolation
- Check(ctx, "3D interpolation Tetrahedral (float) ", Check3DinterpolationFloatTetrahedral);
- Check(ctx, "3D interpolation Trilinear (float) ", Check3DinterpolationFloatTrilinear);
- Check(ctx, "3D interpolation Tetrahedral (16) ", Check3DinterpolationTetrahedral16);
- Check(ctx, "3D interpolation Trilinear (16) ", Check3DinterpolationTrilinear16);
- if (Exhaustive) {
- Check(ctx, "Exhaustive 3D interpolation Tetrahedral (float) ", ExaustiveCheck3DinterpolationFloatTetrahedral);
- Check(ctx, "Exhaustive 3D interpolation Trilinear (float) ", ExaustiveCheck3DinterpolationFloatTrilinear);
- Check(ctx, "Exhaustive 3D interpolation Tetrahedral (16) ", ExhaustiveCheck3DinterpolationTetrahedral16);
- Check(ctx, "Exhaustive 3D interpolation Trilinear (16) ", ExhaustiveCheck3DinterpolationTrilinear16);
- }
- Check(ctx, "Reverse interpolation 3 -> 3", CheckReverseInterpolation3x3);
- Check(ctx, "Reverse interpolation 4 -> 3", CheckReverseInterpolation4x3);
- // High dimensionality interpolation
- Check(ctx, "3D interpolation", Check3Dinterp);
- Check(ctx, "3D interpolation with granularity", Check3DinterpGranular);
- Check(ctx, "4D interpolation", Check4Dinterp);
- Check(ctx, "4D interpolation with granularity", Check4DinterpGranular);
- Check(ctx, "5D interpolation with granularity", Check5DinterpGranular);
- Check(ctx, "6D interpolation with granularity", Check6DinterpGranular);
- Check(ctx, "7D interpolation with granularity", Check7DinterpGranular);
- Check(ctx, "8D interpolation with granularity", Check8DinterpGranular);
- // Encoding of colorspaces
- Check(ctx, "Lab to LCh and back (float only) ", CheckLab2LCh);
- Check(ctx, "Lab to XYZ and back (float only) ", CheckLab2XYZ);
- Check(ctx, "Lab to xyY and back (float only) ", CheckLab2xyY);
- Check(ctx, "Lab V2 encoding", CheckLabV2encoding);
- Check(ctx, "Lab V4 encoding", CheckLabV4encoding);
- // BlackBody
- Check(ctx, "Blackbody radiator", CheckTemp2CHRM);
- // Tone curves
- Check(ctx, "Linear gamma curves (16 bits)", CheckGammaCreation16);
- Check(ctx, "Linear gamma curves (float)", CheckGammaCreationFlt);
- Check(ctx, "Curve 1.8 (float)", CheckGamma18);
- Check(ctx, "Curve 2.2 (float)", CheckGamma22);
- Check(ctx, "Curve 3.0 (float)", CheckGamma30);
- Check(ctx, "Curve 1.8 (table)", CheckGamma18Table);
- Check(ctx, "Curve 2.2 (table)", CheckGamma22Table);
- Check(ctx, "Curve 3.0 (table)", CheckGamma30Table);
- Check(ctx, "Curve 1.8 (word table)", CheckGamma18TableWord);
- Check(ctx, "Curve 2.2 (word table)", CheckGamma22TableWord);
- Check(ctx, "Curve 3.0 (word table)", CheckGamma30TableWord);
- Check(ctx, "Parametric curves", CheckParametricToneCurves);
- Check(ctx, "Join curves", CheckJointCurves);
- Check(ctx, "Join curves descending", CheckJointCurvesDescending);
- Check(ctx, "Join curves degenerated", CheckReverseDegenerated);
- Check(ctx, "Join curves sRGB (Float)", CheckJointFloatCurves_sRGB);
- Check(ctx, "Join curves sRGB (16 bits)", CheckJoint16Curves_sRGB);
- Check(ctx, "Join curves sigmoidal", CheckJointCurvesSShaped);
- // LUT basics
- Check(ctx, "LUT creation & dup", CheckLUTcreation);
- Check(ctx, "1 Stage LUT ", Check1StageLUT);
- Check(ctx, "2 Stage LUT ", Check2StageLUT);
- Check(ctx, "2 Stage LUT (16 bits)", Check2Stage16LUT);
- Check(ctx, "3 Stage LUT ", Check3StageLUT);
- Check(ctx, "3 Stage LUT (16 bits)", Check3Stage16LUT);
- Check(ctx, "4 Stage LUT ", Check4StageLUT);
- Check(ctx, "4 Stage LUT (16 bits)", Check4Stage16LUT);
- Check(ctx, "5 Stage LUT ", Check5StageLUT);
- Check(ctx, "5 Stage LUT (16 bits) ", Check5Stage16LUT);
- Check(ctx, "6 Stage LUT ", Check6StageLUT);
- Check(ctx, "6 Stage LUT (16 bits) ", Check6Stage16LUT);
- // LUT operation
- Check(ctx, "Lab to Lab LUT (float only) ", CheckLab2LabLUT);
- Check(ctx, "XYZ to XYZ LUT (float only) ", CheckXYZ2XYZLUT);
- Check(ctx, "Lab to Lab MAT LUT (float only) ", CheckLab2LabMatLUT);
- Check(ctx, "Named Color LUT", CheckNamedColorLUT);
- Check(ctx, "Usual formatters", CheckFormatters16);
- Check(ctx, "Floating point formatters", CheckFormattersFloat);
- #ifndef CMS_NO_HALF_SUPPORT
- Check(ctx, "HALF formatters", CheckFormattersHalf);
- #endif
- // ChangeBuffersFormat
- Check(ctx, "ChangeBuffersFormat", CheckChangeBufferFormat);
- // MLU
- Check(ctx, "Multilocalized Unicode", CheckMLU);
- Check(ctx, "Multilocalized Unicode (II)", CheckMLU_UTF8);
- // Named color
- Check(ctx, "Named color lists", CheckNamedColorList);
- Check(ctx, "Create named color profile", CreateNamedColorProfile);
- // Profile I/O (this one is huge!)
- Check(ctx, "Profile creation", CheckProfileCreation);
- Check(ctx, "Header version", CheckVersionHeaderWriting);
- Check(ctx, "Multilocalized profile", CheckMultilocalizedProfile);
- // Error reporting
- Check(ctx, "Error reporting on bad profiles", CheckErrReportingOnBadProfiles);
- Check(ctx, "Error reporting on bad transforms", CheckErrReportingOnBadTransforms);
- // Transforms
- Check(ctx, "Curves only transforms", CheckCurvesOnlyTransforms);
- Check(ctx, "Float Lab->Lab transforms", CheckFloatLabTransforms);
- Check(ctx, "Encoded Lab->Lab transforms", CheckEncodedLabTransforms);
- Check(ctx, "Stored identities", CheckStoredIdentities);
- Check(ctx, "Matrix-shaper transform (float)", CheckMatrixShaperXFORMFloat);
- Check(ctx, "Matrix-shaper transform (16 bits)", CheckMatrixShaperXFORM16);
- Check(ctx, "Matrix-shaper transform (8 bits)", CheckMatrixShaperXFORM8);
- Check(ctx, "Primaries of sRGB", CheckRGBPrimaries);
- // Known values
- Check(ctx, "Known values across matrix-shaper", Chack_sRGB_Float);
- Check(ctx, "Gray input profile", CheckInputGray);
- Check(ctx, "Gray Lab input profile", CheckLabInputGray);
- Check(ctx, "Gray output profile", CheckOutputGray);
- Check(ctx, "Gray Lab output profile", CheckLabOutputGray);
- Check(ctx, "Matrix-shaper proofing transform (float)", CheckProofingXFORMFloat);
- Check(ctx, "Matrix-shaper proofing transform (16 bits)", CheckProofingXFORM16);
- Check(ctx, "Gamut check", CheckGamutCheck);
- Check(ctx, "CMYK roundtrip on perceptual transform", CheckCMYKRoundtrip);
- Check(ctx, "CMYK perceptual transform", CheckCMYKPerceptual);
- // Check("CMYK rel.col. transform", CheckCMYKRelCol);
- Check(ctx, "Black ink only preservation", CheckKOnlyBlackPreserving);
- Check(ctx, "Black plane preservation", CheckKPlaneBlackPreserving);
- Check(ctx, "Deciding curve types", CheckV4gamma);
- Check(ctx, "Black point detection", CheckBlackPoint);
- Check(ctx, "TAC detection", CheckTAC);
- Check(ctx, "CGATS parser", CheckCGATS);
- Check(ctx, "CGATS parser on junk", CheckCGATS2);
- Check(ctx, "CGATS parser on overflow", CheckCGATS_Overflow);
- Check(ctx, "PostScript generator", CheckPostScript);
- Check(ctx, "Segment maxima GBD", CheckGBD);
- Check(ctx, "MD5 digest", CheckMD5);
- Check(ctx, "Linking", CheckLinking);
- Check(ctx, "floating point tags on XYZ", CheckFloatXYZ);
- Check(ctx, "RGB->Lab->RGB with alpha on FLT", ChecksRGB2LabFLT);
- Check(ctx, "Parametric curve on Rec709", CheckParametricRec709);
- Check(ctx, "Floating Point sampled curve with non-zero start", CheckFloatSamples);
- Check(ctx, "Floating Point segmented curve with short sampled segment", CheckFloatSegments);
- Check(ctx, "Read RAW tags", CheckReadRAW);
- Check(ctx, "Check MetaTag", CheckMeta);
- Check(ctx, "Null transform on floats", CheckFloatNULLxform);
- Check(ctx, "Set free a tag", CheckRemoveTag);
- Check(ctx, "Matrix simplification", CheckMatrixSimplify);
- Check(ctx, "Planar 8 optimization", CheckPlanar8opt);
- Check(ctx, "Swap endian feature", CheckSE);
- Check(ctx, "Transform line stride RGB", CheckTransformLineStride);
- Check(ctx, "Forged MPE profile", CheckForgedMPE);
- Check(ctx, "Proofing intersection", CheckProofingIntersection);
- Check(ctx, "Empty MLUC", CheckEmptyMLUC);
- Check(ctx, "sRGB round-trips", Check_sRGB_Rountrips);
- Check(ctx, "OkLab color space", Check_OkLab);
- Check(ctx, "OkLab color space (2)", Check_OkLab2);
- Check(ctx, "Gamma space detection", CheckGammaSpaceDetection);
- Check(ctx, "Unbounded mode w/ integer output", CheckIntToFloatTransform);
- Check(ctx, "Corrupted built-in by using cmsWriteRawTag", CheckInducedCorruption);
- Check(ctx, "Bad CGATS file", CheckBadCGATS);
- Check(ctx, "Saving linearization devicelink", CheckSaveLinearizationDevicelink);
- }
- if (DoPluginTests)
- {
- Check(ctx, "Context memory handling", CheckAllocContext);
- Check(ctx, "Simple context functionality", CheckSimpleContext);
- Check(ctx, "Alarm codes context", CheckAlarmColorsContext);
- Check(ctx, "Adaptation state context", CheckAdaptationStateContext);
- Check(ctx, "1D interpolation plugin", CheckInterp1DPlugin);
- Check(ctx, "3D interpolation plugin", CheckInterp3DPlugin);
- Check(ctx, "Parametric curve plugin", CheckParametricCurvePlugin);
- Check(ctx, "Formatters plugin", CheckFormattersPlugin);
- Check(ctx, "Tag type plugin", CheckTagTypePlugin);
- Check(ctx, "MPE type plugin", CheckMPEPlugin);
- Check(ctx, "Optimization plugin", CheckOptimizationPlugin);
- Check(ctx, "Rendering intent plugin", CheckIntentPlugin);
- Check(ctx, "Full transform plugin", CheckTransformPlugin);
- Check(ctx, "Mutex plugin", CheckMutexPlugin);
- }
- if (DoSpeedTests)
- SpeedTest(ctx);
- #ifdef CMS_IS_WINDOWS_
- if (DoZooTests)
- CheckProfileZOO(ctx);
- #endif
- DebugMemPrintTotals();
- cmsUnregisterPlugins(NULL);
- // Cleanup
- if (DoCheckTests || DoSpeedTests)
- RemoveTestProfiles();
- return TotalFail;
- }
|