summit/frontend/node_modules/@monogrid/gainmap-js/dist/encode.min.js

6 lines
16 KiB
JavaScript

/**
* @monogrid/gainmap-js v3.4.0
* With ❤️, by MONOGRID <gainmap@monogrid.com>
*/
import{c as n}from"./compress-DY-CSunh.js";import{DataTexture as e,RGBAFormat as t,UVMapping as o,RepeatWrapping as r,LinearFilter as a,LinearSRGBColorSpace as i,ShaderMaterial as s,NoBlending as c,Vector3 as m,UnsignedByteType as l,ACESFilmicToneMapping as p,LinearToneMapping as d,NeutralToneMapping as u,AgXToneMapping as g,CineonToneMapping as f,ReinhardToneMapping as h,SRGBColorSpace as v,AlphaFormat as M,RGBFormat as x,DepthFormat as _,DepthStencilFormat as C,RedFormat as A,RedIntegerFormat as w,RGFormat as T,RGIntegerFormat as E,RGBIntegerFormat as y,RGBAIntegerFormat as I,Vector2 as S,WebGLRenderTarget as N,ClampToEdgeWrapping as R,NearestFilter as L,DataUtils as O,FloatType as b}from"three";import{Q as U}from"./QuadRenderer-BoQMkXLf.js";const P=n=>{let s;if(n instanceof e){if(!(n.image.data instanceof Uint16Array||n.image.data instanceof Float32Array))throw new Error("Provided image is not HDR");s=n}else s=new e(n.data,n.width,n.height,"format"in n?n.format:t,n.type,o,r,r,a,a,1,"colorSpace"in n&&"srgb"===n.colorSpace?n.colorSpace:i),"header"in n&&"gamma"in n&&(s.flipY=!0),s.needsUpdate=!0;return s};class D extends s{_minContentBoost;_maxContentBoost;_offsetSdr;_offsetHdr;_gamma;constructor({sdr:n,hdr:e,offsetSdr:t,offsetHdr:o,maxContentBoost:r,minContentBoost:a,gamma:i}){if(!r)throw new Error("maxContentBoost is required");if(!n)throw new Error("sdr is required");if(!e)throw new Error("hdr is required");const s=i||[1,1,1],l=t||[1/64,1/64,1/64],p=o||[1/64,1/64,1/64],d=a||1,u=Math.max(r,1.0001);super({name:"GainMapEncoderMaterial",vertexShader:"\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n",fragmentShader:"\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform sampler2D sdr;\nuniform sampler2D hdr;\nuniform vec3 gamma;\nuniform vec3 offsetSdr;\nuniform vec3 offsetHdr;\nuniform float minLog2;\nuniform float maxLog2;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec3 sdrColor = texture2D(sdr, vUv).rgb;\n vec3 hdrColor = texture2D(hdr, vUv).rgb;\n\n vec3 pixelGain = (hdrColor + offsetHdr) / (sdrColor + offsetSdr);\n vec3 logRecovery = (log2(pixelGain) - minLog2) / (maxLog2 - minLog2);\n vec3 clampedRecovery = saturate(logRecovery);\n gl_FragColor = vec4(pow(clampedRecovery, gamma), 1.0);\n}\n",uniforms:{sdr:{value:n},hdr:{value:e},gamma:{value:(new m).fromArray(s)},offsetSdr:{value:(new m).fromArray(l)},offsetHdr:{value:(new m).fromArray(p)},minLog2:{value:Math.log2(d)},maxLog2:{value:Math.log2(u)}},blending:c,depthTest:!1,depthWrite:!1}),this._minContentBoost=d,this._maxContentBoost=u,this._offsetSdr=l,this._offsetHdr=p,this._gamma=s,this.needsUpdate=!0,this.uniformsNeedUpdate=!0}get gamma(){return this._gamma}set gamma(n){this._gamma=n,this.uniforms.gamma.value=(new m).fromArray(n)}get offsetHdr(){return this._offsetHdr}set offsetHdr(n){this._offsetHdr=n,this.uniforms.offsetHdr.value=(new m).fromArray(n)}get offsetSdr(){return this._offsetSdr}set offsetSdr(n){this._offsetSdr=n,this.uniforms.offsetSdr.value=(new m).fromArray(n)}get minContentBoost(){return this._minContentBoost}set minContentBoost(n){this._minContentBoost=n,this.uniforms.minLog2.value=Math.log2(n)}get maxContentBoost(){return this._maxContentBoost}set maxContentBoost(n){this._maxContentBoost=n,this.uniforms.maxLog2.value=Math.log2(n)}get gainMapMin(){return[Math.log2(this._minContentBoost),Math.log2(this._minContentBoost),Math.log2(this._minContentBoost)]}get gainMapMax(){return[Math.log2(this._maxContentBoost),Math.log2(this._maxContentBoost),Math.log2(this._maxContentBoost)]}get hdrCapacityMin(){return Math.min(Math.max(0,this.gainMapMin[0]),Math.max(0,this.gainMapMin[1]),Math.max(0,this.gainMapMin[2]))}get hdrCapacityMax(){return Math.max(Math.max(0,this.gainMapMax[0]),Math.max(0,this.gainMapMax[1]),Math.max(0,this.gainMapMax[2]))}}const B=n=>{const{image:e,sdr:t,renderer:o}=n,r=P(e),a=new D({...n,sdr:t.renderTarget.texture,hdr:r}),s=new U({width:r.image.width,height:r.image.height,type:l,colorSpace:i,material:a,renderer:o,renderTargetOptions:n.renderTargetOptions});try{s.render()}catch(n){throw s.disposeOnDemandRenderer(),n}return s};class F extends s{_brightness=0;_contrast=1;_saturation=1;_exposure=1;_toneMapping;_map;constructor({map:n,toneMapping:e}){super({name:"SDRMaterial",vertexShader:"\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n",fragmentShader:"\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n\nuniform sampler2D map;\nuniform float brightness;\nuniform float contrast;\nuniform float saturation;\nuniform float exposure;\n\nvarying vec2 vUv;\n\nmat4 brightnessMatrix( float brightness ) {\n return mat4(\n 1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n brightness, brightness, brightness, 1\n );\n}\n\nmat4 contrastMatrix( float contrast ) {\n float t = ( 1.0 - contrast ) / 2.0;\n return mat4(\n contrast, 0, 0, 0,\n 0, contrast, 0, 0,\n 0, 0, contrast, 0,\n t, t, t, 1\n );\n}\n\nmat4 saturationMatrix( float saturation ) {\n vec3 luminance = vec3( 0.3086, 0.6094, 0.0820 );\n float oneMinusSat = 1.0 - saturation;\n vec3 red = vec3( luminance.x * oneMinusSat );\n red+= vec3( saturation, 0, 0 );\n vec3 green = vec3( luminance.y * oneMinusSat );\n green += vec3( 0, saturation, 0 );\n vec3 blue = vec3( luminance.z * oneMinusSat );\n blue += vec3( 0, 0, saturation );\n return mat4(\n red, 0,\n green, 0,\n blue, 0,\n 0, 0, 0, 1\n );\n}\n\nvec3 RRTAndODTFit( vec3 v ) {\n vec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n return a / b;\n}\n\nvec3 ACESFilmicToneMapping( vec3 color ) {\n // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT\n const mat3 ACESInputMat = mat3(\n vec3( 0.59719, 0.07600, 0.02840 ), // transposed from source\n vec3( 0.35458, 0.90834, 0.13383 ),\n vec3( 0.04823, 0.01566, 0.83777 )\n );\n // ODT_SAT => XYZ => D60_2_D65 => sRGB\n const mat3 ACESOutputMat = mat3(\n vec3( 1.60475, -0.10208, -0.00327 ), // transposed from source\n vec3( -0.53108, 1.10813, -0.07276 ),\n vec3( -0.07367, -0.00605, 1.07602 )\n );\n color = ACESInputMat * color;\n // Apply RRT and ODT\n color = RRTAndODTFit( color );\n color = ACESOutputMat * color;\n // Clamp to [0, 1]\n return saturate( color );\n}\n\n// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf\nvec3 ReinhardToneMapping( vec3 color ) {\n return saturate( color / ( vec3( 1.0 ) + color ) );\n}\n\n// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/\nvec3 CineonToneMapping( vec3 color ) {\n // optimized filmic operator by Jim Hejl and Richard Burgess-Dawson\n color = max( vec3( 0.0 ), color - 0.004 );\n return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n\n// nothing\nvec3 LinearToneMapping ( vec3 color ) {\n return color;\n}\n\n// Matrices for rec 2020 <> rec 709 color space conversion\n// matrix provided in row-major order so it has been transposed\n// https://www.itu.int/pub/R-REP-BT.2407-2017\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n vec3( 1.6605, - 0.1246, - 0.0182 ),\n vec3( - 0.5876, 1.1329, - 0.1006 ),\n vec3( - 0.0728, - 0.0083, 1.1187 )\n);\n\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n vec3( 0.6274, 0.0691, 0.0164 ),\n vec3( 0.3293, 0.9195, 0.0880 ),\n vec3( 0.0433, 0.0113, 0.8956 )\n);\n\n// https://iolite-engine.com/blog_posts/minimal_agx_implementation\n// Mean error^2: 3.6705141e-06\nvec3 agxDefaultContrastApprox( vec3 x ) {\n vec3 x2 = x * x;\n vec3 x4 = x2 * x2;\n return + 15.5 * x4 * x2\n - 40.14 * x4 * x\n + 31.96 * x4\n - 6.868 * x2 * x\n + 0.4298 * x2\n + 0.1191 * x\n - 0.00232;\n}\n\n// AgX Tone Mapping implementation based on Filament, which in turn is based\n// on Blender's implementation using rec 2020 primaries\n// https://github.com/google/filament/pull/7236\n// Inputs and outputs are encoded as Linear-sRGB.\n\nvec3 AgXToneMapping( vec3 color ) {\n\n // AgX constants\n const mat3 AgXInsetMatrix = mat3(\n vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n );\n\n // explicit AgXOutsetMatrix generated from Filaments AgXOutsetMatrixInv\n const mat3 AgXOutsetMatrix = mat3(\n vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n );\n\n // LOG2_MIN = -10.0\n // LOG2_MAX = +6.5\n // MIDDLE_GRAY = 0.18\n const float AgxMinEv = - 12.47393; // log2( pow( 2, LOG2_MIN ) * MIDDLE_GRAY )\n const float AgxMaxEv = 4.026069; // log2( pow( 2, LOG2_MAX ) * MIDDLE_GRAY )\n\n color = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\n color = AgXInsetMatrix * color;\n\n // Log2 encoding\n color = max( color, 1e-10 ); // avoid 0 or negative numbers for log2\n color = log2( color );\n color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\n color = clamp( color, 0.0, 1.0 );\n\n // Apply sigmoid\n color = agxDefaultContrastApprox( color );\n\n // Apply AgX look\n // v = agxLook(v, look);\n\n color = AgXOutsetMatrix * color;\n\n // Linearize\n color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\n color = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\n // Gamut mapping. Simple clamp for now.\n color = clamp( color, 0.0, 1.0 );\n\n return color;\n\n}\n\n// https://modelviewer.dev/examples/tone-mapping\n\nvec3 NeutralToneMapping( vec3 color ) {\n\n const float StartCompression = 0.8 - 0.04;\n const float Desaturation = 0.15;\n\n float x = min( color.r, min( color.g, color.b ) );\n\n float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n\n color -= offset;\n\n float peak = max( color.r, max( color.g, color.b ) );\n\n if ( peak < StartCompression ) return color;\n\n float d = 1. - StartCompression;\n\n float newPeak = 1. - d * d / ( peak + d - StartCompression );\n\n color *= newPeak / peak;\n\n float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\n\n return mix( color, vec3( newPeak ), g );\n\n}\n\n\n\nvoid main() {\n vec4 color = texture2D(map, vUv);\n\n vec4 exposed = vec4(exposure * color.rgb, color.a);\n\n vec4 tonemapped = vec4(TONEMAPPING_FUNCTION(exposed.rgb), color.a);\n\n vec4 adjusted =\n brightnessMatrix( brightness ) *\n contrastMatrix( contrast ) *\n saturationMatrix( saturation ) *\n tonemapped;\n\n gl_FragColor = adjusted;\n}\n",uniforms:{map:{value:n},brightness:{value:0},contrast:{value:1},saturation:{value:1},exposure:{value:1}},blending:c,depthTest:!1,depthWrite:!1}),this._map=n,this.toneMapping=this._toneMapping=e||p,this.needsUpdate=!0,this.uniformsNeedUpdate=!0}get toneMapping(){return this._toneMapping}set toneMapping(n){let e=!1;switch(n){case p:this.defines.TONEMAPPING_FUNCTION="ACESFilmicToneMapping",e=!0;break;case h:this.defines.TONEMAPPING_FUNCTION="ReinhardToneMapping",e=!0;break;case f:this.defines.TONEMAPPING_FUNCTION="CineonToneMapping",e=!0;break;case d:this.defines.TONEMAPPING_FUNCTION="LinearToneMapping",e=!0;break;case g:this.defines.TONEMAPPING_FUNCTION="AgXToneMapping",e=!0;break;case u:this.defines.TONEMAPPING_FUNCTION="NeutralToneMapping",e=!0;break;default:console.error(`Unsupported toneMapping: ${n}. Using LinearToneMapping.`),this.defines.TONEMAPPING_FUNCTION="LinearToneMapping",this._toneMapping=d}e&&(this._toneMapping=n),this.needsUpdate=!0}get brightness(){return this._brightness}set brightness(n){this._brightness=n,this.uniforms.brightness.value=n}get contrast(){return this._contrast}set contrast(n){this._contrast=n,this.uniforms.contrast.value=n}get saturation(){return this._saturation}set saturation(n){this._saturation=n,this.uniforms.saturation.value=n}get exposure(){return this._exposure}set exposure(n){this._exposure=n,this.uniforms.exposure.value=n}get map(){return this._map}set map(n){this._map=n,this.uniforms.map.value=n}}const G=(n,e,t,o)=>{n.needsUpdate=!0;const r=new U({width:n.image.width,height:n.image.height,type:l,colorSpace:v,material:new F({map:n,toneMapping:t}),renderer:e,renderTargetOptions:o});try{r.render()}catch(n){throw r.disposeOnDemandRenderer(),n}return r},k=n=>{const{image:e,renderer:t}=n,o=P(e),r=G(o,t,n.toneMapping,n.renderTargetOptions),a=B({...n,image:o,sdr:r,renderer:r.renderer});return{sdr:r,gainMap:a,hdr:o,getMetadata:()=>({gainMapMax:a.material.gainMapMax,gainMapMin:a.material.gainMapMin,gamma:a.material.gamma,hdrCapacityMax:a.material.hdrCapacityMax,hdrCapacityMin:a.material.hdrCapacityMin,offsetHdr:a.material.offsetHdr,offsetSdr:a.material.offsetSdr})}},H=async e=>{const t=k(e),{mimeType:o,quality:r,flipY:a,withWorker:i}=e;let s,c,m;const l=new ImageData(t.sdr.toArray(),t.sdr.width,t.sdr.height),p=new ImageData(t.gainMap.toArray(),t.gainMap.width,t.gainMap.height);if(i){const n=await Promise.all([i.compress({source:l,mimeType:o,quality:r,flipY:a}),i.compress({source:p,mimeType:o,quality:r,flipY:a})]);s=n,c=n[0].source,m=n[1].source}else s=await Promise.all([n({source:l,mimeType:o,quality:r,flipY:a}),n({source:p,mimeType:o,quality:r,flipY:a})]),c=l.data,m=p.data;return t.sdr.dispose(),t.gainMap.dispose(),{...t,...t.getMetadata(),sdr:s[0],gainMap:s[1],rawSDR:c,rawGainMap:m}},X=(n,e="max",o)=>{const r=P(n);if(r.format!==M&&r.format!==x&&r.format!==t&&r.format!==_&&r.format!==C&&r.format!==A&&r.format!==w&&r.format!==T&&r.format!==E&&r.format!==y&&r.format!==I)throw new Error("Unsupported texture format");const a=new s({vertexShader:"\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n",fragmentShader:"\nprecision mediump float;\n\n#ifndef CELL_SIZE\n #define CELL_SIZE 2\n#endif\n\n#ifndef COMPARE_FUNCTION\n #define COMPARE_FUNCTION max\n#endif\n\n#ifndef INITIAL_VALUE\n #define INITIAL_VALUE 0\n#endif\n\nuniform sampler2D map;\nuniform vec2 u_srcResolution;\n\nvarying vec2 vUv;\n\nvoid main() {\n // compute the first pixel the source cell\n vec2 srcPixel = floor(gl_FragCoord.xy) * float(CELL_SIZE);\n\n // one pixel in source\n vec2 onePixel = vec2(1) / u_srcResolution;\n\n // uv for first pixel in cell. +0.5 for center of pixel\n vec2 uv = (srcPixel + 0.5) * onePixel;\n\n vec4 resultColor = vec4(INITIAL_VALUE);\n\n for (int y = 0; y < CELL_SIZE; ++y) {\n for (int x = 0; x < CELL_SIZE; ++x) {\n resultColor = COMPARE_FUNCTION(resultColor, texture2D(map, uv + vec2(x, y) * onePixel));\n }\n }\n\n gl_FragColor = resultColor;\n}\n",uniforms:{u_srcResolution:{value:new S(r.image.width,r.image.height)},map:{value:r}},defines:{CELL_SIZE:2,COMPARE_FUNCTION:e,INITIAL_VALUE:"max"===e?0:65504}});r.needsUpdate=!0,a.needsUpdate=!0;let i=r.image.width,c=r.image.height;const m=new U({width:i,height:c,type:r.type,colorSpace:r.colorSpace,material:a,renderer:o}),l=[];for(;i>1||c>1;){i=Math.max(1,(i+2-1)/2|0),c=Math.max(1,(c+2-1)/2|0);const n=new N(i,c,{type:m.type,format:r.format,colorSpace:m.colorSpace,minFilter:L,magFilter:L,wrapS:R,wrapT:R,generateMipmaps:!1,depthBuffer:!1,stencilBuffer:!1});l.push(n)}i=r.image.width,c=r.image.height,l.forEach(n=>{i=Math.max(1,(i+2-1)/2|0),c=Math.max(1,(c+2-1)/2|0),m.renderTarget=n,m.render(),a.uniforms.map.value=n.texture,a.uniforms.u_srcResolution.value.x=i,a.uniforms.u_srcResolution.value.y=c});const p=m.toArray();return m.dispose(),l.forEach(n=>n.dispose()),[m.type===b?p[0]:O.fromHalfFloat(p[0]),m.type===b?p[1]:O.fromHalfFloat(p[1]),m.type===b?p[2]:O.fromHalfFloat(p[2])]};export{D as GainMapEncoderMaterial,F as SDRMaterial,n as compress,k as encode,H as encodeAndCompress,X as findTextureMinMax,B as getGainMap,G as getSDRRendition};