├── .gitmodules ├── AlexaX2.labin ├── Amira709.labin ├── CHANGELOG.md ├── CWLSB.png ├── CWMSB.png ├── Cine709.labin ├── GrayLSB.png ├── GrayMSB.png ├── HDRPreviewLSB.png ├── HDRPreviewMSB.png ├── LC709.labin ├── LC709A.labin ├── LDRPreviewLSB.png ├── LDRPreviewMSB.png ├── LICENSE ├── LUTCalc.icns ├── README.md ├── V709.labin ├── apple-touch-icon.png ├── blob ├── Blob.js ├── LICENSE.md └── README.md ├── cpoutdaylight.labin ├── cpouttungsten.labin ├── favicon-16x16.png ├── favicon-192x192.png ├── favicon-32x32.png ├── favicon.ico ├── filesaver ├── FileSaver.js ├── FileSaver.min.js └── FileSaver.min.js.map ├── img ├── Screenshot-Tall-1.png ├── Screenshot-Wide-1.png ├── lutcalc-1024.png ├── lutcalc-128.png ├── lutcalc-16.png ├── lutcalc-19.png ├── lutcalc-256.png ├── lutcalc-32.png ├── lutcalc-38.png ├── lutcalc-48.png ├── lutcalc-512.png ├── lutcalc-60.png ├── lutcalc-64.png └── lutcalc-90.png ├── index.html ├── indexunminified.html ├── js ├── background.js ├── bounding.js ├── brent.js ├── colourspace.js ├── colourspaceworker.js ├── colourspaceworkerscombined.js ├── gamma.js ├── gammaworker.js ├── gammaworkerscombined.js ├── lut-3dl.js ├── lut-cube.js ├── lut-davinci.js ├── lut-la.js ├── lut-lut.js ├── lut-ncp.js ├── lut-spi1d.js ├── lut-spi3d.js ├── lut-vlt.js ├── lut.js ├── lutanalyst.js ├── lutcalc.js ├── lutcalccombined.js ├── lutcamerabox.js ├── lutfile.js ├── lutformats.js ├── lutgammabox.js ├── lutgeneratebox.js ├── lutinfobox.js ├── lutlutbox.js ├── lutmessage.js ├── lutmobile.js ├── lutpreview.js ├── luttweaksbox.js ├── ring.js ├── splash.js ├── twk-asccdl.js ├── twk-blank.js ├── twk-blkgam.js ├── twk-blkhi.js ├── twk-cs.js ├── twk-display.js ├── twk-fc.js ├── twk-gamlim.js ├── twk-hg.js ├── twk-knee.js ├── twk-la.js ├── twk-multi.js ├── twk-psstcdl.js ├── twk-sampler.js ├── twk-sdrsat.js └── twk-white.js ├── manifest.json ├── mobile.css ├── pngs ├── cust-asc-1.png ├── cust-asc.png ├── cust-bgm-1.png ├── cust-bgm.png ├── cust-bhi-1.png ├── cust-bhi-2.png ├── cust-bhi-3.png ├── cust-bhi.png ├── cust-colour-1.png ├── cust-colour-2.png ├── cust-colour.png ├── cust-dcc-1.png ├── cust-dcc.png ├── cust-fc-1.png ├── cust-fc.png ├── cust-glim-1.png ├── cust-glim-2.png ├── cust-glim-3.png ├── cust-glim.png ├── cust-header.png ├── cust-hg-1.png ├── cust-hg.png ├── cust-knee-1.png ├── cust-knee.png ├── cust-la-1.png ├── cust-la-2.png ├── cust-la-3.png ├── cust-la.png ├── cust-multi-1.jpg ├── cust-multi-2.jpg ├── cust-multi.png ├── cust-psst-1.png ├── cust-psst-2.jpg ├── cust-psst-3.png ├── cust-psst.png ├── cust-samp-1.png ├── cust-samp.png ├── cust-sdrs.png ├── cust-wht-1.png ├── cust-wht-2.png ├── cust-wht.png ├── ins-cam-1.png ├── ins-cust-wht-1.png ├── ins-gam-1.png ├── ins-inf-1.png ├── ins-lut-1.png ├── ins-lut-2.png ├── ins-pre-1.jpg ├── ins-pre-2.jpg ├── ins-pre-3.png ├── main-but-gen.png ├── main-but-gst.png ├── main-but-pre.png ├── main-but-set.png ├── main-cam.png ├── main-footer.png ├── main-gam.png ├── main-header.png ├── main-inf.png ├── main-lut.png ├── main-twk.png ├── mob-chart-icon.png └── mob-preview-icon.png ├── s709.labin ├── style.css ├── window.html ├── xyuvLSB.png └── xyuvMSB.png /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/.gitmodules -------------------------------------------------------------------------------- /AlexaX2.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/AlexaX2.labin -------------------------------------------------------------------------------- /Amira709.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/Amira709.labin -------------------------------------------------------------------------------- /CWLSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/CWLSB.png -------------------------------------------------------------------------------- /CWMSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/CWMSB.png -------------------------------------------------------------------------------- /Cine709.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/Cine709.labin -------------------------------------------------------------------------------- /GrayLSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/GrayLSB.png -------------------------------------------------------------------------------- /GrayMSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/GrayMSB.png -------------------------------------------------------------------------------- /HDRPreviewLSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/HDRPreviewLSB.png -------------------------------------------------------------------------------- /HDRPreviewMSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/HDRPreviewMSB.png -------------------------------------------------------------------------------- /LC709.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/LC709.labin -------------------------------------------------------------------------------- /LC709A.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/LC709A.labin -------------------------------------------------------------------------------- /LDRPreviewLSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/LDRPreviewLSB.png -------------------------------------------------------------------------------- /LDRPreviewMSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/LDRPreviewMSB.png -------------------------------------------------------------------------------- /LUTCalc.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/LUTCalc.icns -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LUTCalc 2 | ======= 3 | 4 | A Web App for generating 1D and 3D Lookup Tables (LUTs) for video cameras that shoot log gammas, principally the Sony CineAlta line. 5 | 6 | LUTCalc generates 1D and 3D .cube format LUTs suitable for use in DaVinci Resolve, Adobe Speedgrade and as user 3D LUTs in Sony's log-recording video cameras. These include the PMW-F5, PMW-F55 and PXW-FS7. 7 | 8 | How To Start 9 | ------------ 10 | Mac OSX Safari: For Mac OSX users, the sister [LUTCalc For Mac](https://github.com/cameramanben/LUTCalc-For-Mac) project provides a native app version using a sandbox-friendly Objective-C Webkit wrapper around the LUTCalc Javascript. 11 | Chrome (Windows, Mac or Linux): LUTCalc currently needs to be run as an app extension. Either click Window->Extensions in the menu bar or type chrome://extensions in the address bar. Check 'developer mode' in the top right, then click 'Load unpacked extension' and find the main LUTCalc directory and click select. LUTCalc should then show up on the list of installed extensions. You can now uncheck developer mode and start LUTCalc either by clicking 'Launch' or from the Chrome App Launcher. 12 | Firefox: I have been developing using Firefox, so opening index.html in the main directory should work. 13 | Internet Explorer: currently looking in to making this work. 14 | 15 | Gamma / Gamut Information 16 | ------------------------- 17 | 18 | The sources of information used are white papers and standards documents, analysis and comparison of test images and LUT calculations using known reference LUTs. 19 | 20 | Sony S-Log3 - [Technical Summary for S-Gamut3.Cine/S-Log3 and S-Gamut3/S-Log3](http://community.sony.com/sony/attachments/sony/large-sensor-camera-F5-F55/12359/2/TechnicalSummary_for_S-Gamut3Cine_S-Gamut3_S-Log3_V1_00.pdf) 21 | 22 | Sony S-Gamut3 / S-Gamut3.cine - [Sony Excel spreadsheet of various gamut matrices](http://community.sony.com/sony/attachments/sony/large-sensor-camera-F5-F55/12359/3/S-Gamut3_S-Gamut3Cine_Matrix.xlsx) 23 | 24 | Sony S-Log2 - [Sony technical paper on S-Log2](https://pro.sony.com/bbsccms/assets/files/micro/dmpc/training/S-Log2_Technical_PaperV1_0.pdf) 25 | 26 | Sony S-Log - [S-Log: A new LUT for digital production mastering and interchange applications](https://pro.sony.com/bbsccms/assets/files/mkt/cinema/solutions/slog_manual.pdf) 27 | 28 | Sony Look Profile LUTs - [Sony Community Website](http://community.sony.com/t5/F5-F55/Release-version-3DLUT-s-for-S-Gamut3-Cine-S-Log3/td-p/287847) 29 | 30 | Arri LogC / Wide Gamut - [ALEXA Log C Curve - Usage in VFX](http://www.arri.com/?eID=registration&file_uid=8026) 31 | 32 | Canon C-Log - [Canon-Log Cine Optoelectronic Transfer Function](http://learn.usa.canon.com/app/pdfs/white_papers/White_Paper_Clog_optoelectronic.pdf) 33 | 34 | Canon LUTs and Gamut Information - [Canon C500 Support Site](http://www.canon-europe.com/Support/Consumer_Products/products/digital_cinema/digital_cinema_camera/EOS_C500.aspx?type=download) 35 | 36 | Canon C300 Input Device Transform (IDT) - [Canon C300 Support Site](http://www.usa.canon.com/cusa/professional/products/professional_cameras/cinema_eos_cameras/eos_c300#DriversAndSoftware) - under 'Software'. You have to specify 'Mountain Lion' on a Mac or 'Windows XP' on a PC for it to be displayed. C500 and C100 have the same IDTs for CP Lock, though the C500 also offers 'Cinema Gamut' (see above link). 37 | 38 | Panasonic Varicam V-Log and V-Gamut - [V-Log/V-Gamut Reference Manual](http://pro-av.panasonic.net/en/varicam/common/pdf/VARICAM_V-Log_V-Gamut.pdf) 39 | 40 | Cineon - [Understanding Cineon](http://www.digital-intermediate.co.uk/film/pdf/Cineon.pdf) 41 | 42 | Rec709 - [ITU BT.709-5](http://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-5-200204-I!!PDF-E.pdf) 43 | 44 | sRGB - [Wikipedia entry](http://en.wikipedia.org/wiki/SRGB) 45 | 46 | Dolby PQ and alternative prospective transfer functions for HDR displays - [Non-linear Opto-Electrical Transfer Functions for High Dynamic Range Television](http://www.bbc.co.uk/rd/publications/whitepaper283) 47 | 48 | Chromatic adaptation and Von Kries transform for colour temperature adjustments - [Wikipedia article](http://en.wikipedia.org/wiki/Chromatic_adaptation) 49 | 50 | 51 | LUTCalc File List 52 | ================= 53 | 54 | Main Files 55 | ---------- 56 | * index.html (window.html) - HTML5 base of LUTCalc. Launch to start. 57 | * lutcalc.js - main Javascript file. Initialises all the UI and calculation objects and sets up the event handlers. 58 | 59 | UI Files 60 | -------- 61 | * lutcamerabox.js - builds the UI object where camera and ISO are chosen. 62 | * lutgammabox.js - builds the UI object for transfer curve (gamma) and colour space (gamut) selection. 63 | * luttweaksbox.js - builds the UI object for customising the transfer (gamma) curves and colour spaces / gamuts. 64 | * lutanalyst.js - extension to luttweaksbox which reads and then analyses LUTs into transfer function and colour space components so that they can be adapted for use with other input colour spaces and further tweaked as with the built-in options. 65 | * lutlutbox.js - builds the UI object containing options concerning the LUT format. 66 | * lutgeneratebox.js - builds the 'Generate' button that triggers the LUT generation, plus the generation logic itself. 67 | * lutpreview.js - builds the UI object which previews LUTs on test images. 68 | * lutinfobox.js - builds the UI object which shows instructions, plots of the input and output gammas against stop and IRE and data values for correct exposure with the chosen output gamma. 69 | 70 | LUT I/O 71 | ------- 72 | * lutformats.js - controller object for the parsers and builders of various LUT formats. 73 | * lut-cube.js - .cube format parsing and building (Adobe format and DaVinci format). 74 | * lut-davinci.js - DaVinci Resolve 1D .ilut input LUT and .olut output LUT parsing and building. 75 | * lut-vlt.js - Panasonic .vlt MLUT format parsing and building. 76 | * lut-3dl.js - .3dl format parsing and building (Assimilate, Autodesk and Kodak formats). 77 | * lut-lut.js - Assimilate 1D .lut parsing and building. 78 | * lut-spi1d.js - Sony Pictures International 1D .spi1d format parsing and building. 79 | * lut-spi3d.js - Sony Pictures International 3D .spi3d format parsing and building. 80 | * lut-la.js - cube-based .lacube and .labin LUTAnalyst parsing and building. 81 | 82 | Adjustment Files 83 | ---------------- 84 | * twk-wb.js - white balance (colour temperature / fluori green / magenta) adjustment. 85 | * twk-asccdl.js - adjustment based on the ASC-CDL operations. 86 | * twk-psstcdl.js - colour-specific adjustment based on the ASC-CDL controls. 87 | * twk-hg.js - adjustment to allow for a second choice of gamut in the highlights. 88 | * twk-blkhi.js - adjustment of the black level and a user-selectable scene reflectance response level. 89 | * twk-fc.js - false colour overlay option. 90 | * twk-la.js - LUTAnalyst UI controls. 91 | * twk-blank.js - empty example object which demonstrates the layout. 92 | 93 | Web Workers 94 | ----------- 95 | * lutmessage.js - handles creation and message passing for multiple web worker calculation threads. 96 | * gamma.js - handles all the calculations relating to transfer functions (gammas). 97 | * colourspace.js - handles all the functions relating to colour spaces (gamuts). 98 | 99 | Binary LUT Files 100 | ---------------- 101 | * LC709.labin - little-endian Float64Array buffer of colour space (S-Log3 to S-Log3, S-Gamut3.cine to LC709) data based on Sony's look profile. 102 | * LC709A.labin - colour space data based on Sony's look profile. 103 | * V709.labin - experimental colour space data based on Panasonic's reference V-log to V709 LUT. 104 | * cpoutdaylight.labin - Canon CP lock to S-Gamut3.cine data developed by testing against Canon's reference daylight IDT. 105 | * cpouttungsten.labin - Canon CP lock to S-Gamut3.cine data developed by testing against Canon's reference tungsten IDT. 106 | 107 | Helper Javascript 108 | ----------------- 109 | * splash.js - displays a splash screen and sets the version. 110 | * tests.js - performs Javascript capabilities tests to see whether and how LUTCalc will run in a given environment. 111 | * lut.js - LUT handling object. Will calculate interpolated values from LUTs using cubic and tricubic interpolation. Also includes code for breaking a 3D LUT into gamma and gamut component LUTs and changing the input gamma / gamut (as used by the LUTAnalyst tool). 112 | * ring.js - ring spline object. Like a 1D LUT which connects back on itself. Used in the PSST-CDL calculations. 113 | * lutfile.js - file handling object. 114 | * lutinputs.js - simple object into which the other objects can place their form input objects, to allow interaction without globals. 115 | * brent.js - Brent's method of root finding for LUTAnalyst. 116 | * tests.js - object containing feature / environment detection tests. 117 | * window.html - web app version of index.html. 118 | * background.js - web app required code. 119 | * manifest.webapp - web app manifest. 120 | * manifest.json - alternative web app manifest format. 121 | 122 | Style Sheets 123 | ------------ 124 | * reset.css - DOM reset stylesheet. 125 | * fonts.css - font options stylesheet. 126 | * ui.css - style sheet controlling specific UI elements. 127 | * style.css - base stylesheet controlling the look of the app. All dimensions (greater than 1 pixel) are em values. 128 | * info.css - stylesheet controlling the information / instructions window. 129 | 130 | Other Files 131 | ----------- 132 | * background.js - Chrome packaged app requirement 133 | * LUTCalc.icns - icon file containing a logo in a format suitable for Mac OSX Apps in XCode. 134 | * logo(x).png - various sizes of png containing the LUTCalc logo for the Chrome app. 135 | * LDR / HDR Preview LSB / MSB .png - test images for use in the preview window. Low dynamic range / contrast (LDR) and high dynamic range (HDR) from 16-bit originals broken into 8-bit most significant and least significant byte images (MSB and LSB) for Javascript. 136 | * Gray LSB/ MSB .png - 16-stop grayscale test image. 137 | * CW LSB / MSB .png - Representation image of the Rec709 Colour Gamut for use in the preview window. 138 | * README.md - this file. 139 | * CHANGELOG.md - changelog. 140 | * LICENSE - GPL2 License document. 141 | 142 | External Code Used 143 | ------------------ 144 | * [FileSaver.js](https://github.com/eligrey/FileSaver.js/) - Cross-browser Javascript file saving. 145 | * [Blob.js](https://github.com/eligrey/Blob.js) - Cross-browser Javascript Blob implementation. 146 | * The function 'createRadioElement' is used to dynamically create radio buttons. This came from a tip by Prestaul on [stackoverflow](http://stackoverflow.com/questions/118693/how-do-you-dynamically-create-a-radio-button-in-javascript-that-works-in-all-bro) 147 | 148 | All other code is by me, Ben Turley. 149 | -------------------------------------------------------------------------------- /V709.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/V709.labin -------------------------------------------------------------------------------- /apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/apple-touch-icon.png -------------------------------------------------------------------------------- /blob/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2014 [Eli Grey][1]. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | [1]: http://eligrey.com 26 | -------------------------------------------------------------------------------- /blob/README.md: -------------------------------------------------------------------------------- 1 | Blob.js 2 | ============== 3 | 4 | Blob.js implements the W3C [`Blob`][1] interface in browsers that do 5 | not natively support it. 6 | 7 | Supported browsers 8 | ------------------ 9 | 10 | Blob.js shares the [same supported browsers as FileSaver.js][2]. 11 | 12 | ![Tracking image](https://in.getclicky.com/212712ns.gif) 13 | 14 | [1]: https://developer.mozilla.org/en-US/docs/Web/API/Blob 15 | [2]: https://github.com/eligrey/FileSaver.js#supported-browsers -------------------------------------------------------------------------------- /cpoutdaylight.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/cpoutdaylight.labin -------------------------------------------------------------------------------- /cpouttungsten.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/cpouttungsten.labin -------------------------------------------------------------------------------- /favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/favicon-16x16.png -------------------------------------------------------------------------------- /favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/favicon-192x192.png -------------------------------------------------------------------------------- /favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/favicon-32x32.png -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/favicon.ico -------------------------------------------------------------------------------- /filesaver/FileSaver.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | if (typeof define === "function" && define.amd) { 3 | define([], factory); 4 | } else if (typeof exports !== "undefined") { 5 | factory(); 6 | } else { 7 | var mod = { 8 | exports: {} 9 | }; 10 | factory(); 11 | global.FileSaver = mod.exports; 12 | } 13 | })(this, function () { 14 | "use strict"; 15 | 16 | /* 17 | * FileSaver.js 18 | * A saveAs() FileSaver implementation. 19 | * 20 | * By Eli Grey, http://eligrey.com 21 | * 22 | * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) 23 | * source : http://purl.eligrey.com/github/FileSaver.js 24 | */ 25 | // The one and only way of getting global scope in all environments 26 | // https://stackoverflow.com/q/3277182/1008999 27 | var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0; 28 | 29 | function bom(blob, opts) { 30 | if (typeof opts === 'undefined') opts = { 31 | autoBom: false 32 | };else if (typeof opts !== 'object') { 33 | console.warn('Deprecated: Expected third argument to be a object'); 34 | opts = { 35 | autoBom: !opts 36 | }; 37 | } // prepend BOM for UTF-8 XML and text/* types (including HTML) 38 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 39 | 40 | if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 41 | return new Blob([String.fromCharCode(0xFEFF), blob], { 42 | type: blob.type 43 | }); 44 | } 45 | 46 | return blob; 47 | } 48 | 49 | function download(url, name, opts) { 50 | var xhr = new XMLHttpRequest(); 51 | xhr.open('GET', url); 52 | xhr.responseType = 'blob'; 53 | 54 | xhr.onload = function () { 55 | saveAs(xhr.response, name, opts); 56 | }; 57 | 58 | xhr.onerror = function () { 59 | console.error('could not download file'); 60 | }; 61 | 62 | xhr.send(); 63 | } 64 | 65 | function corsEnabled(url) { 66 | var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker 67 | 68 | xhr.open('HEAD', url, false); 69 | 70 | try { 71 | xhr.send(); 72 | } catch (e) {} 73 | 74 | return xhr.status >= 200 && xhr.status <= 299; 75 | } // `a.click()` doesn't work for all browsers (#465) 76 | 77 | 78 | function click(node) { 79 | try { 80 | node.dispatchEvent(new MouseEvent('click')); 81 | } catch (e) { 82 | var evt = document.createEvent('MouseEvents'); 83 | evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); 84 | node.dispatchEvent(evt); 85 | } 86 | } // Detect WebView inside a native macOS app by ruling out all browsers 87 | // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too 88 | // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos 89 | 90 | 91 | var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent); 92 | var saveAs = _global.saveAs || ( // probably in some web worker 93 | typeof window !== 'object' || window !== _global ? function saveAs() {} 94 | /* noop */ 95 | // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView 96 | : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) { 97 | var URL = _global.URL || _global.webkitURL; 98 | var a = document.createElement('a'); 99 | name = name || blob.name || 'download'; 100 | a.download = name; 101 | a.rel = 'noopener'; // tabnabbing 102 | // TODO: detect chrome extensions & packaged apps 103 | // a.target = '_blank' 104 | 105 | if (typeof blob === 'string') { 106 | // Support regular links 107 | a.href = blob; 108 | 109 | if (a.origin !== location.origin) { 110 | corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); 111 | } else { 112 | click(a); 113 | } 114 | } else { 115 | // Support blobs 116 | a.href = URL.createObjectURL(blob); 117 | setTimeout(function () { 118 | URL.revokeObjectURL(a.href); 119 | }, 4E4); // 40s 120 | 121 | setTimeout(function () { 122 | click(a); 123 | }, 0); 124 | } 125 | } // Use msSaveOrOpenBlob as a second approach 126 | : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { 127 | name = name || blob.name || 'download'; 128 | 129 | if (typeof blob === 'string') { 130 | if (corsEnabled(blob)) { 131 | download(blob, name, opts); 132 | } else { 133 | var a = document.createElement('a'); 134 | a.href = blob; 135 | a.target = '_blank'; 136 | setTimeout(function () { 137 | click(a); 138 | }); 139 | } 140 | } else { 141 | navigator.msSaveOrOpenBlob(bom(blob, opts), name); 142 | } 143 | } // Fallback to using FileReader and a popup 144 | : function saveAs(blob, name, opts, popup) { 145 | // Open a popup immediately do go around popup blocker 146 | // Mostly only available on user interaction and the fileReader is async so... 147 | popup = popup || open('', '_blank'); 148 | 149 | if (popup) { 150 | popup.document.title = popup.document.body.innerText = 'downloading...'; 151 | } 152 | 153 | if (typeof blob === 'string') return download(blob, name, opts); 154 | var force = blob.type === 'application/octet-stream'; 155 | 156 | var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; 157 | 158 | var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); 159 | 160 | if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') { 161 | // Safari doesn't allow downloading of blob URLs 162 | var reader = new FileReader(); 163 | 164 | reader.onloadend = function () { 165 | var url = reader.result; 166 | url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); 167 | if (popup) popup.location.href = url;else location = url; 168 | popup = null; // reverse-tabnabbing #460 169 | }; 170 | 171 | reader.readAsDataURL(blob); 172 | } else { 173 | var URL = _global.URL || _global.webkitURL; 174 | var url = URL.createObjectURL(blob); 175 | if (popup) popup.location = url;else location.href = url; 176 | popup = null; // reverse-tabnabbing #460 177 | 178 | setTimeout(function () { 179 | URL.revokeObjectURL(url); 180 | }, 4E4); // 40s 181 | } 182 | }); 183 | _global.saveAs = saveAs.saveAs = saveAs; 184 | 185 | if (typeof module !== 'undefined') { 186 | module.exports = saveAs; 187 | } 188 | }); 189 | -------------------------------------------------------------------------------- /filesaver/FileSaver.min.js: -------------------------------------------------------------------------------- 1 | (function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)}); 2 | 3 | //# sourceMappingURL=FileSaver.min.js.map -------------------------------------------------------------------------------- /filesaver/FileSaver.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/FileSaver.js"],"names":[],"mappings":"uLAkBA,QAAS,CAAA,CAAT,CAAc,CAAd,CAAoB,CAApB,CAA0B,OACJ,WAAhB,QAAO,CAAA,CADa,CACS,CAAI,CAAG,CAAE,OAAO,GAAT,CADhB,CAEC,QAAhB,QAAO,CAAA,CAFQ,GAGtB,OAAO,CAAC,IAAR,CAAa,oDAAb,CAHsB,CAItB,CAAI,CAAG,CAAE,OAAO,CAAE,CAAC,CAAZ,CAJe,EASpB,CAAI,CAAC,OAAL,EAAgB,6EAA6E,IAA7E,CAAkF,CAAI,CAAC,IAAvF,CATI,CAUf,GAAI,CAAA,IAAJ,CAAS,UAA8B,CAA9B,CAAT,CAA8C,CAAE,IAAI,CAAE,CAAI,CAAC,IAAb,CAA9C,CAVe,CAYjB,CACR,CAED,QAAS,CAAA,CAAT,CAAmB,CAAnB,CAAwB,CAAxB,CAA8B,CAA9B,CAAoC,CAClC,GAAI,CAAA,CAAG,CAAG,GAAI,CAAA,cAAd,CACA,CAAG,CAAC,IAAJ,CAAS,KAAT,CAAgB,CAAhB,CAFkC,CAGlC,CAAG,CAAC,YAAJ,CAAmB,MAHe,CAIlC,CAAG,CAAC,MAAJ,CAAa,UAAY,CACvB,CAAM,CAAC,CAAG,CAAC,QAAL,CAAe,CAAf,CAAqB,CAArB,CACP,CANiC,CAOlC,CAAG,CAAC,OAAJ,CAAc,UAAY,CACxB,OAAO,CAAC,KAAR,CAAc,yBAAd,CACD,CATiC,CAUlC,CAAG,CAAC,IAAJ,EACD,CAED,QAAS,CAAA,CAAT,CAAsB,CAAtB,CAA2B,CACzB,GAAI,CAAA,CAAG,CAAG,GAAI,CAAA,cAAd,CAEA,CAAG,CAAC,IAAJ,CAAS,MAAT,CAAiB,CAAjB,IAHyB,CAIzB,GAAI,CACF,CAAG,CAAC,IAAJ,EACD,CAAC,MAAO,CAAP,CAAU,CAAE,CACd,MAAqB,IAAd,EAAA,CAAG,CAAC,MAAJ,EAAmC,GAAd,EAAA,CAAG,CAAC,MACjC,CAGD,QAAS,CAAA,CAAT,CAAgB,CAAhB,CAAsB,CACpB,GAAI,CACF,CAAI,CAAC,aAAL,CAAmB,GAAI,CAAA,UAAJ,CAAe,OAAf,CAAnB,CACD,CAAC,MAAO,CAAP,CAAU,CACV,GAAI,CAAA,CAAG,CAAG,QAAQ,CAAC,WAAT,CAAqB,aAArB,CAAV,CACA,CAAG,CAAC,cAAJ,CAAmB,OAAnB,OAAwC,MAAxC,CAAgD,CAAhD,CAAmD,CAAnD,CAAsD,CAAtD,CAAyD,EAAzD,CACsB,EADtB,aACsD,CADtD,CACyD,IADzD,CAFU,CAIV,CAAI,CAAC,aAAL,CAAmB,CAAnB,CACD,CACF,C,GAtDG,CAAA,CAAO,CAAqB,QAAlB,QAAO,CAAA,MAAP,EAA8B,MAAM,CAAC,MAAP,GAAkB,MAAhD,CACV,MADU,CACe,QAAhB,QAAO,CAAA,IAAP,EAA4B,IAAI,CAAC,IAAL,GAAc,IAA1C,CACT,IADS,CACgB,QAAlB,QAAO,CAAA,MAAP,EAA8B,MAAM,CAAC,MAAP,GAAkB,MAAhD,CACP,MADO,O,CAyDP,CAAc,CAAG,YAAY,IAAZ,CAAiB,SAAS,CAAC,SAA3B,GAAyC,cAAc,IAAd,CAAmB,SAAS,CAAC,SAA7B,CAAzC,EAAoF,CAAC,SAAS,IAAT,CAAc,SAAS,CAAC,SAAxB,C,CAEtG,CAAM,CAAG,CAAO,CAAC,MAAR,GAEQ,QAAlB,QAAO,CAAA,MAAP,EAA8B,MAAM,GAAK,CAA1C,CACI,UAAmB,CAAc,CADrC,CAIG,YAAc,CAAA,iBAAiB,CAAC,SAAhC,EAA6C,CAAC,CAA/C,CACA,SAAiB,CAAjB,CAAuB,CAAvB,CAA6B,CAA7B,CAAmC,IAC/B,CAAA,CAAG,CAAG,CAAO,CAAC,GAAR,EAAe,CAAO,CAAC,SADE,CAE/B,CAAC,CAAG,QAAQ,CAAC,aAAT,CAAuB,GAAvB,CAF2B,CAGnC,CAAI,CAAG,CAAI,EAAI,CAAI,CAAC,IAAb,EAAqB,UAHO,CAKnC,CAAC,CAAC,QAAF,CAAa,CALsB,CAMnC,CAAC,CAAC,GAAF,CAAQ,UAN2B,CAWf,QAAhB,QAAO,CAAA,CAXwB,EAajC,CAAC,CAAC,IAAF,CAAS,CAbwB,CAc7B,CAAC,CAAC,MAAF,GAAa,QAAQ,CAAC,MAdO,CAmB/B,CAAK,CAAC,CAAD,CAnB0B,CAe/B,CAAW,CAAC,CAAC,CAAC,IAAH,CAAX,CACI,CAAQ,CAAC,CAAD,CAAO,CAAP,CAAa,CAAb,CADZ,CAEI,CAAK,CAAC,CAAD,CAAI,CAAC,CAAC,MAAF,CAAW,QAAf,CAjBsB,GAuBjC,CAAC,CAAC,IAAF,CAAS,CAAG,CAAC,eAAJ,CAAoB,CAApB,CAvBwB,CAwBjC,UAAU,CAAC,UAAY,CAAE,CAAG,CAAC,eAAJ,CAAoB,CAAC,CAAC,IAAtB,CAA6B,CAA5C,CAA8C,GAA9C,CAxBuB,CAyBjC,UAAU,CAAC,UAAY,CAAE,CAAK,CAAC,CAAD,CAAK,CAAzB,CAA2B,CAA3B,CAzBuB,CA2BpC,CA5BC,CA+BA,oBAAsB,CAAA,SAAtB,CACA,SAAiB,CAAjB,CAAuB,CAAvB,CAA6B,CAA7B,CAAmC,CAGnC,GAFA,CAAI,CAAG,CAAI,EAAI,CAAI,CAAC,IAAb,EAAqB,UAE5B,CAAoB,QAAhB,QAAO,CAAA,CAAX,CAUE,SAAS,CAAC,gBAAV,CAA2B,CAAG,CAAC,CAAD,CAAO,CAAP,CAA9B,CAA4C,CAA5C,CAVF,KACE,IAAI,CAAW,CAAC,CAAD,CAAf,CACE,CAAQ,CAAC,CAAD,CAAO,CAAP,CAAa,CAAb,CADV,KAEO,CACL,GAAI,CAAA,CAAC,CAAG,QAAQ,CAAC,aAAT,CAAuB,GAAvB,CAAR,CACA,CAAC,CAAC,IAAF,CAAS,CAFJ,CAGL,CAAC,CAAC,MAAF,CAAW,QAHN,CAIL,UAAU,CAAC,UAAY,CAAE,CAAK,CAAC,CAAD,CAAK,CAAzB,CACX,CAIJ,CAhBC,CAmBA,SAAiB,CAAjB,CAAuB,CAAvB,CAA6B,CAA7B,CAAmC,CAAnC,CAA0C,CAS1C,GANA,CAAK,CAAG,CAAK,EAAI,IAAI,CAAC,EAAD,CAAK,QAAL,CAMrB,CALI,CAKJ,GAJE,CAAK,CAAC,QAAN,CAAe,KAAf,CACA,CAAK,CAAC,QAAN,CAAe,IAAf,CAAoB,SAApB,CAAgC,gBAGlC,EAAoB,QAAhB,QAAO,CAAA,CAAX,CAA8B,MAAO,CAAA,CAAQ,CAAC,CAAD,CAAO,CAAP,CAAa,CAAb,CAAf,CATY,GAWtC,CAAA,CAAK,CAAiB,0BAAd,GAAA,CAAI,CAAC,IAXyB,CAYtC,CAAQ,CAAG,eAAe,IAAf,CAAoB,CAAO,CAAC,WAA5B,GAA4C,CAAO,CAAC,MAZzB,CAatC,CAAW,CAAG,eAAe,IAAf,CAAoB,SAAS,CAAC,SAA9B,CAbwB,CAe1C,GAAI,CAAC,CAAW,EAAK,CAAK,EAAI,CAAzB,EAAsC,CAAvC,GAAgF,WAAtB,QAAO,CAAA,UAArE,CAAiG,CAE/F,GAAI,CAAA,CAAM,CAAG,GAAI,CAAA,UAAjB,CACA,CAAM,CAAC,SAAP,CAAmB,UAAY,CAC7B,GAAI,CAAA,CAAG,CAAG,CAAM,CAAC,MAAjB,CACA,CAAG,CAAG,CAAW,CAAG,CAAH,CAAS,CAAG,CAAC,OAAJ,CAAY,cAAZ,CAA4B,uBAA5B,CAFG,CAGzB,CAHyB,CAGlB,CAAK,CAAC,QAAN,CAAe,IAAf,CAAsB,CAHJ,CAIxB,QAAQ,CAAG,CAJa,CAK7B,CAAK,CAAG,IACT,CAT8F,CAU/F,CAAM,CAAC,aAAP,CAAqB,CAArB,CACD,CAXD,IAWO,IACD,CAAA,CAAG,CAAG,CAAO,CAAC,GAAR,EAAe,CAAO,CAAC,SAD5B,CAED,CAAG,CAAG,CAAG,CAAC,eAAJ,CAAoB,CAApB,CAFL,CAGD,CAHC,CAGM,CAAK,CAAC,QAAN,CAAiB,CAHvB,CAIA,QAAQ,CAAC,IAAT,CAAgB,CAJhB,CAKL,CAAK,CAAG,IALH,CAML,UAAU,CAAC,UAAY,CAAE,CAAG,CAAC,eAAJ,CAAoB,CAApB,CAA0B,CAAzC,CAA2C,GAA3C,CACX,CACF,CA1FU,C,CA6Fb,CAAO,CAAC,MAAR,CAAiB,CAAM,CAAC,MAAP,CAAgB,C,CAEX,WAAlB,QAAO,CAAA,M,GACT,MAAM,CAAC,OAAP,CAAiB,C","file":"FileSaver.min.js","sourcesContent":["/*\n* FileSaver.js\n* A saveAs() FileSaver implementation.\n*\n* By Eli Grey, http://eligrey.com\n*\n* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)\n* source : http://purl.eligrey.com/github/FileSaver.js\n*/\n\n// The one and only way of getting global scope in all environments\n// https://stackoverflow.com/q/3277182/1008999\nvar _global = typeof window === 'object' && window.window === window\n ? window : typeof self === 'object' && self.self === self\n ? self : typeof global === 'object' && global.global === global\n ? global\n : this\n\nfunction bom (blob, opts) {\n if (typeof opts === 'undefined') opts = { autoBom: false }\n else if (typeof opts !== 'object') {\n console.warn('Deprecated: Expected third argument to be a object')\n opts = { autoBom: !opts }\n }\n\n // prepend BOM for UTF-8 XML and text/* types (including HTML)\n // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\n if (opts.autoBom && /^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\n return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })\n }\n return blob\n}\n\nfunction download (url, name, opts) {\n var xhr = new XMLHttpRequest()\n xhr.open('GET', url)\n xhr.responseType = 'blob'\n xhr.onload = function () {\n saveAs(xhr.response, name, opts)\n }\n xhr.onerror = function () {\n console.error('could not download file')\n }\n xhr.send()\n}\n\nfunction corsEnabled (url) {\n var xhr = new XMLHttpRequest()\n // use sync to avoid popup blocker\n xhr.open('HEAD', url, false)\n try {\n xhr.send()\n } catch (e) {}\n return xhr.status >= 200 && xhr.status <= 299\n}\n\n// `a.click()` doesn't work for all browsers (#465)\nfunction click (node) {\n try {\n node.dispatchEvent(new MouseEvent('click'))\n } catch (e) {\n var evt = document.createEvent('MouseEvents')\n evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,\n 20, false, false, false, false, 0, null)\n node.dispatchEvent(evt)\n }\n}\n\n// Detect WebView inside a native macOS app by ruling out all browsers\n// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too\n// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos\nvar isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)\n\nvar saveAs = _global.saveAs || (\n // probably in some web worker\n (typeof window !== 'object' || window !== _global)\n ? function saveAs () { /* noop */ }\n\n // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView\n : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)\n ? function saveAs (blob, name, opts) {\n var URL = _global.URL || _global.webkitURL\n var a = document.createElement('a')\n name = name || blob.name || 'download'\n\n a.download = name\n a.rel = 'noopener' // tabnabbing\n\n // TODO: detect chrome extensions & packaged apps\n // a.target = '_blank'\n\n if (typeof blob === 'string') {\n // Support regular links\n a.href = blob\n if (a.origin !== location.origin) {\n corsEnabled(a.href)\n ? download(blob, name, opts)\n : click(a, a.target = '_blank')\n } else {\n click(a)\n }\n } else {\n // Support blobs\n a.href = URL.createObjectURL(blob)\n setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s\n setTimeout(function () { click(a) }, 0)\n }\n }\n\n // Use msSaveOrOpenBlob as a second approach\n : 'msSaveOrOpenBlob' in navigator\n ? function saveAs (blob, name, opts) {\n name = name || blob.name || 'download'\n\n if (typeof blob === 'string') {\n if (corsEnabled(blob)) {\n download(blob, name, opts)\n } else {\n var a = document.createElement('a')\n a.href = blob\n a.target = '_blank'\n setTimeout(function () { click(a) })\n }\n } else {\n navigator.msSaveOrOpenBlob(bom(blob, opts), name)\n }\n }\n\n // Fallback to using FileReader and a popup\n : function saveAs (blob, name, opts, popup) {\n // Open a popup immediately do go around popup blocker\n // Mostly only available on user interaction and the fileReader is async so...\n popup = popup || open('', '_blank')\n if (popup) {\n popup.document.title =\n popup.document.body.innerText = 'downloading...'\n }\n\n if (typeof blob === 'string') return download(blob, name, opts)\n\n var force = blob.type === 'application/octet-stream'\n var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari\n var isChromeIOS = /CriOS\\/[\\d]+/.test(navigator.userAgent)\n\n if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {\n // Safari doesn't allow downloading of blob URLs\n var reader = new FileReader()\n reader.onloadend = function () {\n var url = reader.result\n url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')\n if (popup) popup.location.href = url\n else location = url\n popup = null // reverse-tabnabbing #460\n }\n reader.readAsDataURL(blob)\n } else {\n var URL = _global.URL || _global.webkitURL\n var url = URL.createObjectURL(blob)\n if (popup) popup.location = url\n else location.href = url\n popup = null // reverse-tabnabbing #460\n setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s\n }\n }\n)\n\n_global.saveAs = saveAs.saveAs = saveAs\n\nif (typeof module !== 'undefined') {\n module.exports = saveAs;\n}\n"]} -------------------------------------------------------------------------------- /img/Screenshot-Tall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/Screenshot-Tall-1.png -------------------------------------------------------------------------------- /img/Screenshot-Wide-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/Screenshot-Wide-1.png -------------------------------------------------------------------------------- /img/lutcalc-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-1024.png -------------------------------------------------------------------------------- /img/lutcalc-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-128.png -------------------------------------------------------------------------------- /img/lutcalc-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-16.png -------------------------------------------------------------------------------- /img/lutcalc-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-19.png -------------------------------------------------------------------------------- /img/lutcalc-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-256.png -------------------------------------------------------------------------------- /img/lutcalc-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-32.png -------------------------------------------------------------------------------- /img/lutcalc-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-38.png -------------------------------------------------------------------------------- /img/lutcalc-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-48.png -------------------------------------------------------------------------------- /img/lutcalc-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-512.png -------------------------------------------------------------------------------- /img/lutcalc-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-60.png -------------------------------------------------------------------------------- /img/lutcalc-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-64.png -------------------------------------------------------------------------------- /img/lutcalc-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/img/lutcalc-90.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | LUTCalc 16 | 17 | 18 |

LUTCalc - 1D & 3D Cube LUT Calculator

19 |
20 |

*** Please Allow Javascript To Run On This Page ***

21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /indexunminified.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | LUTCalc 16 | 17 | 18 |

LUTCalc - 1D & 3D Cube LUT Calculator

19 |
20 |

*** Please Allow Javascript To Run On This Page ***

21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /js/background.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() { 2 | chrome.app.window.create('window.html', { 3 | 'bounds': { 4 | 'width': 1400, 5 | 'height': 700 6 | } 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /js/brent.js: -------------------------------------------------------------------------------- 1 | /* brent.js 2 | * JS implementation of the Brent's method of root finding 3 | * 4 | * 6th February 2015 5 | * 6 | * The 'findRoot' method tries to find the tightest bracket (sign change) to one side or the other of an initial guess 'I' 7 | * and then performs Brent's method. If a given bracket distance suggests roots on either side of 'I', both brackets are 8 | * evaluated and then the root closest to 'I' is returned. If no root is found, extremes are returned which can then be 9 | * replaced with minimum and maximum values found across the set. 10 | * 11 | * Sources of information: 12 | * Wikipedia: http://en.wikipedia.org/wiki/Brent%27s_method 13 | * Matlab Script by David Eagle: http://uk.mathworks.com/matlabcentral/fileexchange/39973-a-matlab-script-for-earth-to-mars-mission-design/content/brent.m 14 | * 15 | * By Ben Turley, http://turley.tv 16 | * First License: GPLv2 17 | */ 18 | function Brent(func, a, b) { 19 | this.func = func; // Object providing function / data set for analysis - requires a method 'f' which supplies f(x) 20 | if (typeof a === 'number' && typeof b === 'number') { 21 | this.setRange(a,b); 22 | } else { 23 | this.setRange(0,1); 24 | } 25 | this.delta = 1; 26 | this.tol = 0.00000001; // tolerence - OK for Float64s, too small for Float32s 27 | } 28 | Brent.prototype.setRange = function(a,b) { 29 | this.a = a; // For f(x), minimum value of x 30 | this.fMin = this.func.f(a); 31 | this.b = b; // For f(x), maximum value of x 32 | this.fMax = this.func.f(b); 33 | this.mid = this.func.f((a+b)/2); 34 | }; 35 | Brent.prototype.setDelta = function(d) { 36 | this.delta = d; 37 | }; 38 | Brent.prototype.setTolerance = function(tol) { 39 | this.tol = tol; 40 | }; 41 | Brent.prototype.minMax = function(x) { 42 | if (x < this.a) { 43 | this.a = x; 44 | this.fMin = this.o; 45 | } else if (x > this.b) { 46 | this.b = x; 47 | this.fMax = this.o; 48 | } 49 | }; 50 | Brent.prototype.getMinMax = function() { 51 | return { a: this.a, fMin: this.fMin, b: this.b, fMax: this.fMax }; 52 | }; 53 | Brent.prototype.findRoot = function(I,O) { // Public single root method, O is the f(x) to match to if not zero (root), finds closest root to I 54 | var tol = this.tol; 55 | if (typeof O === 'number') { 56 | this.o = O; 57 | } else { 58 | this.o = 0; 59 | } 60 | var y0 = this.func.f(I) - this.o; 61 | if (Math.abs(y0) 65536) { 113 | return 65536; 114 | } else if (i < -65536) { 115 | return -65536; 116 | } else { 117 | return i; 118 | } 119 | }; 120 | Brent.prototype.brent = function(a,fa,b,fb,rtol) { 121 | var eps = 2.22e-16; // Machine epsilon for Float64Arrays 122 | var e = 0; 123 | var tol1, xm, min, tmp; 124 | var p, q, r, s; 125 | var fc = fb; 126 | for (var j=0; j<80; j++) { 127 | if (fb * fc > 0) { 128 | c = a; 129 | fc = fa; 130 | d = b - a; 131 | e = d; 132 | } 133 | if (Math.abs(fc) < Math.abs(fb)) { 134 | a = b; 135 | b = c; 136 | c = a; 137 | fa = fb; 138 | fb = fc; 139 | fc = fa; 140 | } 141 | tol1 = (2*eps*Math.abs(b))+(0.5*rtol); 142 | xm = 0.5 * (c - b); 143 | if (Math.abs(xm) <= tol1 || fb === 0) { 144 | return b; 145 | } 146 | if (Math.abs(e) >= tol1 && Math.abs(fa) > Math.abs(fb)) { 147 | s = fb / fa; 148 | if (a === c) { 149 | p = 2*xm*s; 150 | q = 1-s; 151 | } else { 152 | q = fa/fc; 153 | r = fb/fc; 154 | p = s*((2*xm*q*(q - r))-((b - a)*(r - 1))); 155 | q = (q - 1)*(r - 1)*(s - 1); 156 | } 157 | if (p > 0) { 158 | q = -q; 159 | } 160 | p = Math.abs(p); 161 | min = Math.abs(e * q); 162 | tmp = (3*xm*q) - Math.abs(tol1*q); 163 | if (min < tmp) { 164 | min = tmp; 165 | } 166 | if (2*p < min) { 167 | e = d; 168 | d = p / q; 169 | } else { 170 | d = xm; 171 | e = d; 172 | } 173 | } else { 174 | d = xm; 175 | e = d; 176 | } 177 | a = b; 178 | fa = fb; 179 | if (Math.abs(d) > tol1) { 180 | b = b + d; 181 | } else { 182 | if (xm >=0) { 183 | b = b + tol1; 184 | } else { 185 | b = b - tol1; 186 | } 187 | } 188 | fb = this.func.f(b) - this.o; 189 | } 190 | console.log('none'); 191 | return b; 192 | }; 193 | // Stringify for inline Web Workers 194 | function getBrentString() { 195 | var out = ""; 196 | // Brent 197 | out += Brent.toString() + "\n"; 198 | for (var j in Brent.prototype) { 199 | out += 'Brent.prototype.' + j + '=' + Brent.prototype[j].toString() + "\n"; 200 | } 201 | return out; 202 | } 203 | var workerBrentString = getBrentString(); 204 | -------------------------------------------------------------------------------- /js/colourspaceworker.js: -------------------------------------------------------------------------------- 1 | var lutCSWorker; 2 | if (typeof importScripts === 'function') { 3 | importScripts('colourspaceworkerscombined.js'); 4 | lutCSWorker = new LUTCSWorker(); 5 | } -------------------------------------------------------------------------------- /js/gammaworker.js: -------------------------------------------------------------------------------- 1 | var lutGammaWorker; 2 | if (typeof importScripts === 'function') { 3 | importScripts('gammaworkerscombined.js'); 4 | lutGammaWorker = new LUTGammaWorker(); 5 | } -------------------------------------------------------------------------------- /js/lut-3dl.js: -------------------------------------------------------------------------------- 1 | /* lut-3dl.js 2 | * .3dl LUT building / parsing for the LUTCalc Web App. 3 | * 3rd June 2015 4 | * 5 | * LUTCalc generates 1D and 3D Lookup Tables (LUTs) for video cameras that shoot log gammas, 6 | * principally the Sony CineAlta line. 7 | * 8 | * By Ben Turley, http://turley.tv 9 | * First License: GPLv2 10 | * Github: https://github.com/cameramanben/LUTCalc 11 | */ 12 | function threedlLUT(messages, isLE, flavour) { 13 | this.messages = messages; 14 | this.isLE = isLE; 15 | this.flavour = flavour; 16 | } 17 | threedlLUT.prototype.build = function(buff, fileName, ext) { 18 | var info = {}; 19 | this.messages.getInfo(info); 20 | var lut = new Float64Array(buff); 21 | var max = lut.length; 22 | var d = ''; 23 | max = info.dimension; 24 | var mult = (Math.pow(2,info.inBits)-1)/(max-1); 25 | for (var j=0; j 0) { 37 | d += Math.round(lut[ t ]*mult).toString() + ' '; 38 | } else { 39 | d += '0 '; 40 | } 41 | if (lut[t+1] > 0) { 42 | d += Math.round(lut[t+1]*mult).toString() + ' '; 43 | } else { 44 | d += '0 '; 45 | } 46 | if (lut[t+2] > 0) { 47 | d += Math.round(lut[t+2]*mult).toString() + "\n"; 48 | } else { 49 | d += '0' + "\n"; 50 | } 51 | } 52 | } 53 | } 54 | switch (this.flavour) { 55 | case 1: // Flame 56 | return { 57 | lut: this.header(info) + d, 58 | fileName: fileName, 59 | ext: ext 60 | }; 61 | case 2: // Lustre 62 | return { 63 | lut: this.header(info) + d + this.footer(info), 64 | fileName: fileName, 65 | ext: ext 66 | }; 67 | case 3: // Kodak 68 | return { 69 | lut: this.header(info) + d, 70 | fileName: fileName, 71 | ext: ext 72 | }; 73 | } 74 | }; 75 | threedlLUT.prototype.header = function(info) { 76 | var out = ''; 77 | var date = new Date(); 78 | out += '# Created with LUTCalc ' + info.version + ' by Ben Turley ' + info.date + ' #' + "\n"; 79 | out += '# IDENTIFICATION: LUTCalc - 3DLUT' + "\n"; 80 | out += '# CREATOR: LUTCalc ' + info.version + "\n"; 81 | out += '# USER: LUTCalc' + "\n"; 82 | out += '# DATA: ' + 83 | date.getUTCFullYear() + '-' + 84 | this.addZero(date.getUTCMonth()) + '-' + 85 | this.addZero(date.getUTCDate()) + 'T' + 86 | this.addZero(date.getUTCHours()) + ':' + 87 | this.addZero(date.getUTCMinutes()) + ':' + 88 | this.addZero(date.getUTCSeconds()) + ' #' + "\n"; 89 | out += '# NUMBER OF COLUMNS: 3' + "\n"; 90 | out += '# NUMBER OF ROWS: ' + Math.pow(info.dimension,3).toString() + "\n"; 91 | out += '# NUMBER OF NODES: ' + info.dimension.toString() + "\n"; 92 | out += '# INPUT RANGE: ' + info.inBits.toString() + "\n"; 93 | out += '# OUTPUT RANGE: ' + info.outBits.toString() + "\n"; 94 | out += '# TITLE : ' + info.name + "\n"; 95 | out += '# DESCRIPTION : '; 96 | if (info.nul) { 97 | out += ' Null LUT'; 98 | } else { 99 | if (info.mlut) { 100 | out += 'MLUT'; 101 | } 102 | if (info.doFC) { 103 | out += '*** FALSE COLOUR - DO NOT BAKE IN *** '; 104 | } 105 | if (this.doHG) { 106 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName + '(' + info.hgGamutName + ' in the highlights)'; 107 | } else { 108 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName; 109 | } 110 | out += ', Stop Shift ' + info.cineEI.toFixed(2).toString(); 111 | out += ', Black Level ' + info.blackLevel + '% IRE'; 112 | if (info.legalIn) { 113 | out += ', Legal Input -> '; 114 | } else { 115 | out += ', Data Input -> '; 116 | } 117 | if (info.legalOut) { 118 | out += 'Legal Output'; 119 | } else { 120 | out += 'Data Output'; 121 | } 122 | } 123 | out += "\n"; 124 | if (this.flavour === 2) { 125 | out += '3DMESH' + "\n"; 126 | out += 'Mesh '; 127 | switch (info.dimension) { 128 | case 9: out += '3 '; 129 | break; 130 | case 17: out += '4 '; 131 | break; 132 | case 33: out += '5 '; 133 | break; 134 | case 65: out += '6 '; 135 | break; 136 | case 129: out += '7 '; 137 | break; 138 | } 139 | out += info.outBits.toString() + "\n"; 140 | } 141 | return out; 142 | }; 143 | threedlLUT.prototype.addZero = function(i) { 144 | if (i < 10) { 145 | i = '0' + i; 146 | } 147 | return i; 148 | }; 149 | threedlLUT.prototype.footer = function(info) { 150 | var out = ''; 151 | out += 'LUT8' + "\n"; 152 | out += 'gamma 1.0' + "\n"; 153 | return out; 154 | }; 155 | threedlLUT.prototype.parse = function(title, text, lutMaker, lutDest) { 156 | var size = false; 157 | var minimum = [0,0,0]; 158 | var maximum = [1,1,1]; 159 | var maxIn = 0; 160 | var setMaxIn = false; 161 | var maxOut = false; 162 | var mOut = 0; 163 | var format = 'threedl1'; 164 | var mesh = false; 165 | var outBits = false; 166 | var shaper; 167 | var max = text.length; 168 | if (max === 0) { 169 | return false; 170 | } 171 | var i; 172 | for (i=0; i maxIn) { 184 | maxIn = shaper[l]; 185 | } 186 | if (isNaN(shaper[l])) { 187 | return false; 188 | } 189 | } 190 | i++; 191 | break; 192 | } else if (lower.search('3dmesh') >= 0) { 193 | // 3DMESH line distinguishes two types 194 | mesh = true; 195 | format = 'threedl2'; 196 | } else if (lower.search('mesh') >= 0) { 197 | mesh = true; 198 | format = 'threedl2'; 199 | var bits = line.substr(lower.search('mesh') + 4).trim().split(/\s+/g); 200 | if (!isNaN(bits[0]) && !isNaN(bits[1])) { 201 | size = Math.pow(2,parseInt(bits[0]))+1; 202 | outBits = parseInt(bits[1]); 203 | maxOut = Math.pow(2,outBits)-1; 204 | } 205 | } else if (lower.search('number of rows:') >= 0) { 206 | var val = parseFloat(line.substr(lower.search('number of rows:') + 15)); 207 | if (!isNaN(val)) { 208 | size = Math.round(Math.pow(val, 1/3)); 209 | } 210 | } else if (lower.search('number of nodes:') >= 0) { 211 | var val = parseInt(line.substr(lower.search('number of nodes:') + 16)); 212 | if (!isNaN(val)) { 213 | size = val; 214 | } 215 | } else if (lower.search('input range:') >= 0) { 216 | var val = parseInt(line.substr(lower.search('input range:') + 12).trim()); 217 | if (!isNaN(val)) { 218 | maxIn = Math.pow(2,val)-1; 219 | } 220 | } else if (lower.search('output range:') >= 0) { 221 | var val = parseInt(line.substr(lower.search('output range:') + 13).trim()); 222 | if (!isNaN(val)) { 223 | outBits = val; 224 | maxOut = Math.pow(2,outBits)-1; 225 | } 226 | } else if (lower.search('title:') >= 0) { 227 | title = line.substr(lower.search('title:') + 6).trim(); 228 | } else if (lower.search('gamma') >= 0) { 229 | // Unused at the moment 230 | } else if (lower.search('lut8') >= 0) { 231 | // Unused at the moment 232 | } 233 | } 234 | if (!size) { 235 | // 3D LUT dimension does not need to match shaper, without 'Mesh', must be gauged from the number of entries. Yuck! 236 | size = 0; 237 | for (var k=i; k 0) { 247 | var spline = false; 248 | var doShaper = false; 249 | var m = shaper.length; 250 | if (!setMaxIn) { 251 | if (maxIn < 511) { 252 | maxIn = 255; 253 | } else if (maxIn < 2047) { 254 | maxIn = 1023; 255 | } else if (maxIn < 8191) { 256 | maxIn = 4095; 257 | } else if (maxIn < 32767) { 258 | maxIn = 16383; 259 | } else { 260 | maxIn = 65535; 261 | } 262 | } 263 | for (var j=0; j mOut) { 301 | mOut = R[s]; 302 | } 303 | if (G[s] > mOut) { 304 | mOut = G[s]; 305 | } 306 | if (B[s] > mOut) { 307 | mOut = B[s]; 308 | } 309 | } 310 | b++; 311 | if (b === size) { 312 | b=0; 313 | g++; 314 | } 315 | if (g === size) { 316 | g=0; 317 | r++; 318 | } 319 | s++; 320 | } 321 | } 322 | /* 323 | else if (lower.search('gamma') >= 0) { 324 | // Unused at the moment 325 | } else if (lower.search('lut8') >= 0) { 326 | // Unused at the moment 327 | } 328 | */ 329 | } 330 | if (s === arraySize) { 331 | if (!maxOut) { 332 | if (mOut < 511) { 333 | maxOut = 255; 334 | } else if (mOut < 2047) { 335 | maxOut = 1023; 336 | } else if (mOut < 8191) { 337 | maxOut = 4095; 338 | } else if (mOut < 32767) { 339 | maxOut = 16383; 340 | } else { 341 | maxOut = 65535; 342 | } 343 | for (var j=0; j ' + info.outGammaName; 66 | } else if (this.doHG) { 67 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName + '(' + info.hgGamutName + ' in the highlights)'; 68 | } else { 69 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName; 70 | } 71 | out += ', CineEI Shift ' + info.cineEI.toFixed(2).toString(); 72 | out += ', Black Level ' + info.blackLevel + '% IRE'; 73 | if (info.legalIn) { 74 | out += ', Input 100% -> '; 75 | } else { 76 | out += ', Input 109% -> '; 77 | } 78 | if (info.legalOut) { 79 | out += 'Output 100%'; 80 | } else { 81 | out += 'Output 109%'; 82 | } 83 | } 84 | out += ' - ' + 'Created with LUTCalc ' + info.version + ' by Ben Turley ' + info.date + "\n"; 85 | return out; 86 | }; 87 | cubeLUT.prototype.parse = function(title, text, lutMaker, lutDest) { 88 | var dimensions = false; 89 | var size = false; 90 | var minimum = [0,0,0]; 91 | var maximum = [1,1,1]; 92 | var sysCS = ''; 93 | var laCS = ''; 94 | var laTF = ''; 95 | var laRG = ''; 96 | var laEX = true; 97 | var laMin,laMax; 98 | var baseISO = false; 99 | var interpolation = false; 100 | var laMX = false; 101 | var laMLines = 0; 102 | var max = text.length; 103 | if (max === 0) { 104 | return false; 105 | } 106 | var i; 107 | for (i=0; i= 0) { 114 | title = line.substr(lower.search('title') + 5).trim().replace(/"/g, ''); 115 | } else if (lower.search('lut_3d_size') >= 0) { 116 | var dim = line.substr(lower.search('lut_3d_size') + 11).trim(); 117 | if (!isNaN(dim)) { 118 | dimensions = 3; 119 | size = parseInt(dim); 120 | } 121 | } else if (lower.search('lut_1d_size') >= 0) { 122 | var dim = line.substr(parseInt(lower.search('lut_1d_size')) + 11).trim(); 123 | if (!isNaN(dim)) { 124 | dimensions = 1; 125 | size = parseInt(dim); 126 | } 127 | } else if (lower.search('domain_min') >= 0) { 128 | var dom = line.substr(parseInt(lower.search('domain_min')) + 10).trim().split(/\s+/g); 129 | if (!isNaN(dom[0]) && !isNaN(dom[1]) && !isNaN(dom[2])) { 130 | minimum[0] = parseFloat(dom[0]); 131 | minimum[1] = parseFloat(dom[1]); 132 | minimum[2] = parseFloat(dom[2]); 133 | } 134 | } else if (lower.search('domain_max') >= 0) { 135 | var dom = line.substr(parseInt(lower.search('domain_max')) + 10).trim().split(/\s+/g); 136 | if (!isNaN(dom[0]) && !isNaN(dom[1]) && !isNaN(dom[2])) { 137 | maximum[0] = parseFloat(dom[0]); 138 | maximum[1] = parseFloat(dom[1]); 139 | maximum[2] = parseFloat(dom[2]); 140 | } 141 | } else if (lower.search('lut_3d_input_range') >= 0) { 142 | var ran = line.substr(parseInt(lower.search('lut_3d_input_range')) + 18).trim().split(/\s+/g); 143 | if (!isNaN(ran[0]) && !isNaN(ran[1])) { 144 | minimum[0] = parseFloat(ran[0]); 145 | minimum[1] = minimum[0]; 146 | minimum[2] = minimum[0]; 147 | maximum[0] = parseFloat(ran[1]); 148 | maximum[1] = maximum[0]; 149 | maximum[2] = maximum[0]; 150 | } 151 | } else if (lower.search('lut_1d_input_range') >= 0) { 152 | var ran = line.substr(parseInt(lower.search('lut_1d_input_range')) + 18).trim().split(/\s+/g); 153 | if (!isNaN(ran[0]) && !isNaN(ran[1])) { 154 | minimum[0] = parseFloat(ran[0]); 155 | minimum[1] = minimum[0]; 156 | minimum[2] = minimum[0]; 157 | maximum[0] = parseFloat(ran[1]); 158 | maximum[1] = maximum[0]; 159 | maximum[2] = maximum[0]; 160 | } 161 | } else if (lower.search('# la_system_colourspace') >= 0) { 162 | sysCS = line.substr(parseInt(lower.search('# la_system_colourspace')) + 23).trim(); 163 | } else if (lower.search('# la_input_colourspace') >= 0) { 164 | laCS = line.substr(parseInt(lower.search('# la_input_colourspace')) + 22).trim(); 165 | } else if (lower.search('# la_input_transfer_function') >= 0) { 166 | laTF = line.substr(parseInt(lower.search('# la_input_transfer_function')) + 28).trim(); 167 | } else if (lower.search('# la_base_iso') >= 0) { 168 | baseISO = parseInt(line.substr(parseInt(lower.search('# la_base_iso')) + 13).trim()); 169 | if (isNaN(baseISO)) { 170 | baseISO = false; 171 | } 172 | } else if (lower.search('# la_interpolation') >= 0) { 173 | switch (line.substr(parseInt(lower.search('# la_interpolation')) + 18).trim().toLowerCase()) { 174 | case 'tricubic': interpolation = 0; 175 | break; 176 | case 'tetrahedral': interpolation = 1; 177 | break; 178 | case 'trilinear': interpolation = 2; 179 | break; 180 | } 181 | } else if (lower.search('# la_input_range') >= 0) { 182 | laRG = line.substr(parseInt(lower.search('# la_input_range')) + 16).trim(); 183 | if (laRG === '100') { 184 | laEX = false; 185 | } 186 | } else if (lower.search('# la_input_min') >= 0) { 187 | minimum[0] = parseFloat(line.substr(parseInt(lower.search('# la_input_min')) + 14).trim()); 188 | if (isNaN(minimum[0])) { 189 | minimum[0] = 0; 190 | } else { 191 | minimum[1] = minimum[0]; 192 | minimum[2] = minimum[0]; 193 | } 194 | } else if (lower.search('# la_input_max') >= 0) { 195 | maximum[0] = parseFloat(line.substr(parseInt(lower.search('# la_input_max')) + 14).trim()); 196 | if (isNaN(maximum[0])) { 197 | minimum[0] = 1; 198 | } else { 199 | maximum[1] = maximum[0]; 200 | maximum[2] = maximum[0]; 201 | } 202 | } else if (lower.search('# la_input_matrix_r') >= 0) { 203 | var mat = line.substr(parseInt(lower.search('# la_input_matrix_r')) + 19).trim().split(/\s+/g); 204 | if (!isNaN(mat[0]) && !isNaN(mat[1]) && !isNaN(mat[2])) { 205 | if (laMLines === 0) { 206 | laMX = new Float64Array([1,0,0,0,1,0,0,0,1]); 207 | } 208 | laMX[0] = mat[0]; 209 | laMX[1] = mat[1]; 210 | laMX[2] = mat[2]; 211 | laMLines++; 212 | } 213 | } else if (lower.search('# la_input_matrix_g') >= 0) { 214 | var mat = line.substr(parseInt(lower.search('# la_input_matrix_g')) + 19).trim().split(/\s+/g); 215 | if (!isNaN(mat[0]) && !isNaN(mat[1]) && !isNaN(mat[2])) { 216 | if (laMLines === 0) { 217 | laMX = new Float64Array([1,0,0,0,1,0,0,0,1]); 218 | } 219 | laMX[3] = mat[0]; 220 | laMX[4] = mat[1]; 221 | laMX[5] = mat[2]; 222 | laMLines++; 223 | } 224 | } else if (lower.search('# la_input_matrix_b') >= 0) { 225 | var mat = line.substr(parseInt(lower.search('# la_input_matrix_b')) + 19).trim().split(/\s+/g); 226 | if (!isNaN(mat[0]) && !isNaN(mat[1]) && !isNaN(mat[2])) { 227 | if (laMLines === 0) { 228 | laMX = new Float64Array([1,0,0,0,1,0,0,0,1]); 229 | } 230 | laMX[6] = mat[0]; 231 | laMX[7] = mat[1]; 232 | laMX[8] = mat[2]; 233 | laMLines++; 234 | } 235 | } 236 | } 237 | if (dimensions && size) { 238 | var arraySize = size; 239 | if (dimensions === 3) { 240 | arraySize = size*size*size; 241 | } 242 | var R = new Float64Array(arraySize); 243 | var G = new Float64Array(arraySize); 244 | var B = new Float64Array(arraySize); 245 | var s=0; 246 | for (var k=i; k ' + info.outGammaName; 51 | } else if (this.doHG) { 52 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName + '(' + info.hgGamutName + ' in the highlights)'; 53 | } else { 54 | out += info.inGammaName + '/' + info.inGamutName + ' -> ' + info.outGammaName + '/' + info.outGamutName; 55 | } 56 | out += ', CineEI Shift ' + info.cineEI.toFixed(2).toString(); 57 | out += ', Black Level ' + info.blackLevel + '% IRE'; 58 | if (info.legalIn) { 59 | out += ', Legal Input -> '; 60 | } else { 61 | out += ', Data Input -> '; 62 | } 63 | if (info.legalOut) { 64 | out += 'Legal Output' + "\n"; 65 | } else { 66 | out += 'Data Output' + "\n"; 67 | } 68 | } 69 | out += 'LUT: 3 ' + info.dimension.toString() + "\n"; 70 | return out; 71 | }; 72 | lutLUT.prototype.parse = function(title, text, lutMaker, lutDest) { 73 | var dimensions = 1; 74 | var channels = false; 75 | var size = false; 76 | var max = text.length; 77 | if (max === 0) { 78 | return false; 79 | } 80 | var i; 81 | for (i=0; i= 0) { 88 | var data = line.substr(parseInt(lower.search('lut:')) + 4).trim().split(/\s+/g); 89 | channels = parseInt(data[0]); 90 | size = parseInt(data[1]); 91 | } 92 | } 93 | if (channels && size) { 94 | var arraySize = size; 95 | var div = size-1; 96 | if (channels === 1) { 97 | var L = new Float64Array(arraySize); 98 | var s=0; 99 | max = i+size; 100 | for (var k=i; k= 3) { 136 | var R = new Float64Array(arraySize); 137 | var G = new Float64Array(arraySize); 138 | var B = new Float64Array(arraySize); 139 | var s=0; 140 | max = i+size; 141 | for (var k=i; k yMax) { 54 | yMax = y; 55 | } 56 | } 57 | if (yMin < 0) { 58 | yMin = 0; 59 | } 60 | if (yMax > 1) { 61 | yMax = 1; 62 | } 63 | var yScale = 1/(yMax - yMin); 64 | var h = new Uint8Array(64); 65 | this.header(h, Math.round(yMin*255), Math.round(yMax*255), info); 66 | var p = new Uint8Array(58); 67 | p[0] = 18; 68 | var k = 0; 69 | var i = 0; 70 | for (var j=0; j<18; j++) { 71 | i = j * 15; 72 | p[k+1] = i; 73 | p[k+2] = Math.min(255,Math.max(0,Math.round((( 74 | (0.2126 * (lut[ (i*3) ])) + 75 | (0.7152 * (lut[(i*3)+1])) + 76 | (0.0722 * (lut[(i*3)+2])) 77 | )-yMin)*yScale*255))); 78 | k += 2; 79 | } 80 | var d = new Uint8Array(512); 81 | k=0; 82 | for (var j=0; j 20) { 123 | title = title.substr(0,20); 124 | } else if (title.length === 0) { 125 | title = 'LUTCalc'; 126 | } 127 | this.beString(title,out,k); // Title 128 | k += 20; 129 | var profile = 2; 130 | var m = this.profileName.length; 131 | for (var j=0; j= 0) { 69 | break; 70 | } else if (lower.search('version') >= 0) { 71 | version = parseInt(line.substr(parseInt(lower.search('version')) + 7).trim()); 72 | } else if (lower.search('from') >= 0) { 73 | var data = line.substr(parseInt(lower.search('from')) + 4).trim().split(/\s+/g); 74 | from = parseFloat(data[0]); 75 | to = parseFloat(data[1]); 76 | } else if (lower.search('length') >= 0) { 77 | size = parseInt(line.substr(parseInt(lower.search('length')) + 6).trim()); 78 | } else if (lower.search('components') >= 0) { 79 | channels = parseInt(line.substr(parseInt(lower.search('components')) + 10).trim()); 80 | } 81 | } 82 | if (channels && size) { 83 | var arraySize = size; 84 | i++; 85 | if (channels === 1) { 86 | var L = new Float64Array(arraySize); 87 | var s=0; 88 | for (var k=i; k= 0) { 59 | var i; 60 | for (i=0; i 3) { 79 | // stop parsing when the LUT data is reached 80 | break; 81 | } 82 | } 83 | } 84 | if (dimensions && size) { 85 | var arraySize = size; 86 | if (dimensions === 3) { 87 | arraySize = size[0]*size[1]*size[2]; 88 | } 89 | var R = new Float64Array(arraySize); 90 | var G = new Float64Array(arraySize); 91 | var B = new Float64Array(arraySize); 92 | var s; 93 | var t=0; 94 | for (var k=i; k= 0) { 56 | title = line.substr(lower.search('title') + 5).trim().replace(/"/g, ''); 57 | } else if (lower.search('lut_3d_size') >= 0) { 58 | var dim = line.substr(lower.search('lut_3d_size') + 11).trim(); 59 | if (!isNaN(dim)) { 60 | dimensions = 3; 61 | size = parseInt(dim); 62 | } 63 | } else if (lower.search('lut_1d_size') >= 0) { 64 | var dim = line.substr(parseInt(lower.search('lut_1d_size')) + 11).trim(); 65 | if (!isNaN(dim)) { 66 | dimensions = 1; 67 | size = parseInt(dim); 68 | } 69 | } else if (lower.search('domain_min') >= 0) { 70 | var dom = line.substr(parseInt(lower.search('domain_min')) + 10).trim().split(/\s+/g); 71 | if (!isNaN(dom[0]) && !isNaN(dom[1]) && !isNaN(dom[2])) { 72 | minimum[0] = parseInt(dom[0]); 73 | minimum[1] = parseInt(dom[1]); 74 | minimum[2] = parseInt(dom[2]); 75 | } 76 | } else if (lower.search('domain_max') >= 0) { 77 | var dom = line.substr(parseInt(lower.search('domain_max')) + 10).trim().split(/\s+/g); 78 | if (!isNaN(dom[0]) && !isNaN(dom[1]) && !isNaN(dom[2])) { 79 | maximum[0] = parseInt(dom[0]); 80 | maximum[1] = parseInt(dom[1]); 81 | maximum[2] = parseInt(dom[2]); 82 | } 83 | } else if (lower.search('lut_3d_input_range') >= 0) { 84 | var ran = line.substr(parseInt(lower.search('lut_3d_input_range')) + 18).trim().split(/\s+/g); 85 | if (!isNaN(ran[0]) && !isNaN(ran[1])) { 86 | minimum[0] = parseInt(ran[0]); 87 | minimum[1] = minimum[0]; 88 | minimum[2] = minimum[0]; 89 | maximum[0] = parseInt(ran[1]); 90 | maximum[1] = maximum[0]; 91 | maximum[2] = maximum[0]; 92 | } 93 | } else if (lower.search('lut_1d_input_range') >= 0) { 94 | var ran = line.substr(parseInt(lower.search('lut_1d_input_range')) + 18).trim().split(/\s+/g); 95 | if (!isNaN(ran[0]) && !isNaN(ran[1])) { 96 | minimum[0] = parseInt(ran[0]); 97 | minimum[1] = minimum[0]; 98 | minimum[2] = minimum[0]; 99 | maximum[0] = parseInt(ran[1]); 100 | maximum[1] = maximum[0]; 101 | maximum[2] = maximum[0]; 102 | } 103 | } 104 | } 105 | if (dimensions && size) { 106 | var arraySize = size; 107 | if (dimensions === 3) { 108 | arraySize = size*size*size; 109 | } 110 | var R = new Float64Array(arraySize); 111 | var G = new Float64Array(arraySize); 112 | var B = new Float64Array(arraySize); 113 | var s=0; 114 | for (var k=i; k= 0) { 137 | mono = 1; 138 | } else if (mono < 0) { 139 | mono = -1; 140 | } 141 | if ((C[1]-C[0])*mono <= 0) { 142 | C[0] = (2*C[1]) - C[2]; 143 | if ((C[1]-C[0])*mono <= 0) { // still opposite slope to monotonic 144 | C[0] = C[1] - (0.0075 * mono / (m-1)); 145 | } 146 | } 147 | if ((C[m-1]-C[m-2])*mono <= 0) { 148 | C[m-1] = (2*C[m-2]) - C[m-3]; 149 | if ((C[m-1]-C[m-2])*mono <= 0) { // still opposite slope to monotonic 150 | C[m-1] = C[m-2] + (0.0075 * mono / (m-1)); 151 | } 152 | } 153 | this.tf = this.lutMaker.newLUT({ 154 | title: 'Transfer Function', 155 | format: 'cube', 156 | dims: 1, 157 | s: m, 158 | min: [0,0,0], 159 | max: [1,1,1], 160 | C: [buff.slice(0)], 161 | meta: { 162 | inputTF: inputTF 163 | } 164 | }); 165 | this.tfSpline = new LUTRSpline({buff:buff, fL:0, fH:1}); 166 | this.pass = 1; 167 | this.getCS(); 168 | } else if (this.inLUT.is3D()) { // Colour Space Pass 169 | var m = dim*dim*dim; 170 | var R = new Float64Array(m); 171 | var G = new Float64Array(m); 172 | var B = new Float64Array(m); 173 | var rgb = this.inputData; 174 | var inputMatrix = new Float64Array(buff); 175 | // Run the test data through the input LUT 176 | var method; 177 | if (this.inputs.laIntMethod[0].checked) { 178 | method = 0; 179 | this.inLUT.RGBCub(rgb.buffer); 180 | } else if (this.inputs.laIntMethod[1].checked) { 181 | method = 1; 182 | this.inLUT.RGBTet(rgb.buffer); 183 | } else { 184 | method = 2; 185 | this.inLUT.RGBLin(rgb.buffer); 186 | } 187 | for (var j=0; j= 0) { 218 | mono = 1; 219 | } else if (mono < 0) { 220 | mono = -1; 221 | } 222 | if ((Y[1]-Y[0])*mono <= 0) { 223 | Y[0] = (2*Y[1]) - Y[2]; 224 | if ((Y[1]-Y[0])*mono <= 0) { // still opposite slope to monotonic 225 | Y[0] = Y[1] - (0.0075 * mono / (dim-1)); 226 | } 227 | } 228 | if ((Y[dim-1]-Y[dim-2])*mono <= 0) { 229 | Y[dim-1] = (2*Y[dim-2]) - Y[dim-3]; 230 | if ((Y[dim-1]-Y[dim-2])*mono <= 0) { // still opposite slope to monotonic 231 | Y[dim-1] = Y[dim-2] + (0.0075 * mono / (dim-1)); 232 | } 233 | } 234 | } 235 | var tfSpline = new LUTRSpline({buff:Y.buffer, fL:0, fH:1}); 236 | tfSpline.setMethod(method); 237 | // Find the reverse of the LUTTed data 238 | tfSpline.R(R.buffer); 239 | tfSpline.R(G.buffer); 240 | tfSpline.R(B.buffer); 241 | // Limit the results 242 | var minMax = this.inLUT.minMax(); 243 | var lo = Math.min( 0, tfSpline.r(Math.min(minMax[0],minMax[1],minMax[2]))); // 0, or the lowest value in the mesh, whichever the greater 244 | var hi = Math.max( 1, tfSpline.r(Math.max(minMax[3],minMax[4],minMax[5]))); // 1.0, or the highest value in the mesh, whichever the lesser 245 | var min = lo - (87.6/1023); // 10% IRE below the 'lo' value 246 | var max = hi + (175.2/1023); // 20% IRE above 'hi' value 247 | var dcLo = tfSpline.df(lo); 248 | var dcHi = tfSpline.df(hi); 249 | var numLo = Math.pow(min-lo,2); 250 | var denLo = min-lo; 251 | var numHi = Math.pow(max-hi,2); 252 | var denHi = max-hi; 253 | for (var j=0; j hi) { 257 | R[j] = max - (numHi/((dcHi*(R[j]-hi))+denHi)); 258 | } 259 | if (G[j] < lo) { 260 | G[j] = min - (numLo/((dcLo*(G[j]-lo))+denLo)); 261 | } else if (G[j] > hi) { 262 | G[j] = max - (numHi/((dcHi*(G[j]-hi))+denHi)); 263 | } 264 | if (B[j] < lo) { 265 | B[j] = min - (numLo/((dcLo*(B[j]-lo))+denLo)); 266 | } else if (B[j] > hi) { 267 | B[j] = max - (numHi/((dcHi*(B[j]-hi))+denHi)); 268 | } 269 | } 270 | var inputCS = this.inputs.laGamutSelect.options[this.inputs.laGamutSelect.selectedIndex].text.trim(); 271 | var meta = { 272 | inputTF: inputTF, 273 | systemCS: 'Sony S-Gamut3.cine', 274 | inputCS: inputCS, 275 | inputEX: !this.legIn, 276 | nativeTF: this.natTF, 277 | interpolation: method, 278 | inputMatrix: inputMatrix 279 | }; 280 | if (inputTF.indexOf('LogC') !== -1) { 281 | meta.baseISO = parseInt(this.inputs.cineEI.value); 282 | } 283 | this.cs = this.lutMaker.newLUT({ 284 | title: 'Colour Space', 285 | format: 'cube', 286 | dims: 3, 287 | s: dim, 288 | min: [0,0,0], 289 | max: [1,1,1], 290 | C: [R.buffer,G.buffer,B.buffer], 291 | meta: meta 292 | }); 293 | this.showGt = true; 294 | this.updateLATF(); 295 | this.updateLACS(); 296 | } else { 297 | this.showGt = false; 298 | this.updateLATF(); 299 | } 300 | }; 301 | LUTAnalyst.prototype.updateLACS = function() { 302 | this.gtT = this.messages.getGamutThreads(); 303 | var d = this.cs.getDetails(); 304 | var meta = d.meta; 305 | if (typeof d.min === 'undefined') { 306 | d.min = new Float64Array([0,0,0]); 307 | } 308 | if (typeof d.max === 'undefined') { 309 | d.max = new Float64Array([1,1,1]); 310 | } 311 | var details = { 312 | title: d.title, 313 | format: d.format, 314 | dims: d.dims, 315 | s: d.s, 316 | min: d.min, 317 | max: d.max, 318 | meta: meta 319 | }; 320 | if (d.d === 3 || d.C.length === 3) { 321 | details.C = [ 322 | d.C[0].slice(0), 323 | d.C[1].slice(0), 324 | d.C[2].slice(0) 325 | ]; 326 | } else { 327 | details.C = [d.C[0].slice(0)]; 328 | } 329 | //set LUT here 330 | this.messages.gtTxAll(this.p,6,details); 331 | }; 332 | LUTAnalyst.prototype.getRGB = function() { 333 | if (this.showGt) { 334 | return this.cs.getRGB(); 335 | } else { 336 | return false; 337 | } 338 | }; 339 | LUTAnalyst.prototype.setLUT = function(lut, data) { 340 | this[lut] = this.lutMaker.newLUT(data); 341 | if (typeof this[lut] !== 'undefined') { 342 | this.showGt = true; 343 | return true; 344 | } else { 345 | return false; 346 | } 347 | }; 348 | LUTAnalyst.prototype.noCS = function() { 349 | this.showGt = false; 350 | }; 351 | LUTAnalyst.prototype.showGamut = function() { 352 | return this.showGt; 353 | }; 354 | // Loading progress bar 355 | if (typeof splash !== 'undefined') { 356 | splashProg(); 357 | } 358 | -------------------------------------------------------------------------------- /js/lutmobile.js: -------------------------------------------------------------------------------- 1 | /* lutmobile.js 2 | * Menu and control objects for using the LUTCalc Web App on mobiles. 3 | * 9th March 2017 4 | * 5 | * LUTCalc generates 1D and 3D Lookup Tables (LUTs) for video cameras that shoot log gammas, 6 | * principally the Sony CineAlta line. 7 | * 8 | * By Ben Turley, http://turley.tv 9 | * First License: GPLv2 10 | * Github: https://github.com/cameramanben/LUTCalc 11 | */ 12 | function LUTMobile(fieldset, inputs, messages, modalBox, objects) { 13 | this.inputs = inputs; 14 | this.messages = messages; 15 | this.modalBox = modalBox; 16 | this.objects = objects; 17 | this.box = fieldset; 18 | this.p = 16; 19 | this.messages.addUI(this.p,this); 20 | this.io(); 21 | this.ui(); 22 | } 23 | LUTMobile.prototype.io = function() { 24 | // Main 'Hamburger' menu button 25 | this.menuButton = document.createElement('div'); 26 | this.menuButton.id = 'mob-menu-button'; 27 | this.menuButton.appendChild(document.createElement('div')); 28 | this.menuButton.appendChild(document.createElement('div')); 29 | this.menuButton.appendChild(document.createElement('div')); 30 | // Status text carrier 31 | this.statusText = document.createElement('span'); 32 | this.statusText.id = 'mob-status-text'; 33 | this.statusText.innerHTML = 'LUTCalc ' + this.inputs.version; 34 | // Preview toggle button 35 | this.preButton = document.createElement('div'); 36 | this.preButton.className = 'mob-preview-icon'; 37 | // Main menu options 38 | this.genButton = document.createElement('input'); 39 | this.genButton.setAttribute('type','button'); 40 | this.genButton.className = 'mob-button'; 41 | this.genButton.value = 'Generate LUT'; 42 | this.setButton = document.createElement('input'); 43 | this.setButton.setAttribute('type','button'); 44 | this.setButton.className = 'mob-button'; 45 | this.setButton.value = 'Base Settings'; 46 | this.twkButton = document.createElement('input'); 47 | this.twkButton.setAttribute('type','button'); 48 | this.twkButton.className = 'mob-button'; 49 | this.twkButton.value = 'Adjustments'; 50 | this.infButton = document.createElement('input'); 51 | this.infButton.setAttribute('type','button'); 52 | this.infButton.className = 'mob-button'; 53 | this.infButton.value = 'Instructions'; 54 | // Mobile-specific elements for the main DOM 55 | this.generateButton = document.createElement('input'); 56 | this.generateButton.setAttribute('type','button'); 57 | this.generateButton.className = 'mob-genbutton'; 58 | this.generateButton.value = 'Generate LUT'; 59 | // Get the DOM objects for each of the main options 60 | this.boxes = { 61 | cam: document.getElementById('box-cam'), 62 | gam: document.getElementById('box-gam'), 63 | twk: document.getElementById('box-twk'), 64 | lut: document.getElementById('box-lut'), 65 | pre: document.getElementById('box-pre'), 66 | inf: document.getElementById('box-inf'), 67 | rhs: document.getElementById('right') 68 | }; 69 | // Get the DOM objects for each of the tweak options 70 | var twkBoxes = document.getElementById('tweaksholder').childNodes; 71 | var m = twkBoxes.length; 72 | for (var j=0; j top-2) { 90 | d1 = (this.L[(f + 3)%top] + this.r - this.L[f])/2; 91 | } else { 92 | d1 = (this.L[f + 2] - this.L[f])/2; 93 | } 94 | var a = (2 * p0) + d0 - (2 * p1) + d1; 95 | var b = - (3 * p0) - (2 * d0) + (3 * p1) - d1; 96 | var c = d0; 97 | var d = p0; 98 | L -= f; 99 | return (((((a * L) + b) * L) + c) * L) + d; 100 | }; 101 | Ring.prototype.fCub = function(L) { 102 | if (this.mod) { 103 | return this.cubMod(L); 104 | } else { 105 | return this.cub(L); 106 | } 107 | }; 108 | Ring.prototype.fLin = function(L) { 109 | if (this.mod) { 110 | return this.linMod(L); 111 | } else { 112 | return this.lin(L); 113 | } 114 | }; 115 | Ring.prototype.cub = function(L) { 116 | var top = (this.s - 1); 117 | L = L%1; 118 | if (L<0) { 119 | L += 1; 120 | } 121 | L = L * top; 122 | var f = Math.floor(L); 123 | var p0,p1; 124 | var d0,d1; 125 | p0 = this.L[f]; 126 | if (f === top) { 127 | p1 = this.L[1] + this.r; 128 | d0 = (p1 - this.L[f-1])/2; 129 | } else if (f === 0) { 130 | p1 = this.L[1]; 131 | d0 = (p1 - this.L[top-1] + this.r)/2; 132 | } else { 133 | p1 = this.L[f+1]; 134 | d0 = (p1 - this.L[f - 1])/2; 135 | } 136 | if (f > top-2) { 137 | d1 = (this.L[(f + 3)%top] + this.r - this.L[f])/2; 138 | } else { 139 | d1 = (this.L[f + 2] - this.L[f])/2; 140 | } 141 | var a = (2 * p0) + d0 - (2 * p1) + d1; 142 | var b = - (3 * p0) - (2 * d0) + (3 * p1) - d1; 143 | var c = d0; 144 | var d = p0; 145 | L -= f; 146 | return (((((a * L) + b) * L) + c) * L) + d; 147 | }; 148 | Ring.prototype.cubMod = function(L) { 149 | var top = (this.s - 1); 150 | L = L%1; 151 | if (L<0) { 152 | L += 1; 153 | } 154 | L = L * top; 155 | var f = Math.floor(L); 156 | var mod = this.mod; 157 | var sp = mod * 0.5; 158 | var p0,p1; 159 | var pm1,p2; 160 | var d0,d1; 161 | p0 = this.L[f]; 162 | if (f === top) { 163 | p1 = this.L[1] + this.r; 164 | pm1 = this.L[f-1]; 165 | } else if (f === 0) { 166 | p1 = this.L[1]; 167 | pm1 = this.L[top-1] - this.r; 168 | } else { 169 | p1 = this.L[f+1]; 170 | pm1 = this.L[f - 1]; 171 | } 172 | if (f > top-2) { 173 | p2 = this.L[(f + 3)%top] + this.r; 174 | } else { 175 | p2 = this.L[f + 2]; 176 | } 177 | if (p0-pm1 > sp) { 178 | pm1 += mod; 179 | } else if (pm1-p0 > sp) { 180 | pm1 -= mod; 181 | } 182 | if (p0-p1 > sp) { 183 | p1 += mod; 184 | } else if (p1-p0 > sp) { 185 | p1 -= mod; 186 | } 187 | if (p0-p2 > sp) { 188 | p2 += mod; 189 | } else if (p2-p0 > sp) { 190 | p2 -= mod; 191 | } 192 | pm1 = pm1%mod; 193 | p0 = p0%mod; 194 | p1 = p1%mod; 195 | p2 = p2%mod; 196 | d0 = (p1 - pm1)/2; 197 | d1 = (p2 - p0)/2; 198 | var a = (2 * p0) + d0 - (2 * p1) + d1; 199 | var b = - (3 * p0) - (2 * d0) + (3 * p1) - d1; 200 | var c = d0; 201 | var d = p0; 202 | L -= f; 203 | return (((((a * L) + b) * L) + c) * L) + d; 204 | }; 205 | Ring.prototype.lin = function(L) { 206 | var top = this.s - 1; 207 | L = L%1; 208 | if (L<0) { 209 | L += 1; 210 | } 211 | L *= top; 212 | var f = Math.floor(L); 213 | var dy = L - f; 214 | if (f === top) { 215 | return (this.L[f] * (1 - dy)) + ((this.L[1]+this.r) * dy); 216 | } else { 217 | return (this.L[f] * (1 - dy)) + (this.L[f + 1] * dy); 218 | } 219 | }; 220 | Ring.prototype.linMod = function(L) { 221 | var top = this.s - 1; 222 | var mod = this.mod; 223 | var sp = mod * 0.5; 224 | L = L%1; 225 | if (L<0) { 226 | L += 1; 227 | } 228 | L *= top; 229 | var f = Math.floor(L); 230 | var dy = L - f; 231 | var p0 = this.L[f]; 232 | var p1; 233 | if (f === top) { 234 | p1 = this.L[1]+this.r; 235 | } else { 236 | p1 = this.L[f + 1]; 237 | } 238 | if (p0-p1 > sp) { 239 | p1 += mod; 240 | } else if (p1-p0 > sp) { 241 | p1 -= mod; 242 | } 243 | p1 = p1%mod; 244 | return (p0 * (1 - dy)) + (p1 * dy); 245 | }; 246 | Ring.prototype.lLsCub = function(buff) { 247 | if (this.mod) { 248 | this.cubsMod(buff); 249 | } else { 250 | this.cubs(buff); 251 | } 252 | }; 253 | Ring.prototype.cubs = function(buff) { 254 | var o = new Float64Array(buff); 255 | var m = o.length; 256 | var max = this.s - 1; 257 | var f; 258 | var p0,p1; 259 | var d0,d1; 260 | var a,b,c,d; 261 | for (var j=0; j max-2) { 280 | d1 = (this.L[(f + 3)%max] + this.r - this.L[f])/2; 281 | } else { 282 | d1 = (this.L[f + 2] - this.L[f])/2; 283 | } 284 | a = (2 * p0) + d0 - (2 * p1) + d1; 285 | b = - (3 * p0) - (2 * d0) + (3 * p1) - d1; 286 | c = d0; 287 | d = p0; 288 | o[j] -= f; 289 | o[j] = (((((a * o[j]) + b) * o[j]) + c) * o[j]) + d; 290 | } 291 | }; 292 | Ring.prototype.cubsMod = function(buff) { 293 | var o = new Float64Array(buff); 294 | var m = o.length; 295 | var max = this.s - 1; 296 | var f; 297 | var p0,p1; 298 | var pm1,p2; 299 | var d0,d1; 300 | var a,b,c,d; 301 | var mod = this.mod; 302 | var sp = mod * 0.5; 303 | for (var j=0; j max-2) { 322 | p2 = this.L[(f + 3)%max] + this.r; 323 | } else { 324 | p2 = this.L[f + 2]; 325 | } 326 | if (p0-pm1 > sp) { 327 | pm1 += mod; 328 | } else if (pm1-p0 > sp) { 329 | pm1 -= mod; 330 | } 331 | if (p0-p1 > sp) { 332 | p1 += mod; 333 | } else if (p1-p0 > sp) { 334 | p1 -= mod; 335 | } 336 | if (p0-p2 > sp) { 337 | p2 += mod; 338 | } else if (p2-p0 > sp) { 339 | p2 -= mod; 340 | } 341 | pm1 = pm1%mod; 342 | p0 = p0%mod; 343 | p1 = p1%mod; 344 | p2 = p2%mod; 345 | d0 = (p1 - pm1)/2; 346 | d1 = (p2 - p0)/2; 347 | a = (2 * p0) + d0 - (2 * p1) + d1; 348 | b = - (3 * p0) - (2 * d0) + (3 * p1) - d1; 349 | c = d0; 350 | d = p0; 351 | o[j] -= f; 352 | o[j] = (((((a * o[j]) + b) * o[j]) + c) * o[j]) + d; 353 | } 354 | }; 355 | Ring.prototype.lLsLin = function(buff) { 356 | if (this.mod) { 357 | this.linsMod(buff); 358 | } else { 359 | this.lins(buff); 360 | } 361 | }; 362 | Ring.prototype.lins = function(buff) { 363 | var o = new Float64Array(buff); 364 | var m = o.length; 365 | var max = this.s - 1; 366 | var f, dy; 367 | for (var j=0; j sp) { 405 | p1 += mod; 406 | } else if (p1-p0 > sp) { 407 | p1 -= mod; 408 | } 409 | p1 = p1%mod; 410 | o[j] = (p0 * (1 - dy)) + (p1 * dy); 411 | } 412 | }; 413 | // Stringify for inline Web Workers 414 | function getRingString() { 415 | var out = ""; 416 | // Ring 417 | out += Ring.toString() + "\n"; 418 | for (var j in Ring.prototype) { 419 | out += 'Ring.prototype.' + j + '=' + Ring.prototype[j].toString() + "\n"; 420 | } 421 | return out; 422 | } 423 | var workerRingString = getRingString(); 424 | -------------------------------------------------------------------------------- /js/splash.js: -------------------------------------------------------------------------------- 1 | /* splash.js 2 | * Changes Javascript warning into a splash screen in the LUTCalc Web App. 3 | * Also creates browser feature test and global data objects 4 | * 17th March 2017 5 | * 6 | * LUTCalc generates 1D and 3D Lookup Tables (LUTs) for video cameras that shoot log gammas, 7 | * principally the Sony CineAlta line. 8 | * 9 | * By Ben Turley, http://turley.tv 10 | * First License: GPLv2 11 | * Github: https://github.com/cameramanben/LUTCalc 12 | */ 13 | /************************* LUTInputs *************************/ 14 | /*********** Data available globally within LUTCalc **********/ 15 | function LUTInputs() { 16 | this.ready = [true, 17 | false, // 1 - camerabox 18 | false, // 2 - gammabox 19 | false, // 3 - tweaksbox 20 | false, // 4 - lutbox 21 | false, // 5 - generatebox 22 | false, // 6 - infobox 23 | false, // 7 - LUTAnalyst 24 | false, // 8 - preview 25 | false, // 9 - twkHG 26 | false, // 10 - twkLA 27 | ]; 28 | this.isMobile = false; // Assume not on a mobile until proven otherwise 29 | } 30 | LUTInputs.prototype.addInput = function(inputName,inputValue) { 31 | try { 32 | this[inputName] = inputValue; 33 | return true; 34 | } catch(err) { 35 | return false; 36 | } 37 | }; 38 | LUTInputs.prototype.isReady = function(ui) { 39 | var ready = true; 40 | var m = this.ready.length; 41 | for (var j=0; j 0) { 129 | lutInputs.addInput('isLE', true); 130 | } else { 131 | lutInputs.addInput('isLE', false); 132 | } 133 | }; 134 | LUTTests.prototype.isTransTest = function(worker) { // Test that web workers can use transferrable objects 135 | var trans; 136 | try { 137 | var test = new ArrayBuffer(1); 138 | worker.postMessage(test, [test]); 139 | trans = (test.byteLength === 0); 140 | } catch(error) { 141 | trans = false; 142 | } 143 | this.inputs.isTrans = trans; 144 | }; 145 | /******* Modal box to freeze all UI buttons and inputs *******/ 146 | var modalBox = document.createElement('div'); 147 | modalBox.className = 'modalbox-hide'; 148 | modalBox.onclick = function(here){ return function(){ 149 | // Do nothing - stops anything else from happening whilst the modal box is active. 150 | };}(this); 151 | /********************* Splash screen code ********************/ 152 | function splashStart() { 153 | document.getElementById('titlebar').className = 'titlebar-hide'; 154 | document.getElementById('lutcalcform').className = 'lutcalcform-hide'; 155 | document.getElementById('footer').className = 'footer-hide'; 156 | var splash = document.getElementById('javascriptwarning'); 157 | splash.removeChild(splash.firstChild); 158 | splash.className = 'splash'; 159 | splashTxt(splash); 160 | return splash; 161 | } 162 | var splashInterval = false; 163 | function splashTxt(splash) { 164 | var splashText = document.createElement('div'); 165 | var splashTitle = document.createElement('h1'); 166 | splashTitle.innerHTML = 'LUTCalc ' + lutInputs.version; 167 | splashText.appendChild(splashTitle); 168 | splashText.appendChild(document.createElement('br')); 169 | var splashCredit = document.createElement('h5'); 170 | splashCredit.innerHTML = 'Ben Turley ' + lutInputs.date; 171 | splashText.appendChild(splashCredit); 172 | splash.appendChild(splashText); 173 | lutInputs.addInput('splashProgress',document.createElement('span')); 174 | lutInputs.addInput('splashPer',0); 175 | var progressBox = document.createElement('span'); 176 | progressBox.id = 'splash-progress-box'; 177 | lutInputs.splashProgress.id = 'splash-progress'; 178 | lutInputs.splashProgress.style.width = lutInputs.splashPer.toString() + '%'; 179 | progressBox.appendChild(lutInputs.splashProgress); 180 | splash.appendChild(progressBox); 181 | splashInterval = setInterval(updateSplash,10); 182 | } 183 | function splashProg(step) { 184 | var s; 185 | if (typeof step === 'undefined') { 186 | s = 0.25; 187 | } else { 188 | s = step; 189 | } 190 | lutInputs.splashPer += s; 191 | } 192 | function updateSplash() { 193 | if (lutInputs.splashPer <= 100) { 194 | lutInputs.splashProgress.style.width = Math.round(lutInputs.splashPer).toString() + '%'; 195 | } else { 196 | clearInterval(splashInterval); 197 | return; 198 | } 199 | } 200 | 201 | /********************** Start things up **********************/ 202 | var lutInputs = new LUTInputs(); 203 | lutInputs.addInput('version','v4.09'); 204 | lutInputs.addInput('versionNum', 4.09); 205 | lutInputs.addInput('date','February 2025'); 206 | var splash = splashStart(); 207 | var lutTests = new LUTTests(lutInputs); 208 | -------------------------------------------------------------------------------- /js/twk-asccdl.js: -------------------------------------------------------------------------------- 1 | /* twk-asccdl.js 2 | * ASC-CDL object for the LUTCalc Web App. 3 | * 10th April 2015 4 | * 5 | * LUTCalc generates 1D and 3D Lookup Tables (LUTs) for video cameras that shoot log gammas, 6 | * principally the Sony CineAlta line. 7 | * 8 | * By Ben Turley, http://turley.tv 9 | * First License: GPLv2 10 | * Github: https://github.com/cameramanben/LUTCalc 11 | */ 12 | function TWKASCCDL(tweaksBox, inputs, messages) { 13 | this.tweaksBox = tweaksBox; 14 | this.inputs = inputs; 15 | this.messages = messages; 16 | this.io(); 17 | this.ui(); 18 | } 19 | TWKASCCDL.prototype.io = function() { 20 | // Tweak Checkbox 21 | this.tweakCheck = document.createElement('input'); 22 | this.tweakCheck.setAttribute('type','checkbox'); 23 | this.tweakCheck.className = 'twk-checkbox'; 24 | this.tweakCheck.checked = false; 25 | 26 | // Saturation Slider 27 | this.satS = new lutSlider({ 28 | min: 0, 29 | max: 2, 30 | value: 1, 31 | step: 0.05, 32 | title: false, 33 | lhs: 'Saturation', 34 | minLabel: false, 35 | maxLabel: false, 36 | input: 'number', 37 | inputLim: false, 38 | reset: true 39 | }); 40 | // Colour Channel Selector 41 | this.channelSelect = document.createElement('select'); 42 | this.channelSelect.className = 'twk-select'; 43 | this.channelList(); 44 | // SOP Arrays 45 | this.sS = []; 46 | this.oS = []; 47 | this.pS = []; 48 | for (var j=0; j<4; j++) { 49 | this.sS[j] = new lutSlider({ 50 | min: 0, 51 | mid: 1, 52 | max: 10, 53 | value: 1, 54 | step: 0.0001, 55 | title: false, 56 | lhs: 'Slope', 57 | minLabel: false, 58 | maxLabel: false, 59 | input: 'number', 60 | inputLim: false, 61 | reset: true, 62 | resetAll: true 63 | }); 64 | this.oS[j] = new lutSlider({ 65 | min: -0.5, 66 | max: 0.5, 67 | value: 0, 68 | step: 0.01, 69 | title: false, 70 | lhs: 'Offset', 71 | minLabel: false, 72 | maxLabel: false, 73 | input: 'number', 74 | inputLim: false, 75 | reset: true, 76 | resetAll: true 77 | }); 78 | this.pS[j] = new lutSlider({ 79 | min: 0, 80 | mid: 1, 81 | max: 10, 82 | value: 1, 83 | step: 0.01, 84 | title: false, 85 | lhs: 'Power', 86 | minLabel: false, 87 | maxLabel: false, 88 | input: 'number', 89 | inputLim: false, 90 | reset: true, 91 | resetAll: true 92 | }); 93 | } 94 | }; 95 | TWKASCCDL.prototype.ui = function() { 96 | // General Tweak Holder (Including Checkbox) 97 | this.holder = document.createElement('div'); 98 | this.holder.className = 'tweakholder-hide'; 99 | this.tweaksBox.appendChild(this.holder); 100 | this.holder.appendChild(document.createElement('label').appendChild(document.createTextNode('ASC-CDL'))); 101 | this.holder.appendChild(this.tweakCheck); 102 | // Tweak Box - Inputs Which Appear When the Tweak Checkbox Is Ticked 103 | this.box = document.createElement('div'); 104 | this.box.className = 'tweak-hide'; 105 | // Tweak - Specific UI Elements 106 | // Saturation 107 | this.box.appendChild(this.satS.element); 108 | // Channel Selector 109 | this.box.appendChild(this.channelSelect); 110 | this.box.appendChild(document.createElement('br')); 111 | // SOP Boxes 112 | this.sop = []; 113 | for (var j=0; j<4; j++) { 114 | this.sop[j] = document.createElement('div'); 115 | if (j === 0) { 116 | this.sop[j].className = 'twk-tab'; 117 | } else { 118 | this.sop[j].className = 'twk-tab-hide'; 119 | } 120 | this.sop[j].appendChild(this.sS[j].element); 121 | this.sop[j].appendChild(this.oS[j].element); 122 | this.sop[j].appendChild(this.pS[j].element); 123 | this.box.appendChild(this.sop[j]); 124 | } 125 | // Build Box Hierarchy 126 | this.holder.appendChild(this.box); 127 | }; 128 | TWKASCCDL.prototype.toggleTweaks = function() { 129 | // If The Overall Checkbox Is Ticked 130 | if (this.inputs.tweaks.checked) { 131 | if (this.inputs.outGamma.options[this.inputs.outGamma.selectedIndex].lastChild.nodeValue !== 'Null') { 132 | this.holder.className = 'tweakholder'; 133 | } else { 134 | this.holder.className = 'tweakholder-hide'; 135 | this.tweakCheck.checked = false; 136 | } 137 | if (this.inputs.d[1].checked) { 138 | this.satS.show(); 139 | } else { 140 | this.satS.hide(); 141 | } 142 | } else { 143 | this.holder.className = 'tweakholder-hide'; 144 | this.tweakCheck.checked = false; 145 | } 146 | this.toggleTweak(); 147 | }; 148 | TWKASCCDL.prototype.toggleTweak = function() { 149 | if (this.tweakCheck.checked) { 150 | this.box.className = 'tweak'; 151 | } else { 152 | this.box.className = 'tweak-hide'; 153 | } 154 | }; 155 | TWKASCCDL.prototype.getTFParams = function(params) { 156 | var out = {}; 157 | var tweaks = this.inputs.tweaks.checked; 158 | var tweak = this.tweakCheck.checked; 159 | if (tweaks && tweak) { 160 | out.doASCCDL = true; 161 | var cdl = new Float64Array(10); 162 | for (var j=0; j<3; j++) { 163 | cdl[ j ] = this.sS[j+1].getValue(); 164 | cdl[j+3] = this.oS[j+1].getValue(); 165 | cdl[j+6] = this.pS[j+1].getValue(); 166 | } 167 | cdl[9] = this.satS.getValue(); 168 | out.cdl = cdl.buffer; 169 | } else { 170 | out.doASCCDL = false; 171 | } 172 | params.twkASCCDL = out; 173 | }; 174 | TWKASCCDL.prototype.getCSParams = function(params) { 175 | var out = {}; 176 | var tweaks = this.inputs.tweaks.checked; 177 | var tweak = this.tweakCheck.checked; 178 | if (tweaks && tweak) { 179 | out.doASCCDL = true; 180 | var cdl = new Float64Array(10); 181 | for (var j=0; j<3; j++) { 182 | cdl[ j ] = this.sS[j+1].getValue(); 183 | cdl[j+3] = this.oS[j+1].getValue(); 184 | cdl[j+6] = this.pS[j+1].getValue(); 185 | } 186 | cdl[9] = this.satS.getValue(); 187 | out.cdl = cdl.buffer; 188 | } else { 189 | out.doASCCDL = false; 190 | } 191 | params.twkASCCDL = out; 192 | }; 193 | TWKASCCDL.prototype.setParams = function(params) { 194 | if (typeof params.twkASCCDL !== 'undefined') { 195 | var p = params.twkASCCDL; 196 | this.toggleTweaks(); 197 | } 198 | }; 199 | TWKASCCDL.prototype.getSettings = function(data) { 200 | var cdl = []; 201 | for (var j=0; j<3; j++) { 202 | cdl[ j ] = this.sS[j+1].getValue(); 203 | cdl[j+3] = this.oS[j+1].getValue(); 204 | cdl[j+6] = this.pS[j+1].getValue(); 205 | } 206 | cdl[9] = this.satS.getValue(); 207 | data.ascCDL = { 208 | doASCCDL: this.tweakCheck.checked, 209 | cdl: cdl.toString(), 210 | channel: this.channelSelect.options[this.channelSelect.selectedIndex].lastChild.nodeValue 211 | }; 212 | }; 213 | TWKASCCDL.prototype.setSettings = function(settings) { 214 | if (typeof settings.ascCDL !== 'undefined') { 215 | var data = settings.ascCDL; 216 | if (typeof data.doASCCDL === 'boolean') { 217 | this.tweakCheck.checked = data.doASCCDL; 218 | this.toggleTweak(); 219 | } 220 | if (typeof data.cdl !== 'undefined') { 221 | var cdl = data.cdl.split(',').map(Number); 222 | this.sS[0].setValue((parseFloat(cdl[0])+parseFloat(cdl[1])+parseFloat(cdl[2]))/3); 223 | this.oS[0].setValue((parseFloat(cdl[3])+parseFloat(cdl[4])+parseFloat(cdl[5]))/3); 224 | this.pS[0].setValue((parseFloat(cdl[6])+parseFloat(cdl[7])+parseFloat(cdl[8]))/3); 225 | for (var j=0; j<3; j++) { 226 | this.sS[j+1].setValue(parseFloat(cdl[ j ])); 227 | this.oS[j+1].setValue(parseFloat(cdl[j+3])); 228 | this.pS[j+1].setValue(parseFloat(cdl[j+6])); 229 | } 230 | this.satS.setValue(parseFloat(cdl[9])); 231 | } 232 | if (typeof data.channel !== 'undefined') { 233 | var m = this.channelSelect.options.length; 234 | for (var j=0; j= clip) { 240 | here.clipS.setValue(start + 0.05); 241 | } 242 | here.messages.gaSetParams(); 243 | };}(this); 244 | this.clipS.action = function(here){ return function(){ 245 | var clip = this.getValue(); 246 | var start = here.startS.getValue(); 247 | if (start >= clip) { 248 | here.startS.setValue(start - 0.05); 249 | } 250 | here.messages.gaSetParams(); 251 | };}(this); 252 | this.slopeS.action = function(here){ return function(){ 253 | here.messages.gaSetParams(); 254 | };}(this); 255 | this.smoothS.action = function(here){ return function(){ 256 | here.messages.gaSetParams(); 257 | };}(this); 258 | }; 259 | // Tweak-Specific Code 260 | TWKKnee.prototype.createRadioElement = function(name, checked) { 261 | var radioInput; 262 | try { 263 | var radioHtml = ' -1 && this.wgts.indexOf(oGt) > -1) { 75 | this.holder.className = 'tweakholder'; 76 | } else { 77 | this.holder.className = 'tweakholder-hide'; 78 | this.tweakCheck.checked = false; 79 | } 80 | } else { 81 | this.holder.className = 'tweakholder-hide'; 82 | this.tweakCheck.checked = false; 83 | } 84 | this.toggleTweak(); 85 | }; 86 | TWKSDRSat.prototype.toggleTweak = function() { 87 | if (this.tweakCheck.checked) { 88 | this.box.className = 'tweak'; 89 | } else { 90 | this.box.className = 'tweak-hide'; 91 | } 92 | }; 93 | TWKSDRSat.prototype.getTFParams = function(params) { 94 | // No parameters are relevent 95 | }; 96 | TWKSDRSat.prototype.getCSParams = function(params) { 97 | var out = {}; 98 | var tweaks = this.inputs.tweaks.checked; 99 | var tweak = this.tweakCheck.checked; 100 | if (tweaks && tweak) { 101 | out.doSDRSat = true; 102 | out.gamma = this.gamma.getValue(); 103 | } else { 104 | out.doSDRSat = false; 105 | } 106 | params.twkSDRSat = out; 107 | }; 108 | TWKSDRSat.prototype.setParams = function(params) { 109 | if (typeof params.twkSDRSat !== 'undefined') { 110 | var p = params.twkSDRSat; 111 | this.toggleTweaks(); 112 | } 113 | }; 114 | TWKSDRSat.prototype.getSettings = function(data) { 115 | data.sdrsat = { 116 | doSDRSat: this.tweakCheck.checked, 117 | gamma: this.gamma.getValue() 118 | }; 119 | }; 120 | TWKSDRSat.prototype.setSettings = function(settings) { 121 | if (typeof settings.SDRSAT !== 'undefined') { 122 | var data = settings.SDRSAT; 123 | if (typeof data.doSDRSat === 'boolean') { 124 | this.tweakCheck.checked = data.doSDRSat; 125 | this.gamma.setValue(parseFloat(data.gamma)); 126 | this.toggleTweak(); 127 | } 128 | } 129 | }; 130 | TWKSDRSat.prototype.getInfo = function(info) { 131 | // Provides metadata to LUT formats 132 | var tweaks = this.inputs.tweaks.checked; 133 | var tweak = this.tweakCheck.checked; 134 | if (tweaks && tweak) { 135 | info.doSDRSat = true; 136 | } else { 137 | info.doSDRSat = false; 138 | } 139 | }; 140 | TWKSDRSat.prototype.isCustomGamma = function() { 141 | return false; 142 | }; 143 | TWKSDRSat.prototype.isCustomGamut = function() { 144 | var tweaks = this.inputs.tweaks.checked; 145 | var tweak = this.tweakCheck.checked; 146 | if (tweaks && tweak) { 147 | return true; 148 | } else { 149 | return false; 150 | } 151 | }; 152 | TWKSDRSat.prototype.events = function() { 153 | this.tweakCheck.onclick = function(here){ return function(){ 154 | here.toggleTweak(); 155 | here.messages.gtSetParams(); 156 | };}(this); 157 | this.gamma.action = function(here){ return function(){ 158 | here.messages.gtSetParams(); 159 | };}(this); 160 | }; 161 | // Tweak-Specific Code 162 | // Methods called by event responses should go here 163 | // Requirements: 164 | // style.display should be avoided, use className = 'value'; 165 | // for showing and hiding, it should be of the form className = 'twk-itemclass' and className = 'twk-itemclass-hide' 166 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "LUTCalc", 3 | "name": "LUTCalc", 4 | "version": "4.06", 5 | "developer": { 6 | "name": "Ben Turley", 7 | "url": "https://turley.tv" 8 | }, 9 | "default_locale": "en", 10 | "lang": "en-gb", 11 | "type": "web", 12 | "icons": [ 13 | { 14 | "src": "./img/lutcalc-16.png", 15 | "type": "image/png", 16 | "sizes": "16x16" 17 | }, 18 | { 19 | "src": "./img/lutcalc-19.png", 20 | "type": "image/png", 21 | "sizes": "19x19" 22 | }, 23 | { 24 | "src": "./img/lutcalc-32.png", 25 | "type": "image/png", 26 | "sizes": "32x32" 27 | }, 28 | { 29 | "src": "./img/lutcalc-38.png", 30 | "type": "image/png", 31 | "sizes": "38x38" 32 | }, 33 | { 34 | "src": "./img/lutcalc-48.png", 35 | "type": "image/png", 36 | "sizes": "48x48" 37 | }, 38 | { 39 | "src": "./img/lutcalc-60.png", 40 | "type": "image/png", 41 | "sizes": "60x60" 42 | }, 43 | { 44 | "src": "./img/lutcalc-64.png", 45 | "type": "image/png", 46 | "sizes": "64x64" 47 | }, 48 | { 49 | "src": "./img/lutcalc-90.png", 50 | "type": "image/png", 51 | "sizes": "90x90" 52 | }, 53 | { 54 | "src": "./img/lutcalc-128.png", 55 | "type": "image/png", 56 | "sizes": "128x128" 57 | }, 58 | { 59 | "src": "./img/lutcalc-256.png", 60 | "type": "image/png", 61 | "sizes": "256x256" 62 | }, 63 | { 64 | "src": "./img/lutcalc-512.png", 65 | "type": "image/png", 66 | "sizes": "512x512" 67 | }, 68 | { 69 | "src": "./img/lutcalc-1024.png", 70 | "type": "image/png", 71 | "sizes": "1024x1024" 72 | } 73 | ], 74 | "start_url": "./index.html", 75 | "launch_path": "./index.html", 76 | "background_color": "#eaeaea", 77 | "display": "standalone", 78 | "scope": "./", 79 | "theme_color": "#202090", 80 | "shortcuts": [], 81 | "description": "Camera LUT Generator / Analyser / Visualiser.", 82 | "screenshots": [ 83 | { 84 | "src": "./img/Screenshot-Wide-1.png", 85 | "type": "image/png", 86 | "sizes": "720x389", 87 | "form_factor": "wide" 88 | }, 89 | { 90 | "src": "./img/Screenshot-Tall-1.png", 91 | "type": "image/png", 92 | "sizes": "649x720", 93 | "form_factor": "narrow" 94 | } 95 | ] 96 | } 97 | -------------------------------------------------------------------------------- /pngs/cust-asc-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-asc-1.png -------------------------------------------------------------------------------- /pngs/cust-asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-asc.png -------------------------------------------------------------------------------- /pngs/cust-bgm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bgm-1.png -------------------------------------------------------------------------------- /pngs/cust-bgm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bgm.png -------------------------------------------------------------------------------- /pngs/cust-bhi-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bhi-1.png -------------------------------------------------------------------------------- /pngs/cust-bhi-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bhi-2.png -------------------------------------------------------------------------------- /pngs/cust-bhi-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bhi-3.png -------------------------------------------------------------------------------- /pngs/cust-bhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-bhi.png -------------------------------------------------------------------------------- /pngs/cust-colour-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-colour-1.png -------------------------------------------------------------------------------- /pngs/cust-colour-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-colour-2.png -------------------------------------------------------------------------------- /pngs/cust-colour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-colour.png -------------------------------------------------------------------------------- /pngs/cust-dcc-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-dcc-1.png -------------------------------------------------------------------------------- /pngs/cust-dcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-dcc.png -------------------------------------------------------------------------------- /pngs/cust-fc-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-fc-1.png -------------------------------------------------------------------------------- /pngs/cust-fc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-fc.png -------------------------------------------------------------------------------- /pngs/cust-glim-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-glim-1.png -------------------------------------------------------------------------------- /pngs/cust-glim-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-glim-2.png -------------------------------------------------------------------------------- /pngs/cust-glim-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-glim-3.png -------------------------------------------------------------------------------- /pngs/cust-glim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-glim.png -------------------------------------------------------------------------------- /pngs/cust-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-header.png -------------------------------------------------------------------------------- /pngs/cust-hg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-hg-1.png -------------------------------------------------------------------------------- /pngs/cust-hg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-hg.png -------------------------------------------------------------------------------- /pngs/cust-knee-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-knee-1.png -------------------------------------------------------------------------------- /pngs/cust-knee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-knee.png -------------------------------------------------------------------------------- /pngs/cust-la-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-la-1.png -------------------------------------------------------------------------------- /pngs/cust-la-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-la-2.png -------------------------------------------------------------------------------- /pngs/cust-la-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-la-3.png -------------------------------------------------------------------------------- /pngs/cust-la.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-la.png -------------------------------------------------------------------------------- /pngs/cust-multi-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-multi-1.jpg -------------------------------------------------------------------------------- /pngs/cust-multi-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-multi-2.jpg -------------------------------------------------------------------------------- /pngs/cust-multi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-multi.png -------------------------------------------------------------------------------- /pngs/cust-psst-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-psst-1.png -------------------------------------------------------------------------------- /pngs/cust-psst-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-psst-2.jpg -------------------------------------------------------------------------------- /pngs/cust-psst-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-psst-3.png -------------------------------------------------------------------------------- /pngs/cust-psst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-psst.png -------------------------------------------------------------------------------- /pngs/cust-samp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-samp-1.png -------------------------------------------------------------------------------- /pngs/cust-samp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-samp.png -------------------------------------------------------------------------------- /pngs/cust-sdrs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-sdrs.png -------------------------------------------------------------------------------- /pngs/cust-wht-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-wht-1.png -------------------------------------------------------------------------------- /pngs/cust-wht-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-wht-2.png -------------------------------------------------------------------------------- /pngs/cust-wht.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/cust-wht.png -------------------------------------------------------------------------------- /pngs/ins-cam-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-cam-1.png -------------------------------------------------------------------------------- /pngs/ins-cust-wht-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-cust-wht-1.png -------------------------------------------------------------------------------- /pngs/ins-gam-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-gam-1.png -------------------------------------------------------------------------------- /pngs/ins-inf-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-inf-1.png -------------------------------------------------------------------------------- /pngs/ins-lut-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-lut-1.png -------------------------------------------------------------------------------- /pngs/ins-lut-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-lut-2.png -------------------------------------------------------------------------------- /pngs/ins-pre-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-pre-1.jpg -------------------------------------------------------------------------------- /pngs/ins-pre-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-pre-2.jpg -------------------------------------------------------------------------------- /pngs/ins-pre-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/ins-pre-3.png -------------------------------------------------------------------------------- /pngs/main-but-gen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-but-gen.png -------------------------------------------------------------------------------- /pngs/main-but-gst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-but-gst.png -------------------------------------------------------------------------------- /pngs/main-but-pre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-but-pre.png -------------------------------------------------------------------------------- /pngs/main-but-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-but-set.png -------------------------------------------------------------------------------- /pngs/main-cam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-cam.png -------------------------------------------------------------------------------- /pngs/main-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-footer.png -------------------------------------------------------------------------------- /pngs/main-gam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-gam.png -------------------------------------------------------------------------------- /pngs/main-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-header.png -------------------------------------------------------------------------------- /pngs/main-inf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-inf.png -------------------------------------------------------------------------------- /pngs/main-lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-lut.png -------------------------------------------------------------------------------- /pngs/main-twk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/main-twk.png -------------------------------------------------------------------------------- /pngs/mob-chart-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/mob-chart-icon.png -------------------------------------------------------------------------------- /pngs/mob-preview-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/pngs/mob-preview-icon.png -------------------------------------------------------------------------------- /s709.labin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/s709.labin -------------------------------------------------------------------------------- /window.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | LUTCalc 16 | 17 | 18 |

LUTCalc - 1D & 3D Cube LUT Calculator

19 |
20 |

*** Please Allow Javascript To Run On This Page ***

21 |
22 |
23 |
24 |
Ben Turley
25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /xyuvLSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/xyuvLSB.png -------------------------------------------------------------------------------- /xyuvMSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cameramanben/LUTCalc/fc70eba2198ba577cc87d5a614506bd5e4d49330/xyuvMSB.png --------------------------------------------------------------------------------