diff --git a/codecs/basis/enc/basis_enc.cpp b/codecs/basis/enc/basis_enc.cpp index d32e9808..fb2dfdcf 100644 --- a/codecs/basis/enc/basis_enc.cpp +++ b/codecs/basis/enc/basis_enc.cpp @@ -13,8 +13,10 @@ struct BasisOptions { bool uastc; bool mipmap; bool srgb_mipmap; + std::string mipmap_filter; bool perceptual; bool y_flip; + uint32_t mipmap_min_dimension; }; thread_local const val Uint8Array = val::global("Uint8Array"); @@ -53,7 +55,8 @@ val encode(std::string image_in, int image_width, int image_height, BasisOptions params.m_y_flip = opts.y_flip; params.m_mip_gen = opts.mipmap; params.m_mip_srgb = opts.srgb_mipmap; - params.m_mip_filter = "box"; + params.m_mip_filter = opts.mipmap_filter; + params.m_mip_smallest_dimension = opts.mipmap_min_dimension; params.m_quality_level = opts.quality; params.m_compression_level = opts.compression; params.m_source_images.push_back(img); @@ -80,7 +83,9 @@ EMSCRIPTEN_BINDINGS(my_module) { .field("perceptual", &BasisOptions::perceptual) .field("y_flip", &BasisOptions::y_flip) .field("mipmap", &BasisOptions::mipmap) - .field("srgb_mipmap", &BasisOptions::srgb_mipmap); + .field("srgb_mipmap", &BasisOptions::srgb_mipmap) + .field("mipmap_filter", &BasisOptions::mipmap_filter) + .field("mipmap_min_dimension", &BasisOptions::mipmap_min_dimension); function("encode", &encode); } diff --git a/codecs/basis/enc/basis_enc.d.ts b/codecs/basis/enc/basis_enc.d.ts index 629bd961..ca34aaa6 100644 --- a/codecs/basis/enc/basis_enc.d.ts +++ b/codecs/basis/enc/basis_enc.d.ts @@ -6,6 +6,8 @@ export interface EncodeOptions { mipmap: boolean; srgb_mipmap: boolean; perceptual: boolean; + mipmap_filter: string; + mipmap_min_dimension: number; } export interface BasisModule extends EmscriptenWasm.Module { diff --git a/codecs/basis/enc/basis_enc.js b/codecs/basis/enc/basis_enc.js index b3cf3e7b..68919dda 100644 --- a/codecs/basis/enc/basis_enc.js +++ b/codecs/basis/enc/basis_enc.js @@ -40,10 +40,10 @@ h.length;++p)q=1===p?"thisWired":"arg"+(p-2)+"Wired",null!==h[p].ea&&(m+=q+"_dto c){function d(g){g>>=2;var k=I;return new e(F,k[g+1],k[g])}var e=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=Q(c);P(a,{name:c,fromWireType:d,argPackAdvance:8,readValueFromPointer:d},{qa:!0})},x:function(a,b){b=Q(b);var c="std::string"===b;P(a,{name:b,fromWireType:function(d){var e=I[d>>2];if(c)for(var g=d+4,k=0;k<=e;++k){var h=d+4+k;if(k==e||0==C[h]){g=ia(g,h-g);if(void 0===l)var l=g;else l+=String.fromCharCode(0),l+=g;g=h+1}}else{l=Array(e); for(k=0;k=q&&(q=65536+((q&1023)<<10)|e.charCodeAt(++n)&1023);127>=q?++m:m=2047>=q?m+2:65535>=q?m+3:m+4}return m}: function(){return e.length})(),h=sb(4+k+1);I[h>>2]=k;if(c&&g)ja(e,h+4,k+1);else if(g)for(g=0;g>2],n=k(),q,y=l+4,z=0;z<=m;++z){var p=l+4+z*b;if(z==m||0==n[p>>h])y=d(y,p-y),void 0===q?q=y:(q+=String.fromCharCode(0),q+=y),y=p+b}V(l);return q},toWireType:function(l,m){"string"!==typeof m&&R("Cannot pass non-string to C++ string type "+c);var n=g(m),q=sb(4+n+b);I[q>>2]=n>>h;e(m,q+4,n+b);null!==l&&l.push(V,q);return q},argPackAdvance:8,readValueFromPointer:Oa,ea:function(l){V(l)}})},R:function(a,b,c,d,e,g){Ma[a]={name:Q(b),sa:U(c,d),ta:U(e,g),ia:[]}},m:function(a, +fromWireType:function(l){for(var m=I[l>>2],n=k(),q,y=l+4,z=0;z<=m;++z){var p=l+4+z*b;if(z==m||0==n[p>>h])y=d(y,p-y),void 0===q?q=y:(q+=String.fromCharCode(0),q+=y),y=p+b}V(l);return q},toWireType:function(l,m){"string"!==typeof m&&R("Cannot pass non-string to C++ string type "+c);var n=g(m),q=sb(4+n+b);I[q>>2]=n>>h;e(m,q+4,n+b);null!==l&&l.push(V,q);return q},argPackAdvance:8,readValueFromPointer:Oa,ea:function(l){V(l)}})},R:function(a,b,c,d,e,g){Ma[a]={name:Q(b),sa:U(c,d),ta:U(e,g),ia:[]}},l:function(a, b,c,d,e,g,k,h,l,m){Ma[a].ia.push({la:Q(b),pa:c,na:U(d,e),oa:g,Aa:k,za:U(h,l),Ba:m})},N:function(a,b){b=Q(b);P(a,{Ea:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},o:Za,A:function(a){if(0===a)return T(mb());var b=lb[a];a=void 0===b?Q(a):b;return T(mb()[a])},O:function(a){4>> 2) + "+g+'], "parameter '+g+'");\nvar arg'+g+" = argType"+g+".readValueFromPointer(args);\nargs += argType"+g+"['argPackAdvance'];\n";e=(new Function("requireRegisteredType","Module","__emval_register",k+("var obj = new constructor("+e+");\nreturn __emval_register(obj);\n}\n")))(nb,f,T);ob[b]=e}return e(a,c,d)},z:function(a,b){a=nb(a,"_emval_take_value");a=a.readValueFromPointer(b); -return T(a)},f:function(){x()},h:function(a,b){W(a,b||1);throw"longjmp";},F:function(a,b,c){C.copyWithin(a,b,b+c)},l:function(a){a>>>=0;var b=C.length;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(16777216,a,d);0>>16);va(B.buffer);var e=1;break a}catch(g){}e=void 0}if(e)return!0}return!1},v:function(){return 0},I:function(a,b,c,d){a=La.Da(a);b=La.Ca(a,b,c);E[d>> +return T(a)},f:function(){x()},h:function(a,b){W(a,b||1);throw"longjmp";},F:function(a,b,c){C.copyWithin(a,b,b+c)},m:function(a){a>>>=0;var b=C.length;if(2147483648=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(16777216,a,d);0>>16);va(B.buffer);var e=1;break a}catch(g){}e=void 0}if(e)return!0}return!1},v:function(){return 0},I:function(a,b,c,d){a=La.Da(a);b=La.Ca(a,b,c);E[d>> 2]=b;return 0},C:function(){},u:function(a,b,c,d){for(var e=0,g=0;g>2],h=E[b+(8*g+4)>>2],l=0;l>2]=e;return 0},d:function(){return ea|0},i:function(a){var b=Date.now();E[a>>2]=b/1E3|0;E[a+4>>2]=b%1E3*1E3|0;return 0},n:tb,g:ub,s:vb,r:wb,p:xb,e:yb,D:zb,a:B,G:function(){},c:function(a){ea= a|0},H:function(a){switch(a){case 30:return 16384;case 85:return 131072;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1; case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1E3;case 89:return 700;case 71:return 256; diff --git a/codecs/basis/enc/basis_enc.wasm b/codecs/basis/enc/basis_enc.wasm index 158e42be..32267f2c 100755 Binary files a/codecs/basis/enc/basis_enc.wasm and b/codecs/basis/enc/basis_enc.wasm differ diff --git a/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/index.ts b/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/index.ts index 2a41f13b..4683bc74 100644 --- a/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/index.ts +++ b/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/index.ts @@ -112,18 +112,23 @@ class RangeInputElement extends HTMLElement { this.dispatchEvent(retargetted); }; + private _formatDisplayValue(value: number): string { + const labelPrecision = + Number(this.labelPrecision) || getPrescision(this.step) || 0; + if (labelPrecision) { + return value.toFixed(labelPrecision); + } + return Math.round(value).toString(); + } + private _update = () => { // Not connected? if (!this._valueDisplay) return; const value = Number(this.value) || 0; const min = Number(this.min) || 0; const max = Number(this.max) || 100; - const labelPrecision = - Number(this.labelPrecision) || getPrescision(this.step) || 0; const percent = (100 * (value - min)) / (max - min); - const displayValue = labelPrecision - ? value.toFixed(labelPrecision) - : Math.round(value).toString(); + const displayValue = this._formatDisplayValue(value); this._valueDisplay!.textContent = displayValue; this.style.setProperty('--value-percent', percent + '%'); diff --git a/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/missing-types.d.ts b/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/missing-types.d.ts index 7800e014..fab3b113 100644 --- a/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/missing-types.d.ts +++ b/src/client/lazy-app/Compress/Options/Range/custom-els/RangeInput/missing-types.d.ts @@ -1,7 +1,7 @@ declare module 'preact' { namespace createElement.JSX { interface IntrinsicElements { - 'range-input': HTMLAttributes; + 'range-input': HTMLAttributes & { formatter?: (v: number) => string }; } } } diff --git a/src/features/encoders/basis/client/index.tsx b/src/features/encoders/basis/client/index.tsx index 2317c08b..6fc5ac75 100644 --- a/src/features/encoders/basis/client/index.tsx +++ b/src/features/encoders/basis/client/index.tsx @@ -1,6 +1,6 @@ -import { EncodeOptions } from '../shared/meta'; +import { EncodeOptions, defaultOptions } from '../shared/meta'; import type WorkerBridge from 'client/lazy-app/worker-bridge'; -import { h, Component } from 'preact'; +import { h, Component, Fragment } from 'preact'; import { inputFieldChecked, inputFieldValueAsNumber, @@ -50,7 +50,13 @@ export class Options extends Component { perceptual: inputFieldChecked(form.perceptual, options.perceptual), mipmap: inputFieldChecked(form.mipmap, options.mipmap), srgb_mipmap: inputFieldChecked(form.srgb_mipmap, options.srgb_mipmap), - // .value + mipmap_filter: form.mipmap_filter?.value ?? defaultOptions.mipmap_filter, + mipmap_min_dimension: + 2 ** + inputFieldValueAsNumber( + form.mipmap_min_dimension, + options.mipmap_min_dimension, + ), quality: inputFieldValueAsNumber(form.quality, options.quality), compression: inputFieldValueAsNumber( form.compression, @@ -61,22 +67,20 @@ export class Options extends Component { }; render({ options }: Props, { showAdvanced }: State) { - // I'm rendering both lossy and lossless forms, as it becomes much easier when - // gathering the data. return (
+
- { {options.mipmap ? ( - + +
+ + Smallest mipmap (2^x): + +
+ + +
) : null}
diff --git a/src/features/encoders/basis/shared/meta.ts b/src/features/encoders/basis/shared/meta.ts index ac1e5a81..27bed023 100644 --- a/src/features/encoders/basis/shared/meta.ts +++ b/src/features/encoders/basis/shared/meta.ts @@ -25,4 +25,6 @@ export const defaultOptions: EncodeOptions = { srgb_mipmap: false, perceptual: true, y_flip: false, + mipmap_filter: 'kaiser', + mipmap_min_dimension: 1, };