From 86c18927e83edfdef203cad5288f9bc26481fd61 Mon Sep 17 00:00:00 2001 From: inportb Date: Thu, 10 Aug 2023 18:38:42 -0400 Subject: [PATCH] DICOM viewer --- htdocs/adapter/dicom.ts.js | 30647 +++++++++++++++++++++++++++++++++ htdocs/adapter/view.dcm.html | 64 + 2 files changed, 30711 insertions(+) create mode 100644 htdocs/adapter/dicom.ts.js create mode 100644 htdocs/adapter/view.dcm.html diff --git a/htdocs/adapter/dicom.ts.js b/htdocs/adapter/dicom.ts.js new file mode 100644 index 0000000..ff218ba --- /dev/null +++ b/htdocs/adapter/dicom.ts.js @@ -0,0 +1,30647 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.dicom || (g.dicom = {})).ts = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i (i + 0x10000).toString(16).substr(-4).toUpperCase(); + +const getStringAt = (dataview, start, length, charset, vr) => { + const strBuff = new Uint8Array(dataview.buffer, dataview.byteOffset + start, length); + let str = (0, _dicomCharacterSet.convertBytes)(charset || DefaultCharset, strBuff, { + vr + }); + + while (str && str.charCodeAt(str.length - 1) === 0) { + str = str.slice(0, -1); + } + + return str; +}; + +const stripLeadingZeros = str => str.replace(/^[0]+/g, ""); + +const safeParseInt = str => { + const intStr = stripLeadingZeros(str); + + if (intStr.length > 0) { + return parseInt(intStr, 10); + } + + return 0; +}; + +const convertCamcelCaseToTitleCase = str => { + const result = str.replace(/([A-Z][a-z])/g, " $1"); + return (result.charAt(0).toUpperCase() + result.slice(1)).trim(); +}; + +const safeParseFloat = str => { + const floatStr = stripLeadingZeros(str); + + if (floatStr.length > 0) { + return parseFloat(floatStr); + } + + return 0; +}; // http://stackoverflow.com/questions/8361086/convert-byte-array-to-numbers-in-javascript + + +const bytesToDouble = data => { + const [b0, b1, b2, b3, b4, b5, b6, b7] = data; + const sign = (b0 & 1 << 7) >> 7; + const exponent = (b0 & 127) << 4 | (b1 & 15 << 4) >> 4; + + if (exponent === 0) { + return 0; + } + + if (exponent === 0x7ff) { + return sign ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + } + + const mul = 2 ** exponent - 1023 - 52; + const mantissa = b7 + b6 * 2 ** 8 + b5 * 2 ** (8 * 2) + b4 * 2 ** (8 * 3) + b3 * 2 ** (8 * 4) + b2 * 2 ** (8 * 5) + (b1 & 15) * 2 ** (8 * 6) + 2 ** 52; + return (-1) ** sign * mantissa * mul; +}; + +const concatArrayBuffers = (buffer1, buffer2) => { + const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp.buffer; +}; + +const toArrayBuffer = buffer => { + const ab = new ArrayBuffer(buffer.length); + const view = new Uint8Array(ab); + + for (let i = 0; i < buffer.length; i += 1) { + view[i] = buffer[i]; + } + + return ab; +}; // http://stackoverflow.com/questions/203739/why-does-instanceof-return-false-for-some-literals + + +const isString = s => typeof s === "string" || s instanceof String; // http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript + + +const isValidDate = d => { + if (Object.prototype.toString.call(d) === "[object Date]") { + // eslint-disable-next-line no-restricted-globals + if (isNaN(d.getTime())) { + return false; + } + + return true; + } + + return false; +}; + +const swap32 = val => (val & 0xFF) << 24 | (val & 0xFF00) << 8 | val >> 8 & 0xFF00 | val >> 24 & 0xFF; + +const swap16 = val => ((val & 0xFF) << 8 | val >> 8 & 0xFF) << 16 >> 16 // since JS uses 32-bit when bit shifting +; // http://stackoverflow.com/questions/18638900/javascript-crc32 + + +const makeCRCTable = () => { + crcTable = crcTable || Array(256); + + for (let n = 0; n < 256; n += 1) { + let c = n; + + for (let k = 0; k < 8; k += 1) { + c = c & 1 ? 0xEDB88320 ^ c >>> 1 : c >>> 1; + } + + crcTable[n] = c; + } + + return crcTable; +}; + +const crc32 = dataView => { + crcTable = crcTable || makeCRCTable(); + let crc = 0 ^ -1; + + for (let i = 0; i < dataView.byteLength; i += 1) { + crc = crc >>> 8 ^ crcTable[(crc ^ dataView.getUint8(i)) & 0xFF]; + } + + return (crc ^ -1) >>> 0; +}; + +const createBitMask = (numBytes, bitsStored, unsigned) => { + let mask = 0xFFFFFFFF; + mask >>>= (4 - numBytes) * 8 + (numBytes * 8 - bitsStored); + + if (unsigned) { + if (numBytes === 1) { + mask &= 0x000000FF; + } else if (numBytes === 2) { + mask &= 0x0000FFFF; + } else if (numBytes === 4) { + mask &= 0xFFFFFFFF; + } else if (numBytes === 8) { + mask = 0xFFFFFFFF; + } + } else { + mask = 0xFFFFFFFF; + } + + return mask; +}; + +var Utils = { + __proto__: null, + MAX_VALUE: MAX_VALUE, + MIN_VALUE: MIN_VALUE, + dec2hex: dec2hex$1, + getStringAt: getStringAt, + stripLeadingZeros: stripLeadingZeros, + safeParseInt: safeParseInt, + convertCamcelCaseToTitleCase: convertCamcelCaseToTitleCase, + safeParseFloat: safeParseFloat, + bytesToDouble: bytesToDouble, + concatArrayBuffers: concatArrayBuffers, + toArrayBuffer: toArrayBuffer, + isString: isString, + isValidDate: isValidDate, + swap32: swap32, + swap16: swap16, + makeCRCTable: makeCRCTable, + crc32: crc32, + createBitMask: createBitMask +}; +const { + dec2hex +} = Utils; +const dictPrivate = { + "0207": { + "101F": ["FE", "ElscintDataScale"] // uses special Elscint double type (see Tag class) + + } +}; // strange bug in eslint, thinks the integer prop keys should not be in quotes! + +/* eslint-disable quote-props */ + +const dict = { + "0002": { + "0001": ["OB", "FileMetaInformationVersion"], + "0002": ["UI", "MediaStoredSOPClassUID"], + "0003": ["UI", "MediaStoredSOPInstanceUID"], + "0010": ["UI", "TransferSyntaxUID"], + "0012": ["UI", "ImplementationClassUID"], + "0013": ["SH", "ImplementationVersionName"], + "0016": ["AE", "SourceApplicationEntityTitle"], + "0100": ["UI", "PrivateInformationCreatorUID"], + "0102": ["OB", "PrivateInformation"] + }, + "0004": { + "1130": ["CS", "FilesetID"], + "1141": ["CS", "FilesetDescriptorFileFileID"], + "1142": ["CS", "FilesetDescriptorFileFormat"], + "1200": ["UL", "RootDirectoryEntitysFirstDirectoryRecordOffset"], + "1202": ["UL", "RootDirectoryEntitysLastDirectoryRecordOffset"], + "1212": ["US", "File-setConsistenceFlag"], + "1220": ["SQ", "DirectoryRecordSequence"], + "1400": ["UL", "NextDirectoryRecordOffset"], + "1410": ["US", "RecordInuseFlag"], + "1420": ["UL", "ReferencedLowerlevelDirectoryEntityOffset"], + "1430": ["CS", "DirectoryRecordType"], + "1432": ["UI", "PrivateRecordUID"], + "1500": ["CS", "ReferencedFileID"], + "1510": ["UI", "ReferencedSOPClassUIDInFile"], + "1511": ["UI", "ReferencedSOPInstanceUIDInFile"], + "1600": ["UL", "NumberOfReferences"] + }, + "0008": { + "0001": ["UL", "LengthToEnd"], + "0005": ["CS", "SpecificCharacterSet"], + "0006": ["SQ", "LanguageCodeSequence"], + "0008": ["CS", "ImageType"], + "0010": ["SH", "RecognitionCode"], + "0012": ["DA", "InstanceCreationDate"], + "0013": ["TM", "InstanceCreationTime"], + "0014": ["UI", "InstanceCreatorUID"], + "0016": ["UI", "SOPClassUID"], + "0018": ["UI", "SOPInstanceUID"], + "001A": ["UI", "RelatedGeneralSOPClassUID"], + "001B": ["UI", "OriginalSpecializedSOPClassUID"], + "0020": ["DA", "StudyDate"], + "0021": ["DA", "SeriesDate"], + "0022": ["DA", "AcquisitionDate"], + "0023": ["DA", "ContentDate"], + "0024": ["DA", "OverlayDate"], + "0025": ["DA", "CurveDate"], + "002A": ["DT", "AcquisitionDateTime"], + "0030": ["TM", "StudyTime"], + "0031": ["TM", "SeriesTime"], + "0032": ["TM", "AcquisitionTime"], + "0033": ["TM", "ContentTime"], + "0034": ["TM", "OverlayTime"], + "0035": ["TM", "CurveTime"], + "0040": ["US", "DataSetType"], + "0041": ["LO", "DataSetSubtype"], + "0042": ["CS", "NuclearMedicineSeriesType"], + "0050": ["SH", "AccessionNumber"], + "0051": ["SQ", "IssuerOfAccessionNumberSequence"], + "0052": ["CS", "QueryRetrieveLevel"], + "0054": ["AE", "RetrieveAETitle"], + "0056": ["CS", "InstanceAvailability"], + "0058": ["UI", "FailedSOPInstanceUIDList"], + "0060": ["CS", "Modality"], + "0061": ["CS", "ModalitiesInStudy"], + "0062": ["UI", "SOPClassesInStudy"], + "0064": ["CS", "ConversionType"], + "0068": ["CS", "PresentationIntentType"], + "0070": ["LO", "Manufacturer"], + "0080": ["LO", "InstitutionName"], + "0081": ["ST", "InstitutionAddress"], + "0082": ["SQ", "InstitutionCodeSequence"], + "0090": ["PN", "ReferringPhysicianName"], + "0092": ["ST", "ReferringPhysicianAddress"], + "0094": ["SH", "ReferringPhysicianTelephoneNumbers"], + "0096": ["SQ", "ReferringPhysicianIdentificationSequence"], + "0100": ["SH", "CodeValue"], + "0102": ["SH", "CodingSchemeDesignator"], + "0103": ["SH", "CodingSchemeVersion"], + "0104": ["LO", "CodeMeaning"], + "0105": ["CS", "MappingResource"], + "0106": ["DT", "ContextGroupVersion"], + "0107": ["DT", "ContextGroupLocalVersion"], + "010B": ["CS", "ContextGroupExtensionFlag"], + "010C": ["UI", "CodingSchemeUID"], + "010D": ["UI", "ContextGroupExtensionCreatorUID"], + "010F": ["CS", "ContextIdentifier"], + "0110": ["SQ", "CodingSchemeIdentificationSequence"], + "0112": ["LO", "CodingSchemeRegistry"], + "0114": ["ST", "CodingSchemeExternalID"], + "0115": ["ST", "CodingSchemeName"], + "0116": ["ST", "CodingSchemeResponsibleOrganization"], + "0117": ["UI", "ContextUID"], + "0201": ["SH", "TimezoneOffsetFromUTC"], + "1000": ["AE", "NetworkID"], + "1010": ["SH", "StationName"], + "1030": ["LO", "StudyDescription"], + "1032": ["SQ", "ProcedureCodeSequence"], + "103E": ["LO", "SeriesDescription"], + "103F": ["SQ", "SeriesDescriptionCodeSequence"], + "1040": ["LO", "InstitutionalDepartmentName"], + "1048": ["PN", "PhysiciansOfRecord"], + "1049": ["SQ", "PhysiciansOfRecordIdentificationSequence"], + "1050": ["PN", "PerformingPhysicianName"], + "1052": ["SQ", "PerformingPhysicianIdentificationSequence"], + "1060": ["PN", "NameOfPhysiciansReadingStudy"], + "1062": ["SQ", "PhysiciansReadingStudyIdentificationSequence"], + "1070": ["PN", "OperatorsName"], + "1072": ["SQ", "OperatorIdentificationSequence"], + "1080": ["LO", "AdmittingDiagnosesDescription"], + "1084": ["SQ", "AdmittingDiagnosesCodeSequence"], + "1090": ["LO", "ManufacturerModelName"], + "1100": ["SQ", "ReferencedResultsSequence"], + "1110": ["SQ", "ReferencedStudySequence"], + "1111": ["SQ", "ReferencedPerformedProcedureStepSequence"], + "1115": ["SQ", "ReferencedSeriesSequence"], + "1120": ["SQ", "ReferencedPatientSequence"], + "1125": ["SQ", "ReferencedVisitSequence"], + "1130": ["SQ", "ReferencedOverlaySequence"], + "1134": ["SQ", "ReferencedStereometricInstanceSequence"], + "113A": ["SQ", "ReferencedWaveformSequence"], + "1140": ["SQ", "ReferencedImageSequence"], + "1145": ["SQ", "ReferencedCurveSequence"], + "114A": ["SQ", "ReferencedInstanceSequence"], + "114B": ["SQ", "ReferencedRealWorldValueMappingInstanceSequence"], + "1150": ["UI", "ReferencedSOPClassUID"], + "1155": ["UI", "ReferencedSOPInstanceUID"], + "115A": ["UI", "SOPClassesSupported"], + "1160": ["IS", "ReferencedFrameNumber"], + "1161": ["UL", "SimpleFrameList"], + "1162": ["UL", "CalculatedFrameList"], + "1163": ["FD", "TimeRange"], + "1164": ["SQ", "FrameExtractionSequence"], + "1167": ["UI", "MultiFrameSourceSOPInstanceUID"], + "1195": ["UI", "TransactionUID"], + "1197": ["US", "FailureReason"], + "1198": ["SQ", "FailedSOPSequence"], + "1199": ["SQ", "ReferencedSOPSequence"], + "1200": ["SQ", "StudiesContainingOtherReferencedInstancesSequence"], + "1250": ["SQ", "RelatedSeriesSequence"], + "2110": ["CS", "LossyImageCompressionRetired"], + "2111": ["ST", "DerivationDescription"], + "2112": ["SQ", "SourceImageSequence"], + "2120": ["SH", "StageName"], + "2122": ["IS", "StageNumber"], + "2124": ["IS", "NumberOfStages"], + "2127": ["SH", "ViewName"], + "2128": ["IS", "ViewNumber"], + "2129": ["IS", "NumberOfEventTimers"], + "212A": ["IS", "NumberOfViewsInStage"], + "2130": ["DS", "EventElapsedTimes"], + "2132": ["LO", "EventTimerNames"], + "2133": ["SQ", "EventTimerSequence"], + "2134": ["FD", "EventTimeOffset"], + "2135": ["SQ", "EventCodeSequence"], + "2142": ["IS", "StartTrim"], + "2143": ["IS", "StopTrim"], + "2144": ["IS", "RecommendedDisplayFrameRate"], + "2200": ["CS", "TransducerPosition"], + "2204": ["CS", "TransducerOrientation"], + "2208": ["CS", "AnatomicStructure"], + "2218": ["SQ", "AnatomicRegionSequence"], + "2220": ["SQ", "AnatomicRegionModifierSequence"], + "2228": ["SQ", "PrimaryAnatomicStructureSequence"], + "2229": ["SQ", "AnatomicStructureSpaceOrRegionSequence"], + "2230": ["SQ", "PrimaryAnatomicStructureModifierSequence"], + "2240": ["SQ", "TransducerPositionSequence"], + "2242": ["SQ", "TransducerPositionModifierSequence"], + "2244": ["SQ", "TransducerOrientationSequence"], + "2246": ["SQ", "TransducerOrientationModifierSequence"], + "2251": ["SQ", "AnatomicStructureSpaceOrRegionCodeSequenceTrial"], + "2253": ["SQ", "AnatomicPortalOfEntranceCodeSequenceTrial"], + "2255": ["SQ", "AnatomicApproachDirectionCodeSequenceTrial"], + "2256": ["ST", "AnatomicPerspectiveDescriptionTrial"], + "2257": ["SQ", "AnatomicPerspectiveCodeSequenceTrial"], + "2258": ["ST", "AnatomicLocationOfExaminingInstrumentDescriptionTrial"], + "2259": ["SQ", "AnatomicLocationOfExaminingInstrumentCodeSequenceTrial"], + "225A": ["SQ", "AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial"], + "225C": ["SQ", "OnAxisBackgroundAnatomicStructureCodeSequenceTrial"], + "3001": ["SQ", "AlternateRepresentationSequence"], + "3010": ["UI", "IrradiationEventUID"], + "4000": ["LT", "IdentifyingComments"], + "9007": ["CS", "FrameType"], + "9092": ["SQ", "ReferencedImageEvidenceSequence"], + "9121": ["SQ", "ReferencedRawDataSequence"], + "9123": ["UI", "CreatorVersionUID"], + "9124": ["SQ", "DerivationImageSequence"], + "9154": ["SQ", "SourceImageEvidenceSequence"], + "9205": ["CS", "PixelPresentation"], + "9206": ["CS", "VolumetricProperties"], + "9207": ["CS", "VolumeBasedCalculationTechnique"], + "9208": ["CS", "ComplexImageComponent"], + "9209": ["CS", "AcquisitionContrast"], + "9215": ["SQ", "DerivationCodeSequence"], + "9237": ["SQ", "ReferencedPresentationStateSequence"], + "9410": ["SQ", "ReferencedOtherPlaneSequence"], + "9458": ["SQ", "FrameDisplaySequence"], + "9459": ["FL", "RecommendedDisplayFrameRateInFloat"], + "9460": ["CS", "SkipFrameRangeFlag"] + }, + "0010": { + "0010": ["PN", "PatientName"], + "0020": ["LO", "PatientID"], + "0021": ["LO", "IssuerOfPatientID"], + "0022": ["CS", "TypeOfPatientID"], + "0024": ["SQ", "IssuerOfPatientIDQualifiersSequence"], + "0030": ["DA", "PatientBirthDate"], + "0032": ["TM", "PatientBirthTime"], + "0040": ["CS", "PatientSex"], + "0050": ["SQ", "PatientInsurancePlanCodeSequence"], + "0101": ["SQ", "PatientPrimaryLanguageCodeSequence"], + "0102": ["SQ", "PatientPrimaryLanguageModifierCodeSequence"], + "1000": ["LO", "OtherPatientIDs"], + "1001": ["PN", "OtherPatientNames"], + "1002": ["SQ", "OtherPatientIDsSequence"], + "1005": ["PN", "PatientBirthName"], + "1010": ["AS", "PatientAge"], + "1020": ["DS", "PatientSize"], + "1021": ["SQ", "PatientSizeCodeSequence"], + "1030": ["DS", "PatientWeight"], + "1040": ["LO", "PatientAddress"], + "1050": ["LO", "InsurancePlanIdentification"], + "1060": ["PN", "PatientMotherBirthName"], + "1080": ["LO", "MilitaryRank"], + "1081": ["LO", "BranchOfService"], + "1090": ["LO", "MedicalRecordLocator"], + "2000": ["LO", "MedicalAlerts"], + "2110": ["LO", "Allergies"], + "2150": ["LO", "CountryOfResidence"], + "2152": ["LO", "RegionOfResidence"], + "2154": ["SH", "PatientTelephoneNumbers"], + "2160": ["SH", "EthnicGroup"], + "2180": ["SH", "Occupation"], + "21A0": ["CS", "SmokingStatus"], + "21B0": ["LT", "AdditionalPatientHistory"], + "21C0": ["US", "PregnancyStatus"], + "21D0": ["DA", "LastMenstrualDate"], + "21F0": ["LO", "PatientReligiousPreference"], + "2201": ["LO", "PatientSpeciesDescription"], + "2202": ["SQ", "PatientSpeciesCodeSequence"], + "2203": ["CS", "PatientSexNeutered"], + "2210": ["CS", "AnatomicalOrientationType"], + "2292": ["LO", "PatientBreedDescription"], + "2293": ["SQ", "PatientBreedCodeSequence"], + "2294": ["SQ", "BreedRegistrationSequence"], + "2295": ["LO", "BreedRegistrationNumber"], + "2296": ["SQ", "BreedRegistryCodeSequence"], + "2297": ["PN", "ResponsiblePerson"], + "2298": ["CS", "ResponsiblePersonRole"], + "2299": ["LO", "ResponsibleOrganization"], + "4000": ["LT", "PatientComments"], + "9431": ["FL", "ExaminedBodyThickness"] + }, + "0012": { + "0010": ["LO", "ClinicalTrialSponsorName"], + "0020": ["LO", "ClinicalTrialProtocolID"], + "0021": ["LO", "ClinicalTrialProtocolName"], + "0030": ["LO", "ClinicalTrialSiteID"], + "0031": ["LO", "ClinicalTrialSiteName"], + "0040": ["LO", "ClinicalTrialSubjectID"], + "0042": ["LO", "ClinicalTrialSubjectReadingID"], + "0050": ["LO", "ClinicalTrialTimePointID"], + "0051": ["ST", "ClinicalTrialTimePointDescription"], + "0060": ["LO", "ClinicalTrialCoordinatingCenterName"], + "0062": ["CS", "PatientIdentityRemoved"], + "0063": ["LO", "DeidentificationMethod"], + "0064": ["SQ", "DeidentificationMethodCodeSequence"], + "0071": ["LO", "ClinicalTrialSeriesID"], + "0072": ["LO", "ClinicalTrialSeriesDescription"], + "0081": ["LO", "ClinicalTrialProtocolEthicsCommitteeName"], + "0082": ["LO", "ClinicalTrialProtocolEthicsCommitteeApprovalNumber"], + "0083": ["SQ", "ConsentForClinicalTrialUseSequence"], + "0084": ["CS", "DistributionType"], + "0085": ["CS", "ConsentForDistributionFlag"] + }, + "0014": { + "0023": ["ST", "CADFileFormat"], + "0024": ["ST", "ComponentReferenceSystem"], + "0025": ["ST", "ComponentManufacturingProcedure"], + "0028": ["ST", "ComponentManufacturer"], + "0030": ["DS", "MaterialThickness"], + "0032": ["DS", "MaterialPipeDiameter"], + "0034": ["DS", "MaterialIsolationDiameter"], + "0042": ["ST", "MaterialGrade"], + "0044": ["ST", "MaterialPropertiesFileID"], + "0045": ["ST", "MaterialPropertiesFileFormat"], + "0046": ["LT", "MaterialNotes"], + "0050": ["CS", "ComponentShape"], + "0052": ["CS", "CurvatureType"], + "0054": ["DS", "OuterDiameter"], + "0056": ["DS", "InnerDiameter"], + "1010": ["ST", "ActualEnvironmentalConditions"], + "1020": ["DA", "ExpiryDate"], + "1040": ["ST", "EnvironmentalConditions"], + "2002": ["SQ", "EvaluatorSequence"], + "2004": ["IS", "EvaluatorNumber"], + "2006": ["PN", "EvaluatorName"], + "2008": ["IS", "EvaluationAttempt"], + "2012": ["SQ", "IndicationSequence"], + "2014": ["IS", "IndicationNumber "], + "2016": ["SH", "IndicationLabel"], + "2018": ["ST", "IndicationDescription"], + "201A": ["CS", "IndicationType"], + "201C": ["CS", "IndicationDisposition"], + "201E": ["SQ", "IndicationROISequence"], + "2030": ["SQ", "IndicationPhysicalPropertySequence"], + "2032": ["SH", "PropertyLabel"], + "2202": ["IS", "CoordinateSystemNumberOfAxes "], + "2204": ["SQ", "CoordinateSystemAxesSequence"], + "2206": ["ST", "CoordinateSystemAxisDescription"], + "2208": ["CS", "CoordinateSystemDataSetMapping"], + "220A": ["IS", "CoordinateSystemAxisNumber"], + "220C": ["CS", "CoordinateSystemAxisType"], + "220E": ["CS", "CoordinateSystemAxisUnits"], + "2210": ["OB", "CoordinateSystemAxisValues"], + "2220": ["SQ", "CoordinateSystemTransformSequence"], + "2222": ["ST", "TransformDescription"], + "2224": ["IS", "TransformNumberOfAxes"], + "2226": ["IS", "TransformOrderOfAxes"], + "2228": ["CS", "TransformedAxisUnits"], + "222A": ["DS", "CoordinateSystemTransformRotationAndScaleMatrix"], + "222C": ["DS", "CoordinateSystemTransformTranslationMatrix"], + "3011": ["DS", "InternalDetectorFrameTime"], + "3012": ["DS", "NumberOfFramesIntegrated"], + "3020": ["SQ", "DetectorTemperatureSequence"], + "3022": ["DS", "SensorName"], + "3024": ["DS", "HorizontalOffsetOfSensor"], + "3026": ["DS", "VerticalOffsetOfSensor"], + "3028": ["DS", "SensorTemperature"], + "3040": ["SQ", "DarkCurrentSequence"], + "3050": ["OB", "DarkCurrentCounts"], + "3060": ["SQ", "GainCorrectionReferenceSequence"], + "3070": ["OB", "AirCounts"], + "3071": ["DS", "KVUsedInGainCalibration"], + "3072": ["DS", "MAUsedInGainCalibration"], + "3073": ["DS", "NumberOfFramesUsedForIntegration"], + "3074": ["LO", "FilterMaterialUsedInGainCalibration"], + "3075": ["DS", "FilterThicknessUsedInGainCalibration"], + "3076": ["DA", "DateOfGainCalibration"], + "3077": ["TM", "TimeOfGainCalibration"], + "3080": ["OB", "BadPixelImage"], + "3099": ["LT", "CalibrationNotes"], + "4002": ["SQ", "PulserEquipmentSequence"], + "4004": ["CS", "PulserType"], + "4006": ["LT", "PulserNotes"], + "4008": ["SQ", "ReceiverEquipmentSequence"], + "400A": ["CS", "AmplifierType"], + "400C": ["LT", "ReceiverNotes"], + "400E": ["SQ", "PreAmplifierEquipmentSequence"], + "400F": ["LT", "PreAmplifierNotes"], + "4010": ["SQ", "TransmitTransducerSequence"], + "4011": ["SQ", "ReceiveTransducerSequence"], + "4012": ["US", "NumberOfElements"], + "4013": ["CS", "ElementShape"], + "4014": ["DS", "ElementDimensionA"], + "4015": ["DS", "ElementDimensionB"], + "4016": ["DS", "ElementPitch"], + "4017": ["DS", "MeasuredBeamDimensionA"], + "4018": ["DS", "MeasuredBeamDimensionB"], + "4019": ["DS", "LocationOfMeasuredBeamDiameter"], + "401A": ["DS", "NominalFrequency"], + "401B": ["DS", "MeasuredCenterFrequency"], + "401C": ["DS", "MeasuredBandwidth"], + "4020": ["SQ", "PulserSettingsSequence"], + "4022": ["DS", "PulseWidth"], + "4024": ["DS", "ExcitationFrequency"], + "4026": ["CS", "ModulationType"], + "4028": ["DS", "Damping"], + "4030": ["SQ", "ReceiverSettingsSequence"], + "4031": ["DS", "AcquiredSoundpathLength"], + "4032": ["CS", "AcquisitionCompressionType"], + "4033": ["IS", "AcquisitionSampleSize"], + "4034": ["DS", "RectifierSmoothing"], + "4035": ["SQ", "DACSequence"], + "4036": ["CS", "DACType"], + "4038": ["DS", "DACGainPoints"], + "403A": ["DS", "DACTimePoints"], + "403C": ["DS", "DACAmplitude"], + "4040": ["SQ", "PreAmplifierSettingsSequence"], + "4050": ["SQ", "TransmitTransducerSettingsSequence"], + "4051": ["SQ", "ReceiveTransducerSettingsSequence"], + "4052": ["DS", "IncidentAngle"], + "4054": ["ST", "CouplingTechnique"], + "4056": ["ST", "CouplingMedium"], + "4057": ["DS", "CouplingVelocity"], + "4058": ["DS", "CrystalCenterLocationX"], + "4059": ["DS", "CrystalCenterLocationZ"], + "405A": ["DS", "SoundPathLength"], + "405C": ["ST", "DelayLawIdentifier"], + "4060": ["SQ", "GateSettingsSequence"], + "4062": ["DS", "GateThreshold"], + "4064": ["DS", "VelocityOfSound"], + "4070": ["SQ", "CalibrationSettingsSequence"], + "4072": ["ST", "CalibrationProcedure"], + "4074": ["SH", "ProcedureVersion"], + "4076": ["DA", "ProcedureCreationDate"], + "4078": ["DA", "ProcedureExpirationDate"], + "407A": ["DA", "ProcedureLastModifiedDate"], + "407C": ["TM", "CalibrationTime"], + "407E": ["DA", "CalibrationDate"], + "5002": ["IS", "LINACEnergy"], + "5004": ["IS", "LINACOutput"] + }, + "0018": { + "0010": ["LO", "ContrastBolusAgent"], + "0012": ["SQ", "ContrastBolusAgentSequence"], + "0014": ["SQ", "ContrastBolusAdministrationRouteSequence"], + "0015": ["CS", "BodyPartExamined"], + "0020": ["CS", "ScanningSequence"], + "0021": ["CS", "SequenceVariant"], + "0022": ["CS", "ScanOptions"], + "0023": ["CS", "MRAcquisitionType"], + "0024": ["SH", "SequenceName"], + "0025": ["CS", "AngioFlag"], + "0026": ["SQ", "InterventionDrugInformationSequence"], + "0027": ["TM", "InterventionDrugStopTime"], + "0028": ["DS", "InterventionDrugDose"], + "0029": ["SQ", "InterventionDrugCodeSequence"], + "002A": ["SQ", "AdditionalDrugSequence"], + "0030": ["LO", "Radionuclide"], + "0031": ["LO", "Radiopharmaceutical"], + "0032": ["DS", "EnergyWindowCenterline"], + "0033": ["DS", "EnergyWindowTotalWidth"], + "0034": ["LO", "InterventionDrugName"], + "0035": ["TM", "InterventionDrugStartTime"], + "0036": ["SQ", "InterventionSequence"], + "0037": ["CS", "TherapyType"], + "0038": ["CS", "InterventionStatus"], + "0039": ["CS", "TherapyDescription"], + "003A": ["ST", "InterventionDescription"], + "0040": ["IS", "CineRate"], + "0042": ["CS", "InitialCineRunState"], + "0050": ["DS", "SliceThickness"], + "0060": ["DS", "KVP"], + "0070": ["IS", "CountsAccumulated"], + "0071": ["CS", "AcquisitionTerminationCondition"], + "0072": ["DS", "EffectiveDuration"], + "0073": ["CS", "AcquisitionStartCondition"], + "0074": ["IS", "AcquisitionStartConditionData"], + "0075": ["IS", "AcquisitionTerminationConditionData"], + "0080": ["DS", "RepetitionTime"], + "0081": ["DS", "EchoTime"], + "0082": ["DS", "InversionTime"], + "0083": ["DS", "NumberOfAverages"], + "0084": ["DS", "ImagingFrequency"], + "0085": ["SH", "ImagedNucleus"], + "0086": ["IS", "EchoNumbers"], + "0087": ["DS", "MagneticFieldStrength"], + "0088": ["DS", "SpacingBetweenSlices"], + "0089": ["IS", "NumberOfPhaseEncodingSteps"], + "0090": ["DS", "DataCollectionDiameter"], + "0091": ["IS", "EchoTrainLength"], + "0093": ["DS", "PercentSampling"], + "0094": ["DS", "PercentPhaseFieldOfView"], + "0095": ["DS", "PixelBandwidth"], + "1000": ["LO", "DeviceSerialNumber"], + "1002": ["UI", "DeviceUID"], + "1003": ["LO", "DeviceID"], + "1004": ["LO", "PlateID"], + "1005": ["LO", "GeneratorID"], + "1006": ["LO", "GridID"], + "1007": ["LO", "CassetteID"], + "1008": ["LO", "GantryID"], + "1010": ["LO", "SecondaryCaptureDeviceID"], + "1011": ["LO", "HardcopyCreationDeviceID"], + "1012": ["DA", "DateOfSecondaryCapture"], + "1014": ["TM", "TimeOfSecondaryCapture"], + "1016": ["LO", "SecondaryCaptureDeviceManufacturer"], + "1017": ["LO", "HardcopyDeviceManufacturer"], + "1018": ["LO", "SecondaryCaptureDeviceManufacturerModelName"], + "1019": ["LO", "SecondaryCaptureDeviceSoftwareVersions"], + "101A": ["LO", "HardcopyDeviceSoftwareVersion"], + "101B": ["LO", "HardcopyDeviceManufacturerModelName"], + "1020": ["LO", "SoftwareVersions"], + "1022": ["SH", "VideoImageFormatAcquired"], + "1023": ["LO", "DigitalImageFormatAcquired"], + "1030": ["LO", "ProtocolName"], + "1040": ["LO", "ContrastBolusRoute"], + "1041": ["DS", "ContrastBolusVolume"], + "1042": ["TM", "ContrastBolusStartTime"], + "1043": ["TM", "ContrastBolusStopTime"], + "1044": ["DS", "ContrastBolusTotalDose"], + "1045": ["IS", "SyringeCounts"], + "1046": ["DS", "ContrastFlowRate"], + "1047": ["DS", "ContrastFlowDuration"], + "1048": ["CS", "ContrastBolusIngredient"], + "1049": ["DS", "ContrastBolusIngredientConcentration"], + "1050": ["DS", "SpatialResolution"], + "1060": ["DS", "TriggerTime"], + "1061": ["LO", "TriggerSourceOrType"], + "1062": ["IS", "NominalInterval"], + "1063": ["DS", "FrameTime"], + "1064": ["LO", "CardiacFramingType"], + "1065": ["DS", "FrameTimeVector"], + "1066": ["DS", "FrameDelay"], + "1067": ["DS", "ImageTriggerDelay"], + "1068": ["DS", "MultiplexGroupTimeOffset"], + "1069": ["DS", "TriggerTimeOffset"], + "106A": ["CS", "SynchronizationTrigger"], + "106C": ["US", "SynchronizationChannel"], + "106E": ["UL", "TriggerSamplePosition"], + "1070": ["LO", "RadiopharmaceuticalRoute"], + "1071": ["DS", "RadiopharmaceuticalVolume"], + "1072": ["TM", "RadiopharmaceuticalStartTime"], + "1073": ["TM", "RadiopharmaceuticalStopTime"], + "1074": ["DS", "RadionuclideTotalDose"], + "1075": ["DS", "RadionuclideHalfLife"], + "1076": ["DS", "RadionuclidePositronFraction"], + "1077": ["DS", "RadiopharmaceuticalSpecificActivity"], + "1078": ["DT", "RadiopharmaceuticalStartDateTime"], + "1079": ["DT", "RadiopharmaceuticalStopDateTime"], + "1080": ["CS", "BeatRejectionFlag"], + "1081": ["IS", "LowRRValue"], + "1082": ["IS", "HighRRValue"], + "1083": ["IS", "IntervalsAcquired"], + "1084": ["IS", "IntervalsRejected"], + "1085": ["LO", "PVCRejection"], + "1086": ["IS", "SkipBeats"], + "1088": ["IS", "HeartRate"], + "1090": ["IS", "CardiacNumberOfImages"], + "1094": ["IS", "TriggerWindow"], + "1100": ["DS", "ReconstructionDiameter"], + "1110": ["DS", "DistanceSourceToDetector"], + "1111": ["DS", "DistanceSourceToPatient"], + "1114": ["DS", "EstimatedRadiographicMagnificationFactor"], + "1120": ["DS", "GantryDetectorTilt"], + "1121": ["DS", "GantryDetectorSlew"], + "1130": ["DS", "TableHeight"], + "1131": ["DS", "TableTraverse"], + "1134": ["CS", "TableMotion"], + "1135": ["DS", "TableVerticalIncrement"], + "1136": ["DS", "TableLateralIncrement"], + "1137": ["DS", "TableLongitudinalIncrement"], + "1138": ["DS", "TableAngle"], + "113A": ["CS", "TableType"], + "1140": ["CS", "RotationDirection"], + "1141": ["DS", "AngularPosition"], + "1142": ["DS", "RadialPosition"], + "1143": ["DS", "ScanArc"], + "1144": ["DS", "AngularStep"], + "1145": ["DS", "CenterOfRotationOffset"], + "1146": ["DS", "RotationOffset"], + "1147": ["CS", "FieldOfViewShape"], + "1149": ["IS", "FieldOfViewDimensions"], + "1150": ["IS", "ExposureTime"], + "1151": ["IS", "XRayTubeCurrent"], + "1152": ["IS", "Exposure"], + "1153": ["IS", "ExposureInuAs"], + "1154": ["DS", "AveragePulseWidth"], + "1155": ["CS", "RadiationSetting"], + "1156": ["CS", "RectificationType"], + "115A": ["CS", "RadiationMode"], + "115E": ["DS", "ImageAndFluoroscopyAreaDoseProduct"], + "1160": ["SH", "FilterType"], + "1161": ["LO", "TypeOfFilters"], + "1162": ["DS", "IntensifierSize"], + "1164": ["DS", "ImagerPixelSpacing"], + "1166": ["CS", "Grid"], + "1170": ["IS", "GeneratorPower"], + "1180": ["SH", "CollimatorGridName"], + "1181": ["CS", "CollimatorType"], + "1182": ["IS", "FocalDistance"], + "1183": ["DS", "XFocusCenter"], + "1184": ["DS", "YFocusCenter"], + "1190": ["DS", "FocalSpots"], + "1191": ["CS", "AnodeTargetMaterial"], + "11A0": ["DS", "BodyPartThickness"], + "11A2": ["DS", "CompressionForce"], + "1200": ["DA", "DateOfLastCalibration"], + "1201": ["TM", "TimeOfLastCalibration"], + "1210": ["SH", "ConvolutionKernel"], + "1240": ["IS", "UpperLowerPixelValues"], + "1242": ["IS", "ActualFrameDuration"], + "1243": ["IS", "CountRate"], + "1244": ["US", "PreferredPlaybackSequencing"], + "1250": ["SH", "ReceiveCoilName"], + "1251": ["SH", "TransmitCoilName"], + "1260": ["SH", "PlateType"], + "1261": ["LO", "PhosphorType"], + "1300": ["DS", "ScanVelocity"], + "1301": ["CS", "WholeBodyTechnique"], + "1302": ["IS", "ScanLength"], + "1310": ["US", "AcquisitionMatrix"], + "1312": ["CS", "InPlanePhaseEncodingDirection"], + "1314": ["DS", "FlipAngle"], + "1315": ["CS", "VariableFlipAngleFlag"], + "1316": ["DS", "SAR"], + "1318": ["DS", "dBdt"], + "1400": ["LO", "AcquisitionDeviceProcessingDescription"], + "1401": ["LO", "AcquisitionDeviceProcessingCode"], + "1402": ["CS", "CassetteOrientation"], + "1403": ["CS", "CassetteSize"], + "1404": ["US", "ExposuresOnPlate"], + "1405": ["IS", "RelativeXRayExposure"], + "1411": ["DS", "ExposureIndex"], + "1412": ["DS", "TargetExposureIndex"], + "1413": ["DS", "DeviationIndex"], + "1450": ["DS", "ColumnAngulation"], + "1460": ["DS", "TomoLayerHeight"], + "1470": ["DS", "TomoAngle"], + "1480": ["DS", "TomoTime"], + "1490": ["CS", "TomoType"], + "1491": ["CS", "TomoClass"], + "1495": ["IS", "NumberOfTomosynthesisSourceImages"], + "1500": ["CS", "PositionerMotion"], + "1508": ["CS", "PositionerType"], + "1510": ["DS", "PositionerPrimaryAngle"], + "1511": ["DS", "PositionerSecondaryAngle"], + "1520": ["DS", "PositionerPrimaryAngleIncrement"], + "1521": ["DS", "PositionerSecondaryAngleIncrement"], + "1530": ["DS", "DetectorPrimaryAngle"], + "1531": ["DS", "DetectorSecondaryAngle"], + "1600": ["CS", "ShutterShape"], + "1602": ["IS", "ShutterLeftVerticalEdge"], + "1604": ["IS", "ShutterRightVerticalEdge"], + "1606": ["IS", "ShutterUpperHorizontalEdge"], + "1608": ["IS", "ShutterLowerHorizontalEdge"], + "1610": ["IS", "CenterOfCircularShutter"], + "1612": ["IS", "RadiusOfCircularShutter"], + "1620": ["IS", "VerticesOfThePolygonalShutter"], + "1622": ["US", "ShutterPresentationValue"], + "1623": ["US", "ShutterOverlayGroup"], + "1624": ["US", "ShutterPresentationColorCIELabValue"], + "1700": ["CS", "CollimatorShape"], + "1702": ["IS", "CollimatorLeftVerticalEdge"], + "1704": ["IS", "CollimatorRightVerticalEdge"], + "1706": ["IS", "CollimatorUpperHorizontalEdge"], + "1708": ["IS", "CollimatorLowerHorizontalEdge"], + "1710": ["IS", "CenterOfCircularCollimator"], + "1712": ["IS", "RadiusOfCircularCollimator"], + "1720": ["IS", "VerticesOfThePolygonalCollimator"], + "1800": ["CS", "AcquisitionTimeSynchronized"], + "1801": ["SH", "TimeSource"], + "1802": ["CS", "TimeDistributionProtocol"], + "1803": ["LO", "NTPSourceAddress"], + "2001": ["IS", "PageNumberVector"], + "2002": ["SH", "FrameLabelVector"], + "2003": ["DS", "FramePrimaryAngleVector"], + "2004": ["DS", "FrameSecondaryAngleVector"], + "2005": ["DS", "SliceLocationVector"], + "2006": ["SH", "DisplayWindowLabelVector"], + "2010": ["DS", "NominalScannedPixelSpacing"], + "2020": ["CS", "DigitizingDeviceTransportDirection"], + "2030": ["DS", "RotationOfScannedFilm"], + "3100": ["CS", "IVUSAcquisition"], + "3101": ["DS", "IVUSPullbackRate"], + "3102": ["DS", "IVUSGatedRate"], + "3103": ["IS", "IVUSPullbackStartFrameNumber"], + "3104": ["IS", "IVUSPullbackStopFrameNumber"], + "3105": ["IS", "LesionNumber"], + "4000": ["LT", "AcquisitionComments"], + "5000": ["SH", "OutputPower"], + "5010": ["LO", "TransducerData"], + "5012": ["DS", "FocusDepth"], + "5020": ["LO", "ProcessingFunction"], + "5021": ["LO", "PostprocessingFunction"], + "5022": ["DS", "MechanicalIndex"], + "5024": ["DS", "BoneThermalIndex"], + "5026": ["DS", "CranialThermalIndex"], + "5027": ["DS", "SoftTissueThermalIndex"], + "5028": ["DS", "SoftTissueFocusThermalIndex"], + "5029": ["DS", "SoftTissueSurfaceThermalIndex"], + "5030": ["DS", "DynamicRange"], + "5040": ["DS", "TotalGain"], + "5050": ["IS", "DepthOfScanField"], + "5100": ["CS", "PatientPosition"], + "5101": ["CS", "ViewPosition"], + "5104": ["SQ", "ProjectionEponymousNameCodeSequence"], + "5210": ["DS", "ImageTransformationMatrix"], + "5212": ["DS", "ImageTranslationVector"], + "6000": ["DS", "Sensitivity"], + "6011": ["SQ", "SequenceOfUltrasoundRegions"], + "6012": ["US", "RegionSpatialFormat"], + "6014": ["US", "RegionDataType"], + "6016": ["UL", "RegionFlags"], + "6018": ["UL", "RegionLocationMinX0"], + "601A": ["UL", "RegionLocationMinY0"], + "601C": ["UL", "RegionLocationMaxX1"], + "601E": ["UL", "RegionLocationMaxY1"], + "6020": ["SL", "ReferencePixelX0"], + "6022": ["SL", "ReferencePixelY0"], + "6024": ["US", "PhysicalUnitsXDirection"], + "6026": ["US", "PhysicalUnitsYDirection"], + "6028": ["FD", "ReferencePixelPhysicalValueX"], + "602A": ["FD", "ReferencePixelPhysicalValueY"], + "602C": ["FD", "PhysicalDeltaX"], + "602E": ["FD", "PhysicalDeltaY"], + "6030": ["UL", "TransducerFrequency"], + "6031": ["CS", "TransducerType"], + "6032": ["UL", "PulseRepetitionFrequency"], + "6034": ["FD", "DopplerCorrectionAngle"], + "6036": ["FD", "SteeringAngle"], + "6038": ["UL", "DopplerSampleVolumeXPositionRetired"], + "6039": ["SL", "DopplerSampleVolumeXPosition"], + "603A": ["UL", "DopplerSampleVolumeYPositionRetired"], + "603B": ["SL", "DopplerSampleVolumeYPosition"], + "603C": ["UL", "TMLinePositionX0Retired"], + "603D": ["SL", "TMLinePositionX0"], + "603E": ["UL", "TMLinePositionY0Retired"], + "603F": ["SL", "TMLinePositionY0"], + "6040": ["UL", "TMLinePositionX1Retired"], + "6041": ["SL", "TMLinePositionX1"], + "6042": ["UL", "TMLinePositionY1Retired"], + "6043": ["SL", "TMLinePositionY1"], + "6044": ["US", "PixelComponentOrganization"], + "6046": ["UL", "PixelComponentMask"], + "6048": ["UL", "PixelComponentRangeStart"], + "604A": ["UL", "PixelComponentRangeStop"], + "604C": ["US", "PixelComponentPhysicalUnits"], + "604E": ["US", "PixelComponentDataType"], + "6050": ["UL", "NumberOfTableBreakPoints"], + "6052": ["UL", "TableOfXBreakPoints"], + "6054": ["FD", "TableOfYBreakPoints"], + "6056": ["UL", "NumberOfTableEntries"], + "6058": ["UL", "TableOfPixelValues"], + "605A": ["FL", "TableOfParameterValues"], + "6060": ["FL", "RWaveTimeVector"], + "7000": ["CS", "DetectorConditionsNominalFlag"], + "7001": ["DS", "DetectorTemperature"], + "7004": ["CS", "DetectorType"], + "7005": ["CS", "DetectorConfiguration"], + "7006": ["LT", "DetectorDescription"], + "7008": ["LT", "DetectorMode"], + "700A": ["SH", "DetectorID"], + "700C": ["DA", "DateOfLastDetectorCalibration"], + "700E": ["TM", "TimeOfLastDetectorCalibration"], + "7010": ["IS", "ExposuresOnDetectorSinceLastCalibration"], + "7011": ["IS", "ExposuresOnDetectorSinceManufactured"], + "7012": ["DS", "DetectorTimeSinceLastExposure"], + "7014": ["DS", "DetectorActiveTime"], + "7016": ["DS", "DetectorActivationOffsetFromExposure"], + "701A": ["DS", "DetectorBinning"], + "7020": ["DS", "DetectorElementPhysicalSize"], + "7022": ["DS", "DetectorElementSpacing"], + "7024": ["CS", "DetectorActiveShape"], + "7026": ["DS", "DetectorActiveDimensions"], + "7028": ["DS", "DetectorActiveOrigin"], + "702A": ["LO", "DetectorManufacturerName"], + "702B": ["LO", "DetectorManufacturerModelName"], + "7030": ["DS", "FieldOfViewOrigin"], + "7032": ["DS", "FieldOfViewRotation"], + "7034": ["CS", "FieldOfViewHorizontalFlip"], + "7036": ["FL", "PixelDataAreaOriginRelativeToFOV"], + "7038": ["FL", "PixelDataAreaRotationAngleRelativeToFOV"], + "7040": ["LT", "GridAbsorbingMaterial"], + "7041": ["LT", "GridSpacingMaterial"], + "7042": ["DS", "GridThickness"], + "7044": ["DS", "GridPitch"], + "7046": ["IS", "GridAspectRatio"], + "7048": ["DS", "GridPeriod"], + "704C": ["DS", "GridFocalDistance"], + "7050": ["CS", "FilterMaterial"], + "7052": ["DS", "FilterThicknessMinimum"], + "7054": ["DS", "FilterThicknessMaximum"], + "7056": ["FL", "FilterBeamPathLengthMinimum"], + "7058": ["FL", "FilterBeamPathLengthMaximum"], + "7060": ["CS", "ExposureControlMode"], + "7062": ["LT", "ExposureControlModeDescription"], + "7064": ["CS", "ExposureStatus"], + "7065": ["DS", "PhototimerSetting"], + "8150": ["DS", "ExposureTimeInuS"], + "8151": ["DS", "XRayTubeCurrentInuA"], + "9004": ["CS", "ContentQualification"], + "9005": ["SH", "PulseSequenceName"], + "9006": ["SQ", "MRImagingModifierSequence"], + "9008": ["CS", "EchoPulseSequence"], + "9009": ["CS", "InversionRecovery"], + "9010": ["CS", "FlowCompensation"], + "9011": ["CS", "MultipleSpinEcho"], + "9012": ["CS", "MultiPlanarExcitation"], + "9014": ["CS", "PhaseContrast"], + "9015": ["CS", "TimeOfFlightContrast"], + "9016": ["CS", "Spoiling"], + "9017": ["CS", "SteadyStatePulseSequence"], + "9018": ["CS", "EchoPlanarPulseSequence"], + "9019": ["FD", "TagAngleFirstAxis"], + "9020": ["CS", "MagnetizationTransfer"], + "9021": ["CS", "T2Preparation"], + "9022": ["CS", "BloodSignalNulling"], + "9024": ["CS", "SaturationRecovery"], + "9025": ["CS", "SpectrallySelectedSuppression"], + "9026": ["CS", "SpectrallySelectedExcitation"], + "9027": ["CS", "SpatialPresaturation"], + "9028": ["CS", "Tagging"], + "9029": ["CS", "OversamplingPhase"], + "9030": ["FD", "TagSpacingFirstDimension"], + "9032": ["CS", "GeometryOfKSpaceTraversal"], + "9033": ["CS", "SegmentedKSpaceTraversal"], + "9034": ["CS", "RectilinearPhaseEncodeReordering"], + "9035": ["FD", "TagThickness"], + "9036": ["CS", "PartialFourierDirection"], + "9037": ["CS", "CardiacSynchronizationTechnique"], + "9041": ["LO", "ReceiveCoilManufacturerName"], + "9042": ["SQ", "MRReceiveCoilSequence"], + "9043": ["CS", "ReceiveCoilType"], + "9044": ["CS", "QuadratureReceiveCoil"], + "9045": ["SQ", "MultiCoilDefinitionSequence"], + "9046": ["LO", "MultiCoilConfiguration"], + "9047": ["SH", "MultiCoilElementName"], + "9048": ["CS", "MultiCoilElementUsed"], + "9049": ["SQ", "MRTransmitCoilSequence"], + "9050": ["LO", "TransmitCoilManufacturerName"], + "9051": ["CS", "TransmitCoilType"], + "9052": ["FD", "SpectralWidth"], + "9053": ["FD", "ChemicalShiftReference"], + "9054": ["CS", "VolumeLocalizationTechnique"], + "9058": ["US", "MRAcquisitionFrequencyEncodingSteps"], + "9059": ["CS", "Decoupling"], + "9060": ["CS", "DecoupledNucleus"], + "9061": ["FD", "DecouplingFrequency"], + "9062": ["CS", "DecouplingMethod"], + "9063": ["FD", "DecouplingChemicalShiftReference"], + "9064": ["CS", "KSpaceFiltering"], + "9065": ["CS", "TimeDomainFiltering"], + "9066": ["US", "NumberOfZeroFills"], + "9067": ["CS", "BaselineCorrection"], + "9069": ["FD", "ParallelReductionFactorInPlane"], + "9070": ["FD", "CardiacRRIntervalSpecified"], + "9073": ["FD", "AcquisitionDuration"], + "9074": ["DT", "FrameAcquisitionDateTime"], + "9075": ["CS", "DiffusionDirectionality"], + "9076": ["SQ", "DiffusionGradientDirectionSequence"], + "9077": ["CS", "ParallelAcquisition"], + "9078": ["CS", "ParallelAcquisitionTechnique"], + "9079": ["FD", "InversionTimes"], + "9080": ["ST", "MetaboliteMapDescription"], + "9081": ["CS", "PartialFourier"], + "9082": ["FD", "EffectiveEchoTime"], + "9083": ["SQ", "MetaboliteMapCodeSequence"], + "9084": ["SQ", "ChemicalShiftSequence"], + "9085": ["CS", "CardiacSignalSource"], + "9087": ["FD", "DiffusionBValue"], + "9089": ["FD", "DiffusionGradientOrientation"], + "9090": ["FD", "VelocityEncodingDirection"], + "9091": ["FD", "VelocityEncodingMinimumValue"], + "9092": ["SQ", "VelocityEncodingAcquisitionSequence"], + "9093": ["US", "NumberOfKSpaceTrajectories"], + "9094": ["CS", "CoverageOfKSpace"], + "9095": ["UL", "SpectroscopyAcquisitionPhaseRows"], + "9096": ["FD", "ParallelReductionFactorInPlaneRetired"], + "9098": ["FD", "TransmitterFrequency"], + "9100": ["CS", "ResonantNucleus"], + "9101": ["CS", "FrequencyCorrection"], + "9103": ["SQ", "MRSpectroscopyFOVGeometrySequence"], + "9104": ["FD", "SlabThickness"], + "9105": ["FD", "SlabOrientation"], + "9106": ["FD", "MidSlabPosition"], + "9107": ["SQ", "MRSpatialSaturationSequence"], + "9112": ["SQ", "MRTimingAndRelatedParametersSequence"], + "9114": ["SQ", "MREchoSequence"], + "9115": ["SQ", "MRModifierSequence"], + "9117": ["SQ", "MRDiffusionSequence"], + "9118": ["SQ", "CardiacSynchronizationSequence"], + "9119": ["SQ", "MRAveragesSequence"], + "9125": ["SQ", "MRFOVGeometrySequence"], + "9126": ["SQ", "VolumeLocalizationSequence"], + "9127": ["UL", "SpectroscopyAcquisitionDataColumns"], + "9147": ["CS", "DiffusionAnisotropyType"], + "9151": ["DT", "FrameReferenceDateTime"], + "9152": ["SQ", "MRMetaboliteMapSequence"], + "9155": ["FD", "ParallelReductionFactorOutOfPlane"], + "9159": ["UL", "SpectroscopyAcquisitionOutOfPlanePhaseSteps"], + "9166": ["CS", "BulkMotionStatus"], + "9168": ["FD", "ParallelReductionFactorSecondInPlane"], + "9169": ["CS", "CardiacBeatRejectionTechnique"], + "9170": ["CS", "RespiratoryMotionCompensationTechnique"], + "9171": ["CS", "RespiratorySignalSource"], + "9172": ["CS", "BulkMotionCompensationTechnique"], + "9173": ["CS", "BulkMotionSignalSource"], + "9174": ["CS", "ApplicableSafetyStandardAgency"], + "9175": ["LO", "ApplicableSafetyStandardDescription"], + "9176": ["SQ", "OperatingModeSequence"], + "9177": ["CS", "OperatingModeType"], + "9178": ["CS", "OperatingMode"], + "9179": ["CS", "SpecificAbsorptionRateDefinition"], + "9180": ["CS", "GradientOutputType"], + "9181": ["FD", "SpecificAbsorptionRateValue"], + "9182": ["FD", "GradientOutput"], + "9183": ["CS", "FlowCompensationDirection"], + "9184": ["FD", "TaggingDelay"], + "9185": ["ST", "RespiratoryMotionCompensationTechniqueDescription"], + "9186": ["SH", "RespiratorySignalSourceID"], + "9195": ["FD", "ChemicalShiftMinimumIntegrationLimitInHz"], + "9196": ["FD", "ChemicalShiftMaximumIntegrationLimitInHz"], + "9197": ["SQ", "MRVelocityEncodingSequence"], + "9198": ["CS", "FirstOrderPhaseCorrection"], + "9199": ["CS", "WaterReferencedPhaseCorrection"], + "9200": ["CS", "MRSpectroscopyAcquisitionType"], + "9214": ["CS", "RespiratoryCyclePosition"], + "9217": ["FD", "VelocityEncodingMaximumValue"], + "9218": ["FD", "TagSpacingSecondDimension"], + "9219": ["SS", "TagAngleSecondAxis"], + "9220": ["FD", "FrameAcquisitionDuration"], + "9226": ["SQ", "MRImageFrameTypeSequence"], + "9227": ["SQ", "MRSpectroscopyFrameTypeSequence"], + "9231": ["US", "MRAcquisitionPhaseEncodingStepsInPlane"], + "9232": ["US", "MRAcquisitionPhaseEncodingStepsOutOfPlane"], + "9234": ["UL", "SpectroscopyAcquisitionPhaseColumns"], + "9236": ["CS", "CardiacCyclePosition"], + "9239": ["SQ", "SpecificAbsorptionRateSequence"], + "9240": ["US", "RFEchoTrainLength"], + "9241": ["US", "GradientEchoTrainLength"], + "9250": ["CS", "ArterialSpinLabelingContrast"], + "9251": ["SQ", "MRArterialSpinLabelingSequence"], + "9252": ["LO", "ASLTechniqueDescription"], + "9253": ["US", "ASLSlabNumber"], + "9254": ["FD ", "ASLSlabThickness"], + "9255": ["FD ", "ASLSlabOrientation"], + "9256": ["FD ", "ASLMidSlabPosition"], + "9257": ["CS", "ASLContext"], + "9258": ["UL", "ASLPulseTrainDuration"], + "9259": ["CS", "ASLCrusherFlag"], + "925A": ["FD", "ASLCrusherFlow"], + "925B": ["LO", "ASLCrusherDescription"], + "925C": ["CS", "ASLBolusCutoffFlag"], + "925D": ["SQ", "ASLBolusCutoffTimingSequence"], + "925E": ["LO", "ASLBolusCutoffTechnique"], + "925F": ["UL", "ASLBolusCutoffDelayTime"], + "9260": ["SQ", "ASLSlabSequence"], + "9295": ["FD", "ChemicalShiftMinimumIntegrationLimitInppm"], + "9296": ["FD", "ChemicalShiftMaximumIntegrationLimitInppm"], + "9301": ["SQ", "CTAcquisitionTypeSequence"], + "9302": ["CS", "AcquisitionType"], + "9303": ["FD", "TubeAngle"], + "9304": ["SQ", "CTAcquisitionDetailsSequence"], + "9305": ["FD", "RevolutionTime"], + "9306": ["FD", "SingleCollimationWidth"], + "9307": ["FD", "TotalCollimationWidth"], + "9308": ["SQ", "CTTableDynamicsSequence"], + "9309": ["FD", "TableSpeed"], + "9310": ["FD", "TableFeedPerRotation"], + "9311": ["FD", "SpiralPitchFactor"], + "9312": ["SQ", "CTGeometrySequence"], + "9313": ["FD", "DataCollectionCenterPatient"], + "9314": ["SQ", "CTReconstructionSequence"], + "9315": ["CS", "ReconstructionAlgorithm"], + "9316": ["CS", "ConvolutionKernelGroup"], + "9317": ["FD", "ReconstructionFieldOfView"], + "9318": ["FD", "ReconstructionTargetCenterPatient"], + "9319": ["FD", "ReconstructionAngle"], + "9320": ["SH", "ImageFilter"], + "9321": ["SQ", "CTExposureSequence"], + "9322": ["FD", "ReconstructionPixelSpacing"], + "9323": ["CS", "ExposureModulationType"], + "9324": ["FD", "EstimatedDoseSaving"], + "9325": ["SQ", "CTXRayDetailsSequence"], + "9326": ["SQ", "CTPositionSequence"], + "9327": ["FD", "TablePosition"], + "9328": ["FD", "ExposureTimeInms"], + "9329": ["SQ", "CTImageFrameTypeSequence"], + "9330": ["FD", "XRayTubeCurrentInmA"], + "9332": ["FD", "ExposureInmAs"], + "9333": ["CS", "ConstantVolumeFlag"], + "9334": ["CS", "FluoroscopyFlag"], + "9335": ["FD", "DistanceSourceToDataCollectionCenter"], + "9337": ["US", "ContrastBolusAgentNumber"], + "9338": ["SQ", "ContrastBolusIngredientCodeSequence"], + "9340": ["SQ", "ContrastAdministrationProfileSequence"], + "9341": ["SQ", "ContrastBolusUsageSequence"], + "9342": ["CS", "ContrastBolusAgentAdministered"], + "9343": ["CS", "ContrastBolusAgentDetected"], + "9344": ["CS", "ContrastBolusAgentPhase"], + "9345": ["FD", "CTDIvol"], + "9346": ["SQ", "CTDIPhantomTypeCodeSequence"], + "9351": ["FL", "CalciumScoringMassFactorPatient"], + "9352": ["FL", "CalciumScoringMassFactorDevice"], + "9353": ["FL", "EnergyWeightingFactor"], + "9360": ["SQ", "CTAdditionalXRaySourceSequence"], + "9401": ["SQ", "ProjectionPixelCalibrationSequence"], + "9402": ["FL", "DistanceSourceToIsocenter"], + "9403": ["FL", "DistanceObjectToTableTop"], + "9404": ["FL", "ObjectPixelSpacingInCenterOfBeam"], + "9405": ["SQ", "PositionerPositionSequence"], + "9406": ["SQ", "TablePositionSequence"], + "9407": ["SQ", "CollimatorShapeSequence"], + "9410": ["CS", "PlanesInAcquisition"], + "9412": ["SQ", "XAXRFFrameCharacteristicsSequence"], + "9417": ["SQ", "FrameAcquisitionSequence"], + "9420": ["CS", "XRayReceptorType"], + "9423": ["LO", "AcquisitionProtocolName"], + "9424": ["LT", "AcquisitionProtocolDescription"], + "9425": ["CS", "ContrastBolusIngredientOpaque"], + "9426": ["FL", "DistanceReceptorPlaneToDetectorHousing"], + "9427": ["CS", "IntensifierActiveShape"], + "9428": ["FL", "IntensifierActiveDimensions"], + "9429": ["FL", "PhysicalDetectorSize"], + "9430": ["FL", "PositionOfIsocenterProjection"], + "9432": ["SQ", "FieldOfViewSequence"], + "9433": ["LO", "FieldOfViewDescription"], + "9434": ["SQ", "ExposureControlSensingRegionsSequence"], + "9435": ["CS", "ExposureControlSensingRegionShape"], + "9436": ["SS", "ExposureControlSensingRegionLeftVerticalEdge"], + "9437": ["SS", "ExposureControlSensingRegionRightVerticalEdge"], + "9438": ["SS", "ExposureControlSensingRegionUpperHorizontalEdge"], + "9439": ["SS", "ExposureControlSensingRegionLowerHorizontalEdge"], + "9440": ["SS", "CenterOfCircularExposureControlSensingRegion"], + "9441": ["US", "RadiusOfCircularExposureControlSensingRegion"], + "9442": ["SS", "VerticesOfThePolygonalExposureControlSensingRegion"], + "9447": ["FL", "ColumnAngulationPatient"], + "9449": ["FL", "BeamAngle"], + "9451": ["SQ", "FrameDetectorParametersSequence"], + "9452": ["FL", "CalculatedAnatomyThickness"], + "9455": ["SQ", "CalibrationSequence"], + "9456": ["SQ", "ObjectThicknessSequence"], + "9457": ["CS", "PlaneIdentification"], + "9461": ["FL", "FieldOfViewDimensionsInFloat"], + "9462": ["SQ", "IsocenterReferenceSystemSequence"], + "9463": ["FL", "PositionerIsocenterPrimaryAngle"], + "9464": ["FL", "PositionerIsocenterSecondaryAngle"], + "9465": ["FL", "PositionerIsocenterDetectorRotationAngle"], + "9466": ["FL", "TableXPositionToIsocenter"], + "9467": ["FL", "TableYPositionToIsocenter"], + "9468": ["FL", "TableZPositionToIsocenter"], + "9469": ["FL", "TableHorizontalRotationAngle"], + "9470": ["FL", "TableHeadTiltAngle"], + "9471": ["FL", "TableCradleTiltAngle"], + "9472": ["SQ", "FrameDisplayShutterSequence"], + "9473": ["FL", "AcquiredImageAreaDoseProduct"], + "9474": ["CS", "CArmPositionerTabletopRelationship"], + "9476": ["SQ", "XRayGeometrySequence"], + "9477": ["SQ", "IrradiationEventIdentificationSequence"], + "9504": ["SQ", "XRay3DFrameTypeSequence"], + "9506": ["SQ", "ContributingSourcesSequence"], + "9507": ["SQ", "XRay3DAcquisitionSequence"], + "9508": ["FL", "PrimaryPositionerScanArc"], + "9509": ["FL", "SecondaryPositionerScanArc"], + "9510": ["FL", "PrimaryPositionerScanStartAngle"], + "9511": ["FL", "SecondaryPositionerScanStartAngle"], + "9514": ["FL", "PrimaryPositionerIncrement"], + "9515": ["FL", "SecondaryPositionerIncrement"], + "9516": ["DT", "StartAcquisitionDateTime"], + "9517": ["DT", "EndAcquisitionDateTime"], + "9524": ["LO", "ApplicationName"], + "9525": ["LO", "ApplicationVersion"], + "9526": ["LO", "ApplicationManufacturer"], + "9527": ["CS", "AlgorithmType"], + "9528": ["LO", "AlgorithmDescription"], + "9530": ["SQ", "XRay3DReconstructionSequence"], + "9531": ["LO", "ReconstructionDescription"], + "9538": ["SQ", "PerProjectionAcquisitionSequence"], + "9601": ["SQ", "DiffusionBMatrixSequence"], + "9602": ["FD", "DiffusionBValueXX"], + "9603": ["FD", "DiffusionBValueXY"], + "9604": ["FD", "DiffusionBValueXZ"], + "9605": ["FD", "DiffusionBValueYY"], + "9606": ["FD", "DiffusionBValueYZ"], + "9607": ["FD", "DiffusionBValueZZ"], + "9701": ["DT", "DecayCorrectionDateTime"], + "9715": ["FD", "StartDensityThreshold"], + "9716": ["FD", "StartRelativeDensityDifferenceThreshold"], + "9717": ["FD", "StartCardiacTriggerCountThreshold"], + "9718": ["FD", "StartRespiratoryTriggerCountThreshold"], + "9719": ["FD", "TerminationCountsThreshold"], + "9720": ["FD", "TerminationDensityThreshold"], + "9721": ["FD", "TerminationRelativeDensityThreshold"], + "9722": ["FD", "TerminationTimeThreshold"], + "9723": ["FD", "TerminationCardiacTriggerCountThreshold"], + "9724": ["FD", "TerminationRespiratoryTriggerCountThreshold"], + "9725": ["CS", "DetectorGeometry"], + "9726": ["FD", "TransverseDetectorSeparation"], + "9727": ["FD", "AxialDetectorDimension"], + "9729": ["US", "RadiopharmaceuticalAgentNumber"], + "9732": ["SQ", "PETFrameAcquisitionSequence"], + "9733": ["SQ", "PETDetectorMotionDetailsSequence"], + "9734": ["SQ", "PETTableDynamicsSequence"], + "9735": ["SQ", "PETPositionSequence"], + "9736": ["SQ", "PETFrameCorrectionFactorsSequence"], + "9737": ["SQ", "RadiopharmaceuticalUsageSequence"], + "9738": ["CS", "AttenuationCorrectionSource"], + "9739": ["US", "NumberOfIterations"], + "9740": ["US", "NumberOfSubsets"], + "9749": ["SQ", "PETReconstructionSequence"], + "9751": ["SQ", "PETFrameTypeSequence"], + "9755": ["CS", "TimeOfFlightInformationUsed"], + "9756": ["CS", "ReconstructionType"], + "9758": ["CS", "DecayCorrected"], + "9759": ["CS", "AttenuationCorrected"], + "9760": ["CS", "ScatterCorrected"], + "9761": ["CS", "DeadTimeCorrected"], + "9762": ["CS", "GantryMotionCorrected"], + "9763": ["CS", "PatientMotionCorrected"], + "9764": ["CS", "CountLossNormalizationCorrected"], + "9765": ["CS", "RandomsCorrected"], + "9766": ["CS", "NonUniformRadialSamplingCorrected"], + "9767": ["CS", "SensitivityCalibrated"], + "9768": ["CS", "DetectorNormalizationCorrection"], + "9769": ["CS", "IterativeReconstructionMethod"], + "9770": ["CS", "AttenuationCorrectionTemporalRelationship"], + "9771": ["SQ", "PatientPhysiologicalStateSequence"], + "9772": ["SQ", "PatientPhysiologicalStateCodeSequence"], + "9801": ["FD", "DepthsOfFocus"], + "9803": ["SQ", "ExcludedIntervalsSequence"], + "9804": ["DT", "ExclusionStartDatetime"], + "9805": ["FD", "ExclusionDuration"], + "9806": ["SQ", "USImageDescriptionSequence"], + "9807": ["SQ", "ImageDataTypeSequence"], + "9808": ["CS", "DataType"], + "9809": ["SQ", "TransducerScanPatternCodeSequence"], + "980B": ["CS", "AliasedDataType"], + "980C": ["CS", "PositionMeasuringDeviceUsed"], + "980D": ["SQ", "TransducerGeometryCodeSequence"], + "980E": ["SQ", "TransducerBeamSteeringCodeSequence"], + "980F": ["SQ", "TransducerApplicationCodeSequence"], + "A001": ["SQ", "ContributingEquipmentSequence"], + "A002": ["DT", "ContributionDateTime"], + "A003": ["ST", "ContributionDescription"] + }, + "0020": { + "000D": ["UI", "StudyInstanceUID"], + "000E": ["UI", "SeriesInstanceUID"], + "0010": ["SH", "StudyID"], + "0011": ["IS", "SeriesNumber"], + "0012": ["IS", "AcquisitionNumber"], + "0013": ["IS", "InstanceNumber"], + "0014": ["IS", "IsotopeNumber"], + "0015": ["IS", "PhaseNumber"], + "0016": ["IS", "IntervalNumber"], + "0017": ["IS", "TimeSlotNumber"], + "0018": ["IS", "AngleNumber"], + "0019": ["IS", "ItemNumber"], + "0020": ["CS", "PatientOrientation"], + "0022": ["IS", "OverlayNumber"], + "0024": ["IS", "CurveNumber"], + "0026": ["IS", "LUTNumber"], + "0030": ["DS", "ImagePosition"], + "0032": ["DS", "ImagePositionPatient"], + "0035": ["DS", "ImageOrientation"], + "0037": ["DS", "ImageOrientationPatient"], + "0050": ["DS", "Location"], + "0052": ["UI", "FrameOfReferenceUID"], + "0060": ["CS", "Laterality"], + "0062": ["CS", "ImageLaterality"], + "0070": ["LO", "ImageGeometryType"], + "0080": ["CS", "MaskingImage"], + "00AA": ["IS", "ReportNumber"], + "0100": ["IS", "TemporalPositionIdentifier"], + "0105": ["IS", "NumberOfTemporalPositions"], + "0110": ["DS", "TemporalResolution"], + "0200": ["UI", "SynchronizationFrameOfReferenceUID"], + "0242": ["UI", "SOPInstanceUIDOfConcatenationSource"], + "1000": ["IS", "SeriesInStudy"], + "1001": ["IS", "AcquisitionsInSeries"], + "1002": ["IS", "ImagesInAcquisition"], + "1003": ["IS", "ImagesInSeries"], + "1004": ["IS", "AcquisitionsInStudy"], + "1005": ["IS", "ImagesInStudy"], + "1020": ["LO", "Reference"], + "1040": ["LO", "PositionReferenceIndicator"], + "1041": ["DS", "SliceLocation"], + "1070": ["IS", "OtherStudyNumbers"], + "1200": ["IS", "NumberOfPatientRelatedStudies"], + "1202": ["IS", "NumberOfPatientRelatedSeries"], + "1204": ["IS", "NumberOfPatientRelatedInstances"], + "1206": ["IS", "NumberOfStudyRelatedSeries"], + "1208": ["IS", "NumberOfStudyRelatedInstances"], + "1209": ["IS", "NumberOfSeriesRelatedInstances"], + "3401": ["CS", "ModifyingDeviceID"], + "3402": ["CS", "ModifiedImageID"], + "3403": ["DA", "ModifiedImageDate"], + "3404": ["LO", "ModifyingDeviceManufacturer"], + "3405": ["TM", "ModifiedImageTime"], + "3406": ["LO", "ModifiedImageDescription"], + "4000": ["LT", "ImageComments"], + "5000": ["AT", "OriginalImageIdentification"], + "5002": ["LO", "OriginalImageIdentificationNomenclature"], + "9056": ["SH", "StackID"], + "9057": ["UL", "InStackPositionNumber"], + "9071": ["SQ", "FrameAnatomySequence"], + "9072": ["CS", "FrameLaterality"], + "9111": ["SQ", "FrameContentSequence"], + "9113": ["SQ", "PlanePositionSequence"], + "9116": ["SQ", "PlaneOrientationSequence"], + "9128": ["UL", "TemporalPositionIndex"], + "9153": ["FD", "NominalCardiacTriggerDelayTime"], + "9154": ["FL", "NominalCardiacTriggerTimePriorToRPeak"], + "9155": ["FL", "ActualCardiacTriggerTimePriorToRPeak"], + "9156": ["US", "FrameAcquisitionNumber"], + "9157": ["UL", "DimensionIndexValues"], + "9158": ["LT", "FrameComments"], + "9161": ["UI", "ConcatenationUID"], + "9162": ["US", "InConcatenationNumber"], + "9163": ["US", "InConcatenationTotalNumber"], + "9164": ["UI", "DimensionOrganizationUID"], + "9165": ["AT", "DimensionIndexPointer"], + "9167": ["AT", "FunctionalGroupPointer"], + "9213": ["LO", "DimensionIndexPrivateCreator"], + "9221": ["SQ", "DimensionOrganizationSequence"], + "9222": ["SQ", "DimensionIndexSequence"], + "9228": ["UL", "ConcatenationFrameOffsetNumber"], + "9238": ["LO", "FunctionalGroupPrivateCreator"], + "9241": ["FL", "NominalPercentageOfCardiacPhase"], + "9245": ["FL", "NominalPercentageOfRespiratoryPhase"], + "9246": ["FL", "StartingRespiratoryAmplitude"], + "9247": ["CS", "StartingRespiratoryPhase"], + "9248": ["FL", "EndingRespiratoryAmplitude"], + "9249": ["CS", "EndingRespiratoryPhase"], + "9250": ["CS", "RespiratoryTriggerType"], + "9251": ["FD", "RRIntervalTimeNominal"], + "9252": ["FD", "ActualCardiacTriggerDelayTime"], + "9253": ["SQ", "RespiratorySynchronizationSequence"], + "9254": ["FD", "RespiratoryIntervalTime"], + "9255": ["FD", "NominalRespiratoryTriggerDelayTime"], + "9256": ["FD", "RespiratoryTriggerDelayThreshold"], + "9257": ["FD", "ActualRespiratoryTriggerDelayTime"], + "9301": ["FD", "ImagePositionVolume"], + "9302": ["FD", "ImageOrientationVolume"], + "9307": ["CS", "UltrasoundAcquisitionGeometry"], + "9308": ["FD", "ApexPosition"], + "9309": ["FD", "VolumeToTransducerMappingMatrix"], + "930A": ["FD", "VolumeToTableMappingMatrix"], + "930C": ["CS", "PatientFrameOfReferenceSource"], + "930D": ["FD", "TemporalPositionTimeOffset"], + "930E": ["SQ", "PlanePositionVolumeSequence"], + "930F": ["SQ", "PlaneOrientationVolumeSequence"], + "9310": ["SQ", "TemporalPositionSequence"], + "9311": ["CS", "DimensionOrganizationType"], + "9312": ["UI", "VolumeFrameOfReferenceUID"], + "9313": ["UI", "TableFrameOfReferenceUID"], + "9421": ["LO", "DimensionDescriptionLabel"], + "9450": ["SQ", "PatientOrientationInFrameSequence"], + "9453": ["LO", "FrameLabel"], + "9518": ["US", "AcquisitionIndex"], + "9529": ["SQ", "ContributingSOPInstancesReferenceSequence"], + "9536": ["US", "ReconstructionIndex"] + }, + "0022": { + "0001": ["US", "LightPathFilterPassThroughWavelength"], + "0002": ["US", "LightPathFilterPassBand"], + "0003": ["US", "ImagePathFilterPassThroughWavelength"], + "0004": ["US", "ImagePathFilterPassBand"], + "0005": ["CS", "PatientEyeMovementCommanded"], + "0006": ["SQ", "PatientEyeMovementCommandCodeSequence"], + "0007": ["FL", "SphericalLensPower"], + "0008": ["FL", "CylinderLensPower"], + "0009": ["FL", "CylinderAxis"], + "000A": ["FL", "EmmetropicMagnification"], + "000B": ["FL", "IntraOcularPressure"], + "000C": ["FL", "HorizontalFieldOfView"], + "000D": ["CS", "PupilDilated"], + "000E": ["FL", "DegreeOfDilation"], + "0010": ["FL", "StereoBaselineAngle"], + "0011": ["FL", "StereoBaselineDisplacement"], + "0012": ["FL", "StereoHorizontalPixelOffset"], + "0013": ["FL", "StereoVerticalPixelOffset"], + "0014": ["FL", "StereoRotation"], + "0015": ["SQ", "AcquisitionDeviceTypeCodeSequence"], + "0016": ["SQ", "IlluminationTypeCodeSequence"], + "0017": ["SQ", "LightPathFilterTypeStackCodeSequence"], + "0018": ["SQ", "ImagePathFilterTypeStackCodeSequence"], + "0019": ["SQ", "LensesCodeSequence"], + "001A": ["SQ", "ChannelDescriptionCodeSequence"], + "001B": ["SQ", "RefractiveStateSequence"], + "001C": ["SQ", "MydriaticAgentCodeSequence"], + "001D": ["SQ", "RelativeImagePositionCodeSequence"], + "001E": ["FL", "CameraAngleOfView"], + "0020": ["SQ", "StereoPairsSequence"], + "0021": ["SQ", "LeftImageSequence"], + "0022": ["SQ", "RightImageSequence"], + "0030": ["FL", "AxialLengthOfTheEye"], + "0031": ["SQ", "OphthalmicFrameLocationSequence"], + "0032": ["FL", "ReferenceCoordinates"], + "0035": ["FL", "DepthSpatialResolution"], + "0036": ["FL", "MaximumDepthDistortion"], + "0037": ["FL", "AlongScanSpatialResolution"], + "0038": ["FL", "MaximumAlongScanDistortion"], + "0039": ["CS", "OphthalmicImageOrientation"], + "0041": ["FL", "DepthOfTransverseImage"], + "0042": ["SQ", "MydriaticAgentConcentrationUnitsSequence"], + "0048": ["FL", "AcrossScanSpatialResolution"], + "0049": ["FL", "MaximumAcrossScanDistortion"], + "004E": ["DS", "MydriaticAgentConcentration"], + "0055": ["FL", "IlluminationWaveLength"], + "0056": ["FL", "IlluminationPower"], + "0057": ["FL", "IlluminationBandwidth"], + "0058": ["SQ", "MydriaticAgentSequence"], + "1007": ["SQ", "OphthalmicAxialMeasurementsRightEyeSequence"], + "1008": ["SQ", "OphthalmicAxialMeasurementsLeftEyeSequence"], + "1010": ["CS", "OphthalmicAxialLengthMeasurementsType"], + "1019": ["FL", "OphthalmicAxialLength"], + "1024": ["SQ", "LensStatusCodeSequence"], + "1025": ["SQ", "VitreousStatusCodeSequence"], + "1028": ["SQ", "IOLFormulaCodeSequence"], + "1029": ["LO", "IOLFormulaDetail"], + "1033": ["FL", "KeratometerIndex"], + "1035": ["SQ", "SourceOfOphthalmicAxialLengthCodeSequence"], + "1037": ["FL", "TargetRefraction"], + "1039": ["CS", "RefractiveProcedureOccurred"], + "1040": ["SQ", "RefractiveSurgeryTypeCodeSequence"], + "1044": ["SQ", "OphthalmicUltrasoundAxialMeasurementsTypeCodeSequence"], + "1050": ["SQ", "OphthalmicAxialLengthMeasurementsSequence"], + "1053": ["FL", "IOLPower"], + "1054": ["FL", "PredictedRefractiveError"], + "1059": ["FL", "OphthalmicAxialLengthVelocity"], + "1065": ["LO", "LensStatusDescription"], + "1066": ["LO", "VitreousStatusDescription"], + "1090": ["SQ", "IOLPowerSequence"], + "1092": ["SQ", "LensConstantSequence"], + "1093": ["LO", "IOLManufacturer"], + "1094": ["LO", "LensConstantDescription"], + "1096": ["SQ", "KeratometryMeasurementTypeCodeSequence"], + "1100": ["SQ", "ReferencedOphthalmicAxialMeasurementsSequence"], + "1101": ["SQ", "OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence"], + "1103": ["SQ", "RefractiveErrorBeforeRefractiveSurgeryCodeSequence"], + "1121": ["FL", "IOLPowerForExactEmmetropia"], + "1122": ["FL", "IOLPowerForExactTargetRefraction"], + "1125": ["SQ", "AnteriorChamberDepthDefinitionCodeSequence"], + "1130": ["FL", "LensThickness"], + "1131": ["FL", "AnteriorChamberDepth"], + "1132": ["SQ", "SourceOfLensThicknessDataCodeSequence"], + "1133": ["SQ", "SourceOfAnteriorChamberDepthDataCodeSequence"], + "1135": ["SQ", "SourceOfRefractiveErrorDataCodeSequence"], + "1140": ["CS", "OphthalmicAxialLengthMeasurementModified"], + "1150": ["SQ", "OphthalmicAxialLengthDataSourceCodeSequence"], + "1153": ["SQ", "OphthalmicAxialLengthAcquisitionMethodCodeSequence"], + "1155": ["FL", "SignalToNoiseRatio"], + "1159": ["LO", "OphthalmicAxialLengthDataSourceDescription"], + "1210": ["SQ", "OphthalmicAxialLengthMeasurementsTotalLengthSequence"], + "1211": ["SQ", "OphthalmicAxialLengthMeasurementsSegmentalLengthSequence"], + "1212": ["SQ", "OphthalmicAxialLengthMeasurementsLengthSummationSequence"], + "1220": ["SQ", "UltrasoundOphthalmicAxialLengthMeasurementsSequence"], + "1225": ["SQ", "OpticalOphthalmicAxialLengthMeasurementsSequence"], + "1230": ["SQ", "UltrasoundSelectedOphthalmicAxialLengthSequence"], + "1250": ["SQ", "OphthalmicAxialLengthSelectionMethodCodeSequence"], + "1255": ["SQ", "OpticalSelectedOphthalmicAxialLengthSequence"], + "1257": ["SQ", "SelectedSegmentalOphthalmicAxialLengthSequence"], + "1260": ["SQ", "SelectedTotalOphthalmicAxialLengthSequence"], + "1262": ["SQ", "OphthalmicAxialLengthQualityMetricSequence"], + "1273": ["LO", "OphthalmicAxialLengthQualityMetricTypeDescription"], + "1300": ["SQ", "IntraocularLensCalculationsRightEyeSequence"], + "1310": ["SQ", "IntraocularLensCalculationsLeftEyeSequence"], + "1330": ["SQ", "ReferencedOphthalmicAxialLengthMeasurementQCImageSequence"] + }, + "0024": { + "0010": ["FL", "VisualFieldHorizontalExtent"], + "0011": ["FL", "VisualFieldVerticalExtent"], + "0012": ["CS", "VisualFieldShape"], + "0016": ["SQ", "ScreeningTestModeCodeSequence"], + "0018": ["FL", "MaximumStimulusLuminance"], + "0020": ["FL", "BackgroundLuminance"], + "0021": ["SQ", "StimulusColorCodeSequence"], + "0024": ["SQ", "BackgroundIlluminationColorCodeSequence"], + "0025": ["FL", "StimulusArea"], + "0028": ["FL", "StimulusPresentationTime"], + "0032": ["SQ", "FixationSequence"], + "0033": ["SQ", "FixationMonitoringCodeSequence"], + "0034": ["SQ", "VisualFieldCatchTrialSequence"], + "0035": ["US", "FixationCheckedQuantity"], + "0036": ["US", "PatientNotProperlyFixatedQuantity"], + "0037": ["CS", "PresentedVisualStimuliDataFlag"], + "0038": ["US", "NumberOfVisualStimuli"], + "0039": ["CS", "ExcessiveFixationLossesDataFlag"], + "0040": ["CS", "ExcessiveFixationLosses"], + "0042": ["US", "StimuliRetestingQuantity"], + "0044": ["LT", "CommentsOnPatientPerformanceOfVisualField"], + "0045": ["CS", "FalseNegativesEstimateFlag"], + "0046": ["FL", "FalseNegativesEstimate"], + "0048": ["US", "NegativeCatchTrialsQuantity"], + "0050": ["US", "FalseNegativesQuantity"], + "0051": ["CS", "ExcessiveFalseNegativesDataFlag"], + "0052": ["CS", "ExcessiveFalseNegatives"], + "0053": ["CS", "FalsePositivesEstimateFlag"], + "0054": ["FL", "FalsePositivesEstimate"], + "0055": ["CS", "CatchTrialsDataFlag"], + "0056": ["US", "PositiveCatchTrialsQuantity"], + "0057": ["CS", "TestPointNormalsDataFlag"], + "0058": ["SQ", "TestPointNormalsSequence"], + "0059": ["CS", "GlobalDeviationProbabilityNormalsFlag"], + "0060": ["US", "FalsePositivesQuantity"], + "0061": ["CS", "ExcessiveFalsePositivesDataFlag"], + "0062": ["CS", "ExcessiveFalsePositives"], + "0063": ["CS", "VisualFieldTestNormalsFlag"], + "0064": ["SQ", "ResultsNormalsSequence"], + "0065": ["SQ", "AgeCorrectedSensitivityDeviationAlgorithmSequence"], + "0066": ["FL", "GlobalDeviationFromNormal"], + "0067": ["SQ", "GeneralizedDefectSensitivityDeviationAlgorithmSequence"], + "0068": ["FL", "LocalizedDeviationfromNormal"], + "0069": ["LO", "PatientReliabilityIndicator"], + "0070": ["FL", "VisualFieldMeanSensitivity"], + "0071": ["FL", "GlobalDeviationProbability"], + "0072": ["CS", "LocalDeviationProbabilityNormalsFlag"], + "0073": ["FL", "LocalizedDeviationProbability"], + "0074": ["CS", "ShortTermFluctuationCalculated"], + "0075": ["FL", "ShortTermFluctuation"], + "0076": ["CS", "ShortTermFluctuationProbabilityCalculated"], + "0077": ["FL", "ShortTermFluctuationProbability"], + "0078": ["CS", "CorrectedLocalizedDeviationFromNormalCalculated"], + "0079": ["FL", "CorrectedLocalizedDeviationFromNormal"], + "0080": ["CS", "CorrectedLocalizedDeviationFromNormalProbabilityCalculated"], + "0081": ["FL", "CorrectedLocalizedDeviationFromNormalProbability"], + "0083": ["SQ", "GlobalDeviationProbabilitySequence"], + "0085": ["SQ", "LocalizedDeviationProbabilitySequence"], + "0086": ["CS", "FovealSensitivityMeasured"], + "0087": ["FL", "FovealSensitivity"], + "0088": ["FL", "VisualFieldTestDuration"], + "0089": ["SQ", "VisualFieldTestPointSequence"], + "0090": ["FL", "VisualFieldTestPointXCoordinate"], + "0091": ["FL", "VisualFieldTestPointYCoordinate"], + "0092": ["FL", "AgeCorrectedSensitivityDeviationValue"], + "0093": ["CS", "StimulusResults"], + "0094": ["FL", "SensitivityValue"], + "0095": ["CS", "RetestStimulusSeen"], + "0096": ["FL", "RetestSensitivityValue"], + "0097": ["SQ", "VisualFieldTestPointNormalsSequence"], + "0098": ["FL", "QuantifiedDefect"], + "0100": ["FL", "AgeCorrectedSensitivityDeviationProbabilityValue"], + "0102": ["CS", "GeneralizedDefectCorrectedSensitivityDeviationFlag "], + "0103": ["FL", "GeneralizedDefectCorrectedSensitivityDeviationValue "], + "0104": ["FL", "GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue"], + "0105": ["FL ", "MinimumSensitivityValue"], + "0106": ["CS", "BlindSpotLocalized"], + "0107": ["FL", "BlindSpotXCoordinate"], + "0108": ["FL", "BlindSpotYCoordinate "], + "0110": ["SQ", "VisualAcuityMeasurementSequence"], + "0112": ["SQ", "RefractiveParametersUsedOnPatientSequence"], + "0113": ["CS", "MeasurementLaterality"], + "0114": ["SQ", "OphthalmicPatientClinicalInformationLeftEyeSequence"], + "0115": ["SQ", "OphthalmicPatientClinicalInformationRightEyeSequence"], + "0117": ["CS", "FovealPointNormativeDataFlag"], + "0118": ["FL", "FovealPointProbabilityValue"], + "0120": ["CS", "ScreeningBaselineMeasured"], + "0122": ["SQ", "ScreeningBaselineMeasuredSequence"], + "0124": ["CS", "ScreeningBaselineType"], + "0126": ["FL", "ScreeningBaselineValue"], + "0202": ["LO", "AlgorithmSource"], + "0306": ["LO", "DataSetName"], + "0307": ["LO", "DataSetVersion"], + "0308": ["LO", "DataSetSource"], + "0309": ["LO", "DataSetDescription"], + "0317": ["SQ", "VisualFieldTestReliabilityGlobalIndexSequence"], + "0320": ["SQ", "VisualFieldGlobalResultsIndexSequence"], + "0325": ["SQ", "DataObservationSequence"], + "0338": ["CS", "IndexNormalsFlag"], + "0341": ["FL", "IndexProbability"], + "0344": ["SQ", "IndexProbabilitySequence"] + }, + "0028": { + "0002": ["US", "SamplesPerPixel"], + "0003": ["US", "SamplesPerPixelUsed"], + "0004": ["CS", "PhotometricInterpretation"], + "0005": ["US", "ImageDimensions"], + "0006": ["US", "PlanarConfiguration"], + "0008": ["IS", "NumberOfFrames"], + "0009": ["AT", "FrameIncrementPointer"], + "000A": ["AT", "FrameDimensionPointer"], + "0010": ["US", "Rows"], + "0011": ["US", "Columns"], + "0012": ["US", "Planes"], + "0014": ["US", "UltrasoundColorDataPresent"], + "0030": ["DS", "PixelSpacing"], + "0031": ["DS", "ZoomFactor"], + "0032": ["DS", "ZoomCenter"], + "0034": ["IS", "PixelAspectRatio"], + "0040": ["CS", "ImageFormat"], + "0050": ["LO", "ManipulatedImage"], + "0051": ["CS", "CorrectedImage"], + "005F": ["LO", "CompressionRecognitionCode"], + "0060": ["CS", "CompressionCode"], + "0061": ["SH", "CompressionOriginator"], + "0062": ["LO", "CompressionLabel"], + "0063": ["SH", "CompressionDescription"], + "0065": ["CS", "CompressionSequence"], + "0066": ["AT", "CompressionStepPointers"], + "0068": ["US", "RepeatInterval"], + "0069": ["US", "BitsGrouped"], + "0070": ["US", "PerimeterTable"], + "0071": ["SS", "PerimeterValue"], + "0080": ["US", "PredictorRows"], + "0081": ["US", "PredictorColumns"], + "0082": ["US", "PredictorConstants"], + "0090": ["CS", "BlockedPixels"], + "0091": ["US", "BlockRows"], + "0092": ["US", "BlockColumns"], + "0093": ["US", "RowOverlap"], + "0094": ["US", "ColumnOverlap"], + "0100": ["US", "BitsAllocated"], + "0101": ["US", "BitsStored"], + "0102": ["US", "HighBit"], + "0103": ["US", "PixelRepresentation"], + "0104": ["SS", "SmallestValidPixelValue"], + "0105": ["SS", "LargestValidPixelValue"], + "0106": ["SS", "SmallestImagePixelValue"], + "0107": ["SS", "LargestImagePixelValue"], + "0108": ["SS", "SmallestPixelValueInSeries"], + "0109": ["SS", "LargestPixelValueInSeries"], + "0110": ["SS", "SmallestImagePixelValueInPlane"], + "0111": ["SS", "LargestImagePixelValueInPlane"], + "0120": ["SS", "PixelPaddingValue"], + "0121": ["SS", "PixelPaddingRangeLimit"], + "0200": ["US", "ImageLocation"], + "0300": ["CS", "QualityControlImage"], + "0301": ["CS", "BurnedInAnnotation"], + "0302": ["CS", "RecognizableVisualFeatures"], + "0303": ["CS", "LongitudinalTemporalInformationModified"], + "0400": ["LO", "TransformLabel"], + "0401": ["LO", "TransformVersionNumber"], + "0402": ["US", "NumberOfTransformSteps"], + "0403": ["LO", "SequenceOfCompressedData"], + "0404": ["AT", "DetailsOfCoefficients"], + "0700": ["LO", "DCTLabel"], + "0701": ["CS", "DataBlockDescription"], + "0702": ["AT", "DataBlock"], + "0710": ["US", "NormalizationFactorFormat"], + "0720": ["US", "ZonalMapNumberFormat"], + "0721": ["AT", "ZonalMapLocation"], + "0722": ["US", "ZonalMapFormat"], + "0730": ["US", "AdaptiveMapFormat"], + "0740": ["US", "CodeNumberFormat"], + "0A02": ["CS", "PixelSpacingCalibrationType"], + "0A04": ["LO", "PixelSpacingCalibrationDescription"], + "1040": ["CS", "PixelIntensityRelationship"], + "1041": ["SS", "PixelIntensityRelationshipSign"], + "1050": ["DS", "WindowCenter"], + "1051": ["DS", "WindowWidth"], + "1052": ["DS", "RescaleIntercept"], + "1053": ["DS", "RescaleSlope"], + "1054": ["LO", "RescaleType"], + "1055": ["LO", "WindowCenterWidthExplanation"], + "1056": ["CS", "VOILUTFunction"], + "1080": ["CS", "GrayScale"], + "1090": ["CS", "RecommendedViewingMode"], + "1100": ["SS", "GrayLookupTableDescriptor"], + "1101": ["SS", "RedPaletteColorLookupTableDescriptor"], + "1102": ["SS", "GreenPaletteColorLookupTableDescriptor"], + "1103": ["SS", "BluePaletteColorLookupTableDescriptor"], + "1104": ["US", "AlphaPaletteColorLookupTableDescriptor"], + "1111": ["SS", "LargeRedPaletteColorLookupTableDescriptor"], + "1112": ["SS", "LargeGreenPaletteColorLookupTableDescriptor"], + "1113": ["SS", "LargeBluePaletteColorLookupTableDescriptor"], + "1199": ["UI", "PaletteColorLookupTableUID"], + "1200": ["OW", "GrayLookupTableData"], + "1201": ["OW", "RedPaletteColorLookupTableData"], + "1202": ["OW", "GreenPaletteColorLookupTableData"], + "1203": ["OW", "BluePaletteColorLookupTableData"], + "1204": ["OW", "AlphaPaletteColorLookupTableData"], + "1211": ["OW", "LargeRedPaletteColorLookupTableData"], + "1212": ["OW", "LargeGreenPaletteColorLookupTableData"], + "1213": ["OW", "LargeBluePaletteColorLookupTableData"], + "1214": ["UI", "LargePaletteColorLookupTableUID"], + "1221": ["OW", "SegmentedRedPaletteColorLookupTableData"], + "1222": ["OW", "SegmentedGreenPaletteColorLookupTableData"], + "1223": ["OW", "SegmentedBluePaletteColorLookupTableData"], + "1300": ["CS", "BreastImplantPresent"], + "1350": ["CS", "PartialView"], + "1351": ["ST", "PartialViewDescription"], + "1352": ["SQ", "PartialViewCodeSequence"], + "135A": ["CS", "SpatialLocationsPreserved"], + "1401": ["SQ", "DataFrameAssignmentSequence"], + "1402": ["CS", "DataPathAssignment"], + "1403": ["US", "BitsMappedToColorLookupTable"], + "1404": ["SQ", "BlendingLUT1Sequence"], + "1405": ["CS", "BlendingLUT1TransferFunction"], + "1406": ["FD", "BlendingWeightConstant"], + "1407": ["US", "BlendingLookupTableDescriptor"], + "1408": ["OW", "BlendingLookupTableData"], + "140B": ["SQ", "EnhancedPaletteColorLookupTableSequence"], + "140C": ["SQ", "BlendingLUT2Sequence"], + "140D": ["CS", "BlendingLUT2TransferFunction"], + "140E": ["CS", "DataPathID"], + "140F": ["CS", "RGBLUTTransferFunction"], + "1410": ["CS", "AlphaLUTTransferFunction"], + "2000": ["OB", "ICCProfile"], + "2110": ["CS", "LossyImageCompression"], + "2112": ["DS", "LossyImageCompressionRatio"], + "2114": ["CS", "LossyImageCompressionMethod"], + "3000": ["SQ", "ModalityLUTSequence"], + "3002": ["SS", "LUTDescriptor"], + "3003": ["LO", "LUTExplanation"], + "3004": ["LO", "ModalityLUTType"], + "3006": ["OW", "LUTData"], + "3010": ["SQ", "VOILUTSequence"], + "3110": ["SQ", "SoftcopyVOILUTSequence"], + "4000": ["LT", "ImagePresentationComments"], + "5000": ["SQ", "BiPlaneAcquisitionSequence"], + "6010": ["US", "RepresentativeFrameNumber"], + "6020": ["US", "FrameNumbersOfInterest"], + "6022": ["LO", "FrameOfInterestDescription"], + "6023": ["CS", "FrameOfInterestType"], + "6030": ["US", "MaskPointers"], + "6040": ["US", "RWavePointer"], + "6100": ["SQ", "MaskSubtractionSequence"], + "6101": ["CS", "MaskOperation"], + "6102": ["US", "ApplicableFrameRange"], + "6110": ["US", "MaskFrameNumbers"], + "6112": ["US", "ContrastFrameAveraging"], + "6114": ["FL", "MaskSubPixelShift"], + "6120": ["SS", "TIDOffset"], + "6190": ["ST", "MaskOperationExplanation"], + "7FE0": ["UT", "PixelDataProviderURL"], + "9001": ["UL", "DataPointRows"], + "9002": ["UL", "DataPointColumns"], + "9003": ["CS", "SignalDomainColumns"], + "9099": ["US", "LargestMonochromePixelValue"], + "9108": ["CS", "DataRepresentation"], + "9110": ["SQ", "PixelMeasuresSequence"], + "9132": ["SQ", "FrameVOILUTSequence"], + "9145": ["SQ", "PixelValueTransformationSequence"], + "9235": ["CS", "SignalDomainRows"], + "9411": ["FL", "DisplayFilterPercentage"], + "9415": ["SQ", "FramePixelShiftSequence"], + "9416": ["US", "SubtractionItemID"], + "9422": ["SQ", "PixelIntensityRelationshipLUTSequence"], + "9443": ["SQ", "FramePixelDataPropertiesSequence"], + "9444": ["CS", "GeometricalProperties"], + "9445": ["FL", "GeometricMaximumDistortion"], + "9446": ["CS", "ImageProcessingApplied"], + "9454": ["CS", "MaskSelectionMode"], + "9474": ["CS", "LUTFunction"], + "9478": ["FL", "MaskVisibilityPercentage"], + "9501": ["SQ", "PixelShiftSequence"], + "9502": ["SQ", "RegionPixelShiftSequence"], + "9503": ["SS", "VerticesOfTheRegion"], + "9505": ["SQ", "MultiFramePresentationSequence"], + "9506": ["US", "PixelShiftFrameRange"], + "9507": ["US", "LUTFrameRange"], + "9520": ["DS", "ImageToEquipmentMappingMatrix"], + "9537": ["CS", "EquipmentCoordinateSystemIdentification"] + }, + "0032": { + "000A": ["CS", "StudyStatusID"], + "000C": ["CS", "StudyPriorityID"], + "0012": ["LO", "StudyIDIssuer"], + "0032": ["DA", "StudyVerifiedDate"], + "0033": ["TM", "StudyVerifiedTime"], + "0034": ["DA", "StudyReadDate"], + "0035": ["TM", "StudyReadTime"], + "1000": ["DA", "ScheduledStudyStartDate"], + "1001": ["TM", "ScheduledStudyStartTime"], + "1010": ["DA", "ScheduledStudyStopDate"], + "1011": ["TM", "ScheduledStudyStopTime"], + "1020": ["LO", "ScheduledStudyLocation"], + "1021": ["AE", "ScheduledStudyLocationAETitle"], + "1030": ["LO", "ReasonForStudy"], + "1031": ["SQ", "RequestingPhysicianIdentificationSequence"], + "1032": ["PN", "RequestingPhysician"], + "1033": ["LO", "RequestingService"], + "1034": ["SQ", "RequestingServiceCodeSequence"], + "1040": ["DA", "StudyArrivalDate"], + "1041": ["TM", "StudyArrivalTime"], + "1050": ["DA", "StudyCompletionDate"], + "1051": ["TM", "StudyCompletionTime"], + "1055": ["CS", "StudyComponentStatusID"], + "1060": ["LO", "RequestedProcedureDescription"], + "1064": ["SQ", "RequestedProcedureCodeSequence"], + "1070": ["LO", "RequestedContrastAgent"], + "4000": ["LT", "StudyComments"] + }, + "0038": { + "0004": ["SQ", "ReferencedPatientAliasSequence"], + "0008": ["CS", "VisitStatusID"], + "0010": ["LO", "AdmissionID"], + "0011": ["LO", "IssuerOfAdmissionID"], + "0014": ["SQ", "IssuerOfAdmissionIDSequence"], + "0016": ["LO", "RouteOfAdmissions"], + "001A": ["DA", "ScheduledAdmissionDate"], + "001B": ["TM", "ScheduledAdmissionTime"], + "001C": ["DA", "ScheduledDischargeDate"], + "001D": ["TM", "ScheduledDischargeTime"], + "001E": ["LO", "ScheduledPatientInstitutionResidence"], + "0020": ["DA", "AdmittingDate"], + "0021": ["TM", "AdmittingTime"], + "0030": ["DA", "DischargeDate"], + "0032": ["TM", "DischargeTime"], + "0040": ["LO", "DischargeDiagnosisDescription"], + "0044": ["SQ", "DischargeDiagnosisCodeSequence"], + "0050": ["LO", "SpecialNeeds"], + "0060": ["LO", "ServiceEpisodeID"], + "0061": ["LO", "IssuerOfServiceEpisodeID"], + "0062": ["LO", "ServiceEpisodeDescription"], + "0064": ["SQ", "IssuerOfServiceEpisodeIDSequence"], + "0100": ["SQ", "PertinentDocumentsSequence"], + "0300": ["LO", "CurrentPatientLocation"], + "0400": ["LO", "PatientInstitutionResidence"], + "0500": ["LO", "PatientState"], + "0502": ["SQ", "PatientClinicalTrialParticipationSequence"], + "4000": ["LT", "VisitComments"] + }, + "003A": { + "0004": ["CS", "WaveformOriginality"], + "0005": ["US", "NumberOfWaveformChannels"], + "0010": ["UL", "NumberOfWaveformSamples"], + "001A": ["DS", "SamplingFrequency"], + "0020": ["SH", "MultiplexGroupLabel"], + "0200": ["SQ", "ChannelDefinitionSequence"], + "0202": ["IS", "WaveformChannelNumber"], + "0203": ["SH", "ChannelLabel"], + "0205": ["CS", "ChannelStatus"], + "0208": ["SQ", "ChannelSourceSequence"], + "0209": ["SQ", "ChannelSourceModifiersSequence"], + "020A": ["SQ", "SourceWaveformSequence"], + "020C": ["LO", "ChannelDerivationDescription"], + "0210": ["DS", "ChannelSensitivity"], + "0211": ["SQ", "ChannelSensitivityUnitsSequence"], + "0212": ["DS", "ChannelSensitivityCorrectionFactor"], + "0213": ["DS", "ChannelBaseline"], + "0214": ["DS", "ChannelTimeSkew"], + "0215": ["DS", "ChannelSampleSkew"], + "0218": ["DS", "ChannelOffset"], + "021A": ["US", "WaveformBitsStored"], + "0220": ["DS", "FilterLowFrequency"], + "0221": ["DS", "FilterHighFrequency"], + "0222": ["DS", "NotchFilterFrequency"], + "0223": ["DS", "NotchFilterBandwidth"], + "0230": ["FL", "WaveformDataDisplayScale"], + "0231": ["US", "WaveformDisplayBackgroundCIELabValue"], + "0240": ["SQ", "WaveformPresentationGroupSequence"], + "0241": ["US", "PresentationGroupNumber"], + "0242": ["SQ", "ChannelDisplaySequence"], + "0244": ["US", "ChannelRecommendedDisplayCIELabValue"], + "0245": ["FL", "ChannelPosition"], + "0246": ["CS", "DisplayShadingFlag"], + "0247": ["FL", "FractionalChannelDisplayScale"], + "0248": ["FL", "AbsoluteChannelDisplayScale"], + "0300": ["SQ", "MultiplexedAudioChannelsDescriptionCodeSequence"], + "0301": ["IS", "ChannelIdentificationCode"], + "0302": ["CS", "ChannelMode"] + }, + "0040": { + "0001": ["AE", "ScheduledStationAETitle"], + "0002": ["DA", "ScheduledProcedureStepStartDate"], + "0003": ["TM", "ScheduledProcedureStepStartTime"], + "0004": ["DA", "ScheduledProcedureStepEndDate"], + "0005": ["TM", "ScheduledProcedureStepEndTime"], + "0006": ["PN", "ScheduledPerformingPhysicianName"], + "0007": ["LO", "ScheduledProcedureStepDescription"], + "0008": ["SQ", "ScheduledProtocolCodeSequence"], + "0009": ["SH", "ScheduledProcedureStepID"], + "000A": ["SQ", "StageCodeSequence"], + "000B": ["SQ", "ScheduledPerformingPhysicianIdentificationSequence"], + "0010": ["SH", "ScheduledStationName"], + "0011": ["SH", "ScheduledProcedureStepLocation"], + "0012": ["LO", "PreMedication"], + "0020": ["CS", "ScheduledProcedureStepStatus"], + "0026": ["SQ", "OrderPlacerIdentifierSequence"], + "0027": ["SQ", "OrderFillerIdentifierSequence"], + "0031": ["UT", "LocalNamespaceEntityID"], + "0032": ["UT", "UniversalEntityID"], + "0033": ["CS", "UniversalEntityIDType"], + "0035": ["CS", "IdentifierTypeCode"], + "0036": ["SQ", "AssigningFacilitySequence"], + "0039": ["SQ", "AssigningJurisdictionCodeSequence"], + "003A": ["SQ", "AssigningAgencyOrDepartmentCodeSequence"], + "0100": ["SQ", "ScheduledProcedureStepSequence"], + "0220": ["SQ", "ReferencedNonImageCompositeSOPInstanceSequence"], + "0241": ["AE", "PerformedStationAETitle"], + "0242": ["SH", "PerformedStationName"], + "0243": ["SH", "PerformedLocation"], + "0244": ["DA", "PerformedProcedureStepStartDate"], + "0245": ["TM", "PerformedProcedureStepStartTime"], + "0250": ["DA", "PerformedProcedureStepEndDate"], + "0251": ["TM", "PerformedProcedureStepEndTime"], + "0252": ["CS", "PerformedProcedureStepStatus"], + "0253": ["SH", "PerformedProcedureStepID"], + "0254": ["LO", "PerformedProcedureStepDescription"], + "0255": ["LO", "PerformedProcedureTypeDescription"], + "0260": ["SQ", "PerformedProtocolCodeSequence"], + "0261": ["CS", "PerformedProtocolType"], + "0270": ["SQ", "ScheduledStepAttributesSequence"], + "0275": ["SQ", "RequestAttributesSequence"], + "0280": ["ST", "CommentsOnThePerformedProcedureStep"], + "0281": ["SQ", "PerformedProcedureStepDiscontinuationReasonCodeSequence"], + "0293": ["SQ", "QuantitySequence"], + "0294": ["DS", "Quantity"], + "0295": ["SQ", "MeasuringUnitsSequence"], + "0296": ["SQ", "BillingItemSequence"], + "0300": ["US", "TotalTimeOfFluoroscopy"], + "0301": ["US", "TotalNumberOfExposures"], + "0302": ["US", "EntranceDose"], + "0303": ["US", "ExposedArea"], + "0306": ["DS", "DistanceSourceToEntrance"], + "0307": ["DS", "DistanceSourceToSupport"], + "030E": ["SQ", "ExposureDoseSequence"], + "0310": ["ST", "CommentsOnRadiationDose"], + "0312": ["DS", "XRayOutput"], + "0314": ["DS", "HalfValueLayer"], + "0316": ["DS", "OrganDose"], + "0318": ["CS", "OrganExposed"], + "0320": ["SQ", "BillingProcedureStepSequence"], + "0321": ["SQ", "FilmConsumptionSequence"], + "0324": ["SQ", "BillingSuppliesAndDevicesSequence"], + "0330": ["SQ", "ReferencedProcedureStepSequence"], + "0340": ["SQ", "PerformedSeriesSequence"], + "0400": ["LT", "CommentsOnTheScheduledProcedureStep"], + "0440": ["SQ", "ProtocolContextSequence"], + "0441": ["SQ", "ContentItemModifierSequence"], + "0500": ["SQ", "ScheduledSpecimenSequence"], + "050A": ["LO", "SpecimenAccessionNumber"], + "0512": ["LO", "ContainerIdentifier"], + "0513": ["SQ", "IssuerOfTheContainerIdentifierSequence"], + "0515": ["SQ", "AlternateContainerIdentifierSequence"], + "0518": ["SQ", "ContainerTypeCodeSequence"], + "051A": ["LO", "ContainerDescription"], + "0520": ["SQ", "ContainerComponentSequence"], + "0550": ["SQ", "SpecimenSequence"], + "0551": ["LO", "SpecimenIdentifier"], + "0552": ["SQ", "SpecimenDescriptionSequenceTrial"], + "0553": ["ST", "SpecimenDescriptionTrial"], + "0554": ["UI", "SpecimenUID"], + "0555": ["SQ", "AcquisitionContextSequence"], + "0556": ["ST", "AcquisitionContextDescription"], + "059A": ["SQ", "SpecimenTypeCodeSequence"], + "0560": ["SQ", "SpecimenDescriptionSequence"], + "0562": ["SQ", "IssuerOfTheSpecimenIdentifierSequence"], + "0600": ["LO", "SpecimenShortDescription"], + "0602": ["UT", "SpecimenDetailedDescription"], + "0610": ["SQ", "SpecimenPreparationSequence"], + "0612": ["SQ", "SpecimenPreparationStepContentItemSequence"], + "0620": ["SQ", "SpecimenLocalizationContentItemSequence"], + "06FA": ["LO", "SlideIdentifier"], + "071A": ["SQ", "ImageCenterPointCoordinatesSequence"], + "072A": ["DS", "XOffsetInSlideCoordinateSystem"], + "073A": ["DS", "YOffsetInSlideCoordinateSystem"], + "074A": ["DS", "ZOffsetInSlideCoordinateSystem"], + "08D8": ["SQ", "PixelSpacingSequence"], + "08DA": ["SQ", "CoordinateSystemAxisCodeSequence"], + "08EA": ["SQ", "MeasurementUnitsCodeSequence"], + "09F8": ["SQ", "VitalStainCodeSequenceTrial"], + "1001": ["SH", "RequestedProcedureID"], + "1002": ["LO", "ReasonForTheRequestedProcedure"], + "1003": ["SH", "RequestedProcedurePriority"], + "1004": ["LO", "PatientTransportArrangements"], + "1005": ["LO", "RequestedProcedureLocation"], + "1006": ["SH", "PlacerOrderNumberProcedure"], + "1007": ["SH", "FillerOrderNumberProcedure"], + "1008": ["LO", "ConfidentialityCode"], + "1009": ["SH", "ReportingPriority"], + "100A": ["SQ", "ReasonForRequestedProcedureCodeSequence"], + "1010": ["PN", "NamesOfIntendedRecipientsOfResults"], + "1011": ["SQ", "IntendedRecipientsOfResultsIdentificationSequence"], + "1012": ["SQ", "ReasonForPerformedProcedureCodeSequence"], + "1060": ["LO", "RequestedProcedureDescriptionTrial"], + "1101": ["SQ", "PersonIdentificationCodeSequence"], + "1102": ["ST", "PersonAddress"], + "1103": ["LO", "PersonTelephoneNumbers"], + "1400": ["LT", "RequestedProcedureComments"], + "2001": ["LO", "ReasonForTheImagingServiceRequest"], + "2004": ["DA", "IssueDateOfImagingServiceRequest"], + "2005": ["TM", "IssueTimeOfImagingServiceRequest"], + "2006": ["SH", "PlacerOrderNumberImagingServiceRequestRetired"], + "2007": ["SH", "FillerOrderNumberImagingServiceRequestRetired"], + "2008": ["PN", "OrderEnteredBy"], + "2009": ["SH", "OrderEntererLocation"], + "2010": ["SH", "OrderCallbackPhoneNumber"], + "2016": ["LO", "PlacerOrderNumberImagingServiceRequest"], + "2017": ["LO", "FillerOrderNumberImagingServiceRequest"], + "2400": ["LT", "ImagingServiceRequestComments"], + "3001": ["LO", "ConfidentialityConstraintOnPatientDataDescription"], + "4001": ["CS", "GeneralPurposeScheduledProcedureStepStatus"], + "4002": ["CS", "GeneralPurposePerformedProcedureStepStatus"], + "4003": ["CS", "GeneralPurposeScheduledProcedureStepPriority"], + "4004": ["SQ", "ScheduledProcessingApplicationsCodeSequence"], + "4005": ["DT", "ScheduledProcedureStepStartDateTime"], + "4006": ["CS", "MultipleCopiesFlag"], + "4007": ["SQ", "PerformedProcessingApplicationsCodeSequence"], + "4009": ["SQ", "HumanPerformerCodeSequence"], + "4010": ["DT", "ScheduledProcedureStepModificationDateTime"], + "4011": ["DT", "ExpectedCompletionDateTime"], + "4015": ["SQ", "ResultingGeneralPurposePerformedProcedureStepsSequence"], + "4016": ["SQ", "ReferencedGeneralPurposeScheduledProcedureStepSequence"], + "4018": ["SQ", "ScheduledWorkitemCodeSequence"], + "4019": ["SQ", "PerformedWorkitemCodeSequence"], + "4020": ["CS", "InputAvailabilityFlag"], + "4021": ["SQ", "InputInformationSequence"], + "4022": ["SQ", "RelevantInformationSequence"], + "4023": ["UI", "ReferencedGeneralPurposeScheduledProcedureStepTransactionUID"], + "4025": ["SQ", "ScheduledStationNameCodeSequence"], + "4026": ["SQ", "ScheduledStationClassCodeSequence"], + "4027": ["SQ", "ScheduledStationGeographicLocationCodeSequence"], + "4028": ["SQ", "PerformedStationNameCodeSequence"], + "4029": ["SQ", "PerformedStationClassCodeSequence"], + "4030": ["SQ", "PerformedStationGeographicLocationCodeSequence"], + "4031": ["SQ", "RequestedSubsequentWorkitemCodeSequence"], + "4032": ["SQ", "NonDICOMOutputCodeSequence"], + "4033": ["SQ", "OutputInformationSequence"], + "4034": ["SQ", "ScheduledHumanPerformersSequence"], + "4035": ["SQ", "ActualHumanPerformersSequence"], + "4036": ["LO", "HumanPerformerOrganization"], + "4037": ["PN", "HumanPerformerName"], + "4040": ["CS", "RawDataHandling"], + "4041": ["CS", "InputReadinessState"], + "4050": ["DT", "PerformedProcedureStepStartDateTime"], + "4051": ["DT", "PerformedProcedureStepEndDateTime"], + "4052": ["DT", "ProcedureStepCancellationDateTime"], + "8302": ["DS", "EntranceDoseInmGy"], + "9094": ["SQ", "ReferencedImageRealWorldValueMappingSequence"], + "9096": ["SQ", "RealWorldValueMappingSequence"], + "9098": ["SQ", "PixelValueMappingCodeSequence"], + "9210": ["SH", "LUTLabel"], + "9211": ["SS", "RealWorldValueLastValueMapped"], + "9212": ["FD", "RealWorldValueLUTData"], + "9216": ["SS", "RealWorldValueFirstValueMapped"], + "9224": ["FD", "RealWorldValueIntercept"], + "9225": ["FD", "RealWorldValueSlope"], + "A007": ["CS", "FindingsFlagTrial"], + "A010": ["CS", "RelationshipType"], + "A020": ["SQ", "FindingsSequenceTrial"], + "A021": ["UI", "FindingsGroupUIDTrial"], + "A022": ["UI", "ReferencedFindingsGroupUIDTrial"], + "A023": ["DA", "FindingsGroupRecordingDateTrial"], + "A024": ["TM", "FindingsGroupRecordingTimeTrial"], + "A026": ["SQ", "FindingsSourceCategoryCodeSequenceTrial"], + "A027": ["LO", "VerifyingOrganization"], + "A028": ["SQ", "DocumentingOrganizationIdentifierCodeSequenceTrial"], + "A030": ["DT", "VerificationDateTime"], + "A032": ["DT", "ObservationDateTime"], + "A040": ["CS", "ValueType"], + "A043": ["SQ", "ConceptNameCodeSequence"], + "A047": ["LO", "MeasurementPrecisionDescriptionTrial"], + "A050": ["CS", "ContinuityOfContent"], + "A057": ["CS", "UrgencyOrPriorityAlertsTrial"], + "A060": ["LO", "SequencingIndicatorTrial"], + "A066": ["SQ", "DocumentIdentifierCodeSequenceTrial"], + "A067": ["PN", "DocumentAuthorTrial"], + "A068": ["SQ", "DocumentAuthorIdentifierCodeSequenceTrial"], + "A070": ["SQ", "IdentifierCodeSequenceTrial"], + "A073": ["SQ", "VerifyingObserverSequence"], + "A074": ["OB", "ObjectBinaryIdentifierTrial"], + "A075": ["PN", "VerifyingObserverName"], + "A076": ["SQ", "DocumentingObserverIdentifierCodeSequenceTrial"], + "A078": ["SQ", "AuthorObserverSequence"], + "A07A": ["SQ", "ParticipantSequence"], + "A07C": ["SQ", "CustodialOrganizationSequence"], + "A080": ["CS", "ParticipationType"], + "A082": ["DT", "ParticipationDateTime"], + "A084": ["CS", "ObserverType"], + "A085": ["SQ", "ProcedureIdentifierCodeSequenceTrial"], + "A088": ["SQ", "VerifyingObserverIdentificationCodeSequence"], + "A089": ["OB", "ObjectDirectoryBinaryIdentifierTrial"], + "A090": ["SQ", "EquivalentCDADocumentSequence"], + "A0B0": ["US", "ReferencedWaveformChannels"], + "A110": ["DA", "DateOfDocumentOrVerbalTransactionTrial"], + "A112": ["TM", "TimeOfDocumentCreationOrVerbalTransactionTrial"], + "A120": ["DT", "DateTime"], + "A121": ["DA", "Date"], + "A122": ["TM", "Time"], + "A123": ["PN", "PersonName"], + "A124": ["UI", "UID"], + "A125": ["CS", "ReportStatusIDTrial"], + "A130": ["CS", "TemporalRangeType"], + "A132": ["UL", "ReferencedSamplePositions"], + "A136": ["US", "ReferencedFrameNumbers"], + "A138": ["DS", "ReferencedTimeOffsets"], + "A13A": ["DT", "ReferencedDateTime"], + "A160": ["UT", "TextValue"], + "A167": ["SQ", "ObservationCategoryCodeSequenceTrial"], + "A168": ["SQ", "ConceptCodeSequence"], + "A16A": ["ST", "BibliographicCitationTrial"], + "A170": ["SQ", "PurposeOfReferenceCodeSequence"], + "A171": ["UI", "ObservationUIDTrial"], + "A172": ["UI", "ReferencedObservationUIDTrial"], + "A173": ["CS", "ReferencedObservationClassTrial"], + "A174": ["CS", "ReferencedObjectObservationClassTrial"], + "A180": ["US", "AnnotationGroupNumber"], + "A192": ["DA", "ObservationDateTrial"], + "A193": ["TM", "ObservationTimeTrial"], + "A194": ["CS", "MeasurementAutomationTrial"], + "A195": ["SQ", "ModifierCodeSequence"], + "A224": ["ST", "IdentificationDescriptionTrial"], + "A290": ["CS", "CoordinatesSetGeometricTypeTrial"], + "A296": ["SQ", "AlgorithmCodeSequenceTrial"], + "A297": ["ST", "AlgorithmDescriptionTrial"], + "A29A": ["SL", "PixelCoordinatesSetTrial"], + "A300": ["SQ", "MeasuredValueSequence"], + "A301": ["SQ", "NumericValueQualifierCodeSequence"], + "A307": ["PN", "CurrentObserverTrial"], + "A30A": ["DS", "NumericValue"], + "A313": ["SQ", "ReferencedAccessionSequenceTrial"], + "A33A": ["ST", "ReportStatusCommentTrial"], + "A340": ["SQ", "ProcedureContextSequenceTrial"], + "A352": ["PN", "VerbalSourceTrial"], + "A353": ["ST", "AddressTrial"], + "A354": ["LO", "TelephoneNumberTrial"], + "A358": ["SQ", "VerbalSourceIdentifierCodeSequenceTrial"], + "A360": ["SQ", "PredecessorDocumentsSequence"], + "A370": ["SQ", "ReferencedRequestSequence"], + "A372": ["SQ", "PerformedProcedureCodeSequence"], + "A375": ["SQ", "CurrentRequestedProcedureEvidenceSequence"], + "A380": ["SQ", "ReportDetailSequenceTrial"], + "A385": ["SQ", "PertinentOtherEvidenceSequence"], + "A390": ["SQ", "HL7StructuredDocumentReferenceSequence"], + "A402": ["UI", "ObservationSubjectUIDTrial"], + "A403": ["CS", "ObservationSubjectClassTrial"], + "A404": ["SQ", "ObservationSubjectTypeCodeSequenceTrial"], + "A491": ["CS", "CompletionFlag"], + "A492": ["LO", "CompletionFlagDescription"], + "A493": ["CS", "VerificationFlag"], + "A494": ["CS", "ArchiveRequested"], + "A496": ["CS", "PreliminaryFlag"], + "A504": ["SQ", "ContentTemplateSequence"], + "A525": ["SQ", "IdenticalDocumentsSequence"], + "A600": ["CS", "ObservationSubjectContextFlagTrial"], + "A601": ["CS", "ObserverContextFlagTrial"], + "A603": ["CS", "ProcedureContextFlagTrial"], + "A730": ["SQ", "ContentSequence"], + "A731": ["SQ", "RelationshipSequenceTrial"], + "A732": ["SQ", "RelationshipTypeCodeSequenceTrial"], + "A744": ["SQ", "LanguageCodeSequenceTrial"], + "A992": ["ST", "UniformResourceLocatorTrial"], + "B020": ["SQ", "WaveformAnnotationSequence"], + "DB00": ["CS", "TemplateIdentifier"], + "DB06": ["DT", "TemplateVersion"], + "DB07": ["DT", "TemplateLocalVersion"], + "DB0B": ["CS", "TemplateExtensionFlag"], + "DB0C": ["UI", "TemplateExtensionOrganizationUID"], + "DB0D": ["UI", "TemplateExtensionCreatorUID"], + "DB73": ["UL", "ReferencedContentItemIdentifier"], + "E001": ["ST", "HL7InstanceIdentifier"], + "E004": ["DT", "HL7DocumentEffectiveTime"], + "E006": ["SQ", "HL7DocumentTypeCodeSequence"], + "E008": ["SQ", "DocumentClassCodeSequence"], + "E010": ["UT", "RetrieveURI"], + "E011": ["UI", "RetrieveLocationUID"], + "E020": ["CS", "TypeOfInstances"], + "E021": ["SQ", "DICOMRetrievalSequence"], + "E022": ["SQ", "DICOMMediaRetrievalSequence"], + "E023": ["SQ", "WADORetrievalSequence"], + "E024": ["SQ", "XDSRetrievalSequence"], + "E030": ["UI", "RepositoryUniqueID"], + "E031": ["UI", "HomeCommunityID"] + }, + "0042": { + "0010": ["ST", "DocumentTitle"], + "0011": ["OB", "EncapsulatedDocument"], + "0012": ["LO", "MIMETypeOfEncapsulatedDocument"], + "0013": ["SQ", "SourceInstanceSequence"], + "0014": ["LO", "ListOfMIMETypes"] + }, + "0044": { + "0001": ["ST", "ProductPackageIdentifier"], + "0002": ["CS", "SubstanceAdministrationApproval"], + "0003": ["LT", "ApprovalStatusFurtherDescription"], + "0004": ["DT", "ApprovalStatusDateTime"], + "0007": ["SQ", "ProductTypeCodeSequence"], + "0008": ["LO", "ProductName"], + "0009": ["LT", "ProductDescription"], + "000A": ["LO", "ProductLotIdentifier"], + "000B": ["DT", "ProductExpirationDateTime"], + "0010": ["DT", "SubstanceAdministrationDateTime"], + "0011": ["LO", "SubstanceAdministrationNotes"], + "0012": ["LO", "SubstanceAdministrationDeviceID"], + "0013": ["SQ", "ProductParameterSequence"], + "0019": ["SQ", "SubstanceAdministrationParameterSequence"] + }, + "0046": { + "0012": ["LO", "LensDescription"], + "0014": ["SQ", "RightLensSequence"], + "0015": ["SQ", "LeftLensSequence"], + "0016": ["SQ", "UnspecifiedLateralityLensSequence"], + "0018": ["SQ", "CylinderSequence"], + "0028": ["SQ", "PrismSequence"], + "0030": ["FD", "HorizontalPrismPower"], + "0032": ["CS", "HorizontalPrismBase"], + "0034": ["FD", "VerticalPrismPower"], + "0036": ["CS", "VerticalPrismBase"], + "0038": ["CS", "LensSegmentType"], + "0040": ["FD", "OpticalTransmittance"], + "0042": ["FD", "ChannelWidth"], + "0044": ["FD", "PupilSize"], + "0046": ["FD", "CornealSize"], + "0050": ["SQ", "AutorefractionRightEyeSequence"], + "0052": ["SQ", "AutorefractionLeftEyeSequence"], + "0060": ["FD", "DistancePupillaryDistance"], + "0062": ["FD", "NearPupillaryDistance"], + "0063": ["FD", "IntermediatePupillaryDistance"], + "0064": ["FD", "OtherPupillaryDistance"], + "0070": ["SQ", "KeratometryRightEyeSequence"], + "0071": ["SQ", "KeratometryLeftEyeSequence"], + "0074": ["SQ", "SteepKeratometricAxisSequence"], + "0075": ["FD", "RadiusOfCurvature"], + "0076": ["FD", "KeratometricPower"], + "0077": ["FD", "KeratometricAxis"], + "0080": ["SQ", "FlatKeratometricAxisSequence"], + "0092": ["CS", "BackgroundColor"], + "0094": ["CS", "Optotype"], + "0095": ["CS", "OptotypePresentation"], + "0097": ["SQ", "SubjectiveRefractionRightEyeSequence"], + "0098": ["SQ", "SubjectiveRefractionLeftEyeSequence"], + "0100": ["SQ", "AddNearSequence"], + "0101": ["SQ", "AddIntermediateSequence"], + "0102": ["SQ", "AddOtherSequence"], + "0104": ["FD", "AddPower"], + "0106": ["FD", "ViewingDistance"], + "0121": ["SQ", "VisualAcuityTypeCodeSequence"], + "0122": ["SQ", "VisualAcuityRightEyeSequence"], + "0123": ["SQ", "VisualAcuityLeftEyeSequence"], + "0124": ["SQ", "VisualAcuityBothEyesOpenSequence"], + "0125": ["CS", "ViewingDistanceType"], + "0135": ["SS", "VisualAcuityModifiers"], + "0137": ["FD", "DecimalVisualAcuity"], + "0139": ["LO", "OptotypeDetailedDefinition"], + "0145": ["SQ", "ReferencedRefractiveMeasurementsSequence"], + "0146": ["FD", "SpherePower"], + "0147": ["FD", "CylinderPower"] + }, + "0048": { + "0001": ["FL", "ImagedVolumeWidth"], + "0002": ["FL", "ImagedVolumeHeight"], + "0003": ["FL", "ImagedVolumeDepth"], + "0006": ["UL", "TotalPixelMatrixColumns"], + "0007": ["UL", "TotalPixelMatrixRows"], + "0008": ["SQ", "TotalPixelMatrixOriginSequence"], + "0010": ["CS", "SpecimenLabelInImage"], + "0011": ["CS", "FocusMethod"], + "0012": ["CS", "ExtendedDepthOfField"], + "0013": ["US", "NumberOfFocalPlanes"], + "0014": ["FL", "DistanceBetweenFocalPlanes"], + "0015": ["US", "RecommendedAbsentPixelCIELabValue"], + "0100": ["SQ", "IlluminatorTypeCodeSequence"], + "0102": ["DS", "ImageOrientationSlide"], + "0105": ["SQ", "OpticalPathSequence"], + "0106": ["SH", "OpticalPathIdentifier"], + "0107": ["ST", "OpticalPathDescription"], + "0108": ["SQ", "IlluminationColorCodeSequence"], + "0110": ["SQ", "SpecimenReferenceSequence"], + "0111": ["DS", "CondenserLensPower"], + "0112": ["DS", "ObjectiveLensPower"], + "0113": ["DS", "ObjectiveLensNumericalAperture"], + "0120": ["SQ", "PaletteColorLookupTableSequence"], + "0200": ["SQ", "ReferencedImageNavigationSequence"], + "0201": ["US", "TopLeftHandCornerOfLocalizerArea"], + "0202": ["US", "BottomRightHandCornerOfLocalizerArea"], + "0207": ["SQ", "OpticalPathIdentificationSequence"], + "021A": ["SQ", "PlanePositionSlideSequence"], + "021E": ["SL", "RowPositionInTotalImagePixelMatrix"], + "021F": ["SL", "ColumnPositionInTotalImagePixelMatrix"], + "0301": ["CS", "PixelOriginInterpretation"] + }, + "0050": { + "0004": ["CS", "CalibrationImage"], + "0010": ["SQ", "DeviceSequence"], + "0012": ["SQ", "ContainerComponentTypeCodeSequence"], + "0013": ["FD", "ContainerComponentThickness"], + "0014": ["DS", "DeviceLength"], + "0015": ["FD", "ContainerComponentWidth"], + "0016": ["DS", "DeviceDiameter"], + "0017": ["CS", "DeviceDiameterUnits"], + "0018": ["DS", "DeviceVolume"], + "0019": ["DS", "InterMarkerDistance"], + "001A": ["CS", "ContainerComponentMaterial"], + "001B": ["LO", "ContainerComponentID"], + "001C": ["FD", "ContainerComponentLength"], + "001D": ["FD", "ContainerComponentDiameter"], + "001E": ["LO", "ContainerComponentDescription"], + "0020": ["LO", "DeviceDescription"] + }, + "0052": { + "0001": ["FL", "ContrastBolusIngredientPercentByVolume"], + "0002": ["FD", "OCTFocalDistance"], + "0003": ["FD", "BeamSpotSize"], + "0004": ["FD", "EffectiveRefractiveIndex"], + "0006": ["CS", "OCTAcquisitionDomain"], + "0007": ["FD", "OCTOpticalCenterWavelength"], + "0008": ["FD", "AxialResolution"], + "0009": ["FD", "RangingDepth"], + "0011": ["FD", "ALineRate"], + "0012": ["US", "ALinesPerFrame"], + "0013": ["FD", "CatheterRotationalRate"], + "0014": ["FD", "ALinePixelSpacing"], + "0016": ["SQ", "ModeOfPercutaneousAccessSequence"], + "0025": ["SQ", "IntravascularOCTFrameTypeSequence"], + "0026": ["CS", "OCTZOffsetApplied"], + "0027": ["SQ", "IntravascularFrameContentSequence"], + "0028": ["FD", "IntravascularLongitudinalDistance"], + "0029": ["SQ", "IntravascularOCTFrameContentSequence"], + "0030": ["SS", "OCTZOffsetCorrection"], + "0031": ["CS", "CatheterDirectionOfRotation"], + "0033": ["FD", "SeamLineLocation"], + "0034": ["FD", "FirstALineLocation"], + "0036": ["US", "SeamLineIndex"], + "0038": ["US", "NumberOfPaddedAlines"], + "0039": ["CS", "InterpolationType"], + "003A": ["CS", "RefractiveIndexApplied"] + }, + "0054": { + "0010": ["US", "EnergyWindowVector"], + "0011": ["US", "NumberOfEnergyWindows"], + "0012": ["SQ", "EnergyWindowInformationSequence"], + "0013": ["SQ", "EnergyWindowRangeSequence"], + "0014": ["DS", "EnergyWindowLowerLimit"], + "0015": ["DS", "EnergyWindowUpperLimit"], + "0016": ["SQ", "RadiopharmaceuticalInformationSequence"], + "0017": ["IS", "ResidualSyringeCounts"], + "0018": ["SH", "EnergyWindowName"], + "0020": ["US", "DetectorVector"], + "0021": ["US", "NumberOfDetectors"], + "0022": ["SQ", "DetectorInformationSequence"], + "0030": ["US", "PhaseVector"], + "0031": ["US", "NumberOfPhases"], + "0032": ["SQ", "PhaseInformationSequence"], + "0033": ["US", "NumberOfFramesInPhase"], + "0036": ["IS", "PhaseDelay"], + "0038": ["IS", "PauseBetweenFrames"], + "0039": ["CS", "PhaseDescription"], + "0050": ["US", "RotationVector"], + "0051": ["US", "NumberOfRotations"], + "0052": ["SQ", "RotationInformationSequence"], + "0053": ["US", "NumberOfFramesInRotation"], + "0060": ["US", "RRIntervalVector"], + "0061": ["US", "NumberOfRRIntervals"], + "0062": ["SQ", "GatedInformationSequence"], + "0063": ["SQ", "DataInformationSequence"], + "0070": ["US", "TimeSlotVector"], + "0071": ["US", "NumberOfTimeSlots"], + "0072": ["SQ", "TimeSlotInformationSequence"], + "0073": ["DS", "TimeSlotTime"], + "0080": ["US", "SliceVector"], + "0081": ["US", "NumberOfSlices"], + "0090": ["US", "AngularViewVector"], + "0100": ["US", "TimeSliceVector"], + "0101": ["US", "NumberOfTimeSlices"], + "0200": ["DS", "StartAngle"], + "0202": ["CS", "TypeOfDetectorMotion"], + "0210": ["IS", "TriggerVector"], + "0211": ["US", "NumberOfTriggersInPhase"], + "0220": ["SQ", "ViewCodeSequence"], + "0222": ["SQ", "ViewModifierCodeSequence"], + "0300": ["SQ", "RadionuclideCodeSequence"], + "0302": ["SQ", "AdministrationRouteCodeSequence"], + "0304": ["SQ", "RadiopharmaceuticalCodeSequence"], + "0306": ["SQ", "CalibrationDataSequence"], + "0308": ["US", "EnergyWindowNumber"], + "0400": ["SH", "ImageID"], + "0410": ["SQ", "PatientOrientationCodeSequence"], + "0412": ["SQ", "PatientOrientationModifierCodeSequence"], + "0414": ["SQ", "PatientGantryRelationshipCodeSequence"], + "0500": ["CS", "SliceProgressionDirection"], + "1000": ["CS", "SeriesType"], + "1001": ["CS", "Units"], + "1002": ["CS", "CountsSource"], + "1004": ["CS", "ReprojectionMethod"], + "1006": ["CS", "SUVType"], + "1100": ["CS", "RandomsCorrectionMethod"], + "1101": ["LO", "AttenuationCorrectionMethod"], + "1102": ["CS", "DecayCorrection"], + "1103": ["LO", "ReconstructionMethod"], + "1104": ["LO", "DetectorLinesOfResponseUsed"], + "1105": ["LO", "ScatterCorrectionMethod"], + "1200": ["DS", "AxialAcceptance"], + "1201": ["IS", "AxialMash"], + "1202": ["IS", "TransverseMash"], + "1203": ["DS", "DetectorElementSize"], + "1210": ["DS", "CoincidenceWindowWidth"], + "1220": ["CS", "SecondaryCountsType"], + "1300": ["DS", "FrameReferenceTime"], + "1310": ["IS", "PrimaryPromptsCountsAccumulated"], + "1311": ["IS", "SecondaryCountsAccumulated"], + "1320": ["DS", "SliceSensitivityFactor"], + "1321": ["DS", "DecayFactor"], + "1322": ["DS", "DoseCalibrationFactor"], + "1323": ["DS", "ScatterFractionFactor"], + "1324": ["DS", "DeadTimeFactor"], + "1330": ["US", "ImageIndex"], + "1400": ["CS", "CountsIncluded"], + "1401": ["CS", "DeadTimeCorrectionFlag"] + }, + "0060": { + "3000": ["SQ", "HistogramSequence"], + "3002": ["US", "HistogramNumberOfBins"], + "3004": ["SS", "HistogramFirstBinValue"], + "3006": ["SS", "HistogramLastBinValue"], + "3008": ["US", "HistogramBinWidth"], + "3010": ["LO", "HistogramExplanation"], + "3020": ["UL", "HistogramData"] + }, + "0062": { + "0001": ["CS", "SegmentationType"], + "0002": ["SQ", "SegmentSequence"], + "0003": ["SQ", "SegmentedPropertyCategoryCodeSequence"], + "0004": ["US", "SegmentNumber"], + "0005": ["LO", "SegmentLabel"], + "0006": ["ST", "SegmentDescription"], + "0008": ["CS", "SegmentAlgorithmType"], + "0009": ["LO", "SegmentAlgorithmName"], + "000A": ["SQ", "SegmentIdentificationSequence"], + "000B": ["US", "ReferencedSegmentNumber"], + "000C": ["US", "RecommendedDisplayGrayscaleValue"], + "000D": ["US", "RecommendedDisplayCIELabValue"], + "000E": ["US", "MaximumFractionalValue"], + "000F": ["SQ", "SegmentedPropertyTypeCodeSequence"], + "0010": ["CS", "SegmentationFractionalType"] + }, + "0064": { + "0002": ["SQ", "DeformableRegistrationSequence"], + "0003": ["UI", "SourceFrameOfReferenceUID"], + "0005": ["SQ", "DeformableRegistrationGridSequence"], + "0007": ["UL", "GridDimensions"], + "0008": ["FD", "GridResolution"], + "0009": ["OF", "VectorGridData"], + "000F": ["SQ", "PreDeformationMatrixRegistrationSequence"], + "0010": ["SQ", "PostDeformationMatrixRegistrationSequence"] + }, + "0066": { + "0001": ["UL", "NumberOfSurfaces"], + "0002": ["SQ", "SurfaceSequence"], + "0003": ["UL", "SurfaceNumber"], + "0004": ["LT", "SurfaceComments"], + "0009": ["CS", "SurfaceProcessing"], + "000A": ["FL", "SurfaceProcessingRatio"], + "000B": ["LO", "SurfaceProcessingDescription"], + "000C": ["FL", "RecommendedPresentationOpacity"], + "000D": ["CS", "RecommendedPresentationType"], + "000E": ["CS", "FiniteVolume"], + "0010": ["CS", "Manifold"], + "0011": ["SQ", "SurfacePointsSequence"], + "0012": ["SQ", "SurfacePointsNormalsSequence"], + "0013": ["SQ", "SurfaceMeshPrimitivesSequence"], + "0015": ["UL", "NumberOfSurfacePoints"], + "0016": ["OF", "PointCoordinatesData"], + "0017": ["FL", "PointPositionAccuracy"], + "0018": ["FL", "MeanPointDistance"], + "0019": ["FL", "MaximumPointDistance"], + "001A": ["FL", "PointsBoundingBoxCoordinates"], + "001B": ["FL", "AxisOfRotation"], + "001C": ["FL", "CenterOfRotation"], + "001E": ["UL", "NumberOfVectors"], + "001F": ["US", "VectorDimensionality"], + "0020": ["FL", "VectorAccuracy"], + "0021": ["OF", "VectorCoordinateData"], + "0023": ["OW", "TrianglePointIndexList"], + "0024": ["OW", "EdgePointIndexList"], + "0025": ["OW", "VertexPointIndexList"], + "0026": ["SQ", "TriangleStripSequence"], + "0027": ["SQ", "TriangleFanSequence"], + "0028": ["SQ", "LineSequence"], + "0029": ["OW", "PrimitivePointIndexList"], + "002A": ["UL", "SurfaceCount"], + "002B": ["SQ", "ReferencedSurfaceSequence"], + "002C": ["UL", "ReferencedSurfaceNumber"], + "002D": ["SQ", "SegmentSurfaceGenerationAlgorithmIdentificationSequence"], + "002E": ["SQ", "SegmentSurfaceSourceInstanceSequence"], + "002F": ["SQ", "AlgorithmFamilyCodeSequence"], + "0030": ["SQ", "AlgorithmNameCodeSequence"], + "0031": ["LO", "AlgorithmVersion"], + "0032": ["LT", "AlgorithmParameters"], + "0034": ["SQ", "FacetSequence"], + "0035": ["SQ", "SurfaceProcessingAlgorithmIdentificationSequence"], + "0036": ["LO", "AlgorithmName"] + }, + "0068": { + "6210": ["LO", "ImplantSize"], + "6221": ["LO", "ImplantTemplateVersion"], + "6222": ["SQ", "ReplacedImplantTemplateSequence"], + "6223": ["CS", "ImplantType"], + "6224": ["SQ", "DerivationImplantTemplateSequence"], + "6225": ["SQ", "OriginalImplantTemplateSequence"], + "6226": ["DT", "EffectiveDateTime"], + "6230": ["SQ", "ImplantTargetAnatomySequence"], + "6260": ["SQ", "InformationFromManufacturerSequence"], + "6265": ["SQ", "NotificationFromManufacturerSequence"], + "6270": ["DT", "InformationIssueDateTime"], + "6280": ["ST", "InformationSummary"], + "62A0": ["SQ", "ImplantRegulatoryDisapprovalCodeSequence"], + "62A5": ["FD", "OverallTemplateSpatialTolerance"], + "62C0": ["SQ", "HPGLDocumentSequence"], + "62D0": ["US", "HPGLDocumentID"], + "62D5": ["LO", "HPGLDocumentLabel"], + "62E0": ["SQ", "ViewOrientationCodeSequence"], + "62F0": ["FD", "ViewOrientationModifier"], + "62F2": ["FD", "HPGLDocumentScaling"], + "6300": ["OB", "HPGLDocument"], + "6310": ["US", "HPGLContourPenNumber"], + "6320": ["SQ", "HPGLPenSequence"], + "6330": ["US", "HPGLPenNumber"], + "6340": ["LO", "HPGLPenLabel"], + "6345": ["ST", "HPGLPenDescription"], + "6346": ["FD", "RecommendedRotationPoint"], + "6347": ["FD", "BoundingRectangle"], + "6350": ["US", "ImplantTemplate3DModelSurfaceNumber"], + "6360": ["SQ", "SurfaceModelDescriptionSequence"], + "6380": ["LO", "SurfaceModelLabel"], + "6390": ["FD", "SurfaceModelScalingFactor"], + "63A0": ["SQ", "MaterialsCodeSequence"], + "63A4": ["SQ", "CoatingMaterialsCodeSequence"], + "63A8": ["SQ", "ImplantTypeCodeSequence"], + "63AC": ["SQ", "FixationMethodCodeSequence"], + "63B0": ["SQ", "MatingFeatureSetsSequence"], + "63C0": ["US", "MatingFeatureSetID"], + "63D0": ["LO", "MatingFeatureSetLabel"], + "63E0": ["SQ", "MatingFeatureSequence"], + "63F0": ["US", "MatingFeatureID"], + "6400": ["SQ", "MatingFeatureDegreeOfFreedomSequence"], + "6410": ["US", "DegreeOfFreedomID"], + "6420": ["CS", "DegreeOfFreedomType"], + "6430": ["SQ", "TwoDMatingFeatureCoordinatesSequence"], + "6440": ["US", "ReferencedHPGLDocumentID"], + "6450": ["FD", "TwoDMatingPoint"], + "6460": ["FD", "TwoDMatingAxes"], + "6470": ["SQ", "TwoDDegreeOfFreedomSequence"], + "6490": ["FD", "ThreeDDegreeOfFreedomAxis"], + "64A0": ["FD", "RangeOfFreedom"], + "64C0": ["FD", "ThreeDMatingPoint"], + "64D0": ["FD", "ThreeDMatingAxes"], + "64F0": ["FD", "TwoDDegreeOfFreedomAxis"], + "6500": ["SQ", "PlanningLandmarkPointSequence"], + "6510": ["SQ", "PlanningLandmarkLineSequence"], + "6520": ["SQ", "PlanningLandmarkPlaneSequence"], + "6530": ["US", "PlanningLandmarkID"], + "6540": ["LO", "PlanningLandmarkDescription"], + "6545": ["SQ", "PlanningLandmarkIdentificationCodeSequence"], + "6550": ["SQ", "TwoDPointCoordinatesSequence"], + "6560": ["FD", "TwoDPointCoordinates"], + "6590": ["FD", "ThreeDPointCoordinates"], + "65A0": ["SQ", "TwoDLineCoordinatesSequence"], + "65B0": ["FD", "TwoDLineCoordinates"], + "65D0": ["FD", "ThreeDLineCoordinates"], + "65E0": ["SQ", "TwoDPlaneCoordinatesSequence"], + "65F0": ["FD", "TwoDPlaneIntersection"], + "6610": ["FD", "ThreeDPlaneOrigin"], + "6620": ["FD", "ThreeDPlaneNormal"] + }, + "0070": { + "0001": ["SQ", "GraphicAnnotationSequence"], + "0002": ["CS", "GraphicLayer"], + "0003": ["CS", "BoundingBoxAnnotationUnits"], + "0004": ["CS", "AnchorPointAnnotationUnits"], + "0005": ["CS", "GraphicAnnotationUnits"], + "0006": ["ST", "UnformattedTextValue"], + "0008": ["SQ", "TextObjectSequence"], + "0009": ["SQ", "GraphicObjectSequence"], + "0010": ["FL", "BoundingBoxTopLeftHandCorner"], + "0011": ["FL", "BoundingBoxBottomRightHandCorner"], + "0012": ["CS", "BoundingBoxTextHorizontalJustification"], + "0014": ["FL", "AnchorPoint"], + "0015": ["CS", "AnchorPointVisibility"], + "0020": ["US", "GraphicDimensions"], + "0021": ["US", "NumberOfGraphicPoints"], + "0022": ["FL", "GraphicData"], + "0023": ["CS", "GraphicType"], + "0024": ["CS", "GraphicFilled"], + "0040": ["IS", "ImageRotationRetired"], + "0041": ["CS", "ImageHorizontalFlip"], + "0042": ["US", "ImageRotation"], + "0050": ["US", "DisplayedAreaTopLeftHandCornerTrial"], + "0051": ["US", "DisplayedAreaBottomRightHandCornerTrial"], + "0052": ["SL", "DisplayedAreaTopLeftHandCorner"], + "0053": ["SL", "DisplayedAreaBottomRightHandCorner"], + "005A": ["SQ", "DisplayedAreaSelectionSequence"], + "0060": ["SQ", "GraphicLayerSequence"], + "0062": ["IS", "GraphicLayerOrder"], + "0066": ["US", "GraphicLayerRecommendedDisplayGrayscaleValue"], + "0067": ["US", "GraphicLayerRecommendedDisplayRGBValue"], + "0068": ["LO", "GraphicLayerDescription"], + "0080": ["CS", "ContentLabel"], + "0081": ["LO", "ContentDescription"], + "0082": ["DA", "PresentationCreationDate"], + "0083": ["TM", "PresentationCreationTime"], + "0084": ["PN", "ContentCreatorName"], + "0086": ["SQ", "ContentCreatorIdentificationCodeSequence"], + "0087": ["SQ", "AlternateContentDescriptionSequence"], + "0100": ["CS", "PresentationSizeMode"], + "0101": ["DS", "PresentationPixelSpacing"], + "0102": ["IS", "PresentationPixelAspectRatio"], + "0103": ["FL", "PresentationPixelMagnificationRatio"], + "0207": ["LO", "GraphicGroupLabel"], + "0208": ["ST", "GraphicGroupDescription"], + "0209": ["SQ", "CompoundGraphicSequence"], + "0226": ["UL", "CompoundGraphicInstanceID"], + "0227": ["LO", "FontName"], + "0228": ["CS", "FontNameType"], + "0229": ["LO", "CSSFontName"], + "0230": ["FD", "RotationAngle"], + "0231": ["SQ", "TextStyleSequence"], + "0232": ["SQ", "LineStyleSequence"], + "0233": ["SQ", "FillStyleSequence"], + "0234": ["SQ", "GraphicGroupSequence"], + "0241": ["US", "TextColorCIELabValue"], + "0242": ["CS", "HorizontalAlignment"], + "0243": ["CS", "VerticalAlignment"], + "0244": ["CS", "ShadowStyle"], + "0245": ["FL", "ShadowOffsetX"], + "0246": ["FL", "ShadowOffsetY"], + "0247": ["US", "ShadowColorCIELabValue"], + "0248": ["CS", "Underlined"], + "0249": ["CS", "Bold"], + "0250": ["CS", "Italic"], + "0251": ["US", "PatternOnColorCIELabValue"], + "0252": ["US", "PatternOffColorCIELabValue"], + "0253": ["FL", "LineThickness"], + "0254": ["CS", "LineDashingStyle"], + "0255": ["UL", "LinePattern"], + "0256": ["OB", "FillPattern"], + "0257": ["CS", "FillMode"], + "0258": ["FL", "ShadowOpacity"], + "0261": ["FL", "GapLength"], + "0262": ["FL", "DiameterOfVisibility"], + "0273": ["FL", "RotationPoint"], + "0274": ["CS", "TickAlignment"], + "0278": ["CS", "ShowTickLabel"], + "0279": ["CS", "TickLabelAlignment"], + "0282": ["CS", "CompoundGraphicUnits"], + "0284": ["FL", "PatternOnOpacity"], + "0285": ["FL", "PatternOffOpacity"], + "0287": ["SQ", "MajorTicksSequence"], + "0288": ["FL", "TickPosition"], + "0289": ["SH", "TickLabel"], + "0294": ["CS", "CompoundGraphicType"], + "0295": ["UL", "GraphicGroupID"], + "0306": ["CS", "ShapeType"], + "0308": ["SQ", "RegistrationSequence"], + "0309": ["SQ", "MatrixRegistrationSequence"], + "030A": ["SQ", "MatrixSequence"], + "030C": ["CS", "FrameOfReferenceTransformationMatrixType"], + "030D": ["SQ", "RegistrationTypeCodeSequence"], + "030F": ["ST", "FiducialDescription"], + "0310": ["SH", "FiducialIdentifier"], + "0311": ["SQ", "FiducialIdentifierCodeSequence"], + "0312": ["FD", "ContourUncertaintyRadius"], + "0314": ["SQ", "UsedFiducialsSequence"], + "0318": ["SQ", "GraphicCoordinatesDataSequence"], + "031A": ["UI", "FiducialUID"], + "031C": ["SQ", "FiducialSetSequence"], + "031E": ["SQ", "FiducialSequence"], + "0401": ["US", "GraphicLayerRecommendedDisplayCIELabValue"], + "0402": ["SQ", "BlendingSequence"], + "0403": ["FL", "RelativeOpacity"], + "0404": ["SQ", "ReferencedSpatialRegistrationSequence"], + "0405": ["CS", "BlendingPosition"] + }, + "0072": { + "0002": ["SH", "HangingProtocolName"], + "0004": ["LO", "HangingProtocolDescription"], + "0006": ["CS", "HangingProtocolLevel"], + "0008": ["LO", "HangingProtocolCreator"], + "000A": ["DT", "HangingProtocolCreationDateTime"], + "000C": ["SQ", "HangingProtocolDefinitionSequence"], + "000E": ["SQ", "HangingProtocolUserIdentificationCodeSequence"], + "0010": ["LO", "HangingProtocolUserGroupName"], + "0012": ["SQ", "SourceHangingProtocolSequence"], + "0014": ["US", "NumberOfPriorsReferenced"], + "0020": ["SQ", "ImageSetsSequence"], + "0022": ["SQ", "ImageSetSelectorSequence"], + "0024": ["CS", "ImageSetSelectorUsageFlag"], + "0026": ["AT", "SelectorAttribute"], + "0028": ["US", "SelectorValueNumber"], + "0030": ["SQ", "TimeBasedImageSetsSequence"], + "0032": ["US", "ImageSetNumber"], + "0034": ["CS", "ImageSetSelectorCategory"], + "0038": ["US", "RelativeTime"], + "003A": ["CS", "RelativeTimeUnits"], + "003C": ["SS", "AbstractPriorValue"], + "003E": ["SQ", "AbstractPriorCodeSequence"], + "0040": ["LO", "ImageSetLabel"], + "0050": ["CS", "SelectorAttributeVR"], + "0052": ["AT", "SelectorSequencePointer"], + "0054": ["LO", "SelectorSequencePointerPrivateCreator"], + "0056": ["LO", "SelectorAttributePrivateCreator"], + "0060": ["AT", "SelectorATValue"], + "0062": ["CS", "SelectorCSValue"], + "0064": ["IS", "SelectorISValue"], + "0066": ["LO", "SelectorLOValue"], + "0068": ["LT", "SelectorLTValue"], + "006A": ["PN", "SelectorPNValue"], + "006C": ["SH", "SelectorSHValue"], + "006E": ["ST", "SelectorSTValue"], + "0070": ["UT", "SelectorUTValue"], + "0072": ["DS", "SelectorDSValue"], + "0074": ["FD", "SelectorFDValue"], + "0076": ["FL", "SelectorFLValue"], + "0078": ["UL", "SelectorULValue"], + "007A": ["US", "SelectorUSValue"], + "007C": ["SL", "SelectorSLValue"], + "007E": ["SS", "SelectorSSValue"], + "0080": ["SQ", "SelectorCodeSequenceValue"], + "0100": ["US", "NumberOfScreens"], + "0102": ["SQ", "NominalScreenDefinitionSequence"], + "0104": ["US", "NumberOfVerticalPixels"], + "0106": ["US", "NumberOfHorizontalPixels"], + "0108": ["FD", "DisplayEnvironmentSpatialPosition"], + "010A": ["US", "ScreenMinimumGrayscaleBitDepth"], + "010C": ["US", "ScreenMinimumColorBitDepth"], + "010E": ["US", "ApplicationMaximumRepaintTime"], + "0200": ["SQ", "DisplaySetsSequence"], + "0202": ["US", "DisplaySetNumber"], + "0203": ["LO", "DisplaySetLabel"], + "0204": ["US", "DisplaySetPresentationGroup"], + "0206": ["LO", "DisplaySetPresentationGroupDescription"], + "0208": ["CS", "PartialDataDisplayHandling"], + "0210": ["SQ", "SynchronizedScrollingSequence"], + "0212": ["US", "DisplaySetScrollingGroup"], + "0214": ["SQ", "NavigationIndicatorSequence"], + "0216": ["US", "NavigationDisplaySet"], + "0218": ["US", "ReferenceDisplaySets"], + "0300": ["SQ", "ImageBoxesSequence"], + "0302": ["US", "ImageBoxNumber"], + "0304": ["CS", "ImageBoxLayoutType"], + "0306": ["US", "ImageBoxTileHorizontalDimension"], + "0308": ["US", "ImageBoxTileVerticalDimension"], + "0310": ["CS", "ImageBoxScrollDirection"], + "0312": ["CS", "ImageBoxSmallScrollType"], + "0314": ["US", "ImageBoxSmallScrollAmount"], + "0316": ["CS", "ImageBoxLargeScrollType"], + "0318": ["US", "ImageBoxLargeScrollAmount"], + "0320": ["US", "ImageBoxOverlapPriority"], + "0330": ["FD", "CineRelativeToRealTime"], + "0400": ["SQ", "FilterOperationsSequence"], + "0402": ["CS", "FilterByCategory"], + "0404": ["CS", "FilterByAttributePresence"], + "0406": ["CS", "FilterByOperator"], + "0420": ["US", "StructuredDisplayBackgroundCIELabValue"], + "0421": ["US", "EmptyImageBoxCIELabValue"], + "0422": ["SQ", "StructuredDisplayImageBoxSequence"], + "0424": ["SQ", "StructuredDisplayTextBoxSequence"], + "0427": ["SQ", "ReferencedFirstFrameSequence"], + "0430": ["SQ", "ImageBoxSynchronizationSequence"], + "0432": ["US", "SynchronizedImageBoxList"], + "0434": ["CS", "TypeOfSynchronization"], + "0500": ["CS", "BlendingOperationType"], + "0510": ["CS", "ReformattingOperationType"], + "0512": ["FD", "ReformattingThickness"], + "0514": ["FD", "ReformattingInterval"], + "0516": ["CS", "ReformattingOperationInitialViewDirection"], + "0520": ["CS", "ThreeDRenderingType"], + "0600": ["SQ", "SortingOperationsSequence"], + "0602": ["CS", "SortByCategory"], + "0604": ["CS", "SortingDirection"], + "0700": ["CS", "DisplaySetPatientOrientation"], + "0702": ["CS", "VOIType"], + "0704": ["CS", "PseudoColorType"], + "0705": ["SQ", "PseudoColorPaletteInstanceReferenceSequence"], + "0706": ["CS", "ShowGrayscaleInverted"], + "0710": ["CS", "ShowImageTrueSizeFlag"], + "0712": ["CS", "ShowGraphicAnnotationFlag"], + "0714": ["CS", "ShowPatientDemographicsFlag"], + "0716": ["CS", "ShowAcquisitionTechniquesFlag"], + "0717": ["CS", "DisplaySetHorizontalJustification"], + "0718": ["CS", "DisplaySetVerticalJustification"] + }, + "0074": { + "0120": ["FD", "ContinuationStartMeterset"], + "0121": ["FD", "ContinuationEndMeterset"], + "1000": ["CS", "ProcedureStepState"], + "1002": ["SQ", "ProcedureStepProgressInformationSequence"], + "1004": ["DS", "ProcedureStepProgress"], + "1006": ["ST", "ProcedureStepProgressDescription"], + "1008": ["SQ", "ProcedureStepCommunicationsURISequence"], + "100A": ["ST", "ContactURI"], + "100C": ["LO", "ContactDisplayName"], + "100E": ["SQ", "ProcedureStepDiscontinuationReasonCodeSequence"], + "1020": ["SQ", "BeamTaskSequence"], + "1022": ["CS", "BeamTaskType"], + "1024": ["IS", "BeamOrderIndexTrial"], + "1026": ["FD", "TableTopVerticalAdjustedPosition"], + "1027": ["FD", "TableTopLongitudinalAdjustedPosition"], + "1028": ["FD", "TableTopLateralAdjustedPosition"], + "102A": ["FD", "PatientSupportAdjustedAngle"], + "102B": ["FD", "TableTopEccentricAdjustedAngle"], + "102C": ["FD", "TableTopPitchAdjustedAngle"], + "102D": ["FD", "TableTopRollAdjustedAngle"], + "1030": ["SQ", "DeliveryVerificationImageSequence"], + "1032": ["CS", "VerificationImageTiming"], + "1034": ["CS", "DoubleExposureFlag"], + "1036": ["CS", "DoubleExposureOrdering"], + "1038": ["DS", "DoubleExposureMetersetTrial"], + "103A": ["DS", "DoubleExposureFieldDeltaTrial"], + "1040": ["SQ", "RelatedReferenceRTImageSequence"], + "1042": ["SQ", "GeneralMachineVerificationSequence"], + "1044": ["SQ", "ConventionalMachineVerificationSequence"], + "1046": ["SQ", "IonMachineVerificationSequence"], + "1048": ["SQ", "FailedAttributesSequence"], + "104A": ["SQ", "OverriddenAttributesSequence"], + "104C": ["SQ", "ConventionalControlPointVerificationSequence"], + "104E": ["SQ", "IonControlPointVerificationSequence"], + "1050": ["SQ", "AttributeOccurrenceSequence"], + "1052": ["AT", "AttributeOccurrencePointer"], + "1054": ["UL", "AttributeItemSelector"], + "1056": ["LO", "AttributeOccurrencePrivateCreator"], + "1057": ["IS", "SelectorSequencePointerItems"], + "1200": ["CS", "ScheduledProcedureStepPriority"], + "1202": ["LO", "WorklistLabel"], + "1204": ["LO", "ProcedureStepLabel"], + "1210": ["SQ", "ScheduledProcessingParametersSequence"], + "1212": ["SQ", "PerformedProcessingParametersSequence"], + "1216": ["SQ", "UnifiedProcedureStepPerformedProcedureSequence"], + "1220": ["SQ", "RelatedProcedureStepSequence"], + "1222": ["LO", "ProcedureStepRelationshipType"], + "1224": ["SQ", "ReplacedProcedureStepSequence"], + "1230": ["LO", "DeletionLock"], + "1234": ["AE", "ReceivingAE"], + "1236": ["AE", "RequestingAE"], + "1238": ["LT", "ReasonForCancellation"], + "1242": ["CS", "SCPStatus"], + "1244": ["CS", "SubscriptionListStatus"], + "1246": ["CS", "UnifiedProcedureStepListStatus"], + "1324": ["UL", "BeamOrderIndex"], + "1338": ["FD", "DoubleExposureMeterset"], + "133A": ["FD", "DoubleExposureFieldDelta"] + }, + "0076": { + "0001": ["LO", "ImplantAssemblyTemplateName"], + "0003": ["LO", "ImplantAssemblyTemplateIssuer"], + "0006": ["LO", "ImplantAssemblyTemplateVersion"], + "0008": ["SQ", "ReplacedImplantAssemblyTemplateSequence"], + "000A": ["CS", "ImplantAssemblyTemplateType"], + "000C": ["SQ", "OriginalImplantAssemblyTemplateSequence"], + "000E": ["SQ", "DerivationImplantAssemblyTemplateSequence"], + "0010": ["SQ", "ImplantAssemblyTemplateTargetAnatomySequence"], + "0020": ["SQ", "ProcedureTypeCodeSequence"], + "0030": ["LO", "SurgicalTechnique"], + "0032": ["SQ", "ComponentTypesSequence"], + "0034": ["CS", "ComponentTypeCodeSequence"], + "0036": ["CS", "ExclusiveComponentType"], + "0038": ["CS", "MandatoryComponentType"], + "0040": ["SQ", "ComponentSequence"], + "0055": ["US", "ComponentID"], + "0060": ["SQ", "ComponentAssemblySequence"], + "0070": ["US", "Component1ReferencedID"], + "0080": ["US", "Component1ReferencedMatingFeatureSetID"], + "0090": ["US", "Component1ReferencedMatingFeatureID"], + "00A0": ["US", "Component2ReferencedID"], + "00B0": ["US", "Component2ReferencedMatingFeatureSetID"], + "00C0": ["US", "Component2ReferencedMatingFeatureID"] + }, + "0078": { + "0001": ["LO", "ImplantTemplateGroupName"], + "0010": ["ST", "ImplantTemplateGroupDescription"], + "0020": ["LO", "ImplantTemplateGroupIssuer"], + "0024": ["LO", "ImplantTemplateGroupVersion"], + "0026": ["SQ", "ReplacedImplantTemplateGroupSequence"], + "0028": ["SQ", "ImplantTemplateGroupTargetAnatomySequence"], + "002A": ["SQ", "ImplantTemplateGroupMembersSequence"], + "002E": ["US", "ImplantTemplateGroupMemberID"], + "0050": ["FD", "ThreeDImplantTemplateGroupMemberMatchingPoint"], + "0060": ["FD", "ThreeDImplantTemplateGroupMemberMatchingAxes"], + "0070": ["SQ", "ImplantTemplateGroupMemberMatching2DCoordinatesSequence"], + "0090": ["FD", "TwoDImplantTemplateGroupMemberMatchingPoint"], + "00A0": ["FD", "TwoDImplantTemplateGroupMemberMatchingAxes"], + "00B0": ["SQ", "ImplantTemplateGroupVariationDimensionSequence"], + "00B2": ["LO", "ImplantTemplateGroupVariationDimensionName"], + "00B4": ["SQ", "ImplantTemplateGroupVariationDimensionRankSequence"], + "00B6": ["US", "ReferencedImplantTemplateGroupMemberID"], + "00B8": ["US", "ImplantTemplateGroupVariationDimensionRank"] + }, + "0088": { + "0130": ["SH", "StorageMediaFileSetID"], + "0140": ["UI", "StorageMediaFileSetUID"], + "0200": ["SQ", "IconImageSequence"], + "0904": ["LO", "TopicTitle"], + "0906": ["ST", "TopicSubject"], + "0910": ["LO", "TopicAuthor"], + "0912": ["LO", "TopicKeywords"] + }, + "0100": { + "0410": ["CS", "SOPInstanceStatus"], + "0420": ["DT", "SOPAuthorizationDateTime"], + "0424": ["LT", "SOPAuthorizationComment"], + "0426": ["LO", "AuthorizationEquipmentCertificationNumber"] + }, + "0400": { + "0005": ["US", "MACIDNumber"], + "0010": ["UI", "MACCalculationTransferSyntaxUID"], + "0015": ["CS", "MACAlgorithm"], + "0020": ["AT", "DataElementsSigned"], + "0100": ["UI", "DigitalSignatureUID"], + "0105": ["DT", "DigitalSignatureDateTime"], + "0110": ["CS", "CertificateType"], + "0115": ["OB", "CertificateOfSigner"], + "0120": ["OB", "Signature"], + "0305": ["CS", "CertifiedTimestampType"], + "0310": ["OB", "CertifiedTimestamp"], + "0401": ["SQ", "DigitalSignaturePurposeCodeSequence"], + "0402": ["SQ", "ReferencedDigitalSignatureSequence"], + "0403": ["SQ", "ReferencedSOPInstanceMACSequence"], + "0404": ["OB", "MAC"], + "0500": ["SQ", "EncryptedAttributesSequence"], + "0510": ["UI", "EncryptedContentTransferSyntaxUID"], + "0520": ["OB", "EncryptedContent"], + "0550": ["SQ", "ModifiedAttributesSequence"], + "0561": ["SQ", "OriginalAttributesSequence"], + "0562": ["DT", "AttributeModificationDateTime"], + "0563": ["LO", "ModifyingSystem"], + "0564": ["LO", "SourceOfPreviousValues"], + "0565": ["CS", "ReasonForTheAttributeModification"] + }, + "2000": { + "0010": ["IS", "NumberOfCopies"], + "001E": ["SQ", "PrinterConfigurationSequence"], + "0020": ["CS", "PrintPriority"], + "0030": ["CS", "MediumType"], + "0040": ["CS", "FilmDestination"], + "0050": ["LO", "FilmSessionLabel"], + "0060": ["IS", "MemoryAllocation"], + "0061": ["IS", "MaximumMemoryAllocation"], + "0062": ["CS", "ColorImagePrintingFlag"], + "0063": ["CS", "CollationFlag"], + "0065": ["CS", "AnnotationFlag"], + "0067": ["CS", "ImageOverlayFlag"], + "0069": ["CS", "PresentationLUTFlag"], + "006A": ["CS", "ImageBoxPresentationLUTFlag"], + "00A0": ["US", "MemoryBitDepth"], + "00A1": ["US", "PrintingBitDepth"], + "00A2": ["SQ", "MediaInstalledSequence"], + "00A4": ["SQ", "OtherMediaAvailableSequence"], + "00A8": ["SQ", "SupportedImageDisplayFormatsSequence"], + "0500": ["SQ", "ReferencedFilmBoxSequence"], + "0510": ["SQ", "ReferencedStoredPrintSequence"] + }, + "2010": { + "0010": ["ST", "ImageDisplayFormat"], + "0030": ["CS", "AnnotationDisplayFormatID"], + "0040": ["CS", "FilmOrientation"], + "0050": ["CS", "FilmSizeID"], + "0052": ["CS", "PrinterResolutionID"], + "0054": ["CS", "DefaultPrinterResolutionID"], + "0060": ["CS", "MagnificationType"], + "0080": ["CS", "SmoothingType"], + "00A6": ["CS", "DefaultMagnificationType"], + "00A7": ["CS", "OtherMagnificationTypesAvailable"], + "00A8": ["CS", "DefaultSmoothingType"], + "00A9": ["CS", "OtherSmoothingTypesAvailable"], + "0100": ["CS", "BorderDensity"], + "0110": ["CS", "EmptyImageDensity"], + "0120": ["US", "MinDensity"], + "0130": ["US", "MaxDensity"], + "0140": ["CS", "Trim"], + "0150": ["ST", "ConfigurationInformation"], + "0152": ["LT", "ConfigurationInformationDescription"], + "0154": ["IS", "MaximumCollatedFilms"], + "015E": ["US", "Illumination"], + "0160": ["US", "ReflectedAmbientLight"], + "0376": ["DS", "PrinterPixelSpacing"], + "0500": ["SQ", "ReferencedFilmSessionSequence"], + "0510": ["SQ", "ReferencedImageBoxSequence"], + "0520": ["SQ", "ReferencedBasicAnnotationBoxSequence"] + }, + "2020": { + "0010": ["US", "ImageBoxPosition"], + "0020": ["CS", "Polarity"], + "0030": ["DS", "RequestedImageSize"], + "0040": ["CS", "RequestedDecimateCropBehavior"], + "0050": ["CS", "RequestedResolutionID"], + "00A0": ["CS", "RequestedImageSizeFlag"], + "00A2": ["CS", "DecimateCropResult"], + "0110": ["SQ", "BasicGrayscaleImageSequence"], + "0111": ["SQ", "BasicColorImageSequence"], + "0130": ["SQ", "ReferencedImageOverlayBoxSequence"], + "0140": ["SQ", "ReferencedVOILUTBoxSequence"] + }, + "2030": { + "0010": ["US", "AnnotationPosition"], + "0020": ["LO", "TextString"] + }, + "2040": { + "0010": ["SQ", "ReferencedOverlayPlaneSequence"], + "0011": ["US", "ReferencedOverlayPlaneGroups"], + "0020": ["SQ", "OverlayPixelDataSequence"], + "0060": ["CS", "OverlayMagnificationType"], + "0070": ["CS", "OverlaySmoothingType"], + "0072": ["CS", "OverlayOrImageMagnification"], + "0074": ["US", "MagnifyToNumberOfColumns"], + "0080": ["CS", "OverlayForegroundDensity"], + "0082": ["CS", "OverlayBackgroundDensity"], + "0090": ["CS", "OverlayMode"], + "0100": ["CS", "ThresholdDensity"], + "0500": ["SQ", "ReferencedImageBoxSequenceRetired"] + }, + "2050": { + "0010": ["SQ", "PresentationLUTSequence"], + "0020": ["CS", "PresentationLUTShape"], + "0500": ["SQ", "ReferencedPresentationLUTSequence"] + }, + "2100": { + "0010": ["SH", "PrintJobID"], + "0020": ["CS", "ExecutionStatus"], + "0030": ["CS", "ExecutionStatusInfo"], + "0040": ["DA", "CreationDate"], + "0050": ["TM", "CreationTime"], + "0070": ["AE", "Originator"], + "0140": ["AE", "DestinationAE"], + "0160": ["SH", "OwnerID"], + "0170": ["IS", "NumberOfFilms"], + "0500": ["SQ", "ReferencedPrintJobSequencePullStoredPrint"] + }, + "2110": { + "0010": ["CS", "PrinterStatus"], + "0020": ["CS", "PrinterStatusInfo"], + "0030": ["LO", "PrinterName"], + "0099": ["SH", "PrintQueueID"] + }, + "2120": { + "0010": ["CS", "QueueStatus"], + "0050": ["SQ", "PrintJobDescriptionSequence"], + "0070": ["SQ", "ReferencedPrintJobSequence"] + }, + "2130": { + "0010": ["SQ", "PrintManagementCapabilitiesSequence"], + "0015": ["SQ", "PrinterCharacteristicsSequence"], + "0030": ["SQ", "FilmBoxContentSequence"], + "0040": ["SQ", "ImageBoxContentSequence"], + "0050": ["SQ", "AnnotationContentSequence"], + "0060": ["SQ", "ImageOverlayBoxContentSequence"], + "0080": ["SQ", "PresentationLUTContentSequence"], + "00A0": ["SQ", "ProposedStudySequence"], + "00C0": ["SQ", "OriginalImageSequence"] + }, + "2200": { + "0001": ["CS", "LabelUsingInformationExtractedFromInstances"], + "0002": ["UT", "LabelText"], + "0003": ["CS", "LabelStyleSelection"], + "0004": ["LT", "MediaDisposition"], + "0005": ["LT", "BarcodeValue"], + "0006": ["CS", "BarcodeSymbology"], + "0007": ["CS", "AllowMediaSplitting"], + "0008": ["CS", "IncludeNonDICOMObjects"], + "0009": ["CS", "IncludeDisplayApplication"], + "000A": ["CS", "PreserveCompositeInstancesAfterMediaCreation"], + "000B": ["US", "TotalNumberOfPiecesOfMediaCreated"], + "000C": ["LO", "RequestedMediaApplicationProfile"], + "000D": ["SQ", "ReferencedStorageMediaSequence"], + "000E": ["AT", "FailureAttributes"], + "000F": ["CS", "AllowLossyCompression"], + "0020": ["CS", "RequestPriority"] + }, + "3002": { + "0002": ["SH", "RTImageLabel"], + "0003": ["LO", "RTImageName"], + "0004": ["ST", "RTImageDescription"], + "000A": ["CS", "ReportedValuesOrigin"], + "000C": ["CS", "RTImagePlane"], + "000D": ["DS", "XRayImageReceptorTranslation"], + "000E": ["DS", "XRayImageReceptorAngle"], + "0010": ["DS", "RTImageOrientation"], + "0011": ["DS", "ImagePlanePixelSpacing"], + "0012": ["DS", "RTImagePosition"], + "0020": ["SH", "RadiationMachineName"], + "0022": ["DS", "RadiationMachineSAD"], + "0024": ["DS", "RadiationMachineSSD"], + "0026": ["DS", "RTImageSID"], + "0028": ["DS", "SourceToReferenceObjectDistance"], + "0029": ["IS", "FractionNumber"], + "0030": ["SQ", "ExposureSequence"], + "0032": ["DS", "MetersetExposure"], + "0034": ["DS", "DiaphragmPosition"], + "0040": ["SQ", "FluenceMapSequence"], + "0041": ["CS", "FluenceDataSource"], + "0042": ["DS", "FluenceDataScale"], + "0050": ["SQ", "PrimaryFluenceModeSequence"], + "0051": ["CS", "FluenceMode"], + "0052": ["SH", "FluenceModeID"] + }, + "3004": { + "0001": ["CS", "DVHType"], + "0002": ["CS", "DoseUnits"], + "0004": ["CS", "DoseType"], + "0006": ["LO", "DoseComment"], + "0008": ["DS", "NormalizationPoint"], + "000A": ["CS", "DoseSummationType"], + "000C": ["DS", "GridFrameOffsetVector"], + "000E": ["DS", "DoseGridScaling"], + "0010": ["SQ", "RTDoseROISequence"], + "0012": ["DS", "DoseValue"], + "0014": ["CS", "TissueHeterogeneityCorrection"], + "0040": ["DS", "DVHNormalizationPoint"], + "0042": ["DS", "DVHNormalizationDoseValue"], + "0050": ["SQ", "DVHSequence"], + "0052": ["DS", "DVHDoseScaling"], + "0054": ["CS", "DVHVolumeUnits"], + "0056": ["IS", "DVHNumberOfBins"], + "0058": ["DS", "DVHData"], + "0060": ["SQ", "DVHReferencedROISequence"], + "0062": ["CS", "DVHROIContributionType"], + "0070": ["DS", "DVHMinimumDose"], + "0072": ["DS", "DVHMaximumDose"], + "0074": ["DS", "DVHMeanDose"] + }, + "3006": { + "0002": ["SH", "StructureSetLabel"], + "0004": ["LO", "StructureSetName"], + "0006": ["ST", "StructureSetDescription"], + "0008": ["DA", "StructureSetDate"], + "0009": ["TM", "StructureSetTime"], + "0010": ["SQ", "ReferencedFrameOfReferenceSequence"], + "0012": ["SQ", "RTReferencedStudySequence"], + "0014": ["SQ", "RTReferencedSeriesSequence"], + "0016": ["SQ", "ContourImageSequence"], + "0020": ["SQ", "StructureSetROISequence"], + "0022": ["IS", "ROINumber"], + "0024": ["UI", "ReferencedFrameOfReferenceUID"], + "0026": ["LO", "ROIName"], + "0028": ["ST", "ROIDescription"], + "002A": ["IS", "ROIDisplayColor"], + "002C": ["DS", "ROIVolume"], + "0030": ["SQ", "RTRelatedROISequence"], + "0033": ["CS", "RTROIRelationship"], + "0036": ["CS", "ROIGenerationAlgorithm"], + "0038": ["LO", "ROIGenerationDescription"], + "0039": ["SQ", "ROIContourSequence"], + "0040": ["SQ", "ContourSequence"], + "0042": ["CS", "ContourGeometricType"], + "0044": ["DS", "ContourSlabThickness"], + "0045": ["DS", "ContourOffsetVector"], + "0046": ["IS", "NumberOfContourPoints"], + "0048": ["IS", "ContourNumber"], + "0049": ["IS", "AttachedContours"], + "0050": ["DS", "ContourData"], + "0080": ["SQ", "RTROIObservationsSequence"], + "0082": ["IS", "ObservationNumber"], + "0084": ["IS", "ReferencedROINumber"], + "0085": ["SH", "ROIObservationLabel"], + "0086": ["SQ", "RTROIIdentificationCodeSequence"], + "0088": ["ST", "ROIObservationDescription"], + "00A0": ["SQ", "RelatedRTROIObservationsSequence"], + "00A4": ["CS", "RTROIInterpretedType"], + "00A6": ["PN", "ROIInterpreter"], + "00B0": ["SQ", "ROIPhysicalPropertiesSequence"], + "00B2": ["CS", "ROIPhysicalProperty"], + "00B4": ["DS", "ROIPhysicalPropertyValue"], + "00B6": ["SQ", "ROIElementalCompositionSequence"], + "00B7": ["US", "ROIElementalCompositionAtomicNumber"], + "00B8": ["FL", "ROIElementalCompositionAtomicMassFraction"], + "00C0": ["SQ", "FrameOfReferenceRelationshipSequence"], + "00C2": ["UI", "RelatedFrameOfReferenceUID"], + "00C4": ["CS", "FrameOfReferenceTransformationType"], + "00C6": ["DS", "FrameOfReferenceTransformationMatrix"], + "00C8": ["LO", "FrameOfReferenceTransformationComment"] + }, + "3008": { + "0010": ["SQ", "MeasuredDoseReferenceSequence"], + "0012": ["ST", "MeasuredDoseDescription"], + "0014": ["CS", "MeasuredDoseType"], + "0016": ["DS", "MeasuredDoseValue"], + "0020": ["SQ", "TreatmentSessionBeamSequence"], + "0021": ["SQ", "TreatmentSessionIonBeamSequence"], + "0022": ["IS", "CurrentFractionNumber"], + "0024": ["DA", "TreatmentControlPointDate"], + "0025": ["TM", "TreatmentControlPointTime"], + "002A": ["CS", "TreatmentTerminationStatus"], + "002B": ["SH", "TreatmentTerminationCode"], + "002C": ["CS", "TreatmentVerificationStatus"], + "0030": ["SQ", "ReferencedTreatmentRecordSequence"], + "0032": ["DS", "SpecifiedPrimaryMeterset"], + "0033": ["DS", "SpecifiedSecondaryMeterset"], + "0036": ["DS", "DeliveredPrimaryMeterset"], + "0037": ["DS", "DeliveredSecondaryMeterset"], + "003A": ["DS", "SpecifiedTreatmentTime"], + "003B": ["DS", "DeliveredTreatmentTime"], + "0040": ["SQ", "ControlPointDeliverySequence"], + "0041": ["SQ", "IonControlPointDeliverySequence"], + "0042": ["DS", "SpecifiedMeterset"], + "0044": ["DS", "DeliveredMeterset"], + "0045": ["FL", "MetersetRateSet"], + "0046": ["FL", "MetersetRateDelivered"], + "0047": ["FL", "ScanSpotMetersetsDelivered"], + "0048": ["DS", "DoseRateDelivered"], + "0050": ["SQ", "TreatmentSummaryCalculatedDoseReferenceSequence"], + "0052": ["DS", "CumulativeDoseToDoseReference"], + "0054": ["DA", "FirstTreatmentDate"], + "0056": ["DA", "MostRecentTreatmentDate"], + "005A": ["IS", "NumberOfFractionsDelivered"], + "0060": ["SQ", "OverrideSequence"], + "0061": ["AT", "ParameterSequencePointer"], + "0062": ["AT", "OverrideParameterPointer"], + "0063": ["IS", "ParameterItemIndex"], + "0064": ["IS", "MeasuredDoseReferenceNumber"], + "0065": ["AT", "ParameterPointer"], + "0066": ["ST", "OverrideReason"], + "0068": ["SQ", "CorrectedParameterSequence"], + "006A": ["FL", "CorrectionValue"], + "0070": ["SQ", "CalculatedDoseReferenceSequence"], + "0072": ["IS", "CalculatedDoseReferenceNumber"], + "0074": ["ST", "CalculatedDoseReferenceDescription"], + "0076": ["DS", "CalculatedDoseReferenceDoseValue"], + "0078": ["DS", "StartMeterset"], + "007A": ["DS", "EndMeterset"], + "0080": ["SQ", "ReferencedMeasuredDoseReferenceSequence"], + "0082": ["IS", "ReferencedMeasuredDoseReferenceNumber"], + "0090": ["SQ", "ReferencedCalculatedDoseReferenceSequence"], + "0092": ["IS", "ReferencedCalculatedDoseReferenceNumber"], + "00A0": ["SQ", "BeamLimitingDeviceLeafPairsSequence"], + "00B0": ["SQ", "RecordedWedgeSequence"], + "00C0": ["SQ", "RecordedCompensatorSequence"], + "00D0": ["SQ", "RecordedBlockSequence"], + "00E0": ["SQ", "TreatmentSummaryMeasuredDoseReferenceSequence"], + "00F0": ["SQ", "RecordedSnoutSequence"], + "00F2": ["SQ", "RecordedRangeShifterSequence"], + "00F4": ["SQ", "RecordedLateralSpreadingDeviceSequence"], + "00F6": ["SQ", "RecordedRangeModulatorSequence"], + "0100": ["SQ", "RecordedSourceSequence"], + "0105": ["LO", "SourceSerialNumber"], + "0110": ["SQ", "TreatmentSessionApplicationSetupSequence"], + "0116": ["CS", "ApplicationSetupCheck"], + "0120": ["SQ", "RecordedBrachyAccessoryDeviceSequence"], + "0122": ["IS", "ReferencedBrachyAccessoryDeviceNumber"], + "0130": ["SQ", "RecordedChannelSequence"], + "0132": ["DS", "SpecifiedChannelTotalTime"], + "0134": ["DS", "DeliveredChannelTotalTime"], + "0136": ["IS", "SpecifiedNumberOfPulses"], + "0138": ["IS", "DeliveredNumberOfPulses"], + "013A": ["DS", "SpecifiedPulseRepetitionInterval"], + "013C": ["DS", "DeliveredPulseRepetitionInterval"], + "0140": ["SQ", "RecordedSourceApplicatorSequence"], + "0142": ["IS", "ReferencedSourceApplicatorNumber"], + "0150": ["SQ", "RecordedChannelShieldSequence"], + "0152": ["IS", "ReferencedChannelShieldNumber"], + "0160": ["SQ", "BrachyControlPointDeliveredSequence"], + "0162": ["DA", "SafePositionExitDate"], + "0164": ["TM", "SafePositionExitTime"], + "0166": ["DA", "SafePositionReturnDate"], + "0168": ["TM", "SafePositionReturnTime"], + "0200": ["CS", "CurrentTreatmentStatus"], + "0202": ["ST", "TreatmentStatusComment"], + "0220": ["SQ", "FractionGroupSummarySequence"], + "0223": ["IS", "ReferencedFractionNumber"], + "0224": ["CS", "FractionGroupType"], + "0230": ["CS", "BeamStopperPosition"], + "0240": ["SQ", "FractionStatusSummarySequence"], + "0250": ["DA", "TreatmentDate"], + "0251": ["TM", "TreatmentTime"] + }, + "300A": { + "0002": ["SH", "RTPlanLabel"], + "0003": ["LO", "RTPlanName"], + "0004": ["ST", "RTPlanDescription"], + "0006": ["DA", "RTPlanDate"], + "0007": ["TM", "RTPlanTime"], + "0009": ["LO", "TreatmentProtocols"], + "000A": ["CS", "PlanIntent"], + "000B": ["LO", "TreatmentSites"], + "000C": ["CS", "RTPlanGeometry"], + "000E": ["ST", "PrescriptionDescription"], + "0010": ["SQ", "DoseReferenceSequence"], + "0012": ["IS", "DoseReferenceNumber"], + "0013": ["UI", "DoseReferenceUID"], + "0014": ["CS", "DoseReferenceStructureType"], + "0015": ["CS", "NominalBeamEnergyUnit"], + "0016": ["LO", "DoseReferenceDescription"], + "0018": ["DS", "DoseReferencePointCoordinates"], + "001A": ["DS", "NominalPriorDose"], + "0020": ["CS", "DoseReferenceType"], + "0021": ["DS", "ConstraintWeight"], + "0022": ["DS", "DeliveryWarningDose"], + "0023": ["DS", "DeliveryMaximumDose"], + "0025": ["DS", "TargetMinimumDose"], + "0026": ["DS", "TargetPrescriptionDose"], + "0027": ["DS", "TargetMaximumDose"], + "0028": ["DS", "TargetUnderdoseVolumeFraction"], + "002A": ["DS", "OrganAtRiskFullVolumeDose"], + "002B": ["DS", "OrganAtRiskLimitDose"], + "002C": ["DS", "OrganAtRiskMaximumDose"], + "002D": ["DS", "OrganAtRiskOverdoseVolumeFraction"], + "0040": ["SQ", "ToleranceTableSequence"], + "0042": ["IS", "ToleranceTableNumber"], + "0043": ["SH", "ToleranceTableLabel"], + "0044": ["DS", "GantryAngleTolerance"], + "0046": ["DS", "BeamLimitingDeviceAngleTolerance"], + "0048": ["SQ", "BeamLimitingDeviceToleranceSequence"], + "004A": ["DS", "BeamLimitingDevicePositionTolerance"], + "004B": ["FL", "SnoutPositionTolerance"], + "004C": ["DS", "PatientSupportAngleTolerance"], + "004E": ["DS", "TableTopEccentricAngleTolerance"], + "004F": ["FL", "TableTopPitchAngleTolerance"], + "0050": ["FL", "TableTopRollAngleTolerance"], + "0051": ["DS", "TableTopVerticalPositionTolerance"], + "0052": ["DS", "TableTopLongitudinalPositionTolerance"], + "0053": ["DS", "TableTopLateralPositionTolerance"], + "0055": ["CS", "RTPlanRelationship"], + "0070": ["SQ", "FractionGroupSequence"], + "0071": ["IS", "FractionGroupNumber"], + "0072": ["LO", "FractionGroupDescription"], + "0078": ["IS", "NumberOfFractionsPlanned"], + "0079": ["IS", "NumberOfFractionPatternDigitsPerDay"], + "007A": ["IS", "RepeatFractionCycleLength"], + "007B": ["LT", "FractionPattern"], + "0080": ["IS", "NumberOfBeams"], + "0082": ["DS", "BeamDoseSpecificationPoint"], + "0084": ["DS", "BeamDose"], + "0086": ["DS", "BeamMeterset"], + "0088": ["FL", "BeamDosePointDepth"], + "0089": ["FL", "BeamDosePointEquivalentDepth"], + "008A": ["FL", "BeamDosePointSSD"], + "00A0": ["IS", "NumberOfBrachyApplicationSetups"], + "00A2": ["DS", "BrachyApplicationSetupDoseSpecificationPoint"], + "00A4": ["DS", "BrachyApplicationSetupDose"], + "00B0": ["SQ", "BeamSequence"], + "00B2": ["SH", "TreatmentMachineName"], + "00B3": ["CS", "PrimaryDosimeterUnit"], + "00B4": ["DS", "SourceAxisDistance"], + "00B6": ["SQ", "BeamLimitingDeviceSequence"], + "00B8": ["CS", "RTBeamLimitingDeviceType"], + "00BA": ["DS", "SourceToBeamLimitingDeviceDistance"], + "00BB": ["FL", "IsocenterToBeamLimitingDeviceDistance"], + "00BC": ["IS", "NumberOfLeafJawPairs"], + "00BE": ["DS", "LeafPositionBoundaries"], + "00C0": ["IS", "BeamNumber"], + "00C2": ["LO", "BeamName"], + "00C3": ["ST", "BeamDescription"], + "00C4": ["CS", "BeamType"], + "00C6": ["CS", "RadiationType"], + "00C7": ["CS", "HighDoseTechniqueType"], + "00C8": ["IS", "ReferenceImageNumber"], + "00CA": ["SQ", "PlannedVerificationImageSequence"], + "00CC": ["LO", "ImagingDeviceSpecificAcquisitionParameters"], + "00CE": ["CS", "TreatmentDeliveryType"], + "00D0": ["IS", "NumberOfWedges"], + "00D1": ["SQ", "WedgeSequence"], + "00D2": ["IS", "WedgeNumber"], + "00D3": ["CS", "WedgeType"], + "00D4": ["SH", "WedgeID"], + "00D5": ["IS", "WedgeAngle"], + "00D6": ["DS", "WedgeFactor"], + "00D7": ["FL", "TotalWedgeTrayWaterEquivalentThickness"], + "00D8": ["DS", "WedgeOrientation"], + "00D9": ["FL", "IsocenterToWedgeTrayDistance"], + "00DA": ["DS", "SourceToWedgeTrayDistance"], + "00DB": ["FL", "WedgeThinEdgePosition"], + "00DC": ["SH", "BolusID"], + "00DD": ["ST", "BolusDescription"], + "00E0": ["IS", "NumberOfCompensators"], + "00E1": ["SH", "MaterialID"], + "00E2": ["DS", "TotalCompensatorTrayFactor"], + "00E3": ["SQ", "CompensatorSequence"], + "00E4": ["IS", "CompensatorNumber"], + "00E5": ["SH", "CompensatorID"], + "00E6": ["DS", "SourceToCompensatorTrayDistance"], + "00E7": ["IS", "CompensatorRows"], + "00E8": ["IS", "CompensatorColumns"], + "00E9": ["DS", "CompensatorPixelSpacing"], + "00EA": ["DS", "CompensatorPosition"], + "00EB": ["DS", "CompensatorTransmissionData"], + "00EC": ["DS", "CompensatorThicknessData"], + "00ED": ["IS", "NumberOfBoli"], + "00EE": ["CS", "CompensatorType"], + "00F0": ["IS", "NumberOfBlocks"], + "00F2": ["DS", "TotalBlockTrayFactor"], + "00F3": ["FL", "TotalBlockTrayWaterEquivalentThickness"], + "00F4": ["SQ", "BlockSequence"], + "00F5": ["SH", "BlockTrayID"], + "00F6": ["DS", "SourceToBlockTrayDistance"], + "00F7": ["FL", "IsocenterToBlockTrayDistance"], + "00F8": ["CS", "BlockType"], + "00F9": ["LO", "AccessoryCode"], + "00FA": ["CS", "BlockDivergence"], + "00FB": ["CS", "BlockMountingPosition"], + "00FC": ["IS", "BlockNumber"], + "00FE": ["LO", "BlockName"], + "0100": ["DS", "BlockThickness"], + "0102": ["DS", "BlockTransmission"], + "0104": ["IS", "BlockNumberOfPoints"], + "0106": ["DS", "BlockData"], + "0107": ["SQ", "ApplicatorSequence"], + "0108": ["SH", "ApplicatorID"], + "0109": ["CS", "ApplicatorType"], + "010A": ["LO", "ApplicatorDescription"], + "010C": ["DS", "CumulativeDoseReferenceCoefficient"], + "010E": ["DS", "FinalCumulativeMetersetWeight"], + "0110": ["IS", "NumberOfControlPoints"], + "0111": ["SQ", "ControlPointSequence"], + "0112": ["IS", "ControlPointIndex"], + "0114": ["DS", "NominalBeamEnergy"], + "0115": ["DS", "DoseRateSet"], + "0116": ["SQ", "WedgePositionSequence"], + "0118": ["CS", "WedgePosition"], + "011A": ["SQ", "BeamLimitingDevicePositionSequence"], + "011C": ["DS", "LeafJawPositions"], + "011E": ["DS", "GantryAngle"], + "011F": ["CS", "GantryRotationDirection"], + "0120": ["DS", "BeamLimitingDeviceAngle"], + "0121": ["CS", "BeamLimitingDeviceRotationDirection"], + "0122": ["DS", "PatientSupportAngle"], + "0123": ["CS", "PatientSupportRotationDirection"], + "0124": ["DS", "TableTopEccentricAxisDistance"], + "0125": ["DS", "TableTopEccentricAngle"], + "0126": ["CS", "TableTopEccentricRotationDirection"], + "0128": ["DS", "TableTopVerticalPosition"], + "0129": ["DS", "TableTopLongitudinalPosition"], + "012A": ["DS", "TableTopLateralPosition"], + "012C": ["DS", "IsocenterPosition"], + "012E": ["DS", "SurfaceEntryPoint"], + "0130": ["DS", "SourceToSurfaceDistance"], + "0134": ["DS", "CumulativeMetersetWeight"], + "0140": ["FL", "TableTopPitchAngle"], + "0142": ["CS", "TableTopPitchRotationDirection"], + "0144": ["FL", "TableTopRollAngle"], + "0146": ["CS", "TableTopRollRotationDirection"], + "0148": ["FL", "HeadFixationAngle"], + "014A": ["FL", "GantryPitchAngle"], + "014C": ["CS", "GantryPitchRotationDirection"], + "014E": ["FL", "GantryPitchAngleTolerance"], + "0180": ["SQ", "PatientSetupSequence"], + "0182": ["IS", "PatientSetupNumber"], + "0183": ["LO", "PatientSetupLabel"], + "0184": ["LO", "PatientAdditionalPosition"], + "0190": ["SQ", "FixationDeviceSequence"], + "0192": ["CS", "FixationDeviceType"], + "0194": ["SH", "FixationDeviceLabel"], + "0196": ["ST", "FixationDeviceDescription"], + "0198": ["SH", "FixationDevicePosition"], + "0199": ["FL", "FixationDevicePitchAngle"], + "019A": ["FL", "FixationDeviceRollAngle"], + "01A0": ["SQ", "ShieldingDeviceSequence"], + "01A2": ["CS", "ShieldingDeviceType"], + "01A4": ["SH", "ShieldingDeviceLabel"], + "01A6": ["ST", "ShieldingDeviceDescription"], + "01A8": ["SH", "ShieldingDevicePosition"], + "01B0": ["CS", "SetupTechnique"], + "01B2": ["ST", "SetupTechniqueDescription"], + "01B4": ["SQ", "SetupDeviceSequence"], + "01B6": ["CS", "SetupDeviceType"], + "01B8": ["SH", "SetupDeviceLabel"], + "01BA": ["ST", "SetupDeviceDescription"], + "01BC": ["DS", "SetupDeviceParameter"], + "01D0": ["ST", "SetupReferenceDescription"], + "01D2": ["DS", "TableTopVerticalSetupDisplacement"], + "01D4": ["DS", "TableTopLongitudinalSetupDisplacement"], + "01D6": ["DS", "TableTopLateralSetupDisplacement"], + "0200": ["CS", "BrachyTreatmentTechnique"], + "0202": ["CS", "BrachyTreatmentType"], + "0206": ["SQ", "TreatmentMachineSequence"], + "0210": ["SQ", "SourceSequence"], + "0212": ["IS", "SourceNumber"], + "0214": ["CS", "SourceType"], + "0216": ["LO", "SourceManufacturer"], + "0218": ["DS", "ActiveSourceDiameter"], + "021A": ["DS", "ActiveSourceLength"], + "0222": ["DS", "SourceEncapsulationNominalThickness"], + "0224": ["DS", "SourceEncapsulationNominalTransmission"], + "0226": ["LO", "SourceIsotopeName"], + "0228": ["DS", "SourceIsotopeHalfLife"], + "0229": ["CS", "SourceStrengthUnits"], + "022A": ["DS", "ReferenceAirKermaRate"], + "022B": ["DS", "SourceStrength"], + "022C": ["DA", "SourceStrengthReferenceDate"], + "022E": ["TM", "SourceStrengthReferenceTime"], + "0230": ["SQ", "ApplicationSetupSequence"], + "0232": ["CS", "ApplicationSetupType"], + "0234": ["IS", "ApplicationSetupNumber"], + "0236": ["LO", "ApplicationSetupName"], + "0238": ["LO", "ApplicationSetupManufacturer"], + "0240": ["IS", "TemplateNumber"], + "0242": ["SH", "TemplateType"], + "0244": ["LO", "TemplateName"], + "0250": ["DS", "TotalReferenceAirKerma"], + "0260": ["SQ", "BrachyAccessoryDeviceSequence"], + "0262": ["IS", "BrachyAccessoryDeviceNumber"], + "0263": ["SH", "BrachyAccessoryDeviceID"], + "0264": ["CS", "BrachyAccessoryDeviceType"], + "0266": ["LO", "BrachyAccessoryDeviceName"], + "026A": ["DS", "BrachyAccessoryDeviceNominalThickness"], + "026C": ["DS", "BrachyAccessoryDeviceNominalTransmission"], + "0280": ["SQ", "ChannelSequence"], + "0282": ["IS", "ChannelNumber"], + "0284": ["DS", "ChannelLength"], + "0286": ["DS", "ChannelTotalTime"], + "0288": ["CS", "SourceMovementType"], + "028A": ["IS", "NumberOfPulses"], + "028C": ["DS", "PulseRepetitionInterval"], + "0290": ["IS", "SourceApplicatorNumber"], + "0291": ["SH", "SourceApplicatorID"], + "0292": ["CS", "SourceApplicatorType"], + "0294": ["LO", "SourceApplicatorName"], + "0296": ["DS", "SourceApplicatorLength"], + "0298": ["LO", "SourceApplicatorManufacturer"], + "029C": ["DS", "SourceApplicatorWallNominalThickness"], + "029E": ["DS", "SourceApplicatorWallNominalTransmission"], + "02A0": ["DS", "SourceApplicatorStepSize"], + "02A2": ["IS", "TransferTubeNumber"], + "02A4": ["DS", "TransferTubeLength"], + "02B0": ["SQ", "ChannelShieldSequence"], + "02B2": ["IS", "ChannelShieldNumber"], + "02B3": ["SH", "ChannelShieldID"], + "02B4": ["LO", "ChannelShieldName"], + "02B8": ["DS", "ChannelShieldNominalThickness"], + "02BA": ["DS", "ChannelShieldNominalTransmission"], + "02C8": ["DS", "FinalCumulativeTimeWeight"], + "02D0": ["SQ", "BrachyControlPointSequence"], + "02D2": ["DS", "ControlPointRelativePosition"], + "02D4": ["DS", "ControlPoint3DPosition"], + "02D6": ["DS", "CumulativeTimeWeight"], + "02E0": ["CS", "CompensatorDivergence"], + "02E1": ["CS", "CompensatorMountingPosition"], + "02E2": ["DS", "SourceToCompensatorDistance"], + "02E3": ["FL", "TotalCompensatorTrayWaterEquivalentThickness"], + "02E4": ["FL", "IsocenterToCompensatorTrayDistance"], + "02E5": ["FL", "CompensatorColumnOffset"], + "02E6": ["FL", "IsocenterToCompensatorDistances"], + "02E7": ["FL", "CompensatorRelativeStoppingPowerRatio"], + "02E8": ["FL", "CompensatorMillingToolDiameter"], + "02EA": ["SQ", "IonRangeCompensatorSequence"], + "02EB": ["LT", "CompensatorDescription"], + "0302": ["IS", "RadiationMassNumber"], + "0304": ["IS", "RadiationAtomicNumber"], + "0306": ["SS", "RadiationChargeState"], + "0308": ["CS", "ScanMode"], + "030A": ["FL", "VirtualSourceAxisDistances"], + "030C": ["SQ", "SnoutSequence"], + "030D": ["FL", "SnoutPosition"], + "030F": ["SH", "SnoutID"], + "0312": ["IS", "NumberOfRangeShifters"], + "0314": ["SQ", "RangeShifterSequence"], + "0316": ["IS", "RangeShifterNumber"], + "0318": ["SH", "RangeShifterID"], + "0320": ["CS", "RangeShifterType"], + "0322": ["LO", "RangeShifterDescription"], + "0330": ["IS", "NumberOfLateralSpreadingDevices"], + "0332": ["SQ", "LateralSpreadingDeviceSequence"], + "0334": ["IS", "LateralSpreadingDeviceNumber"], + "0336": ["SH", "LateralSpreadingDeviceID"], + "0338": ["CS", "LateralSpreadingDeviceType"], + "033A": ["LO", "LateralSpreadingDeviceDescription"], + "033C": ["FL", "LateralSpreadingDeviceWaterEquivalentThickness"], + "0340": ["IS", "NumberOfRangeModulators"], + "0342": ["SQ", "RangeModulatorSequence"], + "0344": ["IS", "RangeModulatorNumber"], + "0346": ["SH", "RangeModulatorID"], + "0348": ["CS", "RangeModulatorType"], + "034A": ["LO", "RangeModulatorDescription"], + "034C": ["SH", "BeamCurrentModulationID"], + "0350": ["CS", "PatientSupportType"], + "0352": ["SH", "PatientSupportID"], + "0354": ["LO", "PatientSupportAccessoryCode"], + "0356": ["FL", "FixationLightAzimuthalAngle"], + "0358": ["FL", "FixationLightPolarAngle"], + "035A": ["FL", "MetersetRate"], + "0360": ["SQ", "RangeShifterSettingsSequence"], + "0362": ["LO", "RangeShifterSetting"], + "0364": ["FL", "IsocenterToRangeShifterDistance"], + "0366": ["FL", "RangeShifterWaterEquivalentThickness"], + "0370": ["SQ", "LateralSpreadingDeviceSettingsSequence"], + "0372": ["LO", "LateralSpreadingDeviceSetting"], + "0374": ["FL", "IsocenterToLateralSpreadingDeviceDistance"], + "0380": ["SQ", "RangeModulatorSettingsSequence"], + "0382": ["FL", "RangeModulatorGatingStartValue"], + "0384": ["FL", "RangeModulatorGatingStopValue"], + "0386": ["FL", "RangeModulatorGatingStartWaterEquivalentThickness"], + "0388": ["FL", "RangeModulatorGatingStopWaterEquivalentThickness"], + "038A": ["FL", "IsocenterToRangeModulatorDistance"], + "0390": ["SH", "ScanSpotTuneID"], + "0392": ["IS", "NumberOfScanSpotPositions"], + "0394": ["FL", "ScanSpotPositionMap"], + "0396": ["FL", "ScanSpotMetersetWeights"], + "0398": ["FL", "ScanningSpotSize"], + "039A": ["IS", "NumberOfPaintings"], + "03A0": ["SQ", "IonToleranceTableSequence"], + "03A2": ["SQ", "IonBeamSequence"], + "03A4": ["SQ", "IonBeamLimitingDeviceSequence"], + "03A6": ["SQ", "IonBlockSequence"], + "03A8": ["SQ", "IonControlPointSequence"], + "03AA": ["SQ", "IonWedgeSequence"], + "03AC": ["SQ", "IonWedgePositionSequence"], + "0401": ["SQ", "ReferencedSetupImageSequence"], + "0402": ["ST", "SetupImageComment"], + "0410": ["SQ", "MotionSynchronizationSequence"], + "0412": ["FL", "ControlPointOrientation"], + "0420": ["SQ", "GeneralAccessorySequence"], + "0421": ["SH", "GeneralAccessoryID"], + "0422": ["ST", "GeneralAccessoryDescription"], + "0423": ["CS", "GeneralAccessoryType"], + "0424": ["IS", "GeneralAccessoryNumber"], + "0431": ["SQ", "ApplicatorGeometrySequence"], + "0432": ["CS", "ApplicatorApertureShape"], + "0433": ["FL", "ApplicatorOpening"], + "0434": ["FL", "ApplicatorOpeningX"], + "0435": ["FL", "ApplicatorOpeningY"], + "0436": ["FL", "SourceToApplicatorMountingPositionDistance"] + }, + "300C": { + "0002": ["SQ", "ReferencedRTPlanSequence"], + "0004": ["SQ", "ReferencedBeamSequence"], + "0006": ["IS", "ReferencedBeamNumber"], + "0007": ["IS", "ReferencedReferenceImageNumber"], + "0008": ["DS", "StartCumulativeMetersetWeight"], + "0009": ["DS", "EndCumulativeMetersetWeight"], + "000A": ["SQ", "ReferencedBrachyApplicationSetupSequence"], + "000C": ["IS", "ReferencedBrachyApplicationSetupNumber"], + "000E": ["IS", "ReferencedSourceNumber"], + "0020": ["SQ", "ReferencedFractionGroupSequence"], + "0022": ["IS", "ReferencedFractionGroupNumber"], + "0040": ["SQ", "ReferencedVerificationImageSequence"], + "0042": ["SQ", "ReferencedReferenceImageSequence"], + "0050": ["SQ", "ReferencedDoseReferenceSequence"], + "0051": ["IS", "ReferencedDoseReferenceNumber"], + "0055": ["SQ", "BrachyReferencedDoseReferenceSequence"], + "0060": ["SQ", "ReferencedStructureSetSequence"], + "006A": ["IS", "ReferencedPatientSetupNumber"], + "0080": ["SQ", "ReferencedDoseSequence"], + "00A0": ["IS", "ReferencedToleranceTableNumber"], + "00B0": ["SQ", "ReferencedBolusSequence"], + "00C0": ["IS", "ReferencedWedgeNumber"], + "00D0": ["IS", "ReferencedCompensatorNumber"], + "00E0": ["IS", "ReferencedBlockNumber"], + "00F0": ["IS", "ReferencedControlPointIndex"], + "00F2": ["SQ", "ReferencedControlPointSequence"], + "00F4": ["IS", "ReferencedStartControlPointIndex"], + "00F6": ["IS", "ReferencedStopControlPointIndex"], + "0100": ["IS", "ReferencedRangeShifterNumber"], + "0102": ["IS", "ReferencedLateralSpreadingDeviceNumber"], + "0104": ["IS", "ReferencedRangeModulatorNumber"] + }, + "300E": { + "0002": ["CS", "ApprovalStatus"], + "0004": ["DA", "ReviewDate"], + "0005": ["TM", "ReviewTime"], + "0008": ["PN", "ReviewerName"] + }, + "4000": { + "0010": ["LT", "Arbitrary"], + "4000": ["LT", "TextComments"] + }, + "4008": { + "0040": ["SH", "ResultsID"], + "0042": ["LO", "ResultsIDIssuer"], + "0050": ["SQ", "ReferencedInterpretationSequence"], + "00FF": ["CS", "ReportProductionStatusTrial"], + "0100": ["DA", "InterpretationRecordedDate"], + "0101": ["TM", "InterpretationRecordedTime"], + "0102": ["PN", "InterpretationRecorder"], + "0103": ["LO", "ReferenceToRecordedSound"], + "0108": ["DA", "InterpretationTranscriptionDate"], + "0109": ["TM", "InterpretationTranscriptionTime"], + "010A": ["PN", "InterpretationTranscriber"], + "010B": ["ST", "InterpretationText"], + "010C": ["PN", "InterpretationAuthor"], + "0111": ["SQ", "InterpretationApproverSequence"], + "0112": ["DA", "InterpretationApprovalDate"], + "0113": ["TM", "InterpretationApprovalTime"], + "0114": ["PN", "PhysicianApprovingInterpretation"], + "0115": ["LT", "InterpretationDiagnosisDescription"], + "0117": ["SQ", "InterpretationDiagnosisCodeSequence"], + "0118": ["SQ", "ResultsDistributionListSequence"], + "0119": ["PN", "DistributionName"], + "011A": ["LO", "DistributionAddress"], + "0200": ["SH", "InterpretationID"], + "0202": ["LO", "InterpretationIDIssuer"], + "0210": ["CS", "InterpretationTypeID"], + "0212": ["CS", "InterpretationStatusID"], + "0300": ["ST", "Impressions"], + "4000": ["ST", "ResultsComments"] + }, + "4010": { + "0001": ["CS", "LowEnergyDetectors"], + "0002": ["CS", "HighEnergyDetectors"], + "0004": ["SQ", "DetectorGeometrySequence"], + "1001": ["SQ", "ThreatROIVoxelSequence"], + "1004": ["FL", "ThreatROIBase"], + "1005": ["FL", "ThreatROIExtents"], + "1006": ["OB", "ThreatROIBitmap"], + "1007": ["SH", "RouteSegmentID"], + "1008": ["CS", "GantryType"], + "1009": ["CS", "OOIOwnerType"], + "100A": ["SQ", "RouteSegmentSequence"], + "1010": ["US", "PotentialThreatObjectID"], + "1011": ["SQ", "ThreatSequence"], + "1012": ["CS", "ThreatCategory"], + "1013": ["LT", "ThreatCategoryDescription"], + "1014": ["CS", "ATDAbilityAssessment"], + "1015": ["CS", "ATDAssessmentFlag"], + "1016": ["FL", "ATDAssessmentProbability"], + "1017": ["FL", "Mass"], + "1018": ["FL", "Density"], + "1019": ["FL", "ZEffective"], + "101A": ["SH", "BoardingPassID"], + "101B": ["FL", "CenterOfMass"], + "101C": ["FL", "CenterOfPTO"], + "101D": ["FL", "BoundingPolygon"], + "101E": ["SH", "RouteSegmentStartLocationID"], + "101F": ["SH", "RouteSegmentEndLocationID"], + "1020": ["CS", "RouteSegmentLocationIDType"], + "1021": ["CS", "AbortReason"], + "1023": ["FL", "VolumeOfPTO"], + "1024": ["CS", "AbortFlag"], + "1025": ["DT", "RouteSegmentStartTime"], + "1026": ["DT", "RouteSegmentEndTime"], + "1027": ["CS", "TDRType"], + "1028": ["CS", "InternationalRouteSegment"], + "1029": ["LO", "ThreatDetectionAlgorithmandVersion"], + "102A": ["SH", "AssignedLocation"], + "102B": ["DT", "AlarmDecisionTime"], + "1031": ["CS", "AlarmDecision"], + "1033": ["US", "NumberOfTotalObjects"], + "1034": ["US", "NumberOfAlarmObjects"], + "1037": ["SQ", "PTORepresentationSequence"], + "1038": ["SQ", "ATDAssessmentSequence"], + "1039": ["CS", "TIPType"], + "103A": ["CS", "DICOSVersion"], + "1041": ["DT", "OOIOwnerCreationTime"], + "1042": ["CS", "OOIType"], + "1043": ["FL", "OOISize"], + "1044": ["CS", "AcquisitionStatus"], + "1045": ["SQ", "BasisMaterialsCodeSequence"], + "1046": ["CS", "PhantomType"], + "1047": ["SQ", "OOIOwnerSequence"], + "1048": ["CS", "ScanType"], + "1051": ["LO", "ItineraryID"], + "1052": ["SH", "ItineraryIDType"], + "1053": ["LO", "ItineraryIDAssigningAuthority"], + "1054": ["SH", "RouteID"], + "1055": ["SH", "RouteIDAssigningAuthority"], + "1056": ["CS", "InboundArrivalType"], + "1058": ["SH", "CarrierID"], + "1059": ["CS", "CarrierIDAssigningAuthority"], + "1060": ["FL", "SourceOrientation"], + "1061": ["FL", "SourcePosition"], + "1062": ["FL", "BeltHeight"], + "1064": ["SQ", "AlgorithmRoutingCodeSequence"], + "1067": ["CS", "TransportClassification"], + "1068": ["LT", "OOITypeDescriptor"], + "1069": ["FL", "TotalProcessingTime"], + "106C": ["OB", "DetectorCalibrationData"] + } +}; +/** + * Returns the VR for the specified group and element. + * @param {number} group + * @param {number} element + * @returns {string} + */ + +const getVR = (group, element) => { + let vr; + let elementData; + let groupData; + groupData = dict[dec2hex(group)]; + + if (groupData) { + elementData = groupData[dec2hex(element)]; + + if (elementData) { + [vr] = elementData; + } else if (element === 0) { + vr = "UL"; + } + } + + if (!vr) { + groupData = dictPrivate[dec2hex(group)]; + + if (groupData) { + elementData = groupData[dec2hex(element)]; + + if (elementData) { + [vr] = elementData; + } + } + } + + if (!vr) { + vr = "OB"; + } + + return vr; +}; +/** + * Returns the description for the specified group and element. + * @param {number} group + * @param {number} element + * @returns {string} + */ + + +const getDescription = (group, element) => { + let des; + let elementData; + let groupData; + groupData = dict[dec2hex(group)]; + + if (groupData) { + elementData = groupData[dec2hex(element)]; + + if (elementData) { + [, des] = elementData; + } else if (element === 0) { + des = `Group ${dec2hex(group)} Length`; + } + } + + if (!des) { + groupData = dictPrivate[dec2hex(group)]; + + if (groupData) { + elementData = groupData[dec2hex(element)]; + + if (elementData) { + [, des] = elementData; + } + } + } + + if (!des) { + des = "PrivateData"; + } + + return des; +}; + +var Dictionary = { + getVR, + getDescription +}; +const CSA2_MAGIC_NUMBER = [83, 86, 49, 48]; +const NAME_LENGTH = 64; +const ELEMENT_CSA1 = 0x1010; +const ELEMENT_CSA2 = 0x1020; +const GROUP_CSA = 0x029; +/** + * The Siemens constructor. + * @params {ArrayBuffer} buffer + * @type {Function} + */ + +class Siemens { + constructor(buffer) { + this.output = void 0; + this.data = void 0; + + this.canRead = (group, element) => group === GROUP_CSA && (element === ELEMENT_CSA1 || element === ELEMENT_CSA2); + + this.output = ""; + this.data = new DataView(buffer, 0); + } + /** + * Reads the Siemens header. (See http://nipy.org/nibabel/dicom/siemens_csa.html) + * @returns {string} + */ + + + readHeader() { + let match; + + try { + if (this.data.byteLength > CSA2_MAGIC_NUMBER.length) { + match = true; + const { + data + } = this; + + for (let ctr = 0; ctr < CSA2_MAGIC_NUMBER.length; ctr += 1) { + match = match && data.getUint8(ctr) === CSA2_MAGIC_NUMBER[ctr]; + } + + if (match) { + this.readHeaderAtOffset(CSA2_MAGIC_NUMBER.length + 4); + } else { + this.readHeaderAtOffset(0); + } + } + } catch (error) { + console.log(error); + } + + return this.output; + } + + readHeaderAtOffset(offset) { + this.output += "\n"; + const numTags = swap32(this.data.getUint32(offset)); + + if (numTags < 1 || numTags > 128) { + return this.output; + } + + let newOffset = offset + 4; + newOffset += 4; // unused + + for (let ctr = 0; ctr < numTags; ctr += 1) { + newOffset = this.readTag(newOffset); + + if (offset === -1) { + break; + } + } + + return this.output; + } + + readTag(offset) { + const name = this.readString(offset, NAME_LENGTH); + let newOffset = offset + NAME_LENGTH; + newOffset += 4; // vm + + newOffset += 4; + newOffset += 4; // syngodt + + const numItems = swap32(this.data.getUint32(offset)); + newOffset += 4; + newOffset += 4; // unused + + this.output += ` ${name}=`; + + for (let ctr = 0; ctr < numItems; ctr += 1) { + newOffset = this.readItem(newOffset); + + if (newOffset === -1) { + break; + } else if (newOffset % 4 !== 0) { + newOffset += 4 - newOffset % 4; + } + } + + this.output += "\n"; + return offset; + } + + readString(offset, length) { + let str = ""; + + for (let ctr = 0; ctr < length; ctr += 1) { + const char2 = this.data.getUint8(offset + ctr); + + if (char2 === 0) { + break; + } + + str += String.fromCharCode(char2); + } + + return str; + } + + readItem(offset) { + const itemLength = swap32(this.data.getUint32(offset)); + + if (offset + itemLength > this.data.byteLength) { + return -1; + } + + const newOffset = offset + 16; + + if (itemLength > 0) { + this.output += `${this.readString(newOffset, itemLength)} `; + } + + return newOffset + itemLength; + } + /** + * Returns true if the specified group and element indicate this tag can be read. + * @param {number} group + * @param {number} element + * @returns {boolean} + */ + // eslint-disable-next-line class-methods-use-this + + +} + +const PRIVATE_DATA_READERS = [Siemens]; +const TagIds = { + // metadata + TransferSyntax: [0x0002, 0x0010], + MetaLength: [0x0002, 0x0000], + // sublists + SublistItem: [0xFFFE, 0xE000], + SublistItemDelim: [0xFFFE, 0xE00D], + SequenceDelim: [0xFFFE, 0xE0DD], + // image dims + Rows: [0x0028, 0x0010], + Cols: [0x0028, 0x0011], + AcquisitionMatrix: [0x0018, 0x1310], + NumberOfFrames: [0x0028, 0x0008], + NumberTemporalPositions: [0x0020, 0x0105], + // voxel dims + PixelSpacing: [0x0028, 0x0030], + SliceThickness: [0x0018, 0x0050], + SliceGap: [0x0018, 0x0088], + Tr: [0x0018, 0x0080], + FrameTime: [0x0018, 0x1063], + // datatype + BitsAllocated: [0x0028, 0x0100], + BitsStored: [0x0028, 0x0101], + PixelRepresentation: [0x0028, 0x0103], + PixelPaddingValue: [0x0028, 0x0120], + HighBit: [0x0028, 0x0102], + PhotometricInterpretation: [0x0028, 0x0004], + SamplesPerPixel: [0x0028, 0x0002], + PlanarConfig: [0x0028, 0x0006], + PaletteRedDescriptor: [0x0028, 0x1101], + PaletteRed: [0x0028, 0x1201], + PaletteGreen: [0x0028, 0x1202], + PaletteBlue: [0x0028, 0x1203], + // data scale + DataScaleSlope: [0x0028, 0x1053], + DataScaleIntercept: [0x0028, 0x1052], + DataScaleElscint: [0x0207, 0x101f], + PixelBandwidth: [0x0018, 0x0095], + // LUT + VoiLutSequence: [0x0028, 0x3010], + VoiLutDescriptor: [0x0028, 0x3002], + // VoiLutExplanation: [0x0028, 0x3003], + VoiLutData: [0x0028, 0x3006], + // range + ImageMin: [0x0028, 0x0106], + ImageMax: [0x0028, 0x0107], + WindowCenter: [0x0028, 0x1050], + WindowWidth: [0x0028, 0x1051], + // descriptors + Charset: [0x0008, 0x0005], + PatientName: [0x0010, 0x0010], + PatientId: [0x0010, 0x0020], + StudyDate: [0x0008, 0x0020], + StudyTime: [0x0008, 0x0030], + StudyDes: [0x0008, 0x1030], + ImageType: [0x0008, 0x0008], + ImageComments: [0x0020, 0x4000], + SequenceName: [0x0018, 0x0024], + Modality: [0x0008, 0x0060], + // session ID + FrameOfRefUid: [0x0020, 0x0052], + // study ID + StudyUid: [0x0020, 0x000d], + // volume ID + SeriesDescription: [0x0008, 0x103e], + SeriesInstanceUid: [0x0020, 0x000e], + SeriesNumber: [0x0020, 0x0011], + EchoNumber: [0x0018, 0x0086], + TemporalPosition: [0x0020, 0x0100], + // slice ID + ImageNum: [0x0020, 0x0013], + SliceLocation: [0x0020, 0x1041], + // orientation + ImageOrientation: [0x0020, 0x0037], + ImagePosition: [0x0020, 0x0032], + SliceLocationVector: [0x0018, 0x2005], + // LUT shape + LutShape: [0x2050, 0x0020], + // pixel data + PixelData: [0x7fe0, 0x0010] +}; +/** + * Create an ID string based on the specified group and element + * @param {number} group + * @param {number} element + * @returns {string} + */ + +const createTagId = (group, element) => { + const groupStr = dec2hex$1(group); + const elemStr = dec2hex$1(element); + return groupStr + elemStr; +}; + +const VRMaxLength = { + AE: 16, + AS: 4, + AT: 4, + CS: 16, + DA: 8, + DS: 16, + DT: 26, + FL: 4, + FD: 8, + IS: 12, + LO: 64, + LT: 10240, + OB: -1, + OD: -1, + OF: -1, + OW: -1, + PN: 64 * 5, + SH: 16, + SL: 4, + SS: 2, + ST: 1024, + TM: 16, + UI: 64, + UL: 4, + UN: -1, + US: 2, + UT: -1 +}; +/** + * Create an ID string based on the specified group and element + * @param {Array} tupple with + * @param {number} group + * @param {number} element + * @returns {string} + */ + +const createTagIdWithTag = ([group, element]) => { + const groupStr = dec2hex$1(group); + const elemStr = dec2hex$1(element); + return groupStr + elemStr; +}; + +const getUnsignedInteger16 = (rawData, littleEndian) => { + const data = []; + const mul = rawData.byteLength / 2; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getUint16(ctr * 2, littleEndian); + } + + return data; +}; + +const getSignedInteger16 = (rawData, littleEndian) => { + const data = []; + const mul = rawData.byteLength / 2; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getInt16(ctr * 2, littleEndian); + } + + return data; +}; + +const getFloat32 = (rawData, littleEndian) => { + const data = []; + const mul = rawData.byteLength / 4; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getFloat32(ctr * 4, littleEndian); + } + + return data; +}; + +const getSignedInteger32 = (rawData, littleEndian) => { + const data = []; + const mul = rawData.byteLength / 4; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getInt32(ctr * 4, littleEndian); + } + + return data; +}; + +const getUnsignedInteger32 = (rawData, littleEndian) => { + const data = []; + const mul = rawData.byteLength / 4; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getUint32(ctr * 4, littleEndian); + } + + return data; +}; + +const getFloat64 = (rawData, littleEndian) => { + if (rawData.byteLength < 8) { + return [0]; + } + + const data = []; + const mul = rawData.byteLength / 8; + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = rawData.getFloat64(ctr * 8, littleEndian); + } + + return data; +}; + +const getDoubleElscint = (rawData, littleEndian) => { + const data = Array(8); + + if (littleEndian) { + for (let ctr = 0; ctr < 8; ctr += 1) { + data[ctr] = rawData.getUint8(ctr); + } + } else { + for (let ctr = 0; ctr < 8; ctr += 1) { + data[ctr] = rawData.getUint8(7 - ctr); + } + } + + const reordered = [data[3], data[2], data[1], data[0], data[7], data[6], data[5], data[4]]; + return [bytesToDouble(reordered)]; +}; + +const getFixedLengthStringValue = (rawData, maxLength, charset, vr) => { + const mul = Math.floor(rawData.byteLength / maxLength); + const data = Array(mul); + + for (let ctr = 0; ctr < mul; ctr += 1) { + data[ctr] = getStringAt(rawData, ctr * maxLength, maxLength, charset, vr); + } + + return data; +}; + +const getStringValue = (rawData, charset, vr) => { + const data = getStringAt(rawData, 0, rawData.byteLength, charset, vr).split("\\"); + + for (let ctr = 0; ctr < data.length; ctr += 1) { + data[ctr] = data[ctr].trim(); + } + + return data; +}; + +const getSingleStringValue = (rawData, maxLength = 0, charset = undefined, vr = undefined) => { + const len = Math.min(rawData.byteLength, maxLength); + return [getStringAt(rawData, 0, len, charset, vr).trim()]; +}; + +const getDateStringValue = rawData => { + const dotFormat = getSingleStringValue(rawData)[0].indexOf(".") !== -1; + const stringData = getFixedLengthStringValue(rawData, dotFormat ? 10 : VRMaxLength.DA); + let parts = null; + const data = []; + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + if (dotFormat) { + parts = stringData[ctr].split("."); + + if (parts.length === 3) { + data[ctr] = new Date(safeParseInt(parts[0]), safeParseInt(parts[1]) - 1, safeParseInt(parts[2])); + } else { + data[ctr] = new Date(); + } + } else if (stringData[ctr].length === 8) { + data[ctr] = new Date(safeParseInt(stringData[ctr].substring(0, 4)), safeParseInt(stringData[ctr].substring(4, 6)) - 1, safeParseInt(stringData[ctr].substring(6, 8))); + } else { + data[ctr] = Date.parse(stringData[ctr]); + } + + if (!isValidDate(data[ctr])) { + data[ctr] = stringData[ctr]; + } + } + + return data; +}; + +const getDateTimeStringValue = rawData => { + const stringData = getStringValue(rawData); + const data = []; + let year = 0; + let month = 0; + let date = 0; + let hours = 0; + let minutes = 0; + let seconds = 0; + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + const str = stringData[ctr]; + const strLen = str.length; + + if (strLen >= 4) { + year = parseInt(str.substring(0, 4), 10); // required + + if (strLen >= 6) { + month = safeParseInt(str.substring(4, 6)) - 1; + } + + if (strLen >= 8) { + date = safeParseInt(str.substring(6, 8)); + } + + if (strLen >= 10) { + hours = safeParseInt(str.substring(8, 10)); + } + + if (strLen >= 12) { + minutes = safeParseInt(str.substring(10, 12)); + } + + if (strLen >= 14) { + seconds = safeParseInt(str.substring(12, 14)); + } + + data[ctr] = new Date(year, month, date, hours, minutes, seconds); + } else { + data[ctr] = Date.parse(str); + } + + if (!isValidDate(data[ctr])) { + data[ctr] = str; + } + } + + return data; +}; + +const getTimeStringValue = (rawData, ms = false) => { + const stringData = getStringValue(rawData); + const data = []; + + if (ms) { + let parts = null; + let hours = 0; + let minutes = 0; + let seconds = 0; + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + if (stringData[ctr].indexOf(":") !== -1) { + parts = stringData[ctr].split(":"); + hours = safeParseInt(parts[0]); + + if (parts.length > 1) { + minutes = safeParseInt(parts[1]); + } + + if (parts.length > 2) { + seconds = safeParseFloat(parts[2]); + } + } else { + if (stringData[ctr].length >= 2) { + hours = safeParseInt(stringData[ctr].substring(0, 2)); + } + + if (stringData[ctr].length >= 4) { + minutes = safeParseInt(stringData[ctr].substring(2, 4)); + } + + if (stringData[ctr].length >= 6) { + seconds = safeParseFloat(stringData[ctr].substring(4)); + } + } + + data[ctr] = Math.round(hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000); + } + + return data; + } + + return stringData; +}; + +const getDoubleStringValue = rawData => { + const stringData = getStringValue(rawData); + const data = []; + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + data[ctr] = parseFloat(stringData[ctr]); + } + + return data; +}; + +const getIntegerStringValue = rawData => { + const stringData = getStringValue(rawData); + const data = []; + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + data[ctr] = parseInt(stringData[ctr], 10); + } + + return data; +}; + +const getPersonNameStringValue = (rawData, charset, vr) => { + const stringData = getStringValue(rawData, charset, vr); + const data = Array(stringData.length); + + for (let ctr = 0; ctr < stringData.length; ctr += 1) { + data[ctr] = stringData[ctr].replace("^", " "); + } + + return data; +}; + +const convertPrivateValue = (group, element, rawData) => { + let privReader; + + for (let ctr = 0; ctr < PRIVATE_DATA_READERS.length; ctr += 1) { + privReader = new PRIVATE_DATA_READERS[ctr](rawData.buffer); + + if (privReader.canRead(group, element)) { + return privReader.readHeader(); + } + } + + return rawData; +}; + +const convertValue = (vr, rawData, littleEndian, charset) => { + let data = null; // http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html + + switch (vr) { + case "AE": + data = getSingleStringValue(rawData, VRMaxLength.AE); + break; + + case "AS": + data = getFixedLengthStringValue(rawData, VRMaxLength.AS); + break; + + case "AT": + data = getUnsignedInteger16(rawData, littleEndian); + break; + + case "CS": + data = getStringValue(rawData); + break; + + case "DA": + data = getDateStringValue(rawData); + break; + + case "DS": + data = getDoubleStringValue(rawData); + break; + + case "DT": + data = getDateTimeStringValue(rawData); + break; + + case "FL": + data = getFloat32(rawData, littleEndian); + break; + + case "FD": + data = getFloat64(rawData, littleEndian); + break; + + case "FE": + data = getDoubleElscint(rawData, littleEndian); + break; + + case "IS": + data = getIntegerStringValue(rawData); + break; + + case "LO": + data = getStringValue(rawData, charset, vr); + break; + + case "LT": + data = getSingleStringValue(rawData, VRMaxLength.AT); + break; + + case "OB": + case "OD": + case "OF": + case "OW": + data = rawData; + break; + + case "PN": + data = getPersonNameStringValue(rawData, charset, vr); + break; + + case "SH": + data = getStringValue(rawData, charset, vr); + break; + + case "SL": + data = getSignedInteger32(rawData, littleEndian); + break; + + case "SQ": + data = null; + break; + + case "SS": + data = getSignedInteger16(rawData, littleEndian); + break; + + case "ST": + data = getSingleStringValue(rawData, VRMaxLength.ST); + break; + + case "TM": + data = getTimeStringValue(rawData); + break; + + case "UI": + data = getStringValue(rawData); + break; + + case "UL": + data = getUnsignedInteger32(rawData, littleEndian); + break; + + case "UN": + data = rawData; + break; + + case "US": + data = getUnsignedInteger16(rawData, littleEndian); + break; + + case "UT": + data = getSingleStringValue(rawData, Number.MAX_SAFE_INTEGER, charset, vr); + break; + } + + return data; +}; + +class Tag { + static isEqual({ + group, + element + }, tagId) { + return group === tagId[0] && element === tagId[1]; + } + /** + * The Tag constuctor. + * @property {number} group + * @property {number} element + * @property {string} vr + * @property {number} offsetStart + * @property {number} offsetValue + * @property {number} offsetEnd + * @property {boolean} sublist - true if this tag is a sublist + * @property {number|number[]|string|string[]|object} value + * @type {Function} + */ + + + constructor({ + group, + element, + vr = null, + value = null, + offsetStart = null, + offsetValue = null, + offsetEnd = null, + littleEndian = true, + charset = null + }) { + this.id = void 0; + this.group = void 0; + this.element = void 0; + this.vr = void 0; + this.rawValue = void 0; + this.convertedValue = void 0; + this.offsetStart = void 0; + this.offsetValue = void 0; + this.offsetEnd = void 0; + this.sublist = void 0; + this.preformatted = void 0; + this.littleEndian = void 0; + this.charset = void 0; + this.group = group; + this.element = element; + this.vr = vr; + this.offsetStart = offsetStart; + this.offsetValue = offsetValue; + this.offsetEnd = offsetEnd; + this.sublist = false; + this.preformatted = false; + this.id = createTagId(group, element); + this.littleEndian = littleEndian; + this.charset = charset; + this.rawValue = value; + + if (value instanceof Array) { + this.sublist = true; + this.rawValue = value; + this.convertedValue = value; + } + } + + hasValue() { + return this.rawValue !== null; + } + + get value() { + // oonly convert value if needed + return this.convertedValue || this.getConvertedValue(); + } + + getConvertedValue() { + if (this.rawValue === null) { + return null; + } + + const { + rawValue, + vr, + littleEndian, + charset, + group, + element + } = this; + const dv = rawValue; + let convertedValue = convertValue(vr, dv, littleEndian, charset); + + if (convertedValue === dv && this.isPrivateData()) { + convertedValue = convertPrivateValue(group, element, dv); + this.preformatted = convertedValue !== dv; + } + + this.convertedValue = convertedValue; + return convertedValue; + } + /** + * Returns true if this is the transform syntax tag. + * @returns {boolean} + */ + + + is([group, element]) { + return this.group === group && this.element === element; + } + /** + * Returns true if this tag contains private data. + * @returns {boolean} + */ + + + isPrivateData() { + /* eslint-disable no-bitwise */ + return (this.group & 1) === 1; + } + /** + * Returns true if this tag contains private data that can be read. + * @returns {boolean} + */ + + + hasInterpretedPrivateData() { + return this.isPrivateData() && isString(this.value); + } + /** + * Returns a string representation of this tag. + * @param {number} [level] - the indentation level + * @param {boolean} [html] + * @returns {string} + */ + + + toString(level = 0, html = false) { + let valueStr = ""; + const groupStr = dec2hex$1(this.group); + const elemStr = dec2hex$1(this.element); + let tagStr = `(${groupStr},${elemStr})`; + let des = ""; + let padding; + padding = ""; + + for (let ctr = 0; ctr < level; ctr += 1) { + if (html) { + padding += "  "; + } else { + padding += " "; + } + } + + if (this.sublist) { + const value = this.value; + + for (let ctr = 0; ctr < value.length; ctr += 1) { + const tag = value[ctr]; + valueStr += `\n${tag.toString(level + 1, html)}`; + } + } else if (this.vr === "SQ" || this.is(TagIds.PixelData) || !this.value) { + valueStr = ""; + } else if (html && this.preformatted) { + valueStr = `[
${this.value}
]`; + } else { + valueStr = `[${this.value}]`; + } + + if (this.is(TagIds.SublistItem)) { + tagStr = "Sequence Item"; + } else if (this.is(TagIds.SublistItemDelim)) { + tagStr = "Sequence Item Delimiter"; + } else if (this.is(TagIds.SequenceDelim)) { + tagStr = "Sequence Delimiter"; + } else if (this.is(TagIds.PixelData)) { + tagStr = "Pixel Data"; + } else { + des = convertCamcelCaseToTitleCase(Dictionary.getDescription(this.group, this.element)); + } + + if (html) { + return `${padding}${tagStr}   ${des}   ${valueStr}`; + } + + return `${padding} ${tagStr} ${des} ${valueStr}`; + } + /** + * Returns an HTML string representation of this tag. + * @param {number} level - the indentation level + * @returns {string} + */ + + + toHTMLString(level = 0) { + return this.toString(level, true); + } // for test, ignore any ptotocol changes etc + + + toObject() { + const { + id, + group, + element, + vr, + value, + offsetStart, + offsetValue, + offsetEnd, + sublist, + preformatted + } = this; + return { + id, + group, + element, + vr, + value, + offsetStart, + offsetValue, + offsetEnd, + sublist, + preformatted + }; + } + +} + +const lutInfoFromImage = image => { + const lutDescriptor = image.getTagValue(TagIds.VoiLutDescriptor); + + if ((lutDescriptor === null || lutDescriptor === void 0 ? void 0 : lutDescriptor.length) !== 3) { + return null; + } + + const [nEntries, firstValue, bitsStored] = lutDescriptor; + + if (nEntries === 0 || nEntries >= 2 ** bitsStored - 1) { + return null; + } + + let ArrayType = Uint8Array; + + if (bitsStored > 8) { + ArrayType = Uint16Array; + } + + const lutDataTagValue = image.getTagValue(TagIds.VoiLutData); + + if (!lutDataTagValue) { + return null; + } + + const data = new ArrayType(lutDataTagValue, 0, Math.min(lutDescriptor[0] || 2 ** 16, lutDataTagValue.length)); + return { + nEntries, + firstValue, + bitsStored, + data + }; +}; + +const paletteInfoFromImage = info => { + const { + image + } = info; + const reds = image.getTagValue(TagIds.PaletteRed); + const greens = image.getTagValue(TagIds.PaletteGreen); + const blues = image.getTagValue(TagIds.PaletteBlue); + + if ((reds === null || reds === void 0 ? void 0 : reds.byteLength) > 0 && (greens === null || greens === void 0 ? void 0 : greens.byteLength) > 0 && (blues === null || blues === void 0 ? void 0 : blues.byteLength) > 0) { + const paletteInfo = image.getTagValue(TagIds.PaletteRedDescriptor); + const [nEntries,, bitsAllocated] = paletteInfo; + return { + nEntries, + bitsAllocated, + r: reds, + g: greens, + b: blues + }; + } + + return null; +}; + +const displayInfoFromDecoderInfo = info => { + const { + image + } = info; + let invert = image.getTagValueIndexed(TagIds.LutShape) === "inverse"; + invert = invert || image.photometricInterpretation === "MONOCHROME1"; + + const displayInfo = _extends({}, info, { + nFrames: image.numberOfFrames || 1, + pixelPaddingVal: image.pixelPaddingValue, + lut: lutInfoFromImage(info.image), + palette: paletteInfoFromImage(info), + minPixVal: image.imageMin, + maxPixVal: image.imageMax, + windowCenter: image.windowCenter, + windowWidth: image.windowWidth, + slope: image.dataScaleSlope || 1.0, + intercept: image.dataScaleIntercept || 0.0, + invert + }); + + return displayInfo; +}; + +class FrameInfo { + constructor(info) { + this.frameNo = void 0; + this.imageInfo = void 0; + this.texture = void 0; + this.gl = void 0; + this.imageInfo = info.imageInfo; + this.frameNo = info.frameNo; + this.texture = info.texture; + this.gl = info.gl; + } + + destroy() { + this.gl.deleteTexture(this.texture); + } + +} + +class Decoder { + constructor(image) { + this.image = void 0; + this.outputSize = void 0; + this.image = displayInfoFromDecoderInfo(image); + this.outputSize = image.size; + } + + async getFrame(gl, frameNo) { + const texture = await this.createTexture(gl, frameNo); + return new FrameInfo({ + imageInfo: this.image, + frameNo, + gl, + texture + }); + } // eslint-disable-next-line @typescript-eslint/no-unused-vars + + + decode(frameNo) { + const { + data, + nFrames + } = this.image; + const bytesPerFrame = data.byteLength / nFrames; + const dv = new DataView(data.buffer, data.byteOffset + bytesPerFrame * frameNo, bytesPerFrame); + return Promise.resolve(dv); + } + + async createTexture(gl, frameNo) { + const pixelData = await this.decode(frameNo); + const buffer = new Uint8Array(pixelData.buffer, pixelData.byteOffset, pixelData.byteLength); + let { + height + } = this.outputSize; + const { + width + } = this.outputSize; + const { + image + } = this; + let format = gl.LUMINANCE_ALPHA; + let internalFormat = gl.LUMINANCE_ALPHA; + + if (image.rgb && !image.planar && !image.palette) { + format = gl.RGB; + internalFormat = gl.RGB; + } else if (image.bytesAllocated === 1) { + format = gl.LUMINANCE; + internalFormat = gl.LUMINANCE; + } + + if (image.planar) { + height *= image.samples; + } + + return Promise.resolve(twgl.createTexture(gl, { + src: buffer, + width, + height, + format, + internalFormat, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + })); + } + +} + +const getSingleValueSafely = (tag, index) => { + var _tag$value; + + return (tag === null || tag === void 0 ? void 0 : (_tag$value = tag.value) === null || _tag$value === void 0 ? void 0 : _tag$value[index]) || null; +}; + +const getValueSafely = tag => { + var _tag$value2; + + return (_tag$value2 = tag === null || tag === void 0 ? void 0 : tag.value) !== null && _tag$value2 !== void 0 ? _tag$value2 : null; +}; + +var Axis; + +(function (Axis) { + Axis["R"] = "R"; + Axis["L"] = "L"; + Axis["A"] = "A"; + Axis["P"] = "P"; + Axis["F"] = "F"; + Axis["H"] = "H"; +})(Axis || (Axis = {})); // originally from: http://public.kitware.com/pipermail/insight-users/2005-March/012246.html + + +const ObliquityThresholdCosineValue = 0.8; + +const getMajorAxisFromPatientRelativeDirectionCosine = (x, y, z) => { + const absX = Math.abs(x); + const absY = Math.abs(y); + const absZ = Math.abs(z); // The tests here really don't need to check the other dimensions, + // just the threshold, since the sum of the squares should be == 1.0 + // but just in case ... + + let axis = null; + + if (absX > ObliquityThresholdCosineValue && absX > absY && absX > absZ) { + const orientationX = x < 0 ? Axis.R : Axis.L; + axis = orientationX; + } else if (absY > ObliquityThresholdCosineValue && absY > absX && absY > absZ) { + const orientationY = y < 0 ? Axis.A : Axis.P; + axis = orientationY; + } else if (absZ > ObliquityThresholdCosineValue && absZ > absX && absZ > absY) { + const orientationZ = z < 0 ? Axis.F : Axis.H; + axis = orientationZ; + } + + return axis; +}; + +class DCMImage { + constructor() { + this.tags = {}; + this.tagsFlat = {}; + this.littleEndian = false; + this.index = -1; + this.decompressed = false; + this.privateDataAll = null; + this.bytesAllocated = null; + } + /** + * Returns a tag matching the specified group and element tuple + * @param {TagTupleID} tag - Tuple of group & elem like TagIds values + * @returns + */ + + + getTag(tag) { + var _this$tags$tagId; + + const [group, element] = tag; + const tagId = createTagId(group, element); + return (_this$tags$tagId = this.tags[tagId]) !== null && _this$tags$tagId !== void 0 ? _this$tags$tagId : this.tagsFlat[tagId]; + } + /** + * Returns a tag matching the specified group and element tuple ignoring tagsFlat + * @param {TagTupleID} tag - Tuple of group & elem like TagIds values + * @returns + */ + + + getTopLevelTag(tag) { + const [group, element] = tag; + const tagId = createTagId(group, element); + return this.tags[tagId]; + } + /** + * get the value of the tag if exists + * @param {TagTupleID} tag tuple of group and element ids + * @returns the value of the tag or null if not exist + */ + + + getTagValue(tag) { + return getValueSafely(this.getTag(tag)); + } + /** + * get the value of the tag if exists + * @param {TagTupleID} tag tuple of group and element ids + * @param {Number} index the position in the value + * @returns the value at index or null if not exist + */ + + + getTagValueIndexed(tag, index = 0) { + return getSingleValueSafely(this.getTag(tag), index); + } + /** + * Returns the pixel data tag. + * @returns {Tag} + */ + + + get pixelData() { + return this.tags[createTagIdWithTag(TagIds.PixelData)]; + } + /** + * Returns the number of columns. + * @returns {number} + */ + + + get columns() { + return this.getTagValueIndexed(TagIds.Cols); + } + /** + * Returns the number of rows. + * @returns {number} + */ + + + get rows() { + return this.getTagValueIndexed(TagIds.Rows); + } + /** + * Returns the series description. + * @returns {string} + */ + + + get seriesDescription() { + return this.getTagValueIndexed(TagIds.SeriesDescription); + } + /** + * Returns the series instance UID. + * @returns {string} + */ + + + get seriesInstanceUID() { + return this.getTagValueIndexed(TagIds.SeriesInstanceUid); + } + /** + * Returns the series number. + * @returns {number} + */ + + + get seriesNumber() { + return this.getTagValueIndexed(TagIds.SeriesNumber); + } + /** + * Returns the echo number. + * @returns {number} + */ + + + get echoNumber() { + return this.getTagValueIndexed(TagIds.EchoNumber); + } + /** + * Returns the image position. + * @return {number[]} + */ + + + get imagePosition() { + return this.getTagValue(TagIds.ImagePosition); + } + /** + * Returns the image axis directions + * @return {number[]} + */ + + + get imageDirections() { + return this.getTagValue(TagIds.ImageOrientation); + } + /** + * Returns the image position value by index. + * @param {number} sliceDir - the index + * @returns {number} + */ + + + getImagePositionSliceDir(sliceDir) { + const imagePos = this.imagePosition; + + if (imagePos && sliceDir >= 0) { + return imagePos[sliceDir]; + } + + return 0; + } + /** + * Returns the modality + * @returns {string} + */ + + + get modality() { + return this.getTagValueIndexed(TagIds.Modality); + } + /** + * Returns the slice location. + * @returns {number} + */ + + + get sliceLocation() { + return this.getTagValueIndexed(TagIds.SliceLocation); + } + /** + * Returns the slice location vector. + * @returns {number[]} + */ + + + get sliceLocationVector() { + return this.getTagValue(TagIds.SliceLocationVector); + } + /** + * Returns the image number. + * @returns {number} + */ + + + get imageNumber() { + return this.getTagValueIndexed(TagIds.ImageNum); + } + /** + * Returns the temporal position. + * @returns {number} + */ + + + get temporalPosition() { + return this.getTagValueIndexed(TagIds.TemporalPosition); + } + /** + * Returns the temporal number. + * @returns {number} + */ + + + get temporalNumber() { + return this.getTagValueIndexed(TagIds.NumberTemporalPositions); + } + /** + * Returns the slice gap. + * @returns {number} + */ + + + get sliceGap() { + return this.getTagValueIndexed(TagIds.SliceGap); + } + /** + * Returns the slice thickness. + * @returns {number} + */ + + + get sliceThickness() { + return this.getTagValueIndexed(TagIds.SliceThickness); + } + /** + * Returns the image maximum. + * @returns {number} + */ + + + get imageMax() { + return this.getTagValueIndexed(TagIds.ImageMax); + } + /** + * Returns the image minimum. + * @returns {number} + */ + + + get imageMin() { + return this.getTagValueIndexed(TagIds.ImageMin); + } + /** + * Returns the rescale slope. + * @returns {number} + */ + + + get dataScaleSlope() { + return this.getTagValueIndexed(TagIds.DataScaleSlope); + } + /** + * Returns the rescale intercept. + * @returns {number} + */ + + + get dataScaleIntercept() { + return this.getTagValueIndexed(TagIds.DataScaleIntercept); + } + + get dataScaleElscint() { + let scale = this.getTagValueIndexed(TagIds.DataScaleElscint) || 1; + const bandwidth = this.pixelBandwidth; + scale = Math.sqrt(bandwidth) / (10 * scale); + + if (scale <= 0) { + scale = 1; + } + + return scale; + } + /** + * Returns the window width (from top level as frame data can have these values) + * @returns {number} + */ + + + get windowWidth() { + var _this$getTopLevelTag; + + const tagVal = (_this$getTopLevelTag = this.getTopLevelTag(TagIds.WindowWidth)) === null || _this$getTopLevelTag === void 0 ? void 0 : _this$getTopLevelTag.value; + return tagVal === null || tagVal === void 0 ? void 0 : tagVal[0]; + } + /** + * Returns the window center (from top level as frame data can have these values) + * @returns {number} + */ + + + get windowCenter() { + var _this$getTopLevelTag2; + + const tagVal = (_this$getTopLevelTag2 = this.getTopLevelTag(TagIds.WindowCenter)) === null || _this$getTopLevelTag2 === void 0 ? void 0 : _this$getTopLevelTag2.value; + return tagVal === null || tagVal === void 0 ? void 0 : tagVal[0]; + } + + get pixelBandwidth() { + return this.getTagValueIndexed(TagIds.PixelBandwidth); + } + + get seriesId() { + const ids = [this.seriesDescription, this.seriesInstanceUID, this.seriesNumber, this.echoNumber, this.orientation].filter(id => id != null); // remove nulls + + const { + columns, + rows + } = this; + return `${ids.join(",")} (${columns} x ${rows})`; + } + /** + * Returns the pixel spacing. + * @returns {number[]} + */ + + + get pixelSpacing() { + return this.getTagValue(TagIds.PixelSpacing); + } + /** + * Returns the image type. + * @returns {string[]} + */ + + + get imageType() { + return this.getTagValue(TagIds.ImageType); + } + /** + * Returns the number of bits stored. + * @returns {number} + */ + + + get bitsStored() { + return this.getTagValueIndexed(TagIds.BitsStored); + } + /** + * Returns the number of bits allocated. + * @returns {number} + */ + + + get bitsAllocated() { + return this.getTagValueIndexed(TagIds.BitsAllocated); + } + /** + * Returns the frame time. + * @returns {number} + */ + + + getFrameTime() { + return this.getTagValueIndexed(TagIds.FrameTime); + } + /** + * Returns the acquisition matrix (e.g., "mosaic" data). + * @returns {number[]} + */ + + + getAcquisitionMatrix() { + var _this$privateDataAll; + + const mat = [0, 0]; + mat[0] = this.getTagValueIndexed(TagIds.AcquisitionMatrix); + + if (this.privateDataAll === null) { + this.privateDataAll = this.allInterpretedPrivateData; + } + + if (((_this$privateDataAll = this.privateDataAll) === null || _this$privateDataAll === void 0 ? void 0 : _this$privateDataAll.length) > 0) { + const start = this.privateDataAll.indexOf("AcquisitionMatrixText"); + + if (start !== -1) { + const end = this.privateDataAll.indexOf("\n", start); + + if (end !== -1) { + var _matPrivate$length; + + const str = this.privateDataAll.substring(start, end); + const matPrivate = str.match(/\d+/g); + + if ((_matPrivate$length = matPrivate === null || matPrivate === void 0 ? void 0 : matPrivate.length) !== null && _matPrivate$length !== void 0 ? _matPrivate$length : 0 >= 1) { + mat[0] = parseFloat(matPrivate[0]); + + if ((matPrivate === null || matPrivate === void 0 ? void 0 : matPrivate.length) === 2) { + mat[1] = parseFloat(matPrivate[1]); + } + } + } + } + } + + if (mat[1] === 0) { + [mat[1]] = mat; + } + + return mat; + } + /** + * Returns the TR. + * @returns {number} + */ + + + getTR() { + return this.getTagValueIndexed(TagIds.Tr); + } + + putTag(tag) { + this.tags[tag.id] = tag; + this.putFlattenedTag(this.tagsFlat, tag); + } + + putFlattenedTag(tags, tag) { + if (tag.sublist) { + const value = tag.value; + + for (let ctr = 0; ctr < value.length; ctr += 1) { + this.putFlattenedTag(tags, value[ctr]); + } + } else if (!tags[tag.id]) { + // eslint-disable-next-line no-param-reassign + tags[tag.id] = tag; + } + } + /** + * Returns true if pixel data is found. + * @returns {boolean} + */ + + + hasPixelData() { + return this.tags[createTagIdWithTag(TagIds.PixelData)] !== undefined; + } + /** + * Returns an orientation string (e.g., XYZ+--). + * @returns {string} + */ + + + get orientation() { + let orientation = null; + const dirCos = this.getTagValue(TagIds.ImageOrientation); + let bigRow = 0; + let bigCol = 0; + + if ((dirCos === null || dirCos === void 0 ? void 0 : dirCos.length) !== 6) { + return null; + } + + const spacing = this.pixelSpacing; + + if (!spacing) { + return null; + } + + const [rowSpacing] = spacing; + let biggest = 0; + let ctr = 0; + + for (; ctr < 3; ctr += 1) { + if (Math.abs(dirCos[ctr]) > biggest) { + biggest = Math.abs(dirCos[ctr]); + bigRow = ctr; + } + } + + biggest = 0; + + for (; ctr < 6; ctr += 1) { + if (Math.abs(dirCos[ctr]) > biggest) { + biggest = Math.abs(dirCos[ctr]); + bigCol = ctr; + } + } + + let orient = ""; + + switch (bigRow) { + case 0: + orient += "X"; + + if (bigCol === 4) { + orient += "YZ"; + } else { + orient += "ZY"; + } + + break; + + case 1: + orient += "Y"; + + if (bigCol === 3) { + orient += "XZ"; + } else { + orient += "ZX"; + } + + break; + + case 2: + orient += "Z"; + + if (bigCol === 3) { + orient += "XY"; + } else { + orient += "YX"; + } + + break; + } + + switch (bigRow) { + case 0: + if (dirCos[bigRow] > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + + if (bigCol === 4) { + if (dirCos[bigCol] > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + } else if (dirCos[bigCol] > 0.0) { + orient += "+"; + } else { + orient += "-"; + } + + break; + + case 1: + if (dirCos[bigRow] > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + + if (bigCol === 3) { + if (dirCos[bigCol] > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + } else if (dirCos[bigCol] > 0.0) { + orient += "+"; + } else { + orient += "-"; + } + + break; + + case 2: + if (dirCos[bigRow] > 0.0) { + orient += "+"; + } else { + orient += "-"; + } // Has to be X or Y so opposite senses + + + if (dirCos[bigCol] > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + + break; + } + + if (rowSpacing === 0.0) { + orient += "+"; + orientation = orient; + } else { + { + switch (orient.charAt(2)) { + case "X": + if (rowSpacing > 0.0) { + orient += "-"; + } else { + orient += "+"; + } + + break; + + case "Y": + case "Z": + if (rowSpacing > 0.0) { + orient += "+"; + } else { + orient += "-"; + } + + break; + } + } + orientation = orient; + } + + return orientation; + } + /** + * Returns true if this image is "mosaic". + * @returns {boolean} + */ + + + isMosaic() { + const { + imageType + } = this; + let labeledAsMosaic = false; + + if (imageType !== null) { + for (let ctr = 0; ctr < imageType.length; ctr += 1) { + if (imageType[ctr].toUpperCase().indexOf("MOSAIC") !== -1) { + labeledAsMosaic = true; + break; + } + } + } + + if (!labeledAsMosaic) { + return false; + } + + const [matHeight, matWidth] = this.getAcquisitionMatrix(); + const canReadAsMosaic = matHeight > 0 && (matHeight < this.rows || matWidth < this.columns); + return canReadAsMosaic; + } + /** + * Returns true if this image uses palette colors. + * @returns {boolean} + */ + + + isPalette() { + const value = this.getTagValueIndexed(TagIds.PhotometricInterpretation); + return value != null && value.toLowerCase().indexOf("palette") !== -1; + } + + get mosaicCols() { + return this.columns / this.getAcquisitionMatrix()[1]; + } + + get mosaicRows() { + return this.rows / this.getAcquisitionMatrix()[0]; + } + + isElscint() { + const tag = this.getTag(TagIds.DataScaleElscint); + return tag !== undefined; + } + /** + * Returns true if this image stores compressed data. + * @returns {boolean} + */ + + + isCompressed() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpeg) !== -1) { + return true; + } + + if (transferSyntax.indexOf(TransferSyntax.CompressionRLE) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true if this image stores JPEG data. + * @returns {boolean} + */ + + + isCompressedJPEG() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpeg) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true of this image stores lossless JPEG data. + * @returns {boolean} + */ + + + isCompressedJPEGLossless() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpegLossless) !== -1 || transferSyntax.indexOf(TransferSyntax.CompressionJpegLosslessSel1) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true if this image stores baseline JPEG data. + * @returns {boolean} + */ + + + isCompressedJPEGBaseline() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpegBaseline8bit) !== -1 || transferSyntax.indexOf(TransferSyntax.CompressionJpegBaseline12bit) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true if this image stores JPEG2000 data. + * @returns {boolean} + */ + + + isCompressedJPEG2000() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpeg2000) !== -1 || transferSyntax.indexOf(TransferSyntax.CompressionJpeg2000Lossless) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true if this image stores JPEG-LS data. + * @returns {boolean} + */ + + + isCompressedJPEGLS() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionJpegLs) !== -1 || transferSyntax.indexOf(TransferSyntax.CompressionJpegLsLossless) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns true if this image stores RLE data. + * @returns {boolean} + */ + + + isCompressedRLE() { + const { + transferSyntax + } = this; + + if (transferSyntax) { + if (transferSyntax.indexOf(TransferSyntax.CompressionRLE) !== -1) { + return true; + } + } + + return false; + } + /** + * Returns the number of frames. + * @returns {number} + */ + + + get numberOfFrames() { + const value = this.getTagValueIndexed(TagIds.NumberOfFrames); + return value !== null && value !== void 0 ? value : 1; + } + /** + * Returns the number of samples per pixel. + * @returns {number} + */ + + + get samplesPerPixel() { + const value = this.getTagValueIndexed(TagIds.SamplesPerPixel); + return value !== null && value !== void 0 ? value : 1; + } + + getNumberOfImplicitFrames() { + if (this.isCompressed()) { + return 1; + } + + const { + pixelData + } = this; + const length = pixelData.offsetEnd - pixelData.offsetValue; + const size = this.columns * this.rows * Math.round(this.bitsAllocated / 8); + return Math.floor(length / size); + } + /** + * Returns the pixel representation. + * @returns {PixelRepresentation} + */ + + + get pixelRepresentation() { + return this.getTagValueIndexed(TagIds.PixelRepresentation); + } + /** + * Returns the pixel padding value + * @returns {PixelPaddingValue} + */ + + + get pixelPaddingValue() { + return this.getTagValueIndexed(TagIds.PixelPaddingValue); + } + /** + * Returns the photometric interpretation. + * @returns {string} + */ + + + get photometricInterpretation() { + return this.getTagValueIndexed(TagIds.PhotometricInterpretation); + } + /** + * Returns the patient name. + * @returns {string} + */ + + + get patientName() { + return this.getTagValueIndexed(TagIds.PatientName); + } + /** + * Returns the patient ID. + * @returns {string} + */ + + + get patientID() { + return this.getTagValueIndexed(TagIds.PatientId); + } + /** + * Returns the study time. + * @returns {string} + */ + + + get studyTime() { + return this.getTagValueIndexed(TagIds.StudyTime); + } + /** + * Returns the transfer syntax. + * @returns {string} + */ + + + get transferSyntax() { + return this.getTagValueIndexed(TagIds.TransferSyntax); + } + /** + * Sets the tranfer syntax - so we can override it + */ + + + set transferSyntax(syntax) { + this.getTag(TagIds.TransferSyntax).convertedValue = syntax; + } + /** + * Returns the study date. + * @returns {string} + */ + + + get studyDate() { + return this.getTagValueIndexed(TagIds.StudyDate); + } + /** + * Returns the planar configuration. + * @returns {number} + */ + + + get planarConfig() { + return this.getTagValueIndexed(TagIds.PlanarConfig); + } + /** + * Returns all descriptive info for this image. + * @returns {string} + */ + + + get imageDescription() { + const values = [this.getTagValueIndexed(TagIds.StudyDes), this.getTagValueIndexed(TagIds.SeriesDescription), this.getTagValueIndexed(TagIds.ImageComments)].filter(el => el !== null); + return values.join(" ").trim(); + } + /** + * Returns the datatype (e.g., ByteType.integerUnsigned). + * @returns {number} + */ + + + get dataType() { + var _this$photometricInte; + + const dataType = this.pixelRepresentation; + + if (dataType === null) { + return ByteType.Unkown; + } + + const interp = ((_this$photometricInte = this.photometricInterpretation) === null || _this$photometricInte === void 0 ? void 0 : _this$photometricInte.trim()) || null; + + if (interp && (interp.indexOf("RGB") !== -1 || interp.indexOf("YBR") !== -1 || interp.toLowerCase().indexOf("palette") !== -1)) { + return ByteType.Rgb; + } + + if (dataType === 0) { + return ByteType.IntegerUnsigned; + } + + if (dataType === 1) { + return ByteType.Integer; + } + + return ByteType.Unkown; + } // originally from: http://public.kitware.com/pipermail/insight-users/2005-March/012246.html + + + get acquiredSliceDirection() { + const dirCos = this.getTagValue(TagIds.ImageOrientation); + + if ((dirCos === null || dirCos === void 0 ? void 0 : dirCos.length) !== 6) { + return SliceDirection.Unknown; + } + + const rowAxis = getMajorAxisFromPatientRelativeDirectionCosine(dirCos[0], dirCos[1], dirCos[2]); + const colAxis = getMajorAxisFromPatientRelativeDirectionCosine(dirCos[3], dirCos[4], dirCos[5]); + + if (rowAxis !== null && colAxis !== null) { + if ((rowAxis === "R" || rowAxis === "L") && (colAxis === "A" || colAxis === "P")) { + return SliceDirection.Axial; + } + + if ((colAxis === "R" || colAxis === "L") && (rowAxis === "A" || rowAxis === "P")) { + return SliceDirection.Axial; + } + + if ((rowAxis === "R" || rowAxis === "L") && (colAxis === "H" || colAxis === "F")) { + return SliceDirection.Coronal; + } + + if ((colAxis === "R" || colAxis === "L") && (rowAxis === "H" || rowAxis === "F")) { + return SliceDirection.Coronal; + } + + if ((rowAxis === "A" || rowAxis === "P") && (colAxis === "H" || colAxis === "F")) { + return SliceDirection.Sagittal; + } + + if ((colAxis === "A" || colAxis === "P") && (rowAxis === "H" || rowAxis === "F")) { + return SliceDirection.Sagittal; + } + } + + return SliceDirection.Oblique; + } + /** + * Returns a string of interpreted private data. + * @returns {string} + */ + + + get allInterpretedPrivateData() { + let str = ""; + const sortedKeys = Object.keys(this.tags).sort(); + + for (let ctr = 0; ctr < sortedKeys.length; ctr += 1) { + const key = sortedKeys[ctr]; // eslint-disable-next-line no-prototype-builtins + + if (this.tags.hasOwnProperty(key)) { + const tag = this.tags[key]; + + if (tag.hasInterpretedPrivateData()) { + str += tag.value; + } + } + } + + return str; + } + /** + * Returns a string representation of this image. + * @returns {string} + */ + + + toString() { + let str = ""; + const sortedKeys = Object.keys(this.tags).sort(); + + for (let ctr = 0; ctr < sortedKeys.length; ctr += 1) { + const key = sortedKeys[ctr]; + const tag = this.tags[key]; + + if (tag) { + str += `${tag.toHTMLString()}
`; + } + } + + str = str.replace(/\n\s*\n/g, "\n"); // replace mutli-newlines with single newline + + str = str.replace(/(?:\r\n|\r|\n)/g, "
"); // replace newlines with
+ + return str; + } + +} + +DCMImage.skipPaletteConversion = false; +/* eslint no-use-before-define: ["error", { "classes": false }] */ + +const MAGIC_COOKIE_OFFSET = 128; +const MAGIC_COOKIE = [68, 73, 67, 77]; +/** + * Returns true if the DICOM magic cookie is found. + * @param {DataView} data + * @returns {boolean} + */ + +const isMagicCookieFound = data => { + const offset = MAGIC_COOKIE_OFFSET; + const magicCookieLength = MAGIC_COOKIE.length; + + for (let ctr = 0; ctr < magicCookieLength; ctr += 1) { + if (data.getUint8(offset + ctr) !== MAGIC_COOKIE[ctr]) { + return false; + } + } + + return true; +}; + +const findFirstTagOffset = data => { + const magicCookieLength = MAGIC_COOKIE.length; + + if (isMagicCookieFound(data)) { + return MAGIC_COOKIE_OFFSET + magicCookieLength; + } + + const searchOffsetMax = MAGIC_COOKIE_OFFSET * 5; + let found = false; + let offset = 0; + + for (let ctr = 0; ctr < searchOffsetMax; ctr += 1) { + const ch = data.getUint8(ctr); + + if (ch === MAGIC_COOKIE[0]) { + found = true; + + for (let ctrIn = 1; ctrIn < magicCookieLength; ctrIn += 1) { + if (data.getUint8(ctr + ctrIn) !== MAGIC_COOKIE[ctrIn]) { + found = false; + } + } + + if (found) { + offset = ctr + magicCookieLength; + break; + } + } + } + + return offset; +}; +/** + * Parser class + */ + + +class Parser { + constructor() { + this.littleEndian = true; + this.explicit = true; + this.metaExplicit = true; + this.metaFound = false; + this.metaFinished = false; + this.metaFinishedOffset = -1; + this.needsDeflate = false; + this.inflated = null; + this.encapsulation = false; + this.level = 0; + this.error = null; + this.charset = null; + } + /** + * Parses this data and returns an image object. + * @param {DataView} data + * @returns {Image|null} + */ + + + parse(dataIn) { + let image = null; + let data = dataIn; + + try { + image = new DCMImage(); + const offset = findFirstTagOffset(data); + let tag = this.getNextTag(data, offset); + + while (tag !== null) { + if (Parser.verbose) { + console.log(tag.toString()); + } + + image.putTag(tag); + + if (tag.is(TagIds.PixelData)) { + break; + } + + if (this.needsDeflate && tag.offsetEnd >= this.metaFinishedOffset) { + this.needsDeflate = false; + const copyMeta = data.buffer.slice(0, tag.offsetEnd); + const copyDeflated = data.buffer.slice(tag.offsetEnd); + this.inflated = concatArrayBuffers(copyMeta, _pako.default.inflateRaw(copyDeflated)); + data = new DataView(this.inflated); + } + + tag = this.getNextTag(data, tag.offsetEnd); + } + } catch (err) { + this.error = err; + } + + if (image !== null) { + // set cached tags + image.littleEndian = this.littleEndian; + } + + return image; + } + + parseEncapsulated(data) { + this.encapsulation = true; + const tags = []; + + try { + let tag = this.getNextTag(data, 0); + + while (tag !== null) { + if (tag.is(TagIds.SublistItem)) { + tags.push(tag); + } + + if (Parser.verbose) { + console.log(tag.toString()); + } + + tag = this.getNextTag(data, tag.offsetEnd); + } + } catch (err) { + this.error = err; + } + + return tags; + } + + testForValidTag(data) { + let tag = null; + + try { + const offset = findFirstTagOffset(data); + tag = this.getNextTag(data, offset, false); + } catch (err) { + this.error = err; + } + + return tag; + } + + getNextTag(data, offsetStart, testForTag = false) { + let group = 0; + let value = null; + let offset = offsetStart; + let length = 0; + let little = true; + let vr = null; + + if (offset >= data.byteLength) { + return null; + } + + if (this.metaFinished) { + little = this.littleEndian; + group = data.getUint16(offset, little); + } else { + group = data.getUint16(offset, true); + + if (this.metaFinishedOffset !== -1 && offset >= this.metaFinishedOffset || group !== 0x0002) { + this.metaFinished = true; + little = this.littleEndian; + group = data.getUint16(offset, little); + } + } + + if (!this.metaFound && group === 0x0002) { + this.metaFound = true; + } + + offset += 2; + const element = data.getUint16(offset, little); + offset += 2; + let useImplicitVR = true; + + if (this.explicit && this.metaFinished || this.metaExplicit && !this.metaFinished) { + vr = String.fromCharCode(data.getUint8(offset)) + String.fromCharCode(data.getUint8(offset + 1)); + const foundVR = Parser.VRS.indexOf(vr) !== -1; + + if (!foundVR && (!this.metaFound && this.metaFinished || this.metaFound && !this.metaFinished)) { + if (this.metaFinished) { + this.explicit = false; + } else { + this.metaExplicit = false; + } + } else { + offset += 2; + + if (Parser.DATA_VRS.indexOf(vr) !== -1) { + offset += 2; // skip two empty bytes + + length = data.getUint32(offset, little); + offset += 4; + } else { + length = data.getUint16(offset, little); + offset += 2; + } + + useImplicitVR = false; + } + } + + if (useImplicitVR) { + vr = Dictionary.getVR(group, element); + length = data.getUint32(offset, little); + + if (length === Parser.UNDEFINED_LENGTH) { + vr = "SQ"; + } + + offset += 4; + } + + const offsetValue = offset; + const isPixelData = Tag.isEqual({ + group, + element + }, TagIds.PixelData); + + if (vr === "SQ" || this.level > 0 && Parser.DATA_VRS.indexOf(vr) !== -1) { + value = this.parseSublist(data, offset, length, vr !== "SQ"); + + if (length === Parser.UNDEFINED_LENGTH) { + const _tag = value[value.length - 1]; + length = _tag.offsetEnd - offset; + } + } else if (length > 0 && !testForTag) { + if (length === Parser.UNDEFINED_LENGTH) { + if (isPixelData) { + length = data.byteLength - offset; + } + } + + if (length > 0) { + value = new DataView(data.buffer, data.byteOffset + offset, length); + } + } + + offset += length; + const tag = new Tag({ + group, + element, + vr, + value, + offsetStart, + offsetValue, + offsetEnd: offset, + littleEndian: little, + charset: this.charset + }); + + if (tag.hasValue()) { + if (tag.is(TagIds.TransferSyntax)) { + const [val] = tag.value; + this.explicit = true; + this.littleEndian = true; + + if (val === TransferSyntax.ImplicitLittle) { + this.explicit = false; + } else if (val === TransferSyntax.ExplicitBig) { + this.littleEndian = false; + } else if (val === TransferSyntax.CompressionDeflate) { + this.needsDeflate = true; + } + } else if (tag.is(TagIds.MetaLength)) { + const [val] = tag.value; + this.metaFinishedOffset = val + offset; + } else if (tag.is(TagIds.Charset)) { + const charsetValue = tag.value; + let charset = DefaultCharset; + + if (charsetValue.length === 2) { + charset = `${charsetValue[0] || DefaultCharset}\\${charsetValue[1]}`; + } else if (charsetValue.length === 1) { + [charset] = charsetValue; + } + + this.charset = charset; + } + } + + return tag; + } + + parseSublist(data, offsetStart, length, raw) { + const tags = []; + let offset = offsetStart; + const offsetEnd = offsetStart + length; + this.level += 1; + + if (length === Parser.UNDEFINED_LENGTH) { + let sublistItem = this.parseSublistItem(data, offset, raw); + + while (!sublistItem.is(TagIds.SequenceDelim)) { + tags.push(sublistItem); + offset = sublistItem.offsetEnd || 0; + sublistItem = this.parseSublistItem(data, offset, raw); + } + + tags.push(sublistItem); + } else { + while (offset < offsetEnd) { + const sublistItem = this.parseSublistItem(data, offset, raw); + tags.push(sublistItem); + offset = sublistItem.offsetEnd || 0; + } + } + + this.level -= 1; + return tags; + } + + parseSublistItem(data, offsetStart, raw) { + var _value; + + let offset = offsetStart; + let value = null; + const tags = []; + const group = data.getUint16(offset, this.littleEndian); + offset += 2; + const element = data.getUint16(offset, this.littleEndian); + offset += 2; + let length = data.getUint32(offset, this.littleEndian); + offset += 4; + const offsetValue = offset; + + if (length === Parser.UNDEFINED_LENGTH) { + let tag = this.getNextTag(data, offset); + + while (!tag.is(TagIds.SublistItemDelim)) { + tags.push(tag); + offset = tag.offsetEnd; + tag = this.getNextTag(data, offset); + } + + tags.push(tag); + offset = tag.offsetEnd; + } else if (raw) { + length = Math.min(data.byteLength - offset - data.byteOffset, length); + value = new DataView(data.buffer, offset + data.byteOffset, length); + offset += length; + } else { + const offsetEnd = offset + length; + let tag; + + while (offset < offsetEnd) { + tag = this.getNextTag(data, offset); + tags.push(tag); + offset = tag.offsetEnd; + } + } + + const sublistItemTag = new Tag({ + group, + element, + value: (_value = value) !== null && _value !== void 0 ? _value : tags, + offsetStart, + offsetValue, + offsetEnd: offset, + littleEndian: this.littleEndian + }); + return sublistItemTag; + } + + hasError() { + return this.error !== null; + } + +} + +exports.Parser = Parser; +Parser.verbose = false; +Parser.VRS = ["AE", "AS", "AT", "CS", "DA", "DS", "DT", "FL", "FD", "IS", "LO", "LT", "OB", "OD", "OF", "OW", "PN", "SH", "SL", "SS", "ST", "TM", "UI", "UL", "UN", "US", "UT"]; +Parser.DATA_VRS = ["OB", "OW", "OF", "SQ", "UT", "UN"]; +Parser.RAW_DATA_VRS = ["OB", "OD", "OF", "OW", "UN"]; +Parser.UNDEFINED_LENGTH = 0xFFFFFFFF; + +class OrderedMapIterator { + constructor(orderedMap) { + this.orderedMap = void 0; + this.index = void 0; + this.orderedMap = orderedMap; + this.index = 0; + } + + hasNext() { + return this.index < this.orderedMap.orderedKeys.length; + } + + next() { + const item = this.orderedMap.get(this.orderedMap.orderedKeys[this.index]); + this.index += 1; + return item; + } + + length() { + return this.orderedMap.orderedKeys.length; + } + +} // Based on: http://stackoverflow.com/questions/3549894/javascript-data-structure-for-fast-lookup-and-ordered-looping + + +class OrderedMap { + constructor() { + this.orderedKeys = []; + this.map = new Map(); + this.index = 0; + } // bit of a hack - necessary for Series + + + put(key, value) { + if (!this.map.get(key)) { + // insert new key and value + this.orderedKeys.push(key); + this.orderedKeys.sort((a, b) => parseFloat(a) - parseFloat(b)); + } + + this.map.set(key, value); + } + + remove(key) { + const index = this.orderedKeys.indexOf(key); + + if (index === -1) { + throw new Error("key does not exist"); + } + + this.orderedKeys.splice(index, 1); + this.map.delete(key); + } + + get(key) { + return this.map.get(key); + } + + iterator() { + return new OrderedMapIterator(this); + } + + getOrderedValues() { + const it = this.iterator(); + const orderedValues = Array(it.length()); + + while (it.hasNext()) { + orderedValues.push(it.next()); + } + + return orderedValues; + } + +} + +const getMosaicOffset = (mosaicCols, mosaicColWidth, mosaicRowHeight, mosaicWidth, xLocVal, yLocVal, zLocVal) => { + let xLoc = xLocVal; + let yLoc = yLocVal; + const zLoc = zLocVal; + xLoc = zLoc % mosaicCols * mosaicColWidth + xLoc; + yLoc = (Math.floor(zLoc / mosaicCols) * mosaicRowHeight + yLoc) * mosaicWidth; + return xLoc + yLoc; +}; + +const orderByImagePosition = (images, sliceDir) => { + const dicomMap = new OrderedMap(); + + for (let ctr = 0; ctr < images.length; ctr += 1) { + dicomMap.put(images[ctr].getImagePositionSliceDir(sliceDir), images[ctr]); + } + + return dicomMap.getOrderedValues(); +}; + +const orderBySliceLocation = images => { + const dicomMap = new OrderedMap(); + + for (let ctr = 0; ctr < images.length; ctr += 1) { + dicomMap.put(images[ctr].sliceLocation, images[ctr]); + } + + return dicomMap.getOrderedValues(); +}; + +const orderByImageNumber = images => { + const dicomMap = new OrderedMap(); + + for (let ctr = 0; ctr < images.length; ctr += 1) { + dicomMap.put(images[ctr].imageNumber, images[ctr]); + } + + return dicomMap.getOrderedValues(); +}; + +const hasMatchingSlice = (dg, image, sliceDir, doImagePos, doSliceLoc) => { + let matchingNum = 0; + + if (doImagePos) { + matchingNum = image.getImagePositionSliceDir(sliceDir); + } else if (doSliceLoc) { + matchingNum = image.sliceLocation; + } else { + matchingNum = image.imageNumber; + } + + for (let ctr = 0; ctr < dg.length; ctr += 1) { + const current = dg[ctr]; + + if (doImagePos) { + const imagePos = current.getImagePositionSliceDir(sliceDir); + + if (imagePos === matchingNum) { + return true; + } + } else if (doSliceLoc) { + const sliceLoc = current.sliceLocation; + + if (sliceLoc === matchingNum) { + return true; + } + } else { + const imageNum = current.imageNumber; + + if (imageNum === matchingNum) { + return true; + } + } + } + + return false; +}; + +const orderByTime = (images, numFrames, sliceDir, hasImagePosition, hasSliceLocation) => { + const dicomMap = new OrderedMap(); + const hasTemporalPosition = numFrames > 1 && images[0].temporalPosition !== null; + const hasTemporalNumber = numFrames > 1 && images[0].temporalNumber !== null && images[0].temporalNumber === numFrames; + + if (hasTemporalPosition && hasTemporalNumber) { + // explicit series + for (let ctr = 0; ctr < images.length; ctr += 1) { + const image = images[ctr]; + const tempPos = image.temporalPosition; + let dg = dicomMap.get(tempPos); + + if (!dg) { + dg = []; + dicomMap.put(tempPos, dg); + } + + dg.push(image); + } + } else { + // implicit series + // order data by slice then time + const timeBySliceMap = new OrderedMap(); + + for (let ctr = 0; ctr < images.length; ctr += 1) { + if (images[ctr] !== null) { + let sliceMarker = ctr; + + if (hasImagePosition) { + sliceMarker = images[ctr].getImagePositionSliceDir(sliceDir); + } else if (hasSliceLocation) { + sliceMarker = images[ctr].sliceLocation; + } + + let slice = timeBySliceMap.get(sliceMarker); + + if (slice === null) { + slice = new OrderedMap(); + timeBySliceMap.put(sliceMarker, slice); + } + + slice.put(ctr, images[ctr]); + } + } // copy into DICOM array (ordered by slice by time) + + + const dicomsCopy = []; + let dicomsCopyIndex = 0; + const sliceIt = timeBySliceMap.iterator(); + + while (sliceIt.hasNext()) { + const slice = sliceIt.next(); + const timeIt = slice.iterator(); + + while (timeIt.hasNext()) { + dicomsCopy[dicomsCopyIndex] = timeIt.next(); + dicomsCopyIndex += 1; + } + } // groups dicoms by timepoint + + + for (let ctr = 0; ctr < dicomsCopy.length; ctr += 1) { + if (dicomsCopy[ctr] !== null) { + let dgFound; + const it = dicomMap.iterator(); + + while (it.hasNext()) { + const dg = it.next(); + + if (!hasMatchingSlice(dg, dicomsCopy[ctr], sliceDir, hasImagePosition, hasSliceLocation)) { + dgFound = dg; + break; + } + } + + if (dgFound === null) { + dgFound = []; + dicomMap.put(dicomMap.orderedKeys.length, dgFound); + } + + dgFound.push(dicomsCopy[ctr]); + } + } + } + + return dicomMap; +}; + +const orderDicoms = (images, numFrames, sliceDir) => { + const hasImagePosition = images[0].imagePosition !== null; + const hasSliceLocation = images[0].sliceLocation !== null; + const hasImageNumber = images[0].imageNumber !== null; + const timeMap = orderByTime(images, numFrames, sliceDir, hasImagePosition, hasSliceLocation); + const timeIt = timeMap.orderedKeys; + const imagesOrderedByTimeAndSpace = []; + + for (let ctr = 0; ctr < timeIt.length; ctr += 1) { + const dg = timeMap.get(timeIt[ctr]); + let ordered; + + if (hasImagePosition) { + ordered = orderByImagePosition(dg, sliceDir); + } else if (hasSliceLocation) { + ordered = orderBySliceLocation(dg); + } else if (hasImageNumber) { + ordered = orderByImageNumber(dg); + } else { + ordered = dg; + } + + for (let ctrIn = 0; ctrIn < ordered.length; ctrIn += 1) { + imagesOrderedByTimeAndSpace.push(ordered[ctrIn]); + } + } + + for (let ctrIn = 0; ctrIn < imagesOrderedByTimeAndSpace.length; ctrIn += 1) { + imagesOrderedByTimeAndSpace[ctrIn].index = ctrIn; + } + + return imagesOrderedByTimeAndSpace; +}; +/** + * The Series constructor. + * @property {DCMImage[]} images + * @type {Function} + */ + + +class Series { + constructor() { + this.images = []; + this.imagesOriginalOrder = null; + this.isMosaic = false; + this.isElscint = false; + this.isCompressed = false; + this.numberOfFrames = 0; + this.numberOfFramesInFile = 0; + this.isMultiFrame = false; + this.isMultiFrameVolume = false; + this.isMultiFrameTimeseries = false; + this.isImplicitTimeseries = false; + this.sliceSense = false; + this.sliceDir = SliceDirection.Unknown; + this.error = null; + } + + getOrder() { + const order = []; + + for (let ctr = 0; ctr < this.imagesOriginalOrder.length; ctr += 1) { + order[ctr] = this.imagesOriginalOrder[ctr].index; + } + + return order; + } + /** + * Returns the series ID. + * @returns {string} + */ + + + toString() { + return this.images[0].seriesId; + } + /** + * Returns a nice name for the series. + * @returns {string|null} + */ + + + getName() { + const des = this.images[0].seriesDescription; + const uid = this.images[0].seriesInstanceUID; + + if (des !== null) { + return des; + } + + if (uid !== null) { + return uid; + } + + return null; + } + /** + * Adds an image to the series. + * @param {DCMImage} image + */ + + + addImage(image) { + this.images.push(image); + } + /** + * Returns true if the specified image is part of the series + * (or if no images are yet part of the series). + * @param {DCMImage} image + * @returns {boolean} + */ + + + matchesSeries(image) { + if (this.images.length === 0) { + return true; + } + + return this.images[0].seriesId === image.seriesId; + } + /** + * Orders and organizes the images in this series. + */ + + + buildSeries() { + const [image0] = this.images; + this.isMosaic = image0.isMosaic(); + this.isElscint = image0.isElscint(); + this.isCompressed = image0.isCompressed(); // check for multi-frame + + this.numberOfFrames = image0.numberOfFrames; + this.numberOfFramesInFile = image0.getNumberOfImplicitFrames(); + this.isMultiFrame = this.numberOfFrames > 1 || this.isMosaic && image0.mosaicCols * image0.mosaicRows > 1; + this.isMultiFrameVolume = false; + this.isMultiFrameTimeseries = false; + this.isImplicitTimeseries = false; + + if (this.isMultiFrame) { + const hasFrameTime = image0.getFrameTime() > 0; + + if (this.isMosaic) { + this.isMultiFrameTimeseries = true; + } else if (hasFrameTime) { + this.isMultiFrameTimeseries = true; + } else if (this.numberOfFramesInFile > 1) { + this.isMultiFrameTimeseries = true; + this.numberOfFrames = this.images.length; + } else { + this.isMultiFrameVolume = true; + } + } + + if (!this.isMosaic && this.numberOfFrames <= 1) { + // check for implicit frame count + let imagePos = image0.imagePosition || []; + const sliceLoc = imagePos.toString(); + this.numberOfFrames = 0; + + for (let ctr = 0; ctr < this.images.length; ctr += 1) { + imagePos = this.images[ctr].imagePosition || []; + + if (imagePos.toString() === sliceLoc) { + this.numberOfFrames += 1; + } + } + + if (this.numberOfFrames > 1) { + this.isImplicitTimeseries = true; + } + } + + this.sliceDir = image0.acquiredSliceDirection; + let orderedImages; + + if (Series.useExplicitOrdering) { + orderedImages = this.images.slice(); + } else { + orderedImages = orderDicoms(this.images, this.numberOfFrames, this.sliceDir); + } + + const sliceLocationFirst = orderedImages[0].getImagePositionSliceDir(this.sliceDir); + const sliceLocationLast = orderedImages[orderedImages.length - 1].getImagePositionSliceDir(this.sliceDir); + const sliceLocDiff = sliceLocationLast - sliceLocationFirst; + + if (Series.useExplicitOrdering) { + this.sliceSense = false; + } else if (this.isMosaic) { + this.sliceSense = true; + } else if (this.isMultiFrame) { + const sliceLocations = orderedImages[0].sliceLocationVector; + + if (sliceLocations !== null) { + const { + orientation + } = orderedImages[0]; + + if ((orientation === null || orientation === void 0 ? void 0 : orientation.charAt(2)) === "Z") { + this.sliceSense = sliceLocations[0] - sliceLocations[sliceLocations.length - 1] < 0; + } else { + this.sliceSense = sliceLocations[0] - sliceLocations[sliceLocations.length - 1] > 0; + } + } else { + this.sliceSense = sliceLocationFirst >= 0; + } + } + /* + * "The direction of the axes is defined fully by the patient's orientation. + * The x-axis is increasing to the left hand side of the patient. The + * y-axis is increasing to the posterior side of the patient. + * The z-axis is increasing toward the head of the patient." + */ + else if (this.sliceDir === SliceDirection.Sagittal || this.sliceDir === SliceDirection.Coronal) { + if (sliceLocDiff > 0) { + this.sliceSense = false; + } else { + this.sliceSense = true; + } + } else if (sliceLocDiff > 0) { + this.sliceSense = true; + } else { + this.sliceSense = false; + } + + this.imagesOriginalOrder = this.images; + this.images = orderedImages; + } + + getMosaicData(image, data) { + const [image0] = this.images; + const mosaicWidth = image0.columns; + const mosaicHeight = image0.rows; + const { + mosaicRows, + mosaicCols + } = image0; + const numBytes = image0.bytesAllocated || 1; + const numSlices = mosaicWidth * mosaicHeight; + const numRows = Math.floor(mosaicHeight / mosaicRows); + const numCols = Math.floor(mosaicWidth / mosaicCols); + const mosaicRowHeight = Math.floor(mosaicHeight / mosaicRows); + const mosaicColWidth = Math.floor(mosaicWidth / mosaicCols); + const buffer = new Uint8Array(new ArrayBuffer(numSlices * numRows * numCols * numBytes)); + const dataTyped = new Uint8Array(data); + let index = 0; + + for (let ctrS = 0; ctrS < numSlices; ctrS += 1) { + for (let ctrR = 0; ctrR < numRows; ctrR += 1) { + for (let ctrC = 0; ctrC < numCols; ctrC += 1) { + const offset = getMosaicOffset(mosaicCols, mosaicColWidth, mosaicRowHeight, mosaicWidth, ctrC, ctrR, ctrS); + + for (let ctr = 0; ctr < numBytes; ctr += 1) { + buffer[index] = dataTyped[offset * numBytes + ctr]; + index += 1; + } + } + } + } + + return buffer.buffer; + } + +} +/** + * Parses the DICOM header and return an image object. + * @param {DataView|ArrayBuffer} data + * @returns {DCMImage|null} + */ + + +Series.parserError = null; +Series.useExplicitOrdering = false; +Series.useExplicitSpacing = 0; + +const parseImage = data => { + const parser = new Parser(); + let dataView; + + if (data instanceof DataView) { + dataView = data; + } else { + dataView = new DataView(data); + } + + const image = parser.parse(dataView); + + if (parser.hasError()) { + Series.parserError = parser.error; + return null; + } + + if (parser.inflated) { + image.inflated = parser.inflated; + } + + return image; +}; + +exports.parseImage = parseImage; + +const getEncapsulatedData = data => { + const parser = new Parser(); + return parser.parseEncapsulated(data); +}; + +const concatDataViews = dataViews => { + let length = 0; + let offset = 0; + + for (let ctr = 0; ctr < dataViews.length; ctr += 1) { + length += dataViews[ctr].byteLength; + } + + const tmp = new Uint8Array(length); + let dataView; + + for (let ctr = 0; ctr < dataViews.length; ctr += 1) { + dataView = dataViews[ctr]; + tmp.set(new Uint8Array(dataView.buffer, dataView.byteOffset, dataView.byteLength), offset); + offset += dataViews[ctr].byteLength; + } + + return new DataView(tmp.buffer); +}; + +const JPEG_MAGIC_NUMBER = [0xFF, 0xD8]; +const JPEG2000_MAGIC_NUMBER = [0xFF, 0x4F, 0xFF, 0x51]; + +const isHeaderJPEG = data => { + if (!data) { + return false; + } + + if (data.getUint8(0) !== JPEG_MAGIC_NUMBER[0]) { + return false; + } + + if (data.getUint8(1) !== JPEG_MAGIC_NUMBER[1]) { + return false; + } + + return true; +}; + +const isHeaderJPEG2000 = data => { + if (!data) { + return false; + } + + for (let ctr = 0; ctr < JPEG2000_MAGIC_NUMBER.length; ctr += 1) { + if (data.getUint8(ctr) !== JPEG2000_MAGIC_NUMBER[ctr]) { + return false; + } + } + + return true; +}; + +const getJpegData = inData => { + const encapTags = getEncapsulatedData(inData); + const data = []; + const dataConcat = []; + let currentJpeg; // organize data as an array of an array of JPEG parts + + if (encapTags) { + const numTags = encapTags.length; + + for (let ctr = 0; ctr < numTags; ctr += 1) { + const dataView = encapTags[ctr].value; + + if (isHeaderJPEG(dataView) || isHeaderJPEG2000(dataView)) { + currentJpeg = []; + currentJpeg.push(dataView); + data.push(currentJpeg); + } else if (currentJpeg && dataView) { + currentJpeg.push(dataView); + } + } + } // concat into an array of full JPEGs + + + for (let ctr = 0; ctr < data.length; ctr += 1) { + const buffers = data[ctr]; + + if (buffers.length > 1) { + // TODO: this will be slow...is it necessary? + dataConcat[ctr] = concatDataViews(buffers); + } else { + [dataConcat[ctr]] = data[ctr]; + } + + delete data[ctr]; + } + + return dataConcat; +}; + +class RLEDecoder extends Decoder { + constructor(...args) { + super(...args); + this.rleData = null; + } + + decode(frameNo) { + return import('./rle-2b767c29.js').then(RLE => { + const { + image + } = this; + + if (!this.rleData) { + const encapTags = getEncapsulatedData(image.data); + const numTags = (encapTags === null || encapTags === void 0 ? void 0 : encapTags.length) || 0; + const data = new Array(numTags); // the first sublist item contains offsets - ignore + + for (let ctr = 1; ctr < numTags; ctr += 1) { + const dataView = encapTags[ctr].rawValue; + data[ctr - 1] = dataView; + } + + this.rleData = data; // don't decode to planar...just makes render more complex + // RLE input is the same either way + + if (image.planar) { + image.planar = false; + } + } + + const decompressed = RLE.default(image, this.rleData[frameNo]); + return decompressed; + }); + } + +} + +class NativeDecoder extends Decoder { + constructor(image) { + super(image); + this.jpegData = void 0; + this.image.rgb = true; // native img decoder outputs RGB + + this.jpegData = getJpegData(image.data); + } + + createTexture(gl, frameNo) { + var _this$jpegData; + + const { + width, + height + } = this.outputSize; + const jpegFrameData = (_this$jpegData = this.jpegData) === null || _this$jpegData === void 0 ? void 0 : _this$jpegData[frameNo]; + + if (!jpegFrameData) { + throw Error("No Native JPEG image data"); + } + + const blob = new Blob([jpegFrameData]); + const src = URL.createObjectURL(blob); + return new Promise((resolve, reject) => { + twgl.createTexture(gl, { + src, + width, + height, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }, (error, texture) => { + URL.revokeObjectURL(src); + + if (error) { + reject(error); + } + + resolve(texture); + }); + }); + } + +} + +class JPEGLosslessDecoder$2 extends Decoder { + constructor(...args) { + super(...args); + this.jpegs = null; + } + + decode(frameNo) { + var _this$jpegs; + + const { + image + } = this; + + if (!this.jpegs) { + this.jpegs = getJpegData(image.data); + } + + if (!((_this$jpegs = this.jpegs) !== null && _this$jpegs !== void 0 && _this$jpegs.length)) { + return Promise.reject(new Error("No JPEG lossless image data")); + } + + const decoder = new _jpegLosslessDecoderJs.lossless.Decoder(); + const jpeg = this.jpegs[frameNo]; + const buffer = new Uint8Array(jpeg.buffer, jpeg.byteOffset, jpeg.byteLength); + const temp = decoder.decode(buffer); // const numComponents = decoder.numComp; + + return Promise.resolve(temp); + } + +} + +class JPEGLosslessDecoder$1 extends Decoder { + constructor(...args) { + super(...args); + this.jpegs = null; + } + + decode(frameNo) { + var _this$jpegs; + + const { + image + } = this; + + if (!this.jpegs) { + this.jpegs = getJpegData(image.data); + } + + if (!((_this$jpegs = this.jpegs) !== null && _this$jpegs !== void 0 && _this$jpegs.length)) { + return Promise.reject(new Error("No JPEG-LS image data")); + } + + return new Promise(resolve => { + let charLS; + + const init = () => { + const decoder = new charLS.JpegLSDecoder(); + const jpeg = this.jpegs[frameNo]; + const buffer = new Uint8Array(jpeg.buffer, jpeg.byteOffset, jpeg.byteLength); + const encodedBuffer = decoder.getEncodedBuffer(buffer.length); + encodedBuffer.set(buffer); + decoder.decode(); + const decoded = decoder.getDecodedBuffer(); + return resolve(decoded); + }; + + import('./charlsjs-d0f5a366.js').then(CharLS => { + charLS = CharLS.default({ + onRuntimeInitialized: init + }); + }); + }); + } + +} + +class JPEG2000Decoder extends Decoder { + constructor(...args) { + super(...args); + this.jpegs = null; + } + + decode(frameNo) { + var _this$jpegs; + + const { + image + } = this; + + if (!this.jpegs) { + this.jpegs = getJpegData(image.data); + } + + if (!((_this$jpegs = this.jpegs) !== null && _this$jpegs !== void 0 && _this$jpegs.length)) { + return Promise.reject(new Error("No JPEG2000 image data")); + } + + return new Promise(resolve => { + let OJ; + + const init = () => { + const decoder = new OJ.J2KDecoder(); + const jpeg = this.jpegs[frameNo]; + const buffer = new Uint8Array(jpeg.buffer, jpeg.byteOffset, jpeg.byteLength); + const encodedBuffer = decoder.getEncodedBuffer(buffer.length); + encodedBuffer.set(buffer); + const decodeLevel = 0; + const decodeLayer = 0; + + for (let i = 0; i < 1; i += 1) { + decoder.decodeSubResolution(decodeLevel, decodeLayer); + } + + decoder.getFrameInfo(); + const decodedBuffer = decoder.getDecodedBuffer(); + return resolve(decodedBuffer); + }; + + import('./openjpeg-2693517c.js').then(OpenJpegJS => { + OJ = OpenJpegJS.default({ + onRuntimeInitialized: init + }); + }); + }); + } + +} + +class JPEGLosslessDecoder extends Decoder { + constructor(...args) { + super(...args); + this.jpegs = null; + } + + decode(frameNo) { + return import('./jpeg-baseline-81e0d4be.js').then(jpegBaseline => { + var _this$jpegs; + + const { + image + } = this; + + if (!this.jpegs) { + this.jpegs = getJpegData(image.data); + } + + if (!((_this$jpegs = this.jpegs) !== null && _this$jpegs !== void 0 && _this$jpegs.length)) { + return Promise.reject(new Error("No JPEG image data")); + } + + const decoder = new jpegBaseline.JpegImage(); + const jpeg = this.jpegs[frameNo]; + const buffer = new Uint8Array(jpeg.buffer, jpeg.byteOffset, jpeg.byteLength); + decoder.parse(buffer); + const { + width, + height + } = decoder; + let decoded = null; + + if (image.bitsAllocated === 8) { + decoded = decoder.getData(width, height); + } else { + decoded = decoder.getData16(width, height); + } + + return Promise.resolve(decoded); + }); + } + +} + +class ImageSize { + constructor({ + width, + height, + rows, + columns + }) { + var _ref, _ref2; + + this.width = void 0; + this.height = void 0; + this.width = (_ref = width !== null && width !== void 0 ? width : columns) !== null && _ref !== void 0 ? _ref : 0; + this.height = (_ref2 = height !== null && height !== void 0 ? height : rows) !== null && _ref2 !== void 0 ? _ref2 : 0; + } + + get rows() { + return this.height; + } + + get columns() { + return this.width; + } + + get numberOfPixels() { + const { + width, + height + } = this; + return width * height; + } + + scale(scale) { + let { + width, + height + } = this; + width *= scale; + height *= scale; + return new ImageSize({ + width, + height + }); + } + +} +/* eslint-disable no-bitwise */ + + +var Codec; + +(function (Codec) { + Codec[Codec["Uncompressed"] = 0] = "Uncompressed"; + Codec[Codec["JPEG"] = 1] = "JPEG"; + Codec[Codec["JPEGExt"] = 2] = "JPEGExt"; + Codec[Codec["JPEG2000"] = 4] = "JPEG2000"; + Codec[Codec["JPEGLS"] = 8] = "JPEGLS"; + Codec[Codec["JPEGLossless"] = 16] = "JPEGLossless"; + Codec[Codec["RLE"] = 32] = "RLE"; +})(Codec || (Codec = {})); + +const Signed = 0x8; +var PixelDataType; + +(function (PixelDataType) { + PixelDataType[PixelDataType["Uint8"] = 1] = "Uint8"; + PixelDataType[PixelDataType["Int8"] = 0x1 & Signed] = "Int8"; + PixelDataType[PixelDataType["Uint16"] = 2] = "Uint16"; + PixelDataType[PixelDataType["Int16"] = 0x2 & Signed] = "Int16"; +})(PixelDataType || (PixelDataType = {})); + +class DecoderInfo { + constructor(image) { + this.image = void 0; + this.size = void 0; + this.codec = void 0; + this.rgb = void 0; + this.planar = void 0; + this.samples = void 0; + this.bitsAllocated = void 0; + this.bytesAllocated = void 0; + this.bitsStored = void 0; + this.signed = void 0; + this.littleEndian = void 0; + this.data = void 0; + this.image = image; + + if (!image.pixelData) { + throw Error("Image has no data"); + } + + this.size = new ImageSize(image); + + switch (image.transferSyntax) { + case TransferSyntax.CompressionJpeg: + case TransferSyntax.CompressionJpegBaseline8bit: + this.codec = Codec.JPEG; + break; + + case TransferSyntax.CompressionJpegBaseline12bit: + this.codec = Codec.JPEGExt; + break; + + case TransferSyntax.CompressionJpegLossless: + case TransferSyntax.CompressionJpegLosslessSel1: + this.codec = Codec.JPEGLossless; + break; + + case TransferSyntax.CompressionJpegLs: + case TransferSyntax.CompressionJpegLsLossless: + this.codec = Codec.JPEGLS; + break; + + case TransferSyntax.CompressionJpeg2000Lossless: + case TransferSyntax.CompressionJpeg2000: + this.codec = Codec.JPEG2000; + break; + + case TransferSyntax.CompressionRLE: + this.codec = Codec.RLE; + break; + + case TransferSyntax.CompressionDeflate: + case TransferSyntax.ImplicitLittle: + case TransferSyntax.ExplicitLittle: + case TransferSyntax.ExplicitBig: + this.codec = Codec.Uncompressed; + break; + + default: + this.codec = Codec.Uncompressed; + } + + this.rgb = !(image.photometricInterpretation || "").startsWith("MONO"); + this.planar = !!image.planarConfig; + this.samples = image.samplesPerPixel; + this.bitsAllocated = image.bitsAllocated; + this.bytesAllocated = Math.round(image.bitsAllocated / 8); + this.bitsStored = image.bitsStored; + this.signed = image.pixelRepresentation === 1; + this.data = image.pixelData.value; + this.littleEndian = image.littleEndian; + } + +} + +const decodeInfoForImage = image => new DecoderInfo(image); + +const hasCreateObjectURL = !!URL.createObjectURL; + +const decoderForImage = image => { + const info = decodeInfoForImage(image); + + switch (info.codec) { + case Codec.JPEG: + if (hasCreateObjectURL) { + /* istanbul ignore next */ + return new NativeDecoder(info); + } + + return new JPEGLosslessDecoder(info); + + case Codec.JPEGExt: + return new JPEGLosslessDecoder(info); + + case Codec.JPEGLS: + return new JPEGLosslessDecoder$1(info); + + case Codec.JPEGLossless: + return new JPEGLosslessDecoder$2(info); + + case Codec.JPEG2000: + // safari support native JPEG2000 decode + if (hasCreateObjectURL && /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + /* istanbul ignore next */ + return new NativeDecoder(info); + } + + return new JPEG2000Decoder(info); + + case Codec.RLE: + return new RLEDecoder(info); + + case Codec.Uncompressed: + return new Decoder(info); + } + /* istanbul ignore next */ + + + return null; +}; +/** + * Unpack pseudo integer or a float from a color value + * insert into GLSL to change behaviour depending on data + * @param {Image} image the parsed DICOM image + * @param {Boolean} integerVal should return greyscale psuedo int (0 - 65535) + * else return a 0.0-1.0 float color ratio + */ + + +const glslUnpackWordString = (image, integerVal = true) => { + let val; + let divisor = ""; + const { + bitsAllocated, + signed, + pixelPaddingVal + } = image; + + if (!integerVal) { + divisor = ` / ${2 ** image.bitsStored}.0`; + } + + if (bitsAllocated <= 8) { + // one byte + val = "float p = (color.r * 255.0);\n"; + + if (pixelPaddingVal !== null) { + let pv = pixelPaddingVal; + + if (signed) { + // eslint-disable-next-line prefer-destructuring + pv = new Uint8Array(new Int8Array([pixelPaddingVal]))[0]; + } + + val = `${val}if (floor(p + 0.5) == ${pv}.0) return -1.0;\n`; + } + + if (signed) { + val = `${val}(p > 127.0 ? p - 127.0 : p + 127.0);\n`; + } + } else { + const { + rgb + } = image; // 2nd byte for greyscale images is packed in alpha chan, + // or green channel for RGB based 16bit greyscale + + const byte2Chan = rgb ? "g" : "a"; + + if (image.littleEndian) { + val = `float p = (color.${byte2Chan} * 65280.0 + color.r * 255.0);\n`; + } else { + val = `float p = (color.r * 65280.0 + color.${byte2Chan} * 255.0);\n`; + } + + if (pixelPaddingVal !== null) { + let pv = pixelPaddingVal; + + if (signed) { + // eslint-disable-next-line prefer-destructuring + pv = new Uint16Array(new Int16Array([pixelPaddingVal]))[0]; + } + + val = `${val}if (floor(p + 0.5) == ${pv}.0) return -1.0;\n`; + } + + if (signed) { + val = `${val}p = (p > 32767.0 ? p - 32767.0 : p + 32767.0);\n`; + } + } + + return `${val}return p${divisor};`; +}; +/** + * replace placeholders in the glsl strings with proper code + * @param info the image info we are to display + * @param shaderString input shader program string + * @param integerVal should getWord return a sized integer, or a 0-1 float ratio + * @returns + */ + + +const preCompileGreyscaleShader = (info, shaderString, integerVal = true) => { + let outShaderString = shaderString.replace("$(word)", glslUnpackWordString(info, integerVal)); + const { + invert, + pixelPaddingVal + } = info; + + if (invert) { + outShaderString = outShaderString.replace("// $(shouldInvert)", "grey = 1.0 - grey;"); + } + + if (pixelPaddingVal !== null) { + outShaderString = outShaderString.replace("// $(pixelPadding)", "if (grey < 0.0) {\ngl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\nreturn;\n}\n"); + } + + return outShaderString; +}; + +const vertexShader$4 = "attribute vec4 position;\n\nvoid main() {\n gl_Position = position;\n}\n"; +const minMaxShader = "#extension GL_EXT_draw_buffers : require\n\nprecision mediump float;\n\n#define CELL_SIZE $(cellSize)\n\nuniform sampler2D u_minTexture;\nuniform sampler2D u_maxTexture;\nuniform vec2 u_srcResolution;\n\nfloat greyscale(vec4 color) {\n $(word)\n}\n\nvoid main() {\n // compute the first pixel the source cell\n vec2 srcPixel = floor(gl_FragCoord.xy) * float(CELL_SIZE);\n\n // one pixel in source\n vec2 onePixel = vec2(1) / u_srcResolution;\n\n // uv for first pixel in cell. +0.5 for center of pixel\n vec2 uv = (srcPixel + 0.5) / u_srcResolution;\n\n float minVal = 65535.0;\n float maxVal = 0.0;\n vec4 minColor = vec4(1.0, 1.0, 1.0, 1.0);\n vec4 maxColor = vec4(0.0, 0.0, 0.0, 0.0);\n for (int y = 0; y < CELL_SIZE; ++y) {\n for (int x = 0; x < CELL_SIZE; ++x) {\n vec2 off = uv + vec2(x, y) * onePixel;\n vec4 colorMin = texture2D(u_minTexture, off);\n float grey = greyscale(colorMin);\n if (minVal > grey) {\n minColor = colorMin;\n minVal = grey;\n }\n vec4 colorMax = texture2D(u_maxTexture, off);\n grey = greyscale(colorMax);\n if (maxVal < grey) {\n maxColor = colorMax;\n maxVal = grey;\n }\n }\n }\n\n gl_FragData[0] = minColor;\n gl_FragData[1] = maxColor;\n}\n"; +const contrastifyShader = "precision highp float;\nuniform sampler2D u_minColor;\nuniform sampler2D u_maxColor;\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform float u_slope;\nuniform float u_intercept;\n\nfloat greyscale(vec4 color) {\n\t$(word)\n}\n\nfloat minMaxWord(vec4 color) {\n\t$(minMaxWord)\n}\n\nvoid main() {\n\tvec2 uv = gl_FragCoord.xy / u_resolution;\n\tuv.y = 1.0 - uv.y;\n\tfloat grey = greyscale(texture2D(u_texture, uv));\n\t// $(pixelPadding)\n\tfloat minColor = minMaxWord(texture2D(u_minColor, vec2(0)));\n\tfloat maxColor = minMaxWord(texture2D(u_maxColor, vec2(0)));\n\n\tgrey = grey * u_slope + u_intercept;\n\tminColor = minColor * u_slope + u_intercept;\n\tmaxColor = maxColor * u_slope + u_intercept;\n\n\tfloat ww = maxColor - minColor;\n\tfloat wc = (minColor + maxColor) / 2.0 - 0.5;\n\n\tgrey = ((grey - wc) / ww) + 0.5;\n\tgrey = clamp(grey, 0.0, 1.0);\n\n\t// $(shouldInvert)\n\tgl_FragColor = vec4(grey, grey, grey, 1);\n}\n"; +const cellSize = 16; + +class ContrastifyProgram { + // eslint-disable-next-line camelcase + static programStringForInfo(info) { + // don't ignore pixelPaddingVal in minMax calcs + const getMinMaxWordString = glslUnpackWordString(_extends({}, info, { + pixelPaddingVal: null + }), true); + const minMaxFragString = minMaxShader.replace("$(cellSize)", cellSize.toString()).replace("$(word)", getMinMaxWordString); + const contrastifyShaderString = preCompileGreyscaleShader(info, contrastifyShader.replace("$(minMaxWord)", getMinMaxWordString), true); + return [minMaxFragString, contrastifyShaderString]; + } + + constructor(gl, info) { + this.ext = void 0; + this.minMaxProgramInfo = void 0; + this.contrastProgramInfo = void 0; + this.unitQuadBufferInfo = null; + this.gl = void 0; + const ext = gl.getExtension("WEBGL_draw_buffers"); + + if (!ext) { + throw new Error("Image requires WEBGL_draw_buffers"); + } + + this.ext = ext; // TODO: don;t double up on program string generation + + const [minMaxFrag, contrastifyFrag] = ContrastifyProgram.programStringForInfo(info); + this.minMaxProgramInfo = twgl.createProgramInfo(gl, [vertexShader$4, minMaxFrag]); + this.contrastProgramInfo = twgl.createProgramInfo(gl, [vertexShader$4, contrastifyFrag]); + this.unitQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl); + this.gl = gl; + } // eslint-disable-next-line class-methods-use-this + + + use() {// can't really do anything here... + } + + run(frame, outputSize) { + const framebuffers = []; + const { + gl, + ext, + minMaxProgramInfo, + contrastProgramInfo, + unitQuadBufferInfo + } = this; + const { + imageInfo + } = frame; + const { + size, + slope, + intercept + } = imageInfo; + const { + width, + height + } = size; + let w = width; + let h = height; + const srcTex = frame.texture; + + while (w > 1 || h > 1) { + // | 0 like floor but Infinity/NaN are zero'd + // eslint-disable-next-line no-bitwise + w = Math.max(1, (w + cellSize - 1) / cellSize | 0); // eslint-disable-next-line no-bitwise + + h = Math.max(1, (h + cellSize - 1) / cellSize | 0); // creates a framebuffer and creates and attaches 2 RGBA/UNSIGNED textures + + const fbi = twgl.createFramebufferInfo(gl, [{ + format: gl.RGBA, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }, { + format: gl.RGBA, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }], w, h); // WebGl2 + // gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + + ext.drawBuffersWEBGL([ext.COLOR_ATTACHMENT0_WEBGL, ext.COLOR_ATTACHMENT1_WEBGL]); + framebuffers.push(fbi); + } // need separate FBs to read the output + + + const lastFBI = framebuffers[framebuffers.length - 1]; + const uniforms = { + u_srcResolution: [width, height], + u_minTexture: srcTex, + u_maxTexture: srcTex + }; + gl.useProgram(minMaxProgramInfo.program); + twgl.setBuffersAndAttributes(gl, minMaxProgramInfo, unitQuadBufferInfo); + w = width; + h = height; + framebuffers.forEach(fbi => { + // | 0 like floor but Infinity/NaN are zero'd + // eslint-disable-next-line no-bitwise + w = Math.max(1, (w + cellSize - 1) / cellSize | 0); // eslint-disable-next-line no-bitwise + + h = Math.max(1, (h + cellSize - 1) / cellSize | 0); // uniforms.u_dstResolution = [w, h]; + + twgl.bindFramebufferInfo(gl, fbi); + twgl.setUniforms(minMaxProgramInfo, uniforms); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); + [uniforms.u_minTexture, uniforms.u_maxTexture] = fbi.attachments; + uniforms.u_srcResolution = [w, h]; + }); // // Read min/max pixel onto CPU - slow but might be useful + // const minFBI = twgl.createFramebufferInfo(gl, [ + // { attachment: lastFBI.attachments[0] } + // ], 1, 1); + // const maxFBI = twgl.createFramebufferInfo(gl, [ + // { attachment: lastFBI.attachments[1] } + // ], 1, 1); + // const minVals = new Uint8Array(4); + // const maxVals = new Uint8Array(4); + // twgl.bindFramebufferInfo(gl, minFBI); + // gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, minVals); + // console.log("min: ", minVals[0], minVals[1], minVals[2], minVals[3]); + // twgl.bindFramebufferInfo(gl, maxFBI); + // gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, maxVals); + // console.log("max: ", maxVals[0], maxVals[1], maxVals[2], maxVals[3]); + + twgl.bindFramebufferInfo(gl, null); + gl.useProgram(contrastProgramInfo.program); + twgl.setUniforms(contrastProgramInfo, { + u_resolution: [outputSize.width, outputSize.height], + u_texture: srcTex, + u_minColor: lastFBI.attachments[0], + u_maxColor: lastFBI.attachments[1], + u_slope: slope, + u_intercept: intercept + }); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); // cleanup on next runloop + + setTimeout(() => { + framebuffers.forEach(fbi => { + const { + attachments, + framebuffer + } = fbi; + gl.deleteFramebuffer(framebuffer); + + if (attachments[0] instanceof WebGLRenderbuffer) { + gl.deleteRenderbuffer(attachments[0]); + } else { + gl.deleteTexture(attachments[0]); + } + }); + }, 0); + } + + destroy() { + this.gl.deleteProgram(this.contrastProgramInfo.program); + this.gl.deleteProgram(this.minMaxProgramInfo.program); + } + +} // import { IDisplayInfo } from "../image/DisplayInfo"; + + +const vertexShader$3 = "attribute vec4 position;\n\nvoid main() {\n gl_Position = position;\n}\n"; +const colorShader = "precision highp float;\nuniform bool u_invert;\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\n\nuniform float u_slope;\nuniform float u_intercept;\n\nvec4 getPlanar(vec2 coord) {\n\tfloat third = 1.0 / 3.0;\n\tint col = int(mod(coord.y, 3.0));\n\tfloat yPos = coord.y / 3.0;\n\n\tfloat xPos = coord.x;\n\n\tvec4 red = texture2D(u_texture, vec2(xPos, yPos));\n\n\tyPos = yPos + third;\n\tvec4 green = texture2D(u_texture, vec2(xPos, yPos));\n\n\tyPos = yPos + third;\n\tvec4 blue = texture2D(u_texture, vec2(xPos, yPos));\n\n\tif (col == 0) {\n\t\treturn vec4(red.r, green.r, blue.r, 1.0);\n\t}\n\tif (col == 1) {\n\t\treturn vec4(red.g, green.g, blue.g, 1.0);\n\t}\n\tif (col == 2) {\n\t\treturn vec4(red.b, green.b, blue.b, 1.0);\n\t}\n\treturn vec4(0.0, 0.0, 0.0, 0.0);\n}\n\nvoid main() {\n\tvec4 color;\n\tvec2 uv = gl_FragCoord.xy / u_resolution;\n\tuv.y = 1.0 - uv.y;\n\n\tcolor = // $(getColor);\n\n \tcolor = (color * u_slope) + u_intercept;\n\n\t// $(u_invert)\n\n\tgl_FragColor = color;\n}\n"; + +class ColorProgram { + static programStringForInfo(imageInfo) { + const { + planar, + invert + } = imageInfo; + let shaderString; + + if (planar) { + shaderString = colorShader.replace("// $(getColor);", "getPlanar(uv);\n"); + } else { + shaderString = colorShader.replace("// $(getColor);", "texture2D(u_texture, uv);\n"); + } + + if (invert) { + shaderString = shaderString.replace("// $(u_invert)", "color = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);"); + } + + return shaderString; + } // don't need info! all non palette color images use same program + + + constructor(gl, info) { + this.programInfo = void 0; + this.unitQuadBufferInfo = void 0; + this.gl = void 0; + const shaderString = ColorProgram.programStringForInfo(info); + const programInfo = twgl.createProgramInfo(gl, [vertexShader$3, shaderString]); + this.unitQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl); + this.programInfo = programInfo; + this.gl = gl; + } + + use() { + const { + gl, + programInfo, + unitQuadBufferInfo + } = this; + twgl.bindFramebufferInfo(gl, null); + gl.useProgram(programInfo.program); + twgl.setBuffersAndAttributes(gl, programInfo, unitQuadBufferInfo); + } + + run(frame, outputSize) { + const { + gl, + programInfo, + unitQuadBufferInfo + } = this; + const { + invert, + slope, + intercept + } = frame.imageInfo; + const { + texture + } = frame; + twgl.setUniforms(programInfo, { + u_resolution: [outputSize.width, outputSize.height], + u_texture: texture, + u_invert: invert, + u_slope: slope, + u_intercept: intercept + }); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); + } + + destroy() { + this.gl.deleteProgram(this.programInfo.program); + } + +} + +const vertexShader$2 = "attribute vec4 position;\n\nvoid main() {\n gl_Position = position;\n}\n"; +const greyscaleShader = "precision highp float;\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform float u_slope;\nuniform float u_intercept;\n\nuniform float u_winCenter;\nuniform float u_winWidth;\n\nfloat greyscale(vec4 color) {\n\t$(word)\n}\n\nvoid main() {\n\tvec2 uv = gl_FragCoord.xy / u_resolution;\n\tuv.y = 1.0 - uv.y;\n\n\tfloat grey = greyscale(texture2D(u_texture, uv));\n\t// $(pixelPadding)\n\tgrey = (grey * u_slope) + u_intercept;\n\n\tfloat center = u_winCenter - 0.5;\n\tfloat width = max(u_winWidth, 1.0);\n\tgrey = (grey - center) / width + 0.5;\n\tgrey = clamp(grey, 0.0, 1.0);\n\n\t// $(shouldInvert)\n\tgl_FragColor = vec4(grey, grey, grey, 1);\n}\n"; + +class GreyscaleProgram { + static programStringForInfo(info) { + return preCompileGreyscaleShader(info, greyscaleShader); + } + + constructor(gl, info) { + this.programInfo = void 0; + this.unitQuadBufferInfo = null; + this.gl = void 0; + const greyscaleShaderString = GreyscaleProgram.programStringForInfo(info); + const programInfo = twgl.createProgramInfo(gl, [vertexShader$2, greyscaleShaderString]); + this.unitQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl); + this.programInfo = programInfo; + this.gl = gl; + } + + use() { + const { + gl, + programInfo, + unitQuadBufferInfo + } = this; + twgl.bindFramebufferInfo(gl, null); + gl.useProgram(programInfo.program); + twgl.setBuffersAndAttributes(gl, programInfo, unitQuadBufferInfo); + } + + run(frame, outputSize) { + const { + gl, + unitQuadBufferInfo, + programInfo + } = this; + const { + texture, + imageInfo + } = frame; + let { + windowWidth, + windowCenter + } = imageInfo; + const { + maxPixVal, + minPixVal, + slope, + intercept, + signed, + bitsAllocated + } = imageInfo; + + if (!windowWidth && (maxPixVal !== null || minPixVal !== null)) { + windowWidth = Math.abs((maxPixVal !== null && maxPixVal !== void 0 ? maxPixVal : 0) - (minPixVal !== null && minPixVal !== void 0 ? minPixVal : 0)); + windowCenter = ((maxPixVal || 0) + (minPixVal || 0)) / 2; + } + + if (signed) { + windowCenter = (windowCenter || 0) + 2 ** (bitsAllocated - 1); + } + + twgl.setUniforms(programInfo, { + u_resolution: [outputSize.width, outputSize.height], + u_texture: texture, + u_winWidth: windowWidth, + u_winCenter: windowCenter, + u_slope: slope, + u_intercept: intercept + }); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); + } + + destroy() { + this.gl.deleteProgram(this.programInfo.program); + } + +} + +const vertexShader$1 = "attribute vec4 position;\n\nvoid main() {\n gl_Position = position;\n}\n"; +const greyscaleLUTShader = "precision highp float;\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform sampler2D u_lutTexture;\nuniform float u_lutWidth;\nuniform float u_firstInputValue;\nuniform float u_maxValue;\n\nfloat greyscale(vec4 color) {\n\t$(word)\n}\n\nvoid main() {\n\tvec2 uv = gl_FragCoord.xy / u_resolution;\n\tuv.y = 1.0 - uv.y;\n\n\tfloat grey = greyscale(texture2D(u_texture, uv));\n\t// $(pixelPadding)\n\tfloat lutPos = (max(u_firstInputValue, grey) - u_firstInputValue);\n\tgrey = greyscale(texture2D(u_lutTexture, vec2(lutPos / u_lutWidth, 0.5))) / u_maxValue;\n\t// $(shouldInvert)\n\tgl_FragColor = vec4(grey, grey, grey, 1);\n}\n"; + +class GreyscaleLUTProgram { + static programStringForInfo(info) { + return preCompileGreyscaleShader(info, greyscaleLUTShader); + } + + constructor(gl, info) { + this.programInfo = void 0; + this.unitQuadBufferInfo = null; + this.info = void 0; + this.gl = void 0; + const fragShaderString = GreyscaleLUTProgram.programStringForInfo(info); + const programInfo = twgl.createProgramInfo(gl, [vertexShader$1, fragShaderString]); + this.programInfo = programInfo; + this.gl = gl; + this.info = info; + } + + use() { + const { + gl, + programInfo + } = this; // can this be reused? + + const unitQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl); + twgl.bindFramebufferInfo(gl, null); + gl.useProgram(programInfo.program); + twgl.setBuffersAndAttributes(gl, programInfo, unitQuadBufferInfo); + this.unitQuadBufferInfo = unitQuadBufferInfo; + } + + run(frame, outputSize) { + const { + gl, + unitQuadBufferInfo, + programInfo, + info + } = this; + const { + texture, + imageInfo + } = frame; + const { + lut + } = imageInfo; + let format = gl.LUMINANCE_ALPHA; + let internalFormat = gl.LUMINANCE_ALPHA; + + if (info.bitsAllocated <= 8) { + format = gl.LUMINANCE; + internalFormat = gl.LUMINANCE; + } // 1D tex + + + const lutTexture = twgl.createTexture(gl, { + src: new Uint8Array(lut.data.buffer), + width: lut.data.length, + height: 1, + format, + internalFormat, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }); + twgl.setUniforms(programInfo, { + u_resolution: [outputSize.width, outputSize.height], + u_texture: texture, + u_lutTexture: lutTexture, + u_lutWidth: lut.data.length, + u_firstInputValue: lut.firstValue, + u_maxValue: 2 ** info.bitsStored + }); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); + setTimeout(() => { + gl.deleteTexture(lutTexture); + }, 0); + } + + destroy() { + const { + gl + } = this; + gl.deleteProgram(this.programInfo.program); + } + +} + +const vertexShader = "attribute vec4 position;\n\nvoid main() {\n gl_Position = position;\n}\n"; +const colorPaletteShader = "precision highp float;\nuniform bool u_invert;\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform sampler2D u_redTexture;\nuniform sampler2D u_greenTexture;\nuniform sampler2D u_blueTexture;\nuniform float u_paletteWidthRatio;\n\nfloat getWord(vec4 color) {\n\t$(word)\n}\n\nfloat getPaletteWord(vec4 color) {\n\t$(paletteWord)\n}\n\nvoid main() {\n\tvec2 uv = gl_FragCoord.xy / u_resolution;\n\tuv.y = 1.0 - uv.y;\n\n\tfloat palettePos = getWord(texture2D(u_texture, uv)) * u_paletteWidthRatio;\n\n\tfloat red = getPaletteWord(texture2D(u_redTexture, vec2( palettePos, 0.5)));\n\tfloat green = getPaletteWord(texture2D(u_greenTexture, vec2(palettePos, 0.5)));\n\tfloat blue = getPaletteWord(texture2D(u_blueTexture, vec2(palettePos, 0.5)));\n\n\tvec4 color = vec4(red, green, blue, 1.0);\n\tif (u_invert) {\n\t\tcolor = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, 1.0);\n\t}\n\n\tgl_FragColor = color;\n}\n"; + +class ColorPaletteProgram { + static programStringForInfo(info) { + const { + palette + } = info; + const getWordString = glslUnpackWordString(info, false); + const getPaletteWordString = glslUnpackWordString(_extends({}, info, { + rgb: false, + bitsAllocated: palette.bitsAllocated, + bitsStored: palette.bitsAllocated + }), false); + return colorPaletteShader.replace("$(word)", getWordString).replace("$(paletteWord)", getPaletteWordString); + } + + constructor(gl, info) { + this.programInfo = void 0; + this.unitQuadBufferInfo = void 0; + this.gl = void 0; + const programString = ColorPaletteProgram.programStringForInfo(info); + const programInfo = twgl.createProgramInfo(gl, [vertexShader, programString]); + this.programInfo = programInfo; + this.gl = gl; // can this be reused? + + this.unitQuadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl); + } + + use() { + const { + gl, + programInfo, + unitQuadBufferInfo + } = this; + twgl.bindFramebufferInfo(gl, null); + gl.useProgram(programInfo.program); + twgl.setBuffersAndAttributes(gl, programInfo, unitQuadBufferInfo); + } + + run(frame, outputSize) { + const { + gl, + unitQuadBufferInfo, + programInfo + } = this; + const { + texture, + imageInfo + } = frame; + const { + palette, + invert, + bitsAllocated + } = imageInfo; + let format = gl.LUMINANCE_ALPHA; + let internalFormat = gl.LUMINANCE_ALPHA; + + if (palette.bitsAllocated === 8) { + format = gl.LUMINANCE; + internalFormat = gl.LUMINANCE; + } + + const { + r, + g, + b, + nEntries + } = palette; // 1D tex + + const red = twgl.createTexture(gl, { + src: new Uint8Array(r.buffer, r.byteOffset, r.byteLength), + width: nEntries, + height: 1, + format, + internalFormat, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }); + const green = twgl.createTexture(gl, { + src: new Uint8Array(g.buffer, g.byteOffset, g.byteLength), + width: nEntries, + height: 1, + format, + internalFormat, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }); + const blue = twgl.createTexture(gl, { + src: new Uint8Array(b.buffer, b.byteOffset, b.byteLength), + width: nEntries, + height: 1, + format, + internalFormat, + type: gl.UNSIGNED_BYTE, + min: gl.NEAREST, + mag: gl.NEAREST, + wrap: gl.CLAMP_TO_EDGE + }); + twgl.setUniforms(programInfo, { + u_resolution: [outputSize.width, outputSize.height], + u_texture: texture, + u_redTexture: red, + u_greenTexture: green, + u_blueTexture: blue, + u_paletteWidthRatio: 2 ** bitsAllocated / palette.nEntries, + u_invert: invert + }); + twgl.drawBufferInfo(gl, unitQuadBufferInfo); + setTimeout(() => { + gl.deleteTexture(red); + gl.deleteTexture(green); + gl.deleteTexture(blue); + }); + } + + destroy() { + const { + gl, + programInfo + } = this; + gl.deleteProgram(programInfo.program); + } + +} + +class Renderer { + constructor(inCanvas) { + var _document; + + this.canvas = void 0; + this.image = null; + this.gl = void 0; + this.decoder = null; + this.program = null; + this.outSize = null; + this.programCacheMap = void 0; + const canvas = inCanvas || ((_document = document) === null || _document === void 0 ? void 0 : _document.createElement("canvas")) || new HTMLCanvasElement(); + const gl = canvas.getContext("webgl"); + + if (!gl) { + throw Error("could not create webgl from canvas"); + } + + this.canvas = canvas; + this.gl = gl; + this.programCacheMap = new Map(); + } + /** + * prime the renderer with specific programs + * this can improve 1st image render time quite dramatically + * @param programType + */ + + + primeGreyscale(programType) { + var _ref; + + const { + hasLut, + invert, + signed, + bitsAllocated, + bitsStored, + littleEndian, + hasPixelPaddingValue, + knownWindow + } = programType; + const imageType = { + image: new DCMImage(), + nFrames: 1, + rgb: false, + planar: false, + signed: signed !== null && signed !== void 0 ? signed : false, + size: new ImageSize({ + width: 0, + height: 0 + }), + codec: Codec.Uncompressed, + samples: 0, + bitsAllocated: bitsAllocated !== null && bitsAllocated !== void 0 ? bitsAllocated : 16, + bytesAllocated: (bitsAllocated !== null && bitsAllocated !== void 0 ? bitsAllocated : 16) / 8, + bitsStored: (_ref = bitsStored !== null && bitsStored !== void 0 ? bitsStored : bitsAllocated) !== null && _ref !== void 0 ? _ref : 16, + littleEndian: littleEndian !== null && littleEndian !== void 0 ? littleEndian : true, + data: new DataView(new ArrayBuffer(0)), + lut: hasLut ? { + nEntries: 0, + firstValue: 0, + bitsStored: 0, + data: new Uint8Array(0) + } : null, + palette: null, + invert: invert !== null && invert !== void 0 ? invert : false, + pixelPaddingVal: hasPixelPaddingValue ? 1 : null, + minPixVal: null, + maxPixVal: null, + windowCenter: knownWindow ? 0.5 : null, + windowWidth: knownWindow ? 1 : null, + slope: 1, + intercept: 0 + }; + this.getProgram(imageType); + } + /** + * prime the renderer with specific programs + * this can improve 1st image render time quite dramatically + * @param programType + */ + + + primeColor(programType) { + const { + planar, + bitsAllocated, + signed, + littleEndian, + hasPaletteWithWordBits, + invert + } = programType; + const imageType = { + image: new DCMImage(), + nFrames: 1, + rgb: true, + planar: planar !== null && planar !== void 0 ? planar : false, + signed: signed !== null && signed !== void 0 ? signed : false, + size: new ImageSize({ + width: 0, + height: 0 + }), + codec: Codec.Uncompressed, + samples: 3, + bitsAllocated, + bytesAllocated: bitsAllocated / 8, + bitsStored: bitsAllocated, + littleEndian: littleEndian !== null && littleEndian !== void 0 ? littleEndian : true, + data: new DataView(new ArrayBuffer(0)), + lut: null, + palette: hasPaletteWithWordBits ? { + nEntries: 0, + firstValue: 0, + bitsAllocated: hasPaletteWithWordBits, + r: new DataView(new ArrayBuffer(0)), + g: new DataView(new ArrayBuffer(0)), + b: new DataView(new ArrayBuffer(0)) + } : null, + invert: invert !== null && invert !== void 0 ? invert : false, + pixelPaddingVal: null, + minPixVal: null, + maxPixVal: null, + windowCenter: null, + windowWidth: null, + slope: 1, + intercept: 0 + }; + this.getProgram(imageType); + } + /** + * render the image frame to the canvas + * @param image parsed DCMImage + * @param frameNo the frame index + */ + + + async render(image, frameNo = 0) { + const { + gl, + canvas + } = this; + + if (!this.outSize) { + this.outSize = new ImageSize(image); + } + + const size = this.outSize; + + if (size.width !== canvas.width || size.height !== canvas.height) { + canvas.width = 1; // near zero the canvas, makes resize much faste! + + canvas.height = 1; + canvas.width = size.width; + canvas.height = size.height; + } + + if (this.image !== image) { + this.image = image; + const decoder = decoderForImage(image); + decoder.outputSize = new ImageSize(image); + const imageInfo = decoder.image; + const program = this.getProgram(imageInfo); + program.use(); + this.program = program; + this.decoder = decoder; + } + + const frame = await this.decoder.getFrame(gl, frameNo); + this.program.run(frame, size); + setTimeout(() => { + frame.destroy(); + }, 0); + } + + set outputSize(size) { + this.outSize = new ImageSize(size); + } + + get outputSize() { + if (this.outSize) { + return this.outSize; + } + + return new ImageSize({ + width: 0, + height: 0 + }); + } + + clear() { + const { + gl, + canvas + } = this; + canvas.width = 0; // zero the canvas, makes resize much faster! + + canvas.height = 0; // eslint-disable-next-line no-bitwise + + gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT); + } + + destroy(aggressive = false) { + this.programCacheMap.forEach(program => { + program.destroy(); + }); + this.programCacheMap = new Map(); + this.program = null; + this.image = null; + + if (aggressive) { + var _this$gl$getExtension; // https://stackoverflow.com/questions/23598471/how-do-i-clean-up-and-unload-a-webgl-canvas-context-from-gpu-after-use + + + (_this$gl$getExtension = this.gl.getExtension("WEBGL_lose_context")) === null || _this$gl$getExtension === void 0 ? void 0 : _this$gl$getExtension.loseContext(); + this.canvas.width = 1; + this.canvas.height = 1; + } + } + + getProgram(imageInfo) { + const { + gl + } = this; + let signature = null; + + if (imageInfo.palette) { + signature = { + hash: (0, _sha.default)(ColorPaletteProgram.programStringForInfo(imageInfo)).toString(), + Type: ColorPaletteProgram + }; + } else if (imageInfo.rgb) { + signature = { + hash: (0, _sha.default)(ColorProgram.programStringForInfo(imageInfo)).toString(), + Type: ColorProgram + }; + } else if (imageInfo.windowCenter || imageInfo.minPixVal || imageInfo.maxPixVal) { + signature = { + hash: (0, _sha.default)(GreyscaleProgram.programStringForInfo(imageInfo)).toString(), + Type: GreyscaleProgram + }; + } else if (imageInfo.lut) { + signature = { + hash: (0, _sha.default)(GreyscaleLUTProgram.programStringForInfo(imageInfo)).toString(), + Type: GreyscaleLUTProgram + }; + } else { + const [s0, s1] = ContrastifyProgram.programStringForInfo(imageInfo); + signature = { + hash: (0, _sha.default)(s0 + s1).toString(), + Type: ContrastifyProgram + }; + } + + let program = this.programCacheMap.get(signature.hash); + + if (!program) { + program = new signature.Type(gl, imageInfo); + this.programCacheMap.set(signature.hash, program); + } + + return program; + } + +} + +exports.Renderer = Renderer; + +const render = async (image, canvas, scale = 1.0) => { + if (!image) { + return Promise.reject(Series.parserError); + } + + const renderer = new Renderer(canvas); + const outSize = new ImageSize(image).scale(scale); + renderer.outputSize = outSize; + await renderer.render(image, 0); + renderer.destroy(); + return Promise.resolve(); +}; + +exports.render = render; + +},{"@wearemothership/dicom-character-set":2,"jpeg-lossless-decoder-js":13,"pako":18,"sha1":19,"twgl.js":20}],2:[function(require,module,exports){ +/*! @wearemothership/dicom-character-set - 1.0.4-opt.1 - 2021-03-22 | (c) 2018 Radialogica, LLC | https://github.com/radialogica/dicom-character-set */ +!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports["dicom-character-set"]=n():e["dicom-character-set"]=n()}(this,function(){return(()=>{"use strict";var o={d:(e,n)=>{for(var t in n)o.o(n,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},e={};o.r(e),o.d(e,{characterSets:()=>i,convertBytes:()=>function(e,n,t){return g(y,r,e,n,t)},convertBytesPromise:()=>function(e,n,t){return g(P,m,e,n,t)}});var n={codeElement:"G0",escapeSequence:[27,40,66],encoding:"windows-1252",isASCII:!0,bytesPerCodePoint:1},i={"ISO_IR 6":{encoding:"utf-8"},"ISO_IR 100":{encoding:"windows-1252"},"ISO_IR 101":{encoding:"iso-8859-2"},"ISO_IR 109":{encoding:"iso-8859-3"},"ISO_IR 110":{encoding:"iso-8859-4"},"ISO_IR 144":{encoding:"iso-8859-5"},"ISO_IR 127":{encoding:"iso-8859-6"},"ISO_IR 126":{encoding:"iso-8859-7"},"ISO_IR 138":{encoding:"iso-8859-8"},"ISO_IR 148":{encoding:"windows-1254"},"ISO_IR 13":{encoding:"shift-jis"},"ISO_IR 166":{encoding:"tis-620"},"ISO 2022 IR 6":{extension:!0,elements:[n]},"ISO 2022 IR 100":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,65],encoding:"windows-1252",bytesPerCodePoint:1}]},"ISO 2022 IR 101":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,66],encoding:"iso-8859-2",bytesPerCodePoint:1}]},"ISO 2022 IR 109":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,67],encoding:"iso-8859-3",bytesPerCodePoint:1}]},"ISO 2022 IR 110":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,68],encoding:"iso-8859-4",bytesPerCodePoint:1}]},"ISO 2022 IR 144":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,76],encoding:"iso-8859-5",bytesPerCodePoint:1}]},"ISO 2022 IR 127":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,71],encoding:"iso-8859-6",bytesPerCodePoint:1}]},"ISO 2022 IR 126":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,70],encoding:"iso-8859-7",bytesPerCodePoint:1}]},"ISO 2022 IR 138":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,72],encoding:"iso-8859-8",bytesPerCodePoint:1}]},"ISO 2022 IR 148":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,77],encoding:"windows-1254",bytesPerCodePoint:1}]},"ISO 2022 IR 13":{extension:!0,elements:[{codeElement:"G0",escapeSequence:[27,40,74],encoding:"shift-jis",bytesPerCodePoint:1},{codeElement:"G1",escapeSequence:[27,41,73],encoding:"shift-jis",bytesPerCodePoint:1}]},"ISO 2022 IR 166":{extension:!0,elements:[n,{codeElement:"G1",escapeSequence:[27,45,84],encoding:"tis-620",bytesPerCodePoint:1}]},"ISO 2022 IR 87":{extension:!0,multiByte:!0,elements:[{codeElement:"G0",escapeSequence:[27,36,66],encoding:"euc-jp",setHighBit:!0,bytesPerCodePoint:2}]},"ISO 2022 IR 159":{extension:!0,multiByte:!0,elements:[{codeElement:"G0",escapeSequence:[27,36,40,68],encoding:"euc-jp",isJISX0212:!0,bytesPerCodePoint:2}]},"ISO 2022 IR 149":{extension:!0,multiByte:!0,elements:[{codeElement:"G1",escapeSequence:[27,36,41,67],encoding:"euc-kr",bytesPerCodePoint:2}]},"ISO 2022 IR 58":{extension:!0,multiByte:!0,elements:[{codeElement:"G1",escapeSequence:[27,36,41,65],encoding:"gb18030",bytesPerCodePoint:2}]},"ISO_IR 192":{encoding:"utf-8",multiByte:!0},GB18030:{encoding:"gb18030",multiByte:!0},GBK:{encoding:"gbk",multiByte:!0}},l=27,c=10,s=12,u=13,d=9,a=92,f=61,I=94;function S(e){return e.replace(/~/g,"‾").replace(/\\/g,"¥")}function r(e,n,t,o,r){r=b(n,t,o,r);return e+y(n.encoding,r)}function m(e,t,n,o,r){var i=b(t,n,o,r);return(""===e?Promise.resolve(""):e).then(function(n){return P(t.encoding,i).then(function(e){return n+e})})}function g(e,n,t,o,r){!function(e,n){if(n&&!(n instanceof Uint8Array))throw new Error("bytes must be a Uint8Array");if(e&&"string"!=typeof e)throw new Error("specificCharacterSet must be a string")}(t,o);t=function(e){e=e?e.split("\\").map(function(e){return e.trim().toUpperCase()}):[""];""===e[0]&&(e[0]=1=n.length)return!1;if(n[t+o]!==e[o])return!1}return!0}(c.escapeSequence,e,n))return c}throw new Error("Unknown escape sequence encountered at byte "+n)}(n,d,e),c[a.codeElement]=a,s+=a.escapeSequence.length)}return r}(t.map(function(e){return i[e]}),o,function(e){var n=(e||"").trim().toUpperCase(),e=[c,s,u,d];["UT","ST","LT"].includes(n)||e.push(a);"PN"===n&&(e.push(f),e.push(I));return e}(r.vr),n)}var p={};function y(e,n){var t=p[e];return t||(t=new TextDecoder(e),p[e]=t="shift-jis"===e?{textDecoder:t,decode:function(e){return S(t.decode(e))}}:t),t.decode(n)}function P(o,r){return new Promise(function(e){var n=new FileReader;n.onload="shift-jis"===o?function(){return e(S(n.result))}:function(){return e(n.result)};var t=new Blob([r]);n.readAsText(t,o)})}function h(e,n){return 127 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + +},{}],4:[function(require,module,exports){ +(function (Buffer){(function (){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + var arr = new Uint8Array(1) + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) + } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + var length = byteLength(string, encoding) | 0 + var buf = createBuffer(length) + + var actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf +} + +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf +} + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + var buf = createBuffer(len) + + if (buf.length === 0) { + return buf + } + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) + } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } +} + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + var len = string.length + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + var strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (var i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"base64-js":3,"buffer":4,"ieee754":7}],5:[function(require,module,exports){ +var charenc = { + // UTF-8 encoding + utf8: { + // Convert a string to a byte array + stringToBytes: function(str) { + return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); + } + }, + + // Binary encoding + bin: { + // Convert a string to a byte array + stringToBytes: function(str) { + for (var bytes = [], i = 0; i < str.length; i++) + bytes.push(str.charCodeAt(i) & 0xFF); + return bytes; + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + for (var str = [], i = 0; i < bytes.length; i++) + str.push(String.fromCharCode(bytes[i])); + return str.join(''); + } + } +}; + +module.exports = charenc; + +},{}],6:[function(require,module,exports){ +(function() { + var base64map + = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + + crypt = { + // Bit-wise rotation left + rotl: function(n, b) { + return (n << b) | (n >>> (32 - b)); + }, + + // Bit-wise rotation right + rotr: function(n, b) { + return (n << (32 - b)) | (n >>> b); + }, + + // Swap big-endian to little-endian and vice versa + endian: function(n) { + // If number given, swap endian + if (n.constructor == Number) { + return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; + } + + // Else, assume array and swap all items + for (var i = 0; i < n.length; i++) + n[i] = crypt.endian(n[i]); + return n; + }, + + // Generate an array of any length of random bytes + randomBytes: function(n) { + for (var bytes = []; n > 0; n--) + bytes.push(Math.floor(Math.random() * 256)); + return bytes; + }, + + // Convert a byte array to big-endian 32-bit words + bytesToWords: function(bytes) { + for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) + words[b >>> 5] |= bytes[i] << (24 - b % 32); + return words; + }, + + // Convert big-endian 32-bit words to a byte array + wordsToBytes: function(words) { + for (var bytes = [], b = 0; b < words.length * 32; b += 8) + bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); + return bytes; + }, + + // Convert a byte array to a hex string + bytesToHex: function(bytes) { + for (var hex = [], i = 0; i < bytes.length; i++) { + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + } + return hex.join(''); + }, + + // Convert a hex string to a byte array + hexToBytes: function(hex) { + for (var bytes = [], c = 0; c < hex.length; c += 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; + }, + + // Convert a byte array to a base-64 string + bytesToBase64: function(bytes) { + for (var base64 = [], i = 0; i < bytes.length; i += 3) { + var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + for (var j = 0; j < 4; j++) + if (i * 8 + j * 6 <= bytes.length * 8) + base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); + else + base64.push('='); + } + return base64.join(''); + }, + + // Convert a base-64 string to a byte array + base64ToBytes: function(base64) { + // Remove non-base-64 characters + base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); + + for (var bytes = [], i = 0, imod4 = 0; i < base64.length; + imod4 = ++i % 4) { + if (imod4 == 0) continue; + bytes.push(((base64map.indexOf(base64.charAt(i - 1)) + & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) + | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); + } + return bytes; + } + }; + + module.exports = crypt; +})(); + +},{}],7:[function(require,module,exports){ +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],8:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; + + +/*** Constructor ***/ +jpeg.lossless.ComponentSpec = jpeg.lossless.ComponentSpec || function () { + this.hSamp = 0; // Horizontal sampling factor + this.quantTableSel = 0; // Quantization table destination selector + this.vSamp = 0; // Vertical +}; + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.ComponentSpec; +} + +},{}],9:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; + + +/*** Constructor ***/ +jpeg.lossless.DataStream = jpeg.lossless.DataStream || function (data, offset, length) { + if (offset === undefined && length === undefined) { // Old api + this.buffer = new Uint8Array(data); + } else { + this.buffer = new Uint8Array(data, offset, length); + } + this.index = 0; +}; + + + +jpeg.lossless.DataStream.prototype.get16 = function () { + // var value = this.buffer.getUint16(this.index, false); + var value = (this.buffer[this.index] << 8) + this.buffer[this.index + 1]; // DataView is big-endian by default + this.index += 2; + return value; +}; + + + +jpeg.lossless.DataStream.prototype.get8 = function () { + // var value = this.buffer.getUint8(this.index); + var value = this.buffer[this.index]; + this.index += 1; + return value; +}; + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.DataStream; +} + +},{}],10:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); +jpeg.lossless.HuffmanTable = jpeg.lossless.HuffmanTable || ((typeof require !== 'undefined') ? require('./huffman-table.js') : null); +jpeg.lossless.QuantizationTable = jpeg.lossless.QuantizationTable || ((typeof require !== 'undefined') ? require('./quantization-table.js') : null); +jpeg.lossless.ScanHeader = jpeg.lossless.ScanHeader || ((typeof require !== 'undefined') ? require('./scan-header.js') : null); +jpeg.lossless.FrameHeader = jpeg.lossless.FrameHeader || ((typeof require !== 'undefined') ? require('./frame-header.js') : null); +jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + +/*** Constructor ***/ + +/** + * The Decoder constructor. + * @property {number} xDim - size of x dimension + * @property {number} yDim - size of y dimension + * @property {number} numComp - number of components + * @property {number} numBytes - number of bytes per component + * @type {Function} + */ +jpeg.lossless.Decoder = jpeg.lossless.Decoder || function (buffer, numBytes) { + this.buffer = buffer; + this.frame = new jpeg.lossless.FrameHeader(); + this.huffTable = new jpeg.lossless.HuffmanTable(); + this.quantTable = new jpeg.lossless.QuantizationTable(); + this.scan = new jpeg.lossless.ScanHeader(); + this.DU = jpeg.lossless.Utils.createArray(10, 4, 64); // at most 10 data units in a MCU, at most 4 data units in one component + this.HuffTab = jpeg.lossless.Utils.createArray(4, 2, 50 * 256); + this.IDCT_Source = []; + this.nBlock = []; // number of blocks in the i-th Comp in a scan + this.acTab = jpeg.lossless.Utils.createArray(10, 1); // ac HuffTab for the i-th Comp in a scan + this.dcTab = jpeg.lossless.Utils.createArray(10, 1); // dc HuffTab for the i-th Comp in a scan + this.qTab = jpeg.lossless.Utils.createArray(10, 1); // quantization table for the i-th Comp in a scan + this.marker = 0; + this.markerIndex = 0; + this.numComp = 0; + this.restartInterval = 0; + this.selection = 0; + this.xDim = 0; + this.yDim = 0; + this.xLoc = 0; + this.yLoc = 0; + this.numBytes = 0; + this.outputData = null; + this.restarting = false; + this.mask = 0; + + if (typeof numBytes !== "undefined") { + this.numBytes = numBytes; + } +}; + + +/*** Static Pseudo-constants ***/ + +jpeg.lossless.Decoder.IDCT_P = [0, 5, 40, 16, 45, 2, 7, 42, 21, 56, 8, 61, 18, 47, 1, 4, 41, 23, 58, 13, 32, 24, 37, 10, 63, 17, 44, 3, 6, 43, 20, + 57, 15, 34, 29, 48, 53, 26, 39, 9, 60, 19, 46, 22, 59, 12, 33, 31, 50, 55, 25, 36, 11, 62, 14, 35, 28, 49, 52, 27, 38, 30, 51, 54]; +jpeg.lossless.Decoder.TABLE = [0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63]; +jpeg.lossless.Decoder.MAX_HUFFMAN_SUBTREE = 50; +jpeg.lossless.Decoder.MSB = 0x80000000; +jpeg.lossless.Decoder.RESTART_MARKER_BEGIN = 0xFFD0; +jpeg.lossless.Decoder.RESTART_MARKER_END = 0xFFD7; + +/*** Prototype Methods ***/ + +/** + * Returns decompressed data. + * @param {ArrayBuffer} buffer + * @param {number} [offset] + * @param {number} [length] + * @returns {ArrayBufer} + */ +jpeg.lossless.Decoder.prototype.decompress = function (buffer, offset, length) { + return this.decode(buffer, offset, length).buffer; +}; + + + +jpeg.lossless.Decoder.prototype.decode = function (buffer, offset, length, numBytes) { + /*jslint bitwise: true */ + + var current, scanNum = 0, pred = [], i, compN, temp = [], index = [], mcuNum; + + if (typeof buffer !== "undefined") { + this.buffer = buffer; + } + + if (typeof numBytes !== "undefined") { + this.numBytes = numBytes; + } + + this.stream = new jpeg.lossless.DataStream(this.buffer, offset, length); + this.buffer = null; + + this.xLoc = 0; + this.yLoc = 0; + current = this.stream.get16(); + + if (current !== 0xFFD8) { // SOI + throw new Error("Not a JPEG file"); + } + + current = this.stream.get16(); + + while ((((current >> 4) !== 0x0FFC) || (current === 0xFFC4))) { // SOF 0~15 + switch (current) { + case 0xFFC4: // DHT + this.huffTable.read(this.stream, this.HuffTab); + break; + case 0xFFCC: // DAC + throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)"); + case 0xFFDB: + this.quantTable.read(this.stream, jpeg.lossless.Decoder.TABLE); + break; + case 0xFFDD: + this.restartInterval = this.readNumber(); + break; + case 0xFFE0: + case 0xFFE1: + case 0xFFE2: + case 0xFFE3: + case 0xFFE4: + case 0xFFE5: + case 0xFFE6: + case 0xFFE7: + case 0xFFE8: + case 0xFFE9: + case 0xFFEA: + case 0xFFEB: + case 0xFFEC: + case 0xFFED: + case 0xFFEE: + case 0xFFEF: + this.readApp(); + break; + case 0xFFFE: + this.readComment(); + break; + default: + if ((current >> 8) !== 0xFF) { + throw new Error("ERROR: format throw new IOException! (decode)"); + } + } + + current = this.stream.get16(); + } + + if ((current < 0xFFC0) || (current > 0xFFC7)) { + throw new Error("ERROR: could not handle arithmetic code!"); + } + + this.frame.read(this.stream); + current = this.stream.get16(); + + do { + while (current !== 0x0FFDA) { // SOS + switch (current) { + case 0xFFC4: // DHT + this.huffTable.read(this.stream, this.HuffTab); + break; + case 0xFFCC: // DAC + throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)"); + case 0xFFDB: + this.quantTable.read(this.stream, jpeg.lossless.Decoder.TABLE); + break; + case 0xFFDD: + this.restartInterval = this.readNumber(); + break; + case 0xFFE0: + case 0xFFE1: + case 0xFFE2: + case 0xFFE3: + case 0xFFE4: + case 0xFFE5: + case 0xFFE6: + case 0xFFE7: + case 0xFFE8: + case 0xFFE9: + case 0xFFEA: + case 0xFFEB: + case 0xFFEC: + case 0xFFED: + case 0xFFEE: + case 0xFFEF: + this.readApp(); + break; + case 0xFFFE: + this.readComment(); + break; + default: + if ((current >> 8) !== 0xFF) { + throw new Error("ERROR: format throw new IOException! (Parser.decode)"); + } + } + + current = this.stream.get16(); + } + + this.precision = this.frame.precision; + this.components = this.frame.components; + + if (!this.numBytes) { + this.numBytes = parseInt(Math.ceil(this.precision / 8)); + } + + if (this.numBytes == 1) { + this.mask = 0xFF; + } else { + this.mask = 0xFFFF; + } + + this.scan.read(this.stream); + this.numComp = this.scan.numComp; + this.selection = this.scan.selection; + + if (this.numBytes === 1) { + if (this.numComp === 3) { + this.getter = this.getValueRGB; + this.setter = this.setValueRGB; + this.output = this.outputRGB; + } else { + this.getter = this.getValue8; + this.setter = this.setValue8; + this.output = this.outputSingle; + } + } else { + this.getter = this.getValue16; + this.setter = this.setValue16; + this.output = this.outputSingle; + } + + switch (this.selection) { + case 2: + this.selector = this.select2; + break; + case 3: + this.selector = this.select3; + break; + case 4: + this.selector = this.select4; + break; + case 5: + this.selector = this.select5; + break; + case 6: + this.selector = this.select6; + break; + case 7: + this.selector = this.select7; + break; + default: + this.selector = this.select1; + break; + } + + this.scanComps = this.scan.components; + this.quantTables = this.quantTable.quantTables; + + for (i = 0; i < this.numComp; i+=1) { + compN = this.scanComps[i].scanCompSel; + this.qTab[i] = this.quantTables[this.components[compN].quantTableSel]; + this.nBlock[i] = this.components[compN].vSamp * this.components[compN].hSamp; + this.dcTab[i] = this.HuffTab[this.scanComps[i].dcTabSel][0]; + this.acTab[i] = this.HuffTab[this.scanComps[i].acTabSel][1]; + } + + this.xDim = this.frame.dimX; + this.yDim = this.frame.dimY; + if (this.numBytes == 1) { + this.outputData = new Uint8Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp)); + } else { + this.outputData = new Uint16Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp)); + } + + scanNum+=1; + + while (true) { // Decode one scan + temp[0] = 0; + index[0] = 0; + + for (i = 0; i < 10; i+=1) { + pred[i] = (1 << (this.precision - 1)); + } + + if (this.restartInterval === 0) { + current = this.decodeUnit(pred, temp, index); + + while ((current === 0) && ((this.xLoc < this.xDim) && (this.yLoc < this.yDim))) { + this.output(pred); + current = this.decodeUnit(pred, temp, index); + } + + break; //current=MARKER + } + + for (mcuNum = 0; mcuNum < this.restartInterval; mcuNum+=1) { + this.restarting = (mcuNum == 0); + current = this.decodeUnit(pred, temp, index); + this.output(pred); + + if (current !== 0) { + break; + } + } + + if (current === 0) { + if (this.markerIndex !== 0) { + current = (0xFF00 | this.marker); + this.markerIndex = 0; + } else { + current = this.stream.get16(); + } + } + + if (!((current >= jpeg.lossless.Decoder.RESTART_MARKER_BEGIN) && + (current <= jpeg.lossless.Decoder.RESTART_MARKER_END))) { + break; //current=MARKER + } + } + + if ((current === 0xFFDC) && (scanNum === 1)) { //DNL + this.readNumber(); + current = this.stream.get16(); + } + } while ((current !== 0xFFD9) && ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) && (scanNum === 0)); + + return this.outputData; +}; + + + +jpeg.lossless.Decoder.prototype.decodeUnit = function (prev, temp, index) { + if (this.numComp == 1) { + return this.decodeSingle(prev, temp, index); + } else if (this.numComp == 3) { + return this.decodeRGB(prev, temp, index); + } else { + return -1; + } +}; + + + +jpeg.lossless.Decoder.prototype.select1 = function (compOffset) { + return this.getPreviousX(compOffset); +}; + + + +jpeg.lossless.Decoder.prototype.select2 = function (compOffset) { + return this.getPreviousY(compOffset); +}; + + + +jpeg.lossless.Decoder.prototype.select3 = function (compOffset) { + return this.getPreviousXY(compOffset); +}; + + + +jpeg.lossless.Decoder.prototype.select4 = function (compOffset) { + return (this.getPreviousX(compOffset) + this.getPreviousY(compOffset)) - this.getPreviousXY(compOffset); +}; + + + +jpeg.lossless.Decoder.prototype.select5 = function (compOffset) { + return this.getPreviousX(compOffset) + ((this.getPreviousY(compOffset) - this.getPreviousXY(compOffset)) >> 1); +}; + + + +jpeg.lossless.Decoder.prototype.select6 = function (compOffset) { + return this.getPreviousY(compOffset) + ((this.getPreviousX(compOffset) - this.getPreviousXY(compOffset)) >> 1); +}; + + + +jpeg.lossless.Decoder.prototype.select7 = function (compOffset) { + return ((this.getPreviousX(compOffset) + this.getPreviousY(compOffset)) / 2); +}; + + + +jpeg.lossless.Decoder.prototype.decodeRGB = function (prev, temp, index) { + /*jslint bitwise: true */ + + var value, actab, dctab, qtab, ctrC, i, k, j; + + prev[0] = this.selector(0); + prev[1] = this.selector(1); + prev[2] = this.selector(2); + + for (ctrC = 0; ctrC < this.numComp; ctrC+=1) { + qtab = this.qTab[ctrC]; + actab = this.acTab[ctrC]; + dctab = this.dcTab[ctrC]; + for (i = 0; i < this.nBlock[ctrC]; i+=1) { + for (k = 0; k < this.IDCT_Source.length; k+=1) { + this.IDCT_Source[k] = 0; + } + + value = this.getHuffmanValue(dctab, temp, index); + + if (value >= 0xFF00) { + return value; + } + + prev[ctrC] = this.IDCT_Source[0] = prev[ctrC] + this.getn(index, value, temp, index); + this.IDCT_Source[0] *= qtab[0]; + + for (j = 1; j < 64; j+=1) { + value = this.getHuffmanValue(actab, temp, index); + + if (value >= 0xFF00) { + return value; + } + + j += (value >> 4); + + if ((value & 0x0F) === 0) { + if ((value >> 4) === 0) { + break; + } + } else { + this.IDCT_Source[jpeg.lossless.Decoder.IDCT_P[j]] = this.getn(index, value & 0x0F, temp, index) * qtab[j]; + } + } + } + } + + return 0; +}; + + + +jpeg.lossless.Decoder.prototype.decodeSingle = function (prev, temp, index) { + /*jslint bitwise: true */ + + var value, i, n, nRestart; + + if (this.restarting) { + this.restarting = false; + prev[0] = (1 << (this.frame.precision - 1)); + } else { + prev[0] = this.selector(); + } + + for (i = 0; i < this.nBlock[0]; i+=1) { + value = this.getHuffmanValue(this.dcTab[0], temp, index); + if (value >= 0xFF00) { + return value; + } + + n = this.getn(prev, value, temp, index); + nRestart = (n >> 8); + + if ((nRestart >= jpeg.lossless.Decoder.RESTART_MARKER_BEGIN) && (nRestart <= jpeg.lossless.Decoder.RESTART_MARKER_END)) { + return nRestart; + } + + prev[0] += n; + } + + return 0; +}; + + + +// Huffman table for fast search: (HuffTab) 8-bit Look up table 2-layer search architecture, 1st-layer represent 256 node (8 bits) if codeword-length > 8 +// bits, then the entry of 1st-layer = (# of 2nd-layer table) | MSB and it is stored in the 2nd-layer Size of tables in each layer are 256. +// HuffTab[*][*][0-256] is always the only 1st-layer table. +// +// An entry can be: (1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer (2) (Code length) << 8 | HuffVal +// +// HuffmanValue(table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) +// ): +// return: Huffman Value of table +// 0xFF?? if it receives a MARKER +// Parameter: table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) +// temp temp storage for remainded bits +// index index to bit of temp +// in FILE pointer +// Effect: +// temp store new remainded bits +// index change to new index +// in change to new position +// NOTE: +// Initial by temp=0; index=0; +// NOTE: (explain temp and index) +// temp: is always in the form at calling time or returning time +// | byte 4 | byte 3 | byte 2 | byte 1 | +// | 0 | 0 | 00000000 | 00000??? | if not a MARKER +// ^index=3 (from 0 to 15) +// 321 +// NOTE (marker and marker_index): +// If get a MARKER from 'in', marker=the low-byte of the MARKER +// and marker_index=9 +// If marker_index=9 then index is always > 8, or HuffmanValue() +// will not be called +jpeg.lossless.Decoder.prototype.getHuffmanValue = function (table, temp, index) { + /*jslint bitwise: true */ + + var code, input, mask; + mask = 0xFFFF; + + if (index[0] < 8) { + temp[0] <<= 8; + input = this.stream.get8(); + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + temp[0] |= input; + } else { + index[0] -= 8; + } + + code = table[temp[0] >> index[0]]; + + if ((code & jpeg.lossless.Decoder.MSB) !== 0) { + if (this.markerIndex !== 0) { + this.markerIndex = 0; + return 0xFF00 | this.marker; + } + + temp[0] &= (mask >> (16 - index[0])); + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + code = table[((code & 0xFF) * 256) + (temp[0] >> index[0])]; + index[0] += 8; + } + + index[0] += 8 - (code >> 8); + + if (index[0] < 0) { + throw new Error("index=" + index[0] + " temp=" + temp[0] + " code=" + code + " in HuffmanValue()"); + } + + if (index[0] < this.markerIndex) { + this.markerIndex = 0; + return 0xFF00 | this.marker; + } + + temp[0] &= (mask >> (16 - index[0])); + return code & 0xFF; +}; + + + +jpeg.lossless.Decoder.prototype.getn = function (PRED, n, temp, index) { + /*jslint bitwise: true */ + + var result, one, n_one, mask, input; + one = 1; + n_one = -1; + mask = 0xFFFF; + + if (n === 0) { + return 0; + } + + if (n === 16) { + if (PRED[0] >= 0) { + return -32768; + } else { + return 32768; + } + } + + index[0] -= n; + + if (index[0] >= 0) { + if ((index[0] < this.markerIndex) && !this.isLastPixel()) { // this was corrupting the last pixel in some cases + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + result = temp[0] >> index[0]; + temp[0] &= (mask >> (16 - index[0])); + } else { + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + index[0] += 8; + + if (index[0] < 0) { + if (this.markerIndex !== 0) { + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + temp[0] <<= 8; + input = this.stream.get8(); + + if (input === 0xFF) { + this.marker = this.stream.get8(); + if (this.marker !== 0) { + this.markerIndex = 9; + } + } + + temp[0] |= input; + index[0] += 8; + } + + if (index[0] < 0) { + throw new Error("index=" + index[0] + " in getn()"); + } + + if (index[0] < this.markerIndex) { + this.markerIndex = 0; + return (0xFF00 | this.marker) << 8; + } + + result = temp[0] >> index[0]; + temp[0] &= (mask >> (16 - index[0])); + } + + if (result < (one << (n - 1))) { + result += (n_one << n) + 1; + } + + return result; +}; + + + +jpeg.lossless.Decoder.prototype.getPreviousX = function (compOffset) { + /*jslint bitwise: true */ + + if (this.xLoc > 0) { + return this.getter((((this.yLoc * this.xDim) + this.xLoc) - 1), compOffset); + } else if (this.yLoc > 0) { + return this.getPreviousY(compOffset); + } else { + return (1 << (this.frame.precision - 1)); + } +}; + + + +jpeg.lossless.Decoder.prototype.getPreviousXY = function (compOffset) { + /*jslint bitwise: true */ + + if ((this.xLoc > 0) && (this.yLoc > 0)) { + return this.getter(((((this.yLoc - 1) * this.xDim) + this.xLoc) - 1), compOffset); + } else { + return this.getPreviousY(compOffset); + } +}; + + + +jpeg.lossless.Decoder.prototype.getPreviousY = function (compOffset) { + /*jslint bitwise: true */ + + if (this.yLoc > 0) { + return this.getter((((this.yLoc - 1) * this.xDim) + this.xLoc), compOffset); + } else { + return this.getPreviousX(compOffset); + } +}; + + + +jpeg.lossless.Decoder.prototype.isLastPixel = function () { + return (this.xLoc === (this.xDim - 1)) && (this.yLoc === (this.yDim - 1)); +}; + + + +jpeg.lossless.Decoder.prototype.outputSingle = function (PRED) { + if ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) { + this.setter((((this.yLoc * this.xDim) + this.xLoc)), this.mask & PRED[0]); + + this.xLoc+=1; + + if (this.xLoc >= this.xDim) { + this.yLoc+=1; + this.xLoc = 0; + } + } +}; + + + +jpeg.lossless.Decoder.prototype.outputRGB = function (PRED) { + var offset = ((this.yLoc * this.xDim) + this.xLoc); + + if ((this.xLoc < this.xDim) && (this.yLoc < this.yDim)) { + this.setter(offset, PRED[0], 0); + this.setter(offset, PRED[1], 1); + this.setter(offset, PRED[2], 2); + + this.xLoc+=1; + + if (this.xLoc >= this.xDim) { + this.yLoc+=1; + this.xLoc = 0; + } + } +}; + +jpeg.lossless.Decoder.prototype.setValue8 = function (index, val) { + this.outputData[index] = val; +}; + +jpeg.lossless.Decoder.prototype.getValue8 = function (index) { + return this.outputData[index]; // mask should not be necessary because outputData is either Int8Array or Int16Array +}; + +var littleEndian = (function() { + var buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true /* littleEndian */); + // Int16Array uses the platform's endianness. + return new Int16Array(buffer)[0] === 256; +})(); + +if (littleEndian) { + // just reading from an array is fine then. Int16Array will use platform endianness. + jpeg.lossless.Decoder.prototype.setValue16 = jpeg.lossless.Decoder.prototype.setValue8; + jpeg.lossless.Decoder.prototype.getValue16 = jpeg.lossless.Decoder.prototype.getValue8; +} +else { + // If platform is big-endian, we will need to convert to little-endian + jpeg.lossless.Decoder.prototype.setValue16 = function (index, val) { + this.outputData[index] = ((val & 0xFF) << 8) | ((val >> 8) & 0xFF); + }; + + jpeg.lossless.Decoder.prototype.getValue16 = function (index) { + var val = this.outputData[index]; + return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF); + }; +} + +jpeg.lossless.Decoder.prototype.setValueRGB = function (index, val, compOffset) { + // this.outputData.setUint8(index * 3 + compOffset, val); + this.outputData[index * 3 + compOffset] = val; +}; + +jpeg.lossless.Decoder.prototype.getValueRGB = function (index, compOffset) { + // return this.outputData.getUint8(index * 3 + compOffset); + return this.outputData[index * 3 + compOffset]; +}; + + + +jpeg.lossless.Decoder.prototype.readApp = function() { + var count = 0, length = this.stream.get16(); + count += 2; + + while (count < length) { + this.stream.get8(); + count+=1; + } + + return length; +}; + + + +jpeg.lossless.Decoder.prototype.readComment = function () { + var sb = "", count = 0, length; + + length = this.stream.get16(); + count += 2; + + while (count < length) { + sb += this.stream.get8(); + count+=1; + } + + return sb; +}; + + + +jpeg.lossless.Decoder.prototype.readNumber = function() { + var Ld = this.stream.get16(); + + if (Ld !== 4) { + throw new Error("ERROR: Define number format throw new IOException [Ld!=4]"); + } + + return this.stream.get16(); +}; + + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.Decoder; +} + +},{"./data-stream.js":9,"./frame-header.js":11,"./huffman-table.js":12,"./quantization-table.js":14,"./scan-header.js":16,"./utils.js":17}],11:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; +jpeg.lossless.ComponentSpec = jpeg.lossless.ComponentSpec || ((typeof require !== 'undefined') ? require('./component-spec.js') : null); +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); + + +/*** Constructor ***/ +jpeg.lossless.FrameHeader = jpeg.lossless.FrameHeader || function () { + this.components = []; // Components + this.dimX = 0; // Number of samples per line + this.dimY = 0; // Number of lines + this.numComp = 0; // Number of component in the frame + this.precision = 0; // Sample Precision (from the original image) +}; + + + +/*** Prototype Methods ***/ + +jpeg.lossless.FrameHeader.prototype.read = function (data) { + /*jslint bitwise: true */ + + var count = 0, length, i, c, temp; + + length = data.get16(); + count += 2; + + this.precision = data.get8(); + count+=1; + + this.dimY = data.get16(); + count += 2; + + this.dimX = data.get16(); + count += 2; + + this.numComp = data.get8(); + count+=1; + for (i = 1; i <= this.numComp; i+=1) { + if (count > length) { + throw new Error("ERROR: frame format error"); + } + + c = data.get8(); + count+=1; + + if (count >= length) { + throw new Error("ERROR: frame format error [c>=Lf]"); + } + + temp = data.get8(); + count+=1; + + if (!this.components[c]) { + this.components[c] = new jpeg.lossless.ComponentSpec(); + } + + this.components[c].hSamp = temp >> 4; + this.components[c].vSamp = temp & 0x0F; + this.components[c].quantTableSel = data.get8(); + count+=1; + } + + if (count !== length) { + throw new Error("ERROR: frame format error [Lf!=count]"); + } + + return 1; +}; + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.FrameHeader; +} + +},{"./component-spec.js":8,"./data-stream.js":9}],12:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); +jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + +/*** Constructor ***/ +jpeg.lossless.HuffmanTable = jpeg.lossless.HuffmanTable || function () { + this.l = jpeg.lossless.Utils.createArray(4, 2, 16); + this.th = []; + this.v = jpeg.lossless.Utils.createArray(4, 2, 16, 200); + this.tc = jpeg.lossless.Utils.createArray(4, 2); + + this.tc[0][0] = 0; + this.tc[1][0] = 0; + this.tc[2][0] = 0; + this.tc[3][0] = 0; + this.tc[0][1] = 0; + this.tc[1][1] = 0; + this.tc[2][1] = 0; + this.tc[3][1] = 0; + this.th[0] = 0; + this.th[1] = 0; + this.th[2] = 0; + this.th[3] = 0; +}; + + + +/*** Static Pseudo-constants ***/ + +jpeg.lossless.HuffmanTable.MSB = 0x80000000; + + +/*** Prototype Methods ***/ + +jpeg.lossless.HuffmanTable.prototype.read = function(data, HuffTab) { + /*jslint bitwise: true */ + + var count = 0, length, temp, t, c, i, j; + + length = data.get16(); + count += 2; + + while (count < length) { + temp = data.get8(); + count+=1; + t = temp & 0x0F; + if (t > 3) { + throw new Error("ERROR: Huffman table ID > 3"); + } + + c = temp >> 4; + if (c > 2) { + throw new Error("ERROR: Huffman table [Table class > 2 ]"); + } + + this.th[t] = 1; + this.tc[t][c] = 1; + + for (i = 0; i < 16; i+=1) { + this.l[t][c][i] = data.get8(); + count+=1; + } + + for (i = 0; i < 16; i+=1) { + for (j = 0; j < this.l[t][c][i]; j+=1) { + if (count > length) { + throw new Error("ERROR: Huffman table format error [count>Lh]"); + } + + this.v[t][c][i][j] = data.get8(); + count+=1; + } + } + } + + if (count !== length) { + throw new Error("ERROR: Huffman table format error [count!=Lf]"); + } + + for (i = 0; i < 4; i+=1) { + for (j = 0; j < 2; j+=1) { + if (this.tc[i][j] !== 0) { + this.buildHuffTable(HuffTab[i][j], this.l[i][j], this.v[i][j]); + } + } + } + + return 1; +}; + + + +// Build_HuffTab() +// Parameter: t table ID +// c table class ( 0 for DC, 1 for AC ) +// L[i] # of codewords which length is i +// V[i][j] Huffman Value (length=i) +// Effect: +// build up HuffTab[t][c] using L and V. +jpeg.lossless.HuffmanTable.prototype.buildHuffTable = function(tab, L, V) { + /*jslint bitwise: true */ + + var currentTable, temp, k, i, j, n; + temp = 256; + k = 0; + + for (i = 0; i < 8; i+=1) { // i+1 is Code length + for (j = 0; j < L[i]; j+=1) { + for (n = 0; n < (temp >> (i + 1)); n+=1) { + tab[k] = V[i][j] | ((i + 1) << 8); + k+=1; + } + } + } + + for (i = 1; k < 256; i+=1, k+=1) { + tab[k] = i | jpeg.lossless.HuffmanTable.MSB; + } + + currentTable = 1; + k = 0; + + for (i = 8; i < 16; i+=1) { // i+1 is Code length + for (j = 0; j < L[i]; j+=1) { + for (n = 0; n < (temp >> (i - 7)); n+=1) { + tab[(currentTable * 256) + k] = V[i][j] | ((i + 1) << 8); + k+=1; + } + + if (k >= 256) { + if (k > 256) { + throw new Error("ERROR: Huffman table error(1)!"); + } + + k = 0; + currentTable+=1; + } + } + } +}; + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.HuffmanTable; +} + +},{"./data-stream.js":9,"./utils.js":17}],13:[function(require,module,exports){ +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ****/ + +/** + * jpeg + * @type {*|{}} + */ +var jpeg = jpeg || {}; + +/** + * jpeg.lossless + * @type {*|{}} + */ +jpeg.lossless = jpeg.lossless || {}; + + +jpeg.lossless.ComponentSpec = jpeg.lossless.ComponentSpec || ((typeof require !== 'undefined') ? require('./component-spec.js') : null); +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); +jpeg.lossless.Decoder = jpeg.lossless.Decoder || ((typeof require !== 'undefined') ? require('./decoder.js') : null); +jpeg.lossless.FrameHeader = jpeg.lossless.FrameHeader || ((typeof require !== 'undefined') ? require('./frame-header.js') : null); +jpeg.lossless.HuffmanTable = jpeg.lossless.HuffmanTable || ((typeof require !== 'undefined') ? require('./huffman-table.js') : null); +jpeg.lossless.QuantizationTable = jpeg.lossless.QuantizationTable || ((typeof require !== 'undefined') ? require('./quantization-table.js') : null); +jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || ((typeof require !== 'undefined') ? require('./scan-component.js') : null); +jpeg.lossless.ScanHeader = jpeg.lossless.ScanHeader || ((typeof require !== 'undefined') ? require('./scan-header.js') : null); +jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + +/*** Exports ***/ +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg; +} + +},{"./component-spec.js":8,"./data-stream.js":9,"./decoder.js":10,"./frame-header.js":11,"./huffman-table.js":12,"./quantization-table.js":14,"./scan-component.js":15,"./scan-header.js":16,"./utils.js":17}],14:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); +jpeg.lossless.Utils = jpeg.lossless.Utils || ((typeof require !== 'undefined') ? require('./utils.js') : null); + + +/*** Constructor ***/ +jpeg.lossless.QuantizationTable = jpeg.lossless.QuantizationTable || function () { + this.precision = []; // Quantization precision 8 or 16 + this.tq = []; // 1: this table is presented + this.quantTables = jpeg.lossless.Utils.createArray(4, 64); // Tables + + this.tq[0] = 0; + this.tq[1] = 0; + this.tq[2] = 0; + this.tq[3] = 0; +}; + + + +/*** Static Methods ***/ + +jpeg.lossless.QuantizationTable.enhanceQuantizationTable = function(qtab, table) { + /*jslint bitwise: true */ + + var i; + + for (i = 0; i < 8; i+=1) { + qtab[table[(0 * 8) + i]] *= 90; + qtab[table[(4 * 8) + i]] *= 90; + qtab[table[(2 * 8) + i]] *= 118; + qtab[table[(6 * 8) + i]] *= 49; + qtab[table[(5 * 8) + i]] *= 71; + qtab[table[(1 * 8) + i]] *= 126; + qtab[table[(7 * 8) + i]] *= 25; + qtab[table[(3 * 8) + i]] *= 106; + } + + for (i = 0; i < 8; i+=1) { + qtab[table[0 + (8 * i)]] *= 90; + qtab[table[4 + (8 * i)]] *= 90; + qtab[table[2 + (8 * i)]] *= 118; + qtab[table[6 + (8 * i)]] *= 49; + qtab[table[5 + (8 * i)]] *= 71; + qtab[table[1 + (8 * i)]] *= 126; + qtab[table[7 + (8 * i)]] *= 25; + qtab[table[3 + (8 * i)]] *= 106; + } + + for (i = 0; i < 64; i+=1) { + qtab[i] >>= 6; + } +}; + + +/*** Prototype Methods ***/ + +jpeg.lossless.QuantizationTable.prototype.read = function (data, table) { + /*jslint bitwise: true */ + + var count = 0, length, temp, t, i; + + length = data.get16(); + count += 2; + + while (count < length) { + temp = data.get8(); + count+=1; + t = temp & 0x0F; + + if (t > 3) { + throw new Error("ERROR: Quantization table ID > 3"); + } + + this.precision[t] = temp >> 4; + + if (this.precision[t] === 0) { + this.precision[t] = 8; + } else if (this.precision[t] === 1) { + this.precision[t] = 16; + } else { + throw new Error("ERROR: Quantization table precision error"); + } + + this.tq[t] = 1; + + if (this.precision[t] === 8) { + for (i = 0; i < 64; i+=1) { + if (count > length) { + throw new Error("ERROR: Quantization table format error"); + } + + this.quantTables[t][i] = data.get8(); + count+=1; + } + + jpeg.lossless.QuantizationTable.enhanceQuantizationTable(this.quantTables[t], table); + } else { + for (i = 0; i < 64; i+=1) { + if (count > length) { + throw new Error("ERROR: Quantization table format error"); + } + + this.quantTables[t][i] = data.get16(); + count += 2; + } + + jpeg.lossless.QuantizationTable.enhanceQuantizationTable(this.quantTables[t], table); + } + } + + if (count !== length) { + throw new Error("ERROR: Quantization table error [count!=Lq]"); + } + + return 1; +}; + + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.QuantizationTable; +} + +},{"./data-stream.js":9,"./utils.js":17}],15:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; + + +/*** Constructor ***/ +jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || function () { + this.acTabSel = 0; // AC table selector + this.dcTabSel = 0; // DC table selector + this.scanCompSel = 0; // Scan component selector +}; + + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.ScanComponent; +} + +},{}],16:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; +jpeg.lossless.DataStream = jpeg.lossless.DataStream || ((typeof require !== 'undefined') ? require('./data-stream.js') : null); +jpeg.lossless.ScanComponent = jpeg.lossless.ScanComponent || ((typeof require !== 'undefined') ? require('./scan-component.js') : null); + + +/*** Constructor ***/ +jpeg.lossless.ScanHeader = jpeg.lossless.ScanHeader || function () { + this.ah = 0; + this.al = 0; + this.numComp = 0; // Number of components in the scan + this.selection = 0; // Start of spectral or predictor selection + this.spectralEnd = 0; // End of spectral selection + this.components = []; +}; + + +/*** Prototype Methods ***/ + +jpeg.lossless.ScanHeader.prototype.read = function(data) { + /*jslint bitwise: true */ + + var count = 0, length, i, temp; + + length = data.get16(); + count += 2; + + this.numComp = data.get8(); + count+=1; + + for (i = 0; i < this.numComp; i+=1) { + this.components[i] = new jpeg.lossless.ScanComponent(); + + if (count > length) { + throw new Error("ERROR: scan header format error"); + } + + this.components[i].scanCompSel = data.get8(); + count+=1; + + temp = data.get8(); + count+=1; + + this.components[i].dcTabSel = (temp >> 4); + this.components[i].acTabSel = (temp & 0x0F); + } + + this.selection = data.get8(); + count+=1; + + this.spectralEnd = data.get8(); + count+=1; + + temp = data.get8(); + this.ah = (temp >> 4); + this.al = (temp & 0x0F); + count+=1; + + if (count !== length) { + throw new Error("ERROR: scan header format error [count!=Ns]"); + } + + return 1; +}; + + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.ScanHeader; +} + +},{"./data-stream.js":9,"./scan-component.js":15}],17:[function(require,module,exports){ +/* + * Copyright (C) 2015 Michael Martinez + * Changes: Added support for selection values 2-7, fixed minor bugs & + * warnings, split into multiple class files, and general clean up. + * + * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT. + */ + +/* + * Copyright (C) Helmut Dersch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/*jslint browser: true, node: true */ +/*global require, module */ + +"use strict"; + +/*** Imports ***/ +var jpeg = jpeg || {}; +jpeg.lossless = jpeg.lossless || {}; + + +/*** Constructor ***/ +jpeg.lossless.Utils = jpeg.lossless.Utils || {}; + + +/*** Static methods ***/ + +// http://stackoverflow.com/questions/966225/how-can-i-create-a-two-dimensional-array-in-javascript +jpeg.lossless.Utils.createArray = function (length) { + var arr = new Array(length || 0), + i = length; + + if (arguments.length > 1) { + var args = Array.prototype.slice.call(arguments, 1); + while(i--) arr[length-1 - i] = jpeg.lossless.Utils.createArray.apply(this, args); + } + + return arr; +}; + + +// http://stackoverflow.com/questions/18638900/javascript-crc32 +jpeg.lossless.Utils.makeCRCTable = function(){ + var c; + var crcTable = []; + for(var n =0; n < 256; n++){ + c = n; + for(var k =0; k < 8; k++){ + c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + crcTable[n] = c; + } + return crcTable; +}; + +jpeg.lossless.Utils.crc32 = function(dataView) { + var uint8view = new Uint8Array(dataView.buffer); + var crcTable = jpeg.lossless.Utils.crcTable || (jpeg.lossless.Utils.crcTable = jpeg.lossless.Utils.makeCRCTable()); + var crc = 0 ^ (-1); + + for (var i = 0; i < uint8view.length; i++ ) { + crc = (crc >>> 8) ^ crcTable[(crc ^ uint8view[i]) & 0xFF]; + } + + return (crc ^ (-1)) >>> 0; +}; + + +/*** Exports ***/ + +var moduleType = typeof module; +if ((moduleType !== 'undefined') && module.exports) { + module.exports = jpeg.lossless.Utils; +} + +},{}],18:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ungzip = exports.inflateRaw = exports.inflate = exports.gzip = exports.deflateRaw = exports.deflate = exports.default = exports.constants = exports.Inflate = exports.Deflate = void 0; + +/*! pako 2.0.4 https://github.com/nodeca/pako @license (MIT AND Zlib) */ +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +/* eslint-disable space-unary-ops */ + +/* Public constants ==========================================================*/ + +/* ===========================================================================*/ +//const Z_FILTERED = 1; +//const Z_HUFFMAN_ONLY = 2; +//const Z_RLE = 3; +const Z_FIXED$1 = 4; //const Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ + +const Z_BINARY = 0; +const Z_TEXT = 1; //const Z_ASCII = 1; // = Z_TEXT + +const Z_UNKNOWN$1 = 2; +/*============================================================================*/ + +function zero$1(buf) { + let len = buf.length; + + while (--len >= 0) { + buf[len] = 0; + } +} // From zutil.h + + +const STORED_BLOCK = 0; +const STATIC_TREES = 1; +const DYN_TREES = 2; +/* The three kinds of block type */ + +const MIN_MATCH$1 = 3; +const MAX_MATCH$1 = 258; +/* The minimum and maximum match lengths */ +// From deflate.h + +/* =========================================================================== + * Internal compression state. + */ + +const LENGTH_CODES$1 = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +const LITERALS$1 = 256; +/* number of literal bytes 0..255 */ + +const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1; +/* number of Literal or Length codes, including the END_BLOCK code */ + +const D_CODES$1 = 30; +/* number of distance codes */ + +const BL_CODES$1 = 19; +/* number of codes used to transfer the bit lengths */ + +const HEAP_SIZE$1 = 2 * L_CODES$1 + 1; +/* maximum heap size */ + +const MAX_BITS$1 = 15; +/* All codes must not exceed MAX_BITS bits */ + +const Buf_size = 16; +/* size of bit buffer in bi_buf */ + +/* =========================================================================== + * Constants + */ + +const MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +const END_BLOCK = 256; +/* end of block literal code */ + +const REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +const REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +const REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +/* eslint-disable comma-spacing,array-bracket-spacing */ + +const extra_lbits = +/* extra bits for each length code */ +new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]); +const extra_dbits = +/* extra bits for each distance code */ +new Uint8Array([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]); +const extra_blbits = +/* extra bits for each bit length code */ +new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]); +const bl_order = new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +/* eslint-enable comma-spacing,array-bracket-spacing */ + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ +// We pre-fill arrays with 0 to avoid uninitialized gaps + +const DIST_CODE_LEN = 512; +/* see definition of array dist_code below */ +// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 + +const static_ltree = new Array((L_CODES$1 + 2) * 2); +zero$1(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +const static_dtree = new Array(D_CODES$1 * 2); +zero$1(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +const _dist_code = new Array(DIST_CODE_LEN); + +zero$1(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1); + +zero$1(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +const base_length = new Array(LENGTH_CODES$1); +zero$1(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +const base_dist = new Array(D_CODES$1); +zero$1(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + +function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { + this.static_tree = static_tree; + /* static tree or NULL */ + + this.extra_bits = extra_bits; + /* extra bits for each code or NULL */ + + this.extra_base = extra_base; + /* base index for extra_bits */ + + this.elems = elems; + /* max number of elements in the tree */ + + this.max_length = max_length; + /* max bit length for the codes */ + // show if `static_tree` has data or dummy - needed for monomorphic objects + + this.has_stree = static_tree && static_tree.length; +} + +let static_l_desc; +let static_d_desc; +let static_bl_desc; + +function TreeDesc(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; + /* the dynamic tree */ + + this.max_code = 0; + /* largest code with non zero frequency */ + + this.stat_desc = stat_desc; + /* the corresponding static tree */ +} + +const d_code = dist => { + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +}; +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ + + +const put_short = (s, w) => { + // put_byte(s, (uch)((w) & 0xff)); + // put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = w & 0xff; + s.pending_buf[s.pending++] = w >>> 8 & 0xff; +}; +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ + + +const send_bits = (s, value, length) => { + if (s.bi_valid > Buf_size - length) { + s.bi_buf |= value << s.bi_valid & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> Buf_size - s.bi_valid; + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= value << s.bi_valid & 0xffff; + s.bi_valid += length; + } +}; + +const send_code = (s, c, tree) => { + send_bits(s, tree[c * 2] + /*.Code*/ + , tree[c * 2 + 1] + /*.Len*/ + ); +}; +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ + + +const bi_reverse = (code, len) => { + let res = 0; + + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + + return res >>> 1; +}; +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ + + +const bi_flush = s => { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +}; +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ + + +const gen_bitlen = (s, desc) => // deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + const tree = desc.dyn_tree; + const max_code = desc.max_code; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const extra = desc.stat_desc.extra_bits; + const base = desc.stat_desc.extra_base; + const max_length = desc.stat_desc.max_length; + let h; + /* heap index */ + + let n, m; + /* iterate over the tree elements */ + + let bits; + /* bit length */ + + let xbits; + /* extra bits */ + + let f; + /* frequency */ + + let overflow = 0; + /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS$1; bits++) { + s.bl_count[bits] = 0; + } + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + + + tree[s.heap[s.heap_max] * 2 + 1] + /*.Len*/ + = 0; + /* root of the heap */ + + for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) { + n = s.heap[h]; + bits = tree[tree[n * 2 + 1] + /*.Dad*/ + * 2 + 1] + /*.Len*/ + + 1; + + if (bits > max_length) { + bits = max_length; + overflow++; + } + + tree[n * 2 + 1] + /*.Len*/ + = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { + continue; + } + /* not a leaf node */ + + + s.bl_count[bits]++; + xbits = 0; + + if (n >= base) { + xbits = extra[n - base]; + } + + f = tree[n * 2] + /*.Freq*/ + ; + s.opt_len += f * (bits + xbits); + + if (has_stree) { + s.static_len += f * (stree[n * 2 + 1] + /*.Len*/ + + xbits); + } + } + + if (overflow === 0) { + return; + } // Trace((stderr,"\nbit length overflow\n")); + + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + + + do { + bits = max_length - 1; + + while (s.bl_count[bits] === 0) { + bits--; + } + + s.bl_count[bits]--; + /* move one leaf down the tree */ + + s.bl_count[bits + 1] += 2; + /* move one overflow item as its brother */ + + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + + overflow -= 2; + } while (overflow > 0); + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + + + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + + while (n !== 0) { + m = s.heap[--h]; + + if (m > max_code) { + continue; + } + + if (tree[m * 2 + 1] + /*.Len*/ + !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m * 2 + 1] + /*.Len*/ + ) * tree[m * 2] + /*.Freq*/ + ; + tree[m * 2 + 1] + /*.Len*/ + = bits; + } + + n--; + } + } +}; +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ + + +const gen_codes = (tree, max_code, bl_count) => // ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ +{ + const next_code = new Array(MAX_BITS$1 + 1); + /* next code value for each bit length */ + + let code = 0; + /* running code value */ + + let bits; + /* bit index */ + + let n; + /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + + for (bits = 1; bits <= MAX_BITS$1; bits++) { + next_code[bits] = code = code + bl_count[bits - 1] << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< { + let n; + /* iterates over tree elements */ + + let bits; + /* bit counter */ + + let length; + /* length value */ + + let code; + /* code value */ + + let dist; + /* distance index */ + + const bl_count = new Array(MAX_BITS$1 + 1); + /* number of codes at each bit length for an optimal tree */ + // do check in _tr_init() + //if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + + /*#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + #endif*/ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + + length = 0; + + for (code = 0; code < LENGTH_CODES$1 - 1; code++) { + base_length[code] = length; + + for (n = 0; n < 1 << extra_lbits[code]; n++) { + _length_code[length++] = code; + } + } //Assert (length == 256, "tr_static_init: length != 256"); + + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + + + _length_code[length - 1] = code; + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + + dist = 0; + + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + + for (n = 0; n < 1 << extra_dbits[code]; n++) { + _dist_code[dist++] = code; + } + } //Assert (dist == 256, "tr_static_init: dist != 256"); + + + dist >>= 7; + /* from now on, all distances are divided by 128 */ + + for (; code < D_CODES$1; code++) { + base_dist[code] = dist << 7; + + for (n = 0; n < 1 << extra_dbits[code] - 7; n++) { + _dist_code[256 + dist++] = code; + } + } //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + + + for (bits = 0; bits <= MAX_BITS$1; bits++) { + bl_count[bits] = 0; + } + + n = 0; + + while (n <= 143) { + static_ltree[n * 2 + 1] + /*.Len*/ + = 8; + n++; + bl_count[8]++; + } + + while (n <= 255) { + static_ltree[n * 2 + 1] + /*.Len*/ + = 9; + n++; + bl_count[9]++; + } + + while (n <= 279) { + static_ltree[n * 2 + 1] + /*.Len*/ + = 7; + n++; + bl_count[7]++; + } + + while (n <= 287) { + static_ltree[n * 2 + 1] + /*.Len*/ + = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + + + gen_codes(static_ltree, L_CODES$1 + 1, bl_count); + /* The static distance tree is trivial: */ + + for (n = 0; n < D_CODES$1; n++) { + static_dtree[n * 2 + 1] + /*.Len*/ + = 5; + static_dtree[n * 2] + /*.Code*/ + = bi_reverse(n, 5); + } // Now data ready and we can init static trees + + + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1); + static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS); //static_init_done = true; +}; +/* =========================================================================== + * Initialize a new block. + */ + + +const init_block = s => { + let n; + /* iterates over tree elements */ + + /* Initialize the trees. */ + + for (n = 0; n < L_CODES$1; n++) { + s.dyn_ltree[n * 2] + /*.Freq*/ + = 0; + } + + for (n = 0; n < D_CODES$1; n++) { + s.dyn_dtree[n * 2] + /*.Freq*/ + = 0; + } + + for (n = 0; n < BL_CODES$1; n++) { + s.bl_tree[n * 2] + /*.Freq*/ + = 0; + } + + s.dyn_ltree[END_BLOCK * 2] + /*.Freq*/ + = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; +}; +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ + + +const bi_windup = s => { + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + + s.bi_buf = 0; + s.bi_valid = 0; +}; +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ + + +const copy_block = (s, buf, len, header) => //DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); + /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } // while (len--) { + // put_byte(s, *buf++); + // } + + + s.pending_buf.set(s.window.subarray(buf, buf + len), s.pending); + s.pending += len; +}; +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ + + +const smaller = (tree, n, m, depth) => { + const _n2 = n * 2; + + const _m2 = m * 2; + + return tree[_n2] + /*.Freq*/ + < tree[_m2] + /*.Freq*/ + || tree[_n2] + /*.Freq*/ + === tree[_m2] + /*.Freq*/ + && depth[n] <= depth[m]; +}; +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ + + +const pqdownheap = (s, tree, k) => // deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ +{ + const v = s.heap[k]; + let j = k << 1; + /* left son of k */ + + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + + + if (smaller(tree, v, s.heap[j], s.depth)) { + break; + } + /* Exchange v with the smallest son */ + + + s.heap[k] = s.heap[j]; + k = j; + /* And continue down the tree, setting j to the left son of k */ + + j <<= 1; + } + + s.heap[k] = v; +}; // inlined manually +// const SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ + + +const compress_block = (s, ltree, dtree) => // deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ +{ + let dist; + /* distance of matched string */ + + let lc; + /* match length or unmatched char (if dist == 0) */ + + let lx = 0; + /* running index in l_buf */ + + let code; + /* the code to send */ + + let extra; + /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = s.pending_buf[s.d_buf + lx * 2] << 8 | s.pending_buf[s.d_buf + lx * 2 + 1]; + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); + /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS$1 + 1, ltree); + /* send the length code */ + + extra = extra_lbits[code]; + + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); + /* send the extra length bits */ + } + + dist--; + /* dist is now the match distance - 1 */ + + code = d_code(dist); //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); + /* send the distance code */ + + extra = extra_dbits[code]; + + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); + /* send the extra distance bits */ + } + } + /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); +}; +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ + + +const build_tree = (s, desc) => // deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + const tree = desc.dyn_tree; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const elems = desc.stat_desc.elems; + let n, m; + /* iterate over heap elements */ + + let max_code = -1; + /* largest code with non zero frequency */ + + let node; + /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + + s.heap_len = 0; + s.heap_max = HEAP_SIZE$1; + + for (n = 0; n < elems; n++) { + if (tree[n * 2] + /*.Freq*/ + !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + } else { + tree[n * 2 + 1] + /*.Len*/ + = 0; + } + } + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + + + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0; + tree[node * 2] + /*.Freq*/ + = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node * 2 + 1] + /*.Len*/ + ; + } + /* node is 0 or 1 so it does not have extra bits */ + + } + + desc.max_code = max_code; + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + + for (n = s.heap_len >> 1 + /*int /2*/ + ; n >= 1; n--) { + pqdownheap(s, tree, n); + } + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + + + node = elems; + /* next internal node of the tree */ + + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + + /*** pqremove ***/ + n = s.heap[1 + /*SMALLEST*/ + ]; + s.heap[1 + /*SMALLEST*/ + ] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1 + /*SMALLEST*/ + ); + /***/ + + m = s.heap[1 + /*SMALLEST*/ + ]; + /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; + /* keep the nodes sorted by frequency */ + + s.heap[--s.heap_max] = m; + /* Create a new node father of n and m */ + + tree[node * 2] + /*.Freq*/ + = tree[n * 2] + /*.Freq*/ + + tree[m * 2] + /*.Freq*/ + ; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n * 2 + 1] + /*.Dad*/ + = tree[m * 2 + 1] + /*.Dad*/ + = node; + /* and insert the new node in the heap */ + + s.heap[1 + /*SMALLEST*/ + ] = node++; + pqdownheap(s, tree, 1 + /*SMALLEST*/ + ); + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1 + /*SMALLEST*/ + ]; + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + + gen_bitlen(s, desc); + /* The field len is now set, we can generate the bit codes */ + + gen_codes(tree, max_code, s.bl_count); +}; +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ + + +const scan_tree = (s, tree, max_code) => // deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + let n; + /* iterates over all tree elements */ + + let prevlen = -1; + /* last emitted length */ + + let curlen; + /* length of current code */ + + let nextlen = tree[0 * 2 + 1] + /*.Len*/ + ; + /* length of next code */ + + let count = 0; + /* repeat count of the current code */ + + let max_count = 7; + /* max repeat count */ + + let min_count = 4; + /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + tree[(max_code + 1) * 2 + 1] + /*.Len*/ + = 0xffff; + /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1] + /*.Len*/ + ; + + if (++count < max_count && curlen === nextlen) { + continue; + } else if (count < min_count) { + s.bl_tree[curlen * 2] + /*.Freq*/ + += count; + } else if (curlen !== 0) { + if (curlen !== prevlen) { + s.bl_tree[curlen * 2] /*.Freq*/++; + } + + s.bl_tree[REP_3_6 * 2] /*.Freq*/++; + } else if (count <= 10) { + s.bl_tree[REPZ_3_10 * 2] /*.Freq*/++; + } else { + s.bl_tree[REPZ_11_138 * 2] /*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } +}; +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ + + +const send_tree = (s, tree, max_code) => // deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + let n; + /* iterates over all tree elements */ + + let prevlen = -1; + /* last emitted length */ + + let curlen; + /* length of current code */ + + let nextlen = tree[0 * 2 + 1] + /*.Len*/ + ; + /* length of next code */ + + let count = 0; + /* repeat count of the current code */ + + let max_count = 7; + /* max repeat count */ + + let min_count = 4; + /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ + + /* guard already set */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1] + /*.Len*/ + ; + + if (++count < max_count && curlen === nextlen) { + continue; + } else if (count < min_count) { + do { + send_code(s, curlen, s.bl_tree); + } while (--count !== 0); + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } //Assert(count >= 3 && count <= 6, " 3_6?"); + + + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count - 3, 2); + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count - 3, 3); + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count - 11, 7); + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } +}; +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ + + +const build_bl_tree = s => { + let max_blindex; + /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + /* Build the bit length tree: */ + + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + + for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex] * 2 + 1] + /*.Len*/ + !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + + + s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +}; +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ + + +const send_all_trees = (s, lcodes, dcodes, blcodes) => // deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + let rank; + /* index in bl_order */ + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + + send_bits(s, lcodes - 257, 5); + /* not +255 as stated in appnote.txt */ + + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); + /* not -3 as stated in appnote.txt */ + + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1] + /*.Len*/ + , 3); + } //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + + send_tree(s, s.dyn_ltree, lcodes - 1); + /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes - 1); + /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +}; +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ + + +const detect_data_type = s => { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + let black_mask = 0xf3ffc07f; + let n; + /* Check for non-textual ("black-listed") bytes. */ + + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if (black_mask & 1 && s.dyn_ltree[n * 2] + /*.Freq*/ + !== 0) { + return Z_BINARY; + } + } + /* Check for textual ("white-listed") bytes. */ + + + if (s.dyn_ltree[9 * 2] + /*.Freq*/ + !== 0 || s.dyn_ltree[10 * 2] + /*.Freq*/ + !== 0 || s.dyn_ltree[13 * 2] + /*.Freq*/ + !== 0) { + return Z_TEXT; + } + + for (n = 32; n < LITERALS$1; n++) { + if (s.dyn_ltree[n * 2] + /*.Freq*/ + !== 0) { + return Z_TEXT; + } + } + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + + + return Z_BINARY; +}; + +let static_init_done = false; +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ + +const _tr_init$1 = s => { + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + s.bi_buf = 0; + s.bi_valid = 0; + /* Initialize the first block of the first file: */ + + init_block(s); +}; +/* =========================================================================== + * Send a stored block + */ + + +const _tr_stored_block$1 = (s, buf, stored_len, last) => //DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); + /* send block type */ + + copy_block(s, buf, stored_len, true); + /* with header */ +}; +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ + + +const _tr_align$1 = s => { + send_bits(s, STATIC_TREES << 1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +}; +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ + + +const _tr_flush_block$1 = (s, buf, stored_len, last) => //DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + let opt_lenb, static_lenb; + /* opt_len and static_len in bytes */ + + let max_blindex = 0; + /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + + if (s.level > 0) { + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN$1) { + s.strm.data_type = detect_data_type(s); + } + /* Construct the literal and distance trees */ + + + build_tree(s, s.l_desc); // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + + max_blindex = build_bl_tree(s); + /* Determine the best encoding. Compute the block lengths in bytes. */ + + opt_lenb = s.opt_len + 3 + 7 >>> 3; + static_lenb = s.static_len + 3 + 7 >>> 3; // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { + opt_lenb = static_lenb; + } + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; + /* force a stored block */ + } + + if (stored_len + 4 <= opt_lenb && buf !== -1) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block$1(s, buf, stored_len, last); + } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) { + send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + } else { + send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + + + init_block(s); + + if (last) { + bi_windup(s); + } // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); + +}; +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ + + +const _tr_tally$1 = (s, dist, lc) => // deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + //let out_length, in_length, dcode; + s.pending_buf[s.d_buf + s.last_lit * 2] = dist >>> 8 & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc * 2] /*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + + dist--; + /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2] /*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2] /*.Freq*/++; + } // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef TRUNCATE_BLOCK + // /* Try to guess if it is profitable to stop the current block here */ + // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { + // /* Compute an upper bound for the compressed length */ + // out_length = s.last_lit*8; + // in_length = s.strstart - s.block_start; + // + // for (dcode = 0; dcode < D_CODES; dcode++) { + // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); + // } + // out_length >>>= 3; + // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + // // s->last_lit, in_length, out_length, + // // 100L - out_length*100L/in_length)); + // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { + // return true; + // } + // } + //#endif + + + return s.last_lit === s.lit_bufsize - 1; + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +}; + +var _tr_init_1 = _tr_init$1; +var _tr_stored_block_1 = _tr_stored_block$1; +var _tr_flush_block_1 = _tr_flush_block$1; +var _tr_tally_1 = _tr_tally$1; +var _tr_align_1 = _tr_align$1; +var trees = { + _tr_init: _tr_init_1, + _tr_stored_block: _tr_stored_block_1, + _tr_flush_block: _tr_flush_block_1, + _tr_tally: _tr_tally_1, + _tr_align: _tr_align_1 +}; // Note: adler32 takes 12% for level 0 and 2% for level 6. +// It isn't worth it to make additional optimizations as in original. +// Small size is preferable. +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +const adler32 = (adler, buf, len, pos) => { + let s1 = adler & 0xffff | 0, + s2 = adler >>> 16 & 0xffff | 0, + n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = s1 + buf[pos++] | 0; + s2 = s2 + s1 | 0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return s1 | s2 << 16 | 0; +}; + +var adler32_1 = adler32; // Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// Use ordinary array, since untyped makes no boost here + +const makeTable = () => { + let c, + table = []; + + for (var n = 0; n < 256; n++) { + c = n; + + for (var k = 0; k < 8; k++) { + c = c & 1 ? 0xEDB88320 ^ c >>> 1 : c >>> 1; + } + + table[n] = c; + } + + return table; +}; // Create table on load. Just 255 signed longs. Not a problem. + + +const crcTable = new Uint32Array(makeTable()); + +const crc32 = (crc, buf, len, pos) => { + const t = crcTable; + const end = pos + len; + crc ^= -1; + + for (let i = pos; i < end; i++) { + crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return crc ^ -1; // >>> 0; +}; + +var crc32_1 = crc32; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +var messages = { + 2: 'need dictionary', + + /* Z_NEED_DICT 2 */ + 1: 'stream end', + + /* Z_STREAM_END 1 */ + 0: '', + + /* Z_OK 0 */ + '-1': 'file error', + + /* Z_ERRNO (-1) */ + '-2': 'stream error', + + /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', + + /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', + + /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', + + /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' + /* Z_VERSION_ERROR (-6) */ + +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +var constants$2 = { + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 //Z_NULL: null // Use -1 or null inline, depending on var type + +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +const { + _tr_init, + _tr_stored_block, + _tr_flush_block, + _tr_tally, + _tr_align +} = trees; +/* Public constants ==========================================================*/ + +/* ===========================================================================*/ + +const { + Z_NO_FLUSH: Z_NO_FLUSH$2, + Z_PARTIAL_FLUSH, + Z_FULL_FLUSH: Z_FULL_FLUSH$1, + Z_FINISH: Z_FINISH$3, + Z_BLOCK: Z_BLOCK$1, + Z_OK: Z_OK$3, + Z_STREAM_END: Z_STREAM_END$3, + Z_STREAM_ERROR: Z_STREAM_ERROR$2, + Z_DATA_ERROR: Z_DATA_ERROR$2, + Z_BUF_ERROR: Z_BUF_ERROR$1, + Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1, + Z_FILTERED, + Z_HUFFMAN_ONLY, + Z_RLE, + Z_FIXED, + Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1, + Z_UNKNOWN, + Z_DEFLATED: Z_DEFLATED$2 +} = constants$2; +/*============================================================================*/ + +const MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ + +const MAX_WBITS$1 = 15; +/* 32K LZ77 window */ + +const DEF_MEM_LEVEL = 8; +const LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +const LITERALS = 256; +/* number of literal bytes 0..255 */ + +const L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ + +const D_CODES = 30; +/* number of distance codes */ + +const BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ + +const HEAP_SIZE = 2 * L_CODES + 1; +/* maximum heap size */ + +const MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +const MIN_MATCH = 3; +const MAX_MATCH = 258; +const MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; +const PRESET_DICT = 0x20; +const INIT_STATE = 42; +const EXTRA_STATE = 69; +const NAME_STATE = 73; +const COMMENT_STATE = 91; +const HCRC_STATE = 103; +const BUSY_STATE = 113; +const FINISH_STATE = 666; +const BS_NEED_MORE = 1; +/* block not completed, need more input or more output */ + +const BS_BLOCK_DONE = 2; +/* block flush performed */ + +const BS_FINISH_STARTED = 3; +/* finish started, need only more output at next deflate */ + +const BS_FINISH_DONE = 4; +/* finish done, accept no more input or output */ + +const OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +const err = (strm, errorCode) => { + strm.msg = messages[errorCode]; + return errorCode; +}; + +const rank = f => { + return (f << 1) - (f > 4 ? 9 : 0); +}; + +const zero = buf => { + let len = buf.length; + + while (--len >= 0) { + buf[len] = 0; + } +}; +/* eslint-disable new-cap */ + + +let HASH_ZLIB = (s, prev, data) => (prev << s.hash_shift ^ data) & s.hash_mask; // This hash causes less collisions, https://github.com/nodeca/pako/issues/135 +// But breaks binary compatibility +//let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask; + + +let HASH = HASH_ZLIB; +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ + +const flush_pending = strm => { + const s = strm.state; //_tr_flush_bits(s); + + let len = s.pending; + + if (len > strm.avail_out) { + len = strm.avail_out; + } + + if (len === 0) { + return; + } + + strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + + if (s.pending === 0) { + s.pending_out = 0; + } +}; + +const flush_block_only = (s, last) => { + _tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last); + + s.block_start = s.strstart; + flush_pending(s.strm); +}; + +const put_byte = (s, b) => { + s.pending_buf[s.pending++] = b; +}; +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ + + +const putShortMSB = (s, b) => { + // put_byte(s, (Byte)(b >> 8)); + // put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = b >>> 8 & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +}; +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ + + +const read_buf = (strm, buf, start, size) => { + let len = strm.avail_in; + + if (len > size) { + len = size; + } + + if (len === 0) { + return 0; + } + + strm.avail_in -= len; // zmemcpy(buf, strm->next_in, len); + + buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start); + + if (strm.state.wrap === 1) { + strm.adler = adler32_1(strm.adler, buf, len, start); + } else if (strm.state.wrap === 2) { + strm.adler = crc32_1(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + return len; +}; +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ + + +const longest_match = (s, cur_match) => { + let chain_length = s.max_chain_length; + /* max hash chain length */ + + let scan = s.strstart; + /* current string */ + + let match; + /* matched string */ + + let len; + /* length of current match */ + + let best_len = s.prev_length; + /* best match length so far */ + + let nice_match = s.nice_match; + /* stop if match long enough */ + + const limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0 + /*NIL*/ + ; + const _win = s.window; // shortcut + + const wmask = s.w_mask; + const prev = s.prev; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + const strend = s.strstart + MAX_MATCH; + let scan_end1 = _win[scan + best_len - 1]; + let scan_end = _win[scan + best_len]; + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + + + if (nice_match > s.lookahead) { + nice_match = s.lookahead; + } // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || _win[match + best_len - 1] !== scan_end1 || _win[match] !== _win[scan] || _win[++match] !== _win[scan + 1]) { + continue; + } + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + + + scan += 2; + match++; // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend); // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + + if (len >= nice_match) { + break; + } + + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + + return s.lookahead; +}; +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ + + +const fill_window = s => { + const _w_size = s.w_size; + let p, n, m, more, str; //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; // JS ints have 32 bit, block below not needed + + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + s.window.set(s.window.subarray(_w_size, _w_size + _w_size), 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + + s.block_start -= _w_size; + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + + do { + m = s.head[--p]; + s.head[p] = m >= _w_size ? m - _w_size : 0; + } while (--n); + + n = _w_size; + p = n; + + do { + m = s.prev[--p]; + s.prev[p] = m >= _w_size ? m - _w_size : 0; + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + + if (s.strm.avail_in === 0) { + break; + } + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + + + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + /* Initialize the hash value now that we have some input: */ + + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + + s.ins_h = HASH(s, s.ins_h, s.window[str + 1]); //#if MIN_MATCH != 3 + // Call update_hash() MIN_MATCH-3 more times + //#endif + + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + // if (s.high_water < s.window_size) { + // const curr = s.strstart + s.lookahead; + // let init = 0; + // + // if (s.high_water < curr) { + // /* Previous high water mark below current data -- zero WIN_INIT + // * bytes or up to end of window, whichever is less. + // */ + // init = s.window_size - curr; + // if (init > WIN_INIT) + // init = WIN_INIT; + // zmemzero(s->window + curr, (unsigned)init); + // s->high_water = curr + init; + // } + // else if (s->high_water < (ulg)curr + WIN_INIT) { + // /* High water mark at or above current data, but below current data + // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + // * to end of window, whichever is less. + // */ + // init = (ulg)curr + WIN_INIT - s->high_water; + // if (init > s->window_size - s->high_water) + // init = s->window_size - s->high_water; + // zmemzero(s->window + s->high_water, (unsigned)init); + // s->high_water += init; + // } + // } + // + // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + // "not enough room for search"); + +}; +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ + + +const deflate_stored = (s, flush) => { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + let max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + /* Copy as much as possible from input to output: */ + + + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); + // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || + // s.block_start >= s.w_size)) { + // throw new Error("slide too late"); + // } + fill_window(s); + + if (s.lookahead === 0 && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + + } //Assert(s->block_start >= 0L, "block gone"); + // if (s.block_start < 0) throw new Error("block gone"); + + + s.strstart += s.lookahead; + s.lookahead = 0; + /* Emit a stored block if pending_buf will be full: */ + + const max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + + + if (s.strstart - s.block_start >= s.w_size - MIN_LOOKAHEAD) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + } + + s.insert = 0; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + + + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + + return BS_NEED_MORE; +}; +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ + + +const deflate_fast = (s, flush) => { + let hash_head; + /* head of the hash chain */ + + let bflush; + /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + /* flush the current block */ + } + } + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + + + hash_head = 0 + /*NIL*/ + ; + + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + + + if (hash_head !== 0 + /*NIL*/ + && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + s.lookahead -= s.match_length; + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + + if (s.match_length <= s.max_lazy_match + /*max_insert_length*/ + && s.lookahead >= MIN_MATCH) { + s.match_length--; + /* string at strstart already in table */ + + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + + s.strstart++; + } else { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]); //#if MIN_MATCH != 3 + // Call UPDATE_HASH() MIN_MATCH-3 more times + //#endif + + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + } + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + } + + s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + + + return BS_FINISH_DONE; + } + + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + + return BS_BLOCK_DONE; +}; +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ + + +const deflate_slow = (s, flush) => { + let hash_head; + /* head of hash chain */ + + let bflush; + /* set if current block must be flushed */ + + let max_insert; + /* Process the input block. */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + + } + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + + + hash_head = 0 + /*NIL*/ + ; + + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + /* Find the longest match, discarding those <= prev_length. + */ + + + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH - 1; + + if (hash_head !== 0 + /*NIL*/ + && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD + /*MAX_DIST(s)*/ + ) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && (s.strategy === Z_FILTERED || s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096 + /*TOO_FAR*/ + )) { + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + + + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + + bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + + s.lookahead -= s.prev_length - 1; + s.prev_length -= 2; + + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + + s.match_available = 0; + s.match_length = MIN_MATCH - 1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + + s.strstart++; + s.lookahead--; + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } //Assert (flush != Z_NO_FLUSH, "no flush?"); + + + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); + s.match_available = 0; + } + + s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + + + return BS_FINISH_DONE; + } + + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + + return BS_BLOCK_DONE; +}; +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ + + +const deflate_rle = (s, flush) => { + let bflush; + /* set if current block must be flushed */ + + let prev; + /* byte at distance one to match */ + + let scan, strend; + /* scan goes up to strend for length of run */ + + const _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + + } + /* See how many times the previous byte repeats */ + + + s.match_length = 0; + + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && scan < strend); + + s.match_length = MAX_MATCH - (strend - scan); + + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + + } + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + + + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH); + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + } + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + } + + s.insert = 0; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + + + return BS_FINISH_DONE; + } + + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + + return BS_BLOCK_DONE; +}; +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ + + +const deflate_huff = (s, flush) => { + let bflush; + /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + + break; + /* flush the current block */ + } + } + /* Output a literal byte */ + + + s.match_length = 0; //Tracevv((stderr,"%c", s->window[s->strstart])); + + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + + bflush = _tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + } + + s.insert = 0; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + + + return BS_FINISH_DONE; + } + + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + } + + return BS_BLOCK_DONE; +}; +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + + +function Config(good_length, max_lazy, nice_length, max_chain, func) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +} + +const configuration_table = [ +/* good lazy nice chain */ +new Config(0, 0, 0, 0, deflate_stored), +/* 0 store only */ +new Config(4, 4, 8, 4, deflate_fast), +/* 1 max speed, no lazy matches */ +new Config(4, 5, 16, 8, deflate_fast), +/* 2 */ +new Config(4, 6, 32, 32, deflate_fast), +/* 3 */ +new Config(4, 4, 16, 16, deflate_slow), +/* 4 lazy matches */ +new Config(8, 16, 32, 32, deflate_slow), +/* 5 */ +new Config(8, 16, 128, 128, deflate_slow), +/* 6 */ +new Config(8, 32, 128, 256, deflate_slow), +/* 7 */ +new Config(32, 128, 258, 1024, deflate_slow), +/* 8 */ +new Config(32, 258, 258, 4096, deflate_slow) +/* 9 max compression */ +]; +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ + +const lm_init = s => { + s.window_size = 2 * s.w_size; + /*** CLEAR_HASH(s); ***/ + + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +}; + +function DeflateState() { + this.strm = null; + /* pointer back to this zlib stream */ + + this.status = 0; + /* as the name implies */ + + this.pending_buf = null; + /* output still pending */ + + this.pending_buf_size = 0; + /* size of pending_buf */ + + this.pending_out = 0; + /* next pending byte to output to the stream */ + + this.pending = 0; + /* nb of bytes in the pending buffer */ + + this.wrap = 0; + /* bit 0 true for zlib, bit 1 true for gzip */ + + this.gzhead = null; + /* gzip header information to write */ + + this.gzindex = 0; + /* where in extra, name, or comment */ + + this.method = Z_DEFLATED$2; + /* can only be DEFLATED */ + + this.last_flush = -1; + /* value of flush param for previous deflate call */ + + this.w_size = 0; + /* LZ77 window size (32K by default) */ + + this.w_bits = 0; + /* log2(w_size) (8..16) */ + + this.w_mask = 0; + /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; + /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; + /* hash index of string to be inserted */ + + this.hash_size = 0; + /* number of elements in hash table */ + + this.hash_bits = 0; + /* log2(hash_size) */ + + this.hash_mask = 0; + /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; + /* length of best match */ + + this.prev_match = 0; + /* previous match */ + + this.match_available = 0; + /* set if previous match exists */ + + this.strstart = 0; + /* start of string to insert */ + + this.match_start = 0; + /* start of matching string */ + + this.lookahead = 0; + /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; + /* compression level (1..9) */ + + this.strategy = 0; + /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; + /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + + this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2); + this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2); + this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + this.l_desc = null; + /* desc. for literal tree */ + + this.d_desc = null; + /* desc. for distance tree */ + + this.bl_desc = null; + /* desc. for bit length tree */ + //ush bl_count[MAX_BITS+1]; + + this.bl_count = new Uint16Array(MAX_BITS + 1); + /* number of codes at each bit length for an optimal tree */ + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + + this.heap = new Uint16Array(2 * L_CODES + 1); + /* heap used to build the Huffman trees */ + + zero(this.heap); + this.heap_len = 0; + /* number of elements in the heap */ + + this.heap_max = 0; + /* element of largest frequency */ + + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; + + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; + /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; + /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; + /* bit length of current block with optimal trees */ + + this.static_len = 0; + /* bit length of current block with static trees */ + + this.matches = 0; + /* number of string matches in current block */ + + this.insert = 0; + /* bytes at end of window left to insert */ + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + +const deflateResetKeep = strm => { + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR$2); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + const s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + + s.status = s.wrap ? INIT_STATE : BUSY_STATE; + strm.adler = s.wrap === 2 ? 0 // crc32(0, Z_NULL, 0) + : 1; // adler32(0, Z_NULL, 0) + + s.last_flush = Z_NO_FLUSH$2; + + _tr_init(s); + + return Z_OK$3; +}; + +const deflateReset = strm => { + const ret = deflateResetKeep(strm); + + if (ret === Z_OK$3) { + lm_init(strm.state); + } + + return ret; +}; + +const deflateSetHeader = (strm, head) => { + if (!strm || !strm.state) { + return Z_STREAM_ERROR$2; + } + + if (strm.state.wrap !== 2) { + return Z_STREAM_ERROR$2; + } + + strm.state.gzhead = head; + return Z_OK$3; +}; + +const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => { + if (!strm) { + // === Z_NULL + return Z_STREAM_ERROR$2; + } + + let wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION$1) { + level = 6; + } + + if (windowBits < 0) { + /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } else if (windowBits > 15) { + wrap = 2; + /* write gzip wrapper instead */ + + windowBits -= 16; + } + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR$2); + } + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + + const s = new DeflateState(); + strm.state = s; + s.strm = strm; + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + s.window = new Uint8Array(s.w_size * 2); + s.head = new Uint16Array(s.hash_size); + s.prev = new Uint16Array(s.w_size); // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << memLevel + 6; + /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + //s->pending_buf = (uchf *) overlay; + + s.pending_buf = new Uint8Array(s.pending_buf_size); // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) + //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + + s.d_buf = 1 * s.lit_bufsize; //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s.l_buf = (1 + 2) * s.lit_bufsize; + s.level = level; + s.strategy = strategy; + s.method = method; + return deflateReset(strm); +}; + +const deflateInit = (strm, level) => { + return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1); +}; + +const deflate$2 = (strm, flush) => { + let beg, val; // for gzip header write only + + if (!strm || !strm.state || flush > Z_BLOCK$1 || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2; + } + + const s = strm.state; + + if (!strm.output || !strm.input && strm.avail_in !== 0 || s.status === FINISH_STATE && flush !== Z_FINISH$3) { + return err(strm, strm.avail_out === 0 ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2); + } + + s.strm = strm; + /* just in case */ + + const old_flush = s.last_flush; + s.last_flush = flush; + /* Write the header */ + + if (s.status === INIT_STATE) { + if (s.wrap === 2) { + // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + + if (!s.gzhead) { + // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } else { + put_byte(s, (s.gzhead.text ? 1 : 0) + (s.gzhead.hcrc ? 2 : 0) + (!s.gzhead.extra ? 0 : 4) + (!s.gzhead.name ? 0 : 8) + (!s.gzhead.comment ? 0 : 16)); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, s.gzhead.time >> 8 & 0xff); + put_byte(s, s.gzhead.time >> 16 & 0xff); + put_byte(s, s.gzhead.time >> 24 & 0xff); + put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); + put_byte(s, s.gzhead.os & 0xff); + + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, s.gzhead.extra.length >> 8 & 0xff); + } + + if (s.gzhead.hcrc) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0); + } + + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } else // DEFLATE header + { + let header = Z_DEFLATED$2 + (s.w_bits - 8 << 4) << 8; + let level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + + header |= level_flags << 6; + + if (s.strstart !== 0) { + header |= PRESET_DICT; + } + + header += 31 - header % 31; + s.status = BUSY_STATE; + putShortMSB(s, header); + /* Save the adler32 of the preset dictionary: */ + + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } //#ifdef GZIP + + + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra + /* != Z_NULL*/ + ) { + beg = s.pending; + /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + flush_pending(strm); + beg = s.pending; + + if (s.pending === s.pending_buf_size) { + break; + } + } + + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } else { + s.status = NAME_STATE; + } + } + + if (s.status === NAME_STATE) { + if (s.gzhead.name + /* != Z_NULL*/ + ) { + beg = s.pending; + /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + flush_pending(strm); + beg = s.pending; + + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } // JS specific: little magic to add zero terminator to end of string + + + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } else { + s.status = COMMENT_STATE; + } + } + + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment + /* != Z_NULL*/ + ) { + beg = s.pending; + /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + flush_pending(strm); + beg = s.pending; + + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } // JS specific: little magic to add zero terminator to end of string + + + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + + if (val === 0) { + s.status = HCRC_STATE; + } + } else { + s.status = HCRC_STATE; + } + } + + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, strm.adler >> 8 & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + + s.status = BUSY_STATE; + } + } else { + s.status = BUSY_STATE; + } + } //#endif + + /* Flush as much pending output as possible */ + + + if (s.pending !== 0) { + flush_pending(strm); + + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK$3; + } + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== Z_FINISH$3) { + return err(strm, Z_BUF_ERROR$1); + } + /* User must not provide more input after the first FINISH: */ + + + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR$1); + } + /* Start a new block or continue the current one. + */ + + + if (strm.avail_in !== 0 || s.lookahead !== 0 || flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE) { + let bstate = s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s.strategy === Z_RLE ? deflate_rle(s, flush) : configuration_table[s.level].func(s, flush); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + + return Z_OK$3; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush !== Z_BLOCK$1) { + /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + + + if (flush === Z_FULL_FLUSH$1) { + /*** CLEAR_HASH(s); ***/ + + /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + + flush_pending(strm); + + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR at next call, see above */ + + return Z_OK$3; + } + } + } //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + + if (flush !== Z_FINISH$3) { + return Z_OK$3; + } + + if (s.wrap <= 0) { + return Z_STREAM_END$3; + } + /* Write the trailer */ + + + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, strm.adler >> 8 & 0xff); + put_byte(s, strm.adler >> 16 & 0xff); + put_byte(s, strm.adler >> 24 & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, strm.total_in >> 8 & 0xff); + put_byte(s, strm.total_in >> 16 & 0xff); + put_byte(s, strm.total_in >> 24 & 0xff); + } else { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + + if (s.wrap > 0) { + s.wrap = -s.wrap; + } + /* write the trailer only once! */ + + + return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3; +}; + +const deflateEnd = strm => { + if (!strm + /*== Z_NULL*/ + || !strm.state + /*== Z_NULL*/ + ) { + return Z_STREAM_ERROR$2; + } + + const status = strm.state.status; + + if (status !== INIT_STATE && status !== EXTRA_STATE && status !== NAME_STATE && status !== COMMENT_STATE && status !== HCRC_STATE && status !== BUSY_STATE && status !== FINISH_STATE) { + return err(strm, Z_STREAM_ERROR$2); + } + + strm.state = null; + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3; +}; +/* ========================================================================= + * Initializes the compression dictionary from the given byte + * sequence without producing any compressed output. + */ + + +const deflateSetDictionary = (strm, dictionary) => { + let dictLength = dictionary.length; + + if (!strm + /*== Z_NULL*/ + || !strm.state + /*== Z_NULL*/ + ) { + return Z_STREAM_ERROR$2; + } + + const s = strm.state; + const wrap = s.wrap; + + if (wrap === 2 || wrap === 1 && s.status !== INIT_STATE || s.lookahead) { + return Z_STREAM_ERROR$2; + } + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + + + if (wrap === 1) { + /* adler32(strm->adler, dictionary, dictLength); */ + strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0); + } + + s.wrap = 0; + /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + + if (dictLength >= s.w_size) { + if (wrap === 0) { + /* already empty otherwise */ + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + /* use the tail */ + // dictionary = dictionary.slice(dictLength - s.w_size); + + + let tmpDict = new Uint8Array(s.w_size); + tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0); + dictionary = tmpDict; + dictLength = s.w_size; + } + /* insert dictionary into window and hash */ + + + const avail = strm.avail_in; + const next = strm.next_in; + const input = strm.input; + strm.avail_in = dictLength; + strm.next_in = 0; + strm.input = dictionary; + fill_window(s); + + while (s.lookahead >= MIN_MATCH) { + let str = s.strstart; + let n = s.lookahead - (MIN_MATCH - 1); + + do { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + } while (--n); + + s.strstart = str; + s.lookahead = MIN_MATCH - 1; + fill_window(s); + } + + s.strstart += s.lookahead; + s.block_start = s.strstart; + s.insert = s.lookahead; + s.lookahead = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + strm.next_in = next; + strm.input = input; + strm.avail_in = avail; + s.wrap = wrap; + return Z_OK$3; +}; + +var deflateInit_1 = deflateInit; +var deflateInit2_1 = deflateInit2; +var deflateReset_1 = deflateReset; +var deflateResetKeep_1 = deflateResetKeep; +var deflateSetHeader_1 = deflateSetHeader; +var deflate_2$1 = deflate$2; +var deflateEnd_1 = deflateEnd; +var deflateSetDictionary_1 = deflateSetDictionary; +var deflateInfo = 'pako deflate (from Nodeca project)'; +/* Not implemented +module.exports.deflateBound = deflateBound; +module.exports.deflateCopy = deflateCopy; +module.exports.deflateParams = deflateParams; +module.exports.deflatePending = deflatePending; +module.exports.deflatePrime = deflatePrime; +module.exports.deflateTune = deflateTune; +*/ + +var deflate_1$2 = { + deflateInit: deflateInit_1, + deflateInit2: deflateInit2_1, + deflateReset: deflateReset_1, + deflateResetKeep: deflateResetKeep_1, + deflateSetHeader: deflateSetHeader_1, + deflate: deflate_2$1, + deflateEnd: deflateEnd_1, + deflateSetDictionary: deflateSetDictionary_1, + deflateInfo: deflateInfo +}; + +const _has = (obj, key) => { + return Object.prototype.hasOwnProperty.call(obj, key); +}; + +var assign = function (obj +/*from1, from2, from3, ...*/ +) { + const sources = Array.prototype.slice.call(arguments, 1); + + while (sources.length) { + const source = sources.shift(); + + if (!source) { + continue; + } + + if (typeof source !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (const p in source) { + if (_has(source, p)) { + obj[p] = source[p]; + } + } + } + + return obj; +}; // Join array of chunks to single array. + + +var flattenChunks = chunks => { + // calculate data length + let len = 0; + + for (let i = 0, l = chunks.length; i < l; i++) { + len += chunks[i].length; + } // join chunks + + + const result = new Uint8Array(len); + + for (let i = 0, pos = 0, l = chunks.length; i < l; i++) { + let chunk = chunks[i]; + result.set(chunk, pos); + pos += chunk.length; + } + + return result; +}; + +var common = { + assign: assign, + flattenChunks: flattenChunks +}; // String encode/decode helpers +// Quick check if we can use fast array to bin string conversion +// +// - apply(Array) can fail on Android 2.2 +// - apply(Uint8Array) can fail on iOS 5.1 Safari +// + +let STR_APPLY_UIA_OK = true; + +try { + String.fromCharCode.apply(null, new Uint8Array(1)); +} catch (__) { + STR_APPLY_UIA_OK = false; +} // Table with utf8 lengths (calculated by first byte of sequence) +// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, +// because max possible codepoint is 0x10ffff + + +const _utf8len = new Uint8Array(256); + +for (let q = 0; q < 256; q++) { + _utf8len[q] = q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1; +} + +_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start +// convert string to array (typed, when possible) + +var string2buf = str => { + if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) { + return new TextEncoder().encode(str); + } + + let buf, + c, + c2, + m_pos, + i, + str_len = str.length, + buf_len = 0; // count binary size + + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + + if ((c & 0xfc00) === 0xd800 && m_pos + 1 < str_len) { + c2 = str.charCodeAt(m_pos + 1); + + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + (c - 0xd800 << 10) + (c2 - 0xdc00); + m_pos++; + } + } + + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } // allocate buffer + + + buf = new Uint8Array(buf_len); // convert + + for (i = 0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + + if ((c & 0xfc00) === 0xd800 && m_pos + 1 < str_len) { + c2 = str.charCodeAt(m_pos + 1); + + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + (c - 0xd800 << 10) + (c2 - 0xdc00); + m_pos++; + } + } + + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | c >>> 6; + buf[i++] = 0x80 | c & 0x3f; + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | c >>> 12; + buf[i++] = 0x80 | c >>> 6 & 0x3f; + buf[i++] = 0x80 | c & 0x3f; + } else { + /* four bytes */ + buf[i++] = 0xf0 | c >>> 18; + buf[i++] = 0x80 | c >>> 12 & 0x3f; + buf[i++] = 0x80 | c >>> 6 & 0x3f; + buf[i++] = 0x80 | c & 0x3f; + } + } + + return buf; +}; // Helper + + +const buf2binstring = (buf, len) => { + // On Chrome, the arguments in a function call that are allowed is `65534`. + // If the length of the buffer is smaller than that, we can use this optimization, + // otherwise we will take a slower path. + if (len < 65534) { + if (buf.subarray && STR_APPLY_UIA_OK) { + return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len)); + } + } + + let result = ''; + + for (let i = 0; i < len; i++) { + result += String.fromCharCode(buf[i]); + } + + return result; +}; // convert array to string + + +var buf2string = (buf, max) => { + const len = max || buf.length; + + if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) { + return new TextDecoder().decode(buf.subarray(0, max)); + } + + let i, out; // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + + const utf16buf = new Array(len * 2); + + for (out = 0, i = 0; i < len;) { + let c = buf[i++]; // quick process ascii + + if (c < 0x80) { + utf16buf[out++] = c; + continue; + } + + let c_len = _utf8len[c]; // skip 5 & 6 byte codes + + if (c_len > 4) { + utf16buf[out++] = 0xfffd; + i += c_len - 1; + continue; + } // apply mask on first byte + + + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; // join the rest + + while (c_len > 1 && i < len) { + c = c << 6 | buf[i++] & 0x3f; + c_len--; + } // terminated by end of string? + + + if (c_len > 1) { + utf16buf[out++] = 0xfffd; + continue; + } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | c >> 10 & 0x3ff; + utf16buf[out++] = 0xdc00 | c & 0x3ff; + } + } + + return buf2binstring(utf16buf, out); +}; // Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); + + +var utf8border = (buf, max) => { + max = max || buf.length; + + if (max > buf.length) { + max = buf.length; + } // go back from last position, until start of sequence found + + + let pos = max - 1; + + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { + pos--; + } // Very small and broken sequence, + // return max, because we should return something anyway. + + + if (pos < 0) { + return max; + } // If we came to start of buffer - that means buffer is too small, + // return max too. + + + if (pos === 0) { + return max; + } + + return pos + _utf8len[buf[pos]] > max ? pos : max; +}; + +var strings = { + string2buf: string2buf, + buf2string: buf2string, + utf8border: utf8border +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + + this.next_in = 0; + /* number of bytes available at input */ + + this.avail_in = 0; + /* total number of input bytes read so far */ + + this.total_in = 0; + /* next output byte should be put there */ + + this.output = null; // JS specific, because we have no pointers + + this.next_out = 0; + /* remaining free space at output */ + + this.avail_out = 0; + /* total number of bytes output so far */ + + this.total_out = 0; + /* last error message, NULL if no error */ + + this.msg = '' + /*Z_NULL*/ + ; + /* not visible by applications */ + + this.state = null; + /* best guess about the data type: binary or text */ + + this.data_type = 2 + /*Z_UNKNOWN*/ + ; + /* adler32 value of the uncompressed data */ + + this.adler = 0; +} + +var zstream = ZStream; +const toString$1 = Object.prototype.toString; +/* Public constants ==========================================================*/ + +/* ===========================================================================*/ + +const { + Z_NO_FLUSH: Z_NO_FLUSH$1, + Z_SYNC_FLUSH, + Z_FULL_FLUSH, + Z_FINISH: Z_FINISH$2, + Z_OK: Z_OK$2, + Z_STREAM_END: Z_STREAM_END$2, + Z_DEFAULT_COMPRESSION, + Z_DEFAULT_STRATEGY, + Z_DEFLATED: Z_DEFLATED$1 +} = constants$2; +/* ===========================================================================*/ + +/** + * class Deflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[deflate]], + * [[deflateRaw]] and [[gzip]]. + **/ + +/* internal + * Deflate.chunks -> Array + * + * Chunks of output data, if [[Deflate#onData]] not overridden. + **/ + +/** + * Deflate.result -> Uint8Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + +/** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + +/** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * const deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ + +function Deflate$1(options) { + this.options = common.assign({ + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED$1, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY + }, options || {}); + let opt = this.options; + + if (opt.raw && opt.windowBits > 0) { + opt.windowBits = -opt.windowBits; + } else if (opt.gzip && opt.windowBits > 0 && opt.windowBits < 16) { + opt.windowBits += 16; + } + + this.err = 0; // error code, if happens (0 = Z_OK) + + this.msg = ''; // error message + + this.ended = false; // used to avoid multiple onEnd() calls + + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + let status = deflate_1$2.deflateInit2(this.strm, opt.level, opt.method, opt.windowBits, opt.memLevel, opt.strategy); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); + } + + if (opt.header) { + deflate_1$2.deflateSetHeader(this.strm, opt.header); + } + + if (opt.dictionary) { + let dict; // Convert data if needed + + if (typeof opt.dictionary === 'string') { + // If we need to compress text, change encoding to utf8. + dict = strings.string2buf(opt.dictionary); + } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') { + dict = new Uint8Array(opt.dictionary); + } else { + dict = opt.dictionary; + } + + status = deflate_1$2.deflateSetDictionary(this.strm, dict); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); + } + + this._dict_set = true; + } +} +/** + * Deflate#push(data[, flush_mode]) -> Boolean + * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be + * converted to utf8 byte sequence. + * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must + * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending + * buffers and call [[Deflate#onEnd]]. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ + + +Deflate$1.prototype.push = function (data, flush_mode) { + const strm = this.strm; + const chunkSize = this.options.chunkSize; + + let status, _flush_mode; + + if (this.ended) { + return false; + } + + if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1; // Convert data if needed + + if (typeof data === 'string') { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(data); + } else if (toString$1.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + for (;;) { + if (strm.avail_out === 0) { + strm.output = new Uint8Array(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } // Make sure avail_out > 6 to avoid repeating markers + + + if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + status = deflate_1$2.deflate(strm, _flush_mode); // Ended => flush and finish + + if (status === Z_STREAM_END$2) { + if (strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + } + + status = deflate_1$2.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK$2; + } // Flush if out buffer full + + + if (strm.avail_out === 0) { + this.onData(strm.output); + continue; + } // Flush if requested and has data + + + if (_flush_mode > 0 && strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + if (strm.avail_in === 0) break; + } + + return true; +}; +/** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array): output data. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ + + +Deflate$1.prototype.onData = function (chunk) { + this.chunks.push(chunk); +}; +/** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate that the input stream is + * complete (Z_FINISH). By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ + + +Deflate$1.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK$2) { + this.result = common.flattenChunks(this.chunks); + } + + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; +/** + * deflate(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate algorithm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * - dictionary + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ + + +function deflate$1(input, options) { + const deflator = new Deflate$1(options); + deflator.push(input, true); // That will never happens, if you don't cheat with options :) + + if (deflator.err) { + throw deflator.msg || messages[deflator.err]; + } + + return deflator.result; +} +/** + * deflateRaw(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + + +function deflateRaw$1(input, options) { + options = options || {}; + options.raw = true; + return deflate$1(input, options); +} +/** + * gzip(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but create gzip wrapper instead of + * deflate one. + **/ + + +function gzip$1(input, options) { + options = options || {}; + options.gzip = true; + return deflate$1(input, options); +} + +var Deflate_1$1 = Deflate$1; +var deflate_2 = deflate$1; +var deflateRaw_1$1 = deflateRaw$1; +var gzip_1$1 = gzip$1; +var constants$1 = constants$2; +var deflate_1$1 = { + Deflate: Deflate_1$1, + deflate: deflate_2, + deflateRaw: deflateRaw_1$1, + gzip: gzip_1$1, + constants: constants$1 +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// See state defs from inflate.js + +const BAD$1 = 30; +/* got a data error -- remain here until reset */ + +const TYPE$1 = 12; +/* i: waiting for type bits, including last-flag bit */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ + +var inffast = function inflate_fast(strm, start) { + let _in; + /* local strm.input */ + + + let last; + /* have enough input while in < last */ + + let _out; + /* local strm.output */ + + + let beg; + /* inflate()'s initial strm.output */ + + let end; + /* while out < end, enough space available */ + //#ifdef INFLATE_STRICT + + let dmax; + /* maximum distance from zlib header */ + //#endif + + let wsize; + /* window size or zero if not using window */ + + let whave; + /* valid bytes in the window */ + + let wnext; + /* window write index */ + // Use `s_window` instead `window`, avoid conflict with instrumentation tools + + let s_window; + /* allocated sliding window, if wsize != 0 */ + + let hold; + /* local strm.hold */ + + let bits; + /* local strm.bits */ + + let lcode; + /* local strm.lencode */ + + let dcode; + /* local strm.distcode */ + + let lmask; + /* mask for first level of length codes */ + + let dmask; + /* mask for first level of distance codes */ + + let here; + /* retrieved table entry */ + + let op; + /* code bits, operation, extra bits, or */ + + /* window position, window bytes to copy */ + + let len; + /* match length, unused bytes */ + + let dist; + /* match distance */ + + let from; + /* where to copy match from */ + + let from_source; + let input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + + const state = strm.state; //here = state.here; + + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); //#ifdef INFLATE_STRICT + + dmax = state.dmax; //#endif + + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + s_window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: for (;;) { + // Goto emulation + op = here >>> 24 + /*here.bits*/ + ; + hold >>>= op; + bits -= op; + op = here >>> 16 & 0xff + /*here.op*/ + ; + + if (op === 0) { + /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff + /*here.val*/ + ; + } else if (op & 16) { + /* length base */ + len = here & 0xffff + /*here.val*/ + ; + op &= 15; + /* number of extra bits */ + + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + + len += hold & (1 << op) - 1; + hold >>>= op; + bits -= op; + } //Tracevv((stderr, "inflate: length %u\n", len)); + + + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = dcode[hold & dmask]; + + dodist: for (;;) { + // goto emulation + op = here >>> 24 + /*here.bits*/ + ; + hold >>>= op; + bits -= op; + op = here >>> 16 & 0xff + /*here.op*/ + ; + + if (op & 16) { + /* distance base */ + dist = here & 0xffff + /*here.val*/ + ; + op &= 15; + /* number of extra bits */ + + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + + dist += hold & (1 << op) - 1; //#ifdef INFLATE_STRICT + + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD$1; + break top; + } //#endif + + + hold >>>= op; + bits -= op; //Tracevv((stderr, "inflate: distance %u\n", dist)); + + op = _out - beg; + /* max distance in output */ + + if (dist > op) { + /* see if copy from window */ + op = dist - op; + /* distance back in window */ + + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD$1; + break top; + } // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // if (len <= op - whave) { + // do { + // output[_out++] = 0; + // } while (--len); + // continue top; + // } + // len -= op - whave; + // do { + // output[_out++] = 0; + // } while (--op > whave); + // if (op === 0) { + // from = _out - dist; + // do { + // output[_out++] = output[from++]; + // } while (--len); + // continue top; + // } + //#endif + + } + + from = 0; // window index + + from_source = s_window; + + if (wnext === 0) { + /* very common case */ + from += wsize - op; + + if (op < len) { + /* some from window */ + len -= op; + + do { + output[_out++] = s_window[from++]; + } while (--op); + + from = _out - dist; + /* rest from output */ + + from_source = output; + } + } else if (wnext < op) { + /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + + if (op < len) { + /* some from end of window */ + len -= op; + + do { + output[_out++] = s_window[from++]; + } while (--op); + + from = 0; + + if (wnext < len) { + /* some from start of window */ + op = wnext; + len -= op; + + do { + output[_out++] = s_window[from++]; + } while (--op); + + from = _out - dist; + /* rest from output */ + + from_source = output; + } + } + } else { + /* contiguous in window */ + from += wnext - op; + + if (op < len) { + /* some from window */ + len -= op; + + do { + output[_out++] = s_window[from++]; + } while (--op); + + from = _out - dist; + /* rest from output */ + + from_source = output; + } + } + + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + + if (len) { + output[_out++] = from_source[from++]; + + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } else { + from = _out - dist; + /* copy direct from output */ + + do { + /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + + if (len) { + output[_out++] = output[from++]; + + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } else if ((op & 64) === 0) { + /* 2nd level distance code */ + here = dcode[(here & 0xffff + /*here.val*/ + ) + (hold & (1 << op) - 1)]; + continue dodist; + } else { + strm.msg = 'invalid distance code'; + state.mode = BAD$1; + break top; + } + + break; // need to emulate goto via "continue" + } + } else if ((op & 64) === 0) { + /* 2nd level length code */ + here = lcode[(here & 0xffff + /*here.val*/ + ) + (hold & (1 << op) - 1)]; + continue dolen; + } else if (op & 32) { + /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE$1; + break top; + } else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD$1; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + + + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + /* update state and return */ + + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last); + strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end); + state.hold = hold; + state.bits = bits; + return; +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + + +const MAXBITS = 15; +const ENOUGH_LENS$1 = 852; +const ENOUGH_DISTS$1 = 592; //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +const CODES$1 = 0; +const LENS$1 = 1; +const DISTS$1 = 2; +const lbase = new Uint16Array([ +/* Length codes 257..285 base */ +3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0]); +const lext = new Uint8Array([ +/* Length codes 257..285 extra */ +16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78]); +const dbase = new Uint16Array([ +/* Distance codes 0..29 base */ +1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0]); +const dext = new Uint8Array([ +/* Distance codes 0..29 extra */ +16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64]); + +const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) => { + const bits = opts.bits; //here = opts.here; /* table entry for duplication */ + + let len = 0; + /* a code's length in bits */ + + let sym = 0; + /* index of code symbols */ + + let min = 0, + max = 0; + /* minimum and maximum code lengths */ + + let root = 0; + /* number of index bits for root table */ + + let curr = 0; + /* number of index bits for current table */ + + let drop = 0; + /* code bits to drop for sub-table */ + + let left = 0; + /* number of prefix codes available */ + + let used = 0; + /* code entries in table used */ + + let huff = 0; + /* Huffman code */ + + let incr; + /* for incrementing code, index */ + + let fill; + /* index for replicating entries */ + + let low; + /* low bits for current root entry */ + + let mask; + /* mask for low root bits */ + + let next; + /* next available space in table */ + + let base = null; + /* base value table to use */ + + let base_index = 0; // let shoextra; /* extra bits table to use */ + + let end; + /* use base and extra for symbol > end */ + + const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ + + const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ + + let extra = null; + let extra_index = 0; + let here_bits, here_op, here_val; + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + /* bound code lengths, force root to be within code lengths */ + + + root = bits; + + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { + break; + } + } + + if (root > max) { + root = max; + } + + if (max === 0) { + /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = 1 << 24 | 64 << 16 | 0; //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + + table[table_index++] = 1 << 24 | 64 << 16 | 0; + opts.bits = 1; + return 0; + /* no symbols, but wait for decoding to report error */ + } + + for (min = 1; min < max; min++) { + if (count[min] !== 0) { + break; + } + } + + if (root < min) { + root = min; + } + /* check for an over-subscribed or incomplete set of lengths */ + + + left = 1; + + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + + if (left < 0) { + return -1; + } + /* over-subscribed */ + + } + + if (left > 0 && (type === CODES$1 || max !== 1)) { + return -1; + /* incomplete set */ + } + /* generate offsets into symbol table for each length for sorting */ + + + offs[1] = 0; + + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + /* sort symbols by length, by symbol order within each length */ + + + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; + } + } + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + + + if (type === CODES$1) { + base = extra = work; + /* dummy value--not used */ + + end = 19; + } else if (type === LENS$1) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + } else { + /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + /* initialize opts for loop */ + + + huff = 0; + /* starting code */ + + sym = 0; + /* starting code symbol */ + + len = min; + /* starting code length */ + + next = table_index; + /* current table to fill in */ + + curr = root; + /* current table index bits */ + + drop = 0; + /* current bits to drop from code for index */ + + low = -1; + /* trigger new sub-table when len > root */ + + used = 1 << root; + /* use root table entries */ + + mask = used - 1; + /* mask for comparing low */ + + /* check available table space */ + + if (type === LENS$1 && used > ENOUGH_LENS$1 || type === DISTS$1 && used > ENOUGH_DISTS$1) { + return 1; + } + /* process all codes and make table entries */ + + + for (;;) { + /* create table entry */ + here_bits = len - drop; + + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; + } else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; + } else { + here_op = 32 + 64; + /* end of block */ + + here_val = 0; + } + /* replicate for those indices with low len bits equal to huff */ + + + incr = 1 << len - drop; + fill = 1 << curr; + min = fill; + /* save offset to next table */ + + do { + fill -= incr; + table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0; + } while (fill !== 0); + /* backwards increment the len-bit code huff */ + + + incr = 1 << len - 1; + + while (huff & incr) { + incr >>= 1; + } + + if (incr !== 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + /* go to next symbol, update count, len */ + + + sym++; + + if (--count[len] === 0) { + if (len === max) { + break; + } + + len = lens[lens_index + work[sym]]; + } + /* create new sub-table if needed */ + + + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + /* increment past last table */ + + + next += min; + /* here min is 1 << curr */ + + /* determine length of next table */ + + curr = len - drop; + left = 1 << curr; + + while (curr + drop < max) { + left -= count[curr + drop]; + + if (left <= 0) { + break; + } + + curr++; + left <<= 1; + } + /* check for enough space */ + + + used += 1 << curr; + + if (type === LENS$1 && used > ENOUGH_LENS$1 || type === DISTS$1 && used > ENOUGH_DISTS$1) { + return 1; + } + /* point entry in root table to sub-table */ + + + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + + table[low] = root << 24 | curr << 16 | next - table_index | 0; + } + } + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + + + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = len - drop << 24 | 64 << 16 | 0; + } + /* set return parameters */ + //opts.table_index += used; + + + opts.bits = root; + return 0; +}; + +var inftrees = inflate_table; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +const CODES = 0; +const LENS = 1; +const DISTS = 2; +/* Public constants ==========================================================*/ + +/* ===========================================================================*/ + +const { + Z_FINISH: Z_FINISH$1, + Z_BLOCK, + Z_TREES, + Z_OK: Z_OK$1, + Z_STREAM_END: Z_STREAM_END$1, + Z_NEED_DICT: Z_NEED_DICT$1, + Z_STREAM_ERROR: Z_STREAM_ERROR$1, + Z_DATA_ERROR: Z_DATA_ERROR$1, + Z_MEM_ERROR: Z_MEM_ERROR$1, + Z_BUF_ERROR, + Z_DEFLATED +} = constants$2; +/* STATES ====================================================================*/ + +/* ===========================================================================*/ + +const HEAD = 1; +/* i: waiting for magic header */ + +const FLAGS = 2; +/* i: waiting for method and flags (gzip) */ + +const TIME = 3; +/* i: waiting for modification time (gzip) */ + +const OS = 4; +/* i: waiting for extra flags and operating system (gzip) */ + +const EXLEN = 5; +/* i: waiting for extra length (gzip) */ + +const EXTRA = 6; +/* i: waiting for extra bytes (gzip) */ + +const NAME = 7; +/* i: waiting for end of file name (gzip) */ + +const COMMENT = 8; +/* i: waiting for end of comment (gzip) */ + +const HCRC = 9; +/* i: waiting for header crc (gzip) */ + +const DICTID = 10; +/* i: waiting for dictionary check value */ + +const DICT = 11; +/* waiting for inflateSetDictionary() call */ + +const TYPE = 12; +/* i: waiting for type bits, including last-flag bit */ + +const TYPEDO = 13; +/* i: same, but skip check to exit inflate on new block */ + +const STORED = 14; +/* i: waiting for stored size (length and complement) */ + +const COPY_ = 15; +/* i/o: same as COPY below, but only first time in */ + +const COPY = 16; +/* i/o: waiting for input or output to copy stored block */ + +const TABLE = 17; +/* i: waiting for dynamic block table lengths */ + +const LENLENS = 18; +/* i: waiting for code length code lengths */ + +const CODELENS = 19; +/* i: waiting for length/lit and distance code lengths */ + +const LEN_ = 20; +/* i: same as LEN below, but only first time in */ + +const LEN = 21; +/* i: waiting for length/lit/eob code */ + +const LENEXT = 22; +/* i: waiting for length extra bits */ + +const DIST = 23; +/* i: waiting for distance code */ + +const DISTEXT = 24; +/* i: waiting for distance extra bits */ + +const MATCH = 25; +/* o: waiting for output space to copy string */ + +const LIT = 26; +/* o: waiting for output space to write literal */ + +const CHECK = 27; +/* i: waiting for 32-bit check value */ + +const LENGTH = 28; +/* i: waiting for 32-bit length (gzip) */ + +const DONE = 29; +/* finished check, done -- remain here until reset */ + +const BAD = 30; +/* got a data error -- remain here until reset */ + +const MEM = 31; +/* got an inflate() memory error -- remain here until reset */ + +const SYNC = 32; +/* looking for synchronization bytes to restart inflate() */ + +/* ===========================================================================*/ + +const ENOUGH_LENS = 852; +const ENOUGH_DISTS = 592; //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +const MAX_WBITS = 15; +/* 32K LZ77 window */ + +const DEF_WBITS = MAX_WBITS; + +const zswap32 = q => { + return (q >>> 24 & 0xff) + (q >>> 8 & 0xff00) + ((q & 0xff00) << 8) + ((q & 0xff) << 24); +}; + +function InflateState() { + this.mode = 0; + /* current inflate mode */ + + this.last = false; + /* true if processing last block */ + + this.wrap = 0; + /* bit 0 true for zlib, bit 1 true for gzip */ + + this.havedict = false; + /* true if dictionary provided */ + + this.flags = 0; + /* gzip header method and flags (0 if zlib) */ + + this.dmax = 0; + /* zlib header max distance (INFLATE_STRICT) */ + + this.check = 0; + /* protected copy of check value */ + + this.total = 0; + /* protected copy of output count */ + // TODO: may be {} + + this.head = null; + /* where to save gzip header information */ + + /* sliding window */ + + this.wbits = 0; + /* log base 2 of requested window size */ + + this.wsize = 0; + /* window size or zero if not using window */ + + this.whave = 0; + /* valid bytes in the window */ + + this.wnext = 0; + /* window write index */ + + this.window = null; + /* allocated sliding window, if needed */ + + /* bit accumulator */ + + this.hold = 0; + /* input bit accumulator */ + + this.bits = 0; + /* number of bits in "in" */ + + /* for string and stored block copying */ + + this.length = 0; + /* literal or length of data to copy */ + + this.offset = 0; + /* distance back to copy string from */ + + /* for table and code decoding */ + + this.extra = 0; + /* extra bits needed */ + + /* fixed and dynamic code tables */ + + this.lencode = null; + /* starting table for length/literal codes */ + + this.distcode = null; + /* starting table for distance codes */ + + this.lenbits = 0; + /* index bits for lencode */ + + this.distbits = 0; + /* index bits for distcode */ + + /* dynamic table building */ + + this.ncode = 0; + /* number of code length code lengths */ + + this.nlen = 0; + /* number of length code lengths */ + + this.ndist = 0; + /* number of distance code lengths */ + + this.have = 0; + /* number of code lengths in lens[] */ + + this.next = null; + /* next available space in codes[] */ + + this.lens = new Uint16Array(320); + /* temporary storage for code lengths */ + + this.work = new Uint16Array(288); + /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new Int32Array(ENOUGH); /* space for code tables */ + + this.lendyn = null; + /* dynamic table for length/literal codes (JS specific) */ + + this.distdyn = null; + /* dynamic table for distance codes (JS specific) */ + + this.sane = 0; + /* if false, allow invalid distance too far */ + + this.back = 0; + /* bits back of last unprocessed length/lit */ + + this.was = 0; + /* initial length of match */ +} + +const inflateResetKeep = strm => { + if (!strm || !strm.state) { + return Z_STREAM_ERROR$1; + } + + const state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; + /*Z_NULL*/ + + if (state.wrap) { + /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null + /*Z_NULL*/ + ; + state.hold = 0; + state.bits = 0; //state.lencode = state.distcode = state.next = state.codes; + + state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS); + state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS); + state.sane = 1; + state.back = -1; //Tracev((stderr, "inflate: reset\n")); + + return Z_OK$1; +}; + +const inflateReset = strm => { + if (!strm || !strm.state) { + return Z_STREAM_ERROR$1; + } + + const state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); +}; + +const inflateReset2 = (strm, windowBits) => { + let wrap; + /* get the state */ + + if (!strm || !strm.state) { + return Z_STREAM_ERROR$1; + } + + const state = strm.state; + /* extract wrap request from windowBits parameter */ + + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } else { + wrap = (windowBits >> 4) + 1; + + if (windowBits < 48) { + windowBits &= 15; + } + } + /* set number of window bits, free window if different */ + + + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR$1; + } + + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; + } + /* update state and reset the rest of it */ + + + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); +}; + +const inflateInit2 = (strm, windowBits) => { + if (!strm) { + return Z_STREAM_ERROR$1; + } //strm.msg = Z_NULL; /* in case we return an error */ + + + const state = new InflateState(); //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + + strm.state = state; + state.window = null + /*Z_NULL*/ + ; + const ret = inflateReset2(strm, windowBits); + + if (ret !== Z_OK$1) { + strm.state = null + /*Z_NULL*/ + ; + } + + return ret; +}; + +const inflateInit = strm => { + return inflateInit2(strm, DEF_WBITS); +}; +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ + + +let virgin = true; +let lenfix, distfix; // We have no pointers in JS, so keep tables separate + +const fixedtables = state => { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + lenfix = new Int32Array(512); + distfix = new Int32Array(32); + /* literal/length table */ + + let sym = 0; + + while (sym < 144) { + state.lens[sym++] = 8; + } + + while (sym < 256) { + state.lens[sym++] = 9; + } + + while (sym < 280) { + state.lens[sym++] = 7; + } + + while (sym < 288) { + state.lens[sym++] = 8; + } + + inftrees(LENS, state.lens, 0, 288, lenfix, 0, state.work, { + bits: 9 + }); + /* distance table */ + + sym = 0; + + while (sym < 32) { + state.lens[sym++] = 5; + } + + inftrees(DISTS, state.lens, 0, 32, distfix, 0, state.work, { + bits: 5 + }); + /* do this just once */ + + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +}; +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ + + +const updatewindow = (strm, src, end, copy) => { + let dist; + const state = strm.state; + /* if it hasn't been done already, allocate space for the window */ + + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + state.window = new Uint8Array(state.wsize); + } + /* copy state->wsize or less output bytes into the circular window */ + + + if (copy >= state.wsize) { + state.window.set(src.subarray(end - state.wsize, end), 0); + state.wnext = 0; + state.whave = state.wsize; + } else { + dist = state.wsize - state.wnext; + + if (dist > copy) { + dist = copy; + } //zmemcpy(state->window + state->wnext, end - copy, dist); + + + state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext); + copy -= dist; + + if (copy) { + //zmemcpy(state->window, end - copy, copy); + state.window.set(src.subarray(end - copy, end), 0); + state.wnext = copy; + state.whave = state.wsize; + } else { + state.wnext += dist; + + if (state.wnext === state.wsize) { + state.wnext = 0; + } + + if (state.whave < state.wsize) { + state.whave += dist; + } + } + } + + return 0; +}; + +const inflate$2 = (strm, flush) => { + let state; + let input, output; // input/output buffers + + let next; + /* next input INDEX */ + + let put; + /* next output INDEX */ + + let have, left; + /* available input and output */ + + let hold; + /* bit buffer */ + + let bits; + /* bits in bit buffer */ + + let _in, _out; + /* save starting available input and output */ + + + let copy; + /* number of stored or match bytes to copy */ + + let from; + /* where to copy match bytes from */ + + let from_source; + let here = 0; + /* current decoding table entry */ + + let here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //let last; /* parent table entry */ + + let last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + + let len; + /* length to copy for repeats, bits to drop */ + + let ret; + /* return code */ + + const hbuf = new Uint8Array(4); + /* buffer for gzip header crc calculation */ + + let opts; + let n; // temporary variable for NEED_BITS + + const order = + /* permutation of code lengths */ + new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); + + if (!strm || !strm.state || !strm.output || !strm.input && strm.avail_in !== 0) { + return Z_STREAM_ERROR$1; + } + + state = strm.state; + + if (state.mode === TYPE) { + state.mode = TYPEDO; + } + /* skip check */ + //--- LOAD() --- + + + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; //--- + + _in = have; + _out = left; + ret = Z_OK$1; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } //=== NEEDBITS(16); + + + while (bits < 16) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if (state.wrap & 2 && hold === 0x8b1f) { + /* gzip header */ + state.check = 0 + /*crc32(0L, Z_NULL, 0)*/ + ; //=== CRC2(state.check, hold); + + hbuf[0] = hold & 0xff; + hbuf[1] = hold >>> 8 & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); //===// + //=== INITBITS(); + + hold = 0; + bits = 0; //===// + + state.mode = FLAGS; + break; + } + + state.flags = 0; + /* expect zlib header */ + + if (state.head) { + state.head.done = false; + } + + if (!(state.wrap & 1) || + /* check if zlib header allowed */ + (((hold & 0xff + /*BITS(8)*/ + ) << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + + if ((hold & 0x0f + /*BITS(4)*/ + ) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } //--- DROPBITS(4) ---// + + + hold >>>= 4; + bits -= 4; //---// + + len = (hold & 0x0f + /*BITS(4)*/ + ) + 8; + + if (state.wbits === 0) { + state.wbits = len; + } else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } // !!! pako patch. Force use `options.windowBits` if passed. + // Required to always use max window size by default. + + + state.dmax = 1 << state.wbits; //state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + + strm.adler = state.check = 1 + /*adler32(0L, Z_NULL, 0)*/ + ; + state.mode = hold & 0x200 ? DICTID : TYPE; //=== INITBITS(); + + hold = 0; + bits = 0; //===// + + break; + + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.flags = hold; + + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + + if (state.head) { + state.head.text = hold >> 8 & 1; + } + + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = hold >>> 8 & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); //===// + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + + state.mode = TIME; + + /* falls through */ + + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if (state.head) { + state.head.time = hold; + } + + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = hold >>> 8 & 0xff; + hbuf[2] = hold >>> 16 & 0xff; + hbuf[3] = hold >>> 24 & 0xff; + state.check = crc32_1(state.check, hbuf, 4, 0); //=== + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + + state.mode = OS; + + /* falls through */ + + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if (state.head) { + state.head.xflags = hold & 0xff; + state.head.os = hold >> 8; + } + + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = hold >>> 8 & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); //===// + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + + state.mode = EXLEN; + + /* falls through */ + + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.length = hold; + + if (state.head) { + state.head.extra_len = hold; + } + + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = hold >>> 8 & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); //===// + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + } else if (state.head) { + state.head.extra = null + /*Z_NULL*/ + ; + } + + state.mode = EXTRA; + + /* falls through */ + + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + + if (copy > have) { + copy = have; + } + + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + + if (!state.head.extra) { + // Use untyped array for more convenient processing later + state.head.extra = new Uint8Array(state.head.extra_len); + } + + state.head.extra.set(input.subarray(next, // extra field is limited to 65536 bytes + // - no need for additional size check + next + copy), + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len); //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + + have -= copy; + next += copy; + state.length -= copy; + } + + if (state.length) { + break inf_leave; + } + } + + state.length = 0; + state.mode = NAME; + + /* falls through */ + + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { + break inf_leave; + } + + copy = 0; + + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + + if (state.head && len && state.length < 65536 + /*state.head.name_max*/ + ) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + + have -= copy; + next += copy; + + if (len) { + break inf_leave; + } + } else if (state.head) { + state.head.name = null; + } + + state.length = 0; + state.mode = COMMENT; + + /* falls through */ + + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { + break inf_leave; + } + + copy = 0; + + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + + if (state.head && len && state.length < 65536 + /*state.head.comm_max*/ + ) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + + have -= copy; + next += copy; + + if (len) { + break inf_leave; + } + } else if (state.head) { + state.head.comment = null; + } + + state.mode = HCRC; + + /* falls through */ + + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + } + + if (state.head) { + state.head.hcrc = state.flags >> 9 & 1; + state.head.done = true; + } + + strm.adler = state.check = 0; + state.mode = TYPE; + break; + + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + strm.adler = state.check = zswap32(hold); //=== INITBITS(); + + hold = 0; + bits = 0; //===// + + state.mode = DICT; + + /* falls through */ + + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; //--- + + return Z_NEED_DICT$1; + } + + strm.adler = state.check = 1 + /*adler32(0L, Z_NULL, 0)*/ + ; + state.mode = TYPE; + + /* falls through */ + + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { + break inf_leave; + } + + /* falls through */ + + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; //---// + + state.mode = CHECK; + break; + } //=== NEEDBITS(3); */ + + + while (bits < 3) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.last = hold & 0x01 + /*BITS(1)*/ + ; //--- DROPBITS(1) ---// + + hold >>>= 1; + bits -= 1; //---// + + switch (hold & 0x03 + /*BITS(2)*/ + ) { + case 0: + /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + + case 1: + /* fixed block */ + fixedtables(state); //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + + state.mode = LEN_; + /* decode codes */ + + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; //---// + + break inf_leave; + } + + break; + + case 2: + /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } //--- DROPBITS(2) ---// + + + hold >>>= 2; + bits -= 2; //---// + + break; + + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; //---// + //=== NEEDBITS(32); */ + + while (bits < 32) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if ((hold & 0xffff) !== (hold >>> 16 ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + + state.length = hold & 0xffff; //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + + hold = 0; + bits = 0; //===// + + state.mode = COPY_; + + if (flush === Z_TREES) { + break inf_leave; + } + + /* falls through */ + + case COPY_: + state.mode = COPY; + + /* falls through */ + + case COPY: + copy = state.length; + + if (copy) { + if (copy > have) { + copy = have; + } + + if (copy > left) { + copy = left; + } + + if (copy === 0) { + break inf_leave; + } //--- zmemcpy(put, next, copy); --- + + + output.set(input.subarray(next, next + copy), put); //---// + + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } //Tracev((stderr, "inflate: stored end\n")); + + + state.mode = TYPE; + break; + + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.nlen = (hold & 0x1f + /*BITS(5)*/ + ) + 257; //--- DROPBITS(5) ---// + + hold >>>= 5; + bits -= 5; //---// + + state.ndist = (hold & 0x1f + /*BITS(5)*/ + ) + 1; //--- DROPBITS(5) ---// + + hold >>>= 5; + bits -= 5; //---// + + state.ncode = (hold & 0x0f + /*BITS(4)*/ + ) + 4; //--- DROPBITS(4) ---// + + hold >>>= 4; + bits -= 4; //---// + //#ifndef PKZIP_BUG_WORKAROUND + + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } //#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + + + state.have = 0; + state.mode = LENLENS; + + /* falls through */ + + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.lens[order[state.have++]] = hold & 0x07; //BITS(3); + //--- DROPBITS(3) ---// + + hold >>>= 3; + bits -= 3; //---// + } + + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + + + state.lencode = state.lendyn; + state.lenbits = 7; + opts = { + bits: state.lenbits + }; + ret = inftrees(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } //Tracev((stderr, "inflate: code lengths ok\n")); + + + state.have = 0; + state.mode = CODELENS; + + /* falls through */ + + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & (1 << state.lenbits) - 1]; + /*BITS(state.lenbits)*/ + + here_bits = here >>> 24; + here_op = here >>> 16 & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { + break; + } //--- PULLBYTE() ---// + + + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; //---// + } + + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; //---// + + state.lens[state.have++] = here_val; + } else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + + while (bits < n) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + //--- DROPBITS(here.bits) ---// + + + hold >>>= here_bits; + bits -= here_bits; //---// + + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03); //BITS(2); + //--- DROPBITS(2) ---// + + hold >>>= 2; + bits -= 2; //---// + } else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + + while (bits < n) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + //--- DROPBITS(here.bits) ---// + + + hold >>>= here_bits; + bits -= here_bits; //---// + + len = 0; + copy = 3 + (hold & 0x07); //BITS(3); + //--- DROPBITS(3) ---// + + hold >>>= 3; + bits -= 3; //---// + } else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + + while (bits < n) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + //--- DROPBITS(here.bits) ---// + + + hold >>>= here_bits; + bits -= here_bits; //---// + + len = 0; + copy = 11 + (hold & 0x7f); //BITS(7); + //--- DROPBITS(7) ---// + + hold >>>= 7; + bits -= 7; //---// + } + + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + + while (copy--) { + state.lens[state.have++] = len; + } + } + } + /* handle error breaks in while */ + + + if (state.mode === BAD) { + break; + } + /* check for end-of-block code (better have one) */ + + + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + + + state.lenbits = 9; + opts = { + bits: state.lenbits + }; + ret = inftrees(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + + state.lenbits = opts.bits; // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; //state.distcode.copy(state.codes); + // Switch to use dynamic table + + state.distcode = state.distdyn; + opts = { + bits: state.distbits + }; + ret = inftrees(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + + state.distbits = opts.bits; // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } //Tracev((stderr, 'inflate: codes ok\n')); + + + state.mode = LEN_; + + if (flush === Z_TREES) { + break inf_leave; + } + + /* falls through */ + + case LEN_: + state.mode = LEN; + + /* falls through */ + + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; //--- + + inffast(strm, _out); //--- LOAD() --- + + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; //--- + + if (state.mode === TYPE) { + state.back = -1; + } + + break; + } + + state.back = 0; + + for (;;) { + here = state.lencode[hold & (1 << state.lenbits) - 1]; + /*BITS(state.lenbits)*/ + + here_bits = here >>> 24; + here_op = here >>> 16 & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { + break; + } //--- PULLBYTE() ---// + + + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; //---// + } + + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + + for (;;) { + here = state.lencode[last_val + ((hold & (1 << last_bits + last_op) - 1 + /*BITS(last.bits + last.op)*/ + ) >> last_bits)]; + here_bits = here >>> 24; + here_op = here >>> 16 & 0xff; + here_val = here & 0xffff; + + if (last_bits + here_bits <= bits) { + break; + } //--- PULLBYTE() ---// + + + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; //---// + } //--- DROPBITS(last.bits) ---// + + + hold >>>= last_bits; + bits -= last_bits; //---// + + state.back += last_bits; + } //--- DROPBITS(here.bits) ---// + + + hold >>>= here_bits; + bits -= here_bits; //---// + + state.back += here_bits; + state.length = here_val; + + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + + state.extra = here_op & 15; + state.mode = LENEXT; + + /* falls through */ + + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + + while (bits < n) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.length += hold & (1 << state.extra) - 1 + /*BITS(state.extra)*/ + ; //--- DROPBITS(state.extra) ---// + + hold >>>= state.extra; + bits -= state.extra; //---// + + state.back += state.extra; + } //Tracevv((stderr, "inflate: length %u\n", state.length)); + + + state.was = state.length; + state.mode = DIST; + + /* falls through */ + + case DIST: + for (;;) { + here = state.distcode[hold & (1 << state.distbits) - 1]; + /*BITS(state.distbits)*/ + + here_bits = here >>> 24; + here_op = here >>> 16 & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { + break; + } //--- PULLBYTE() ---// + + + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; //---// + } + + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + + for (;;) { + here = state.distcode[last_val + ((hold & (1 << last_bits + last_op) - 1 + /*BITS(last.bits + last.op)*/ + ) >> last_bits)]; + here_bits = here >>> 24; + here_op = here >>> 16 & 0xff; + here_val = here & 0xffff; + + if (last_bits + here_bits <= bits) { + break; + } //--- PULLBYTE() ---// + + + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; //---// + } //--- DROPBITS(last.bits) ---// + + + hold >>>= last_bits; + bits -= last_bits; //---// + + state.back += last_bits; + } //--- DROPBITS(here.bits) ---// + + + hold >>>= here_bits; + bits -= here_bits; //---// + + state.back += here_bits; + + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + + state.offset = here_val; + state.extra = here_op & 15; + state.mode = DISTEXT; + + /* falls through */ + + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + + while (bits < n) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + state.offset += hold & (1 << state.extra) - 1 + /*BITS(state.extra)*/ + ; //--- DROPBITS(state.extra) ---// + + hold >>>= state.extra; + bits -= state.extra; //---// + + state.back += state.extra; + } //#ifdef INFLATE_STRICT + + + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } //#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + + + state.mode = MATCH; + + /* falls through */ + + case MATCH: + if (left === 0) { + break inf_leave; + } + + copy = _out - left; + + if (state.offset > copy) { + /* copy from window */ + copy = state.offset - copy; + + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // Trace((stderr, "inflate.c too far\n")); + // copy -= state.whave; + // if (copy > state.length) { copy = state.length; } + // if (copy > left) { copy = left; } + // left -= copy; + // state.length -= copy; + // do { + // output[put++] = 0; + // } while (--copy); + // if (state.length === 0) { state.mode = LEN; } + // break; + //#endif + + } + + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } else { + from = state.wnext - copy; + } + + if (copy > state.length) { + copy = state.length; + } + + from_source = state.window; + } else { + /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + + if (copy > left) { + copy = left; + } + + left -= copy; + state.length -= copy; + + do { + output[put++] = from_source[from++]; + } while (--copy); + + if (state.length === 0) { + state.mode = LEN; + } + + break; + + case LIT: + if (left === 0) { + break inf_leave; + } + + output[put++] = state.length; + left--; + state.mode = LEN; + break; + + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { + break inf_leave; + } + + have--; // Use '|' instead of '+' to make sure that result is signed + + hold |= input[next++] << bits; + bits += 8; + } //===// + + + _out -= left; + strm.total_out += _out; + state.total += _out; + + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out); + } + + _out = left; // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too + + if ((state.flags ? hold : zswap32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + + state.mode = LENGTH; + + /* falls through */ + + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { + break inf_leave; + } + + have--; + hold += input[next++] << bits; + bits += 8; + } //===// + + + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } //=== INITBITS(); + + + hold = 0; + bits = 0; //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + + state.mode = DONE; + + /* falls through */ + + case DONE: + ret = Z_STREAM_END$1; + break inf_leave; + + case BAD: + ret = Z_DATA_ERROR$1; + break inf_leave; + + case MEM: + return Z_MEM_ERROR$1; + + case SYNC: + /* falls through */ + + default: + return Z_STREAM_ERROR$1; + } + } // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + //--- RESTORE() --- + + + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; //--- + + if (state.wsize || _out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== Z_FINISH$1)) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ; + } + + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + + if (state.wrap && _out) { + strm.adler = state.check = + /*UPDATE(state.check, strm.next_out - _out, _out);*/ + state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out); + } + + strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + + if ((_in === 0 && _out === 0 || flush === Z_FINISH$1) && ret === Z_OK$1) { + ret = Z_BUF_ERROR; + } + + return ret; +}; + +const inflateEnd = strm => { + if (!strm || !strm.state + /*|| strm->zfree == (free_func)0*/ + ) { + return Z_STREAM_ERROR$1; + } + + let state = strm.state; + + if (state.window) { + state.window = null; + } + + strm.state = null; + return Z_OK$1; +}; + +const inflateGetHeader = (strm, head) => { + /* check state */ + if (!strm || !strm.state) { + return Z_STREAM_ERROR$1; + } + + const state = strm.state; + + if ((state.wrap & 2) === 0) { + return Z_STREAM_ERROR$1; + } + /* save header structure */ + + + state.head = head; + head.done = false; + return Z_OK$1; +}; + +const inflateSetDictionary = (strm, dictionary) => { + const dictLength = dictionary.length; + let state; + let dictid; + let ret; + /* check state */ + + if (!strm + /* == Z_NULL */ + || !strm.state + /* == Z_NULL */ + ) { + return Z_STREAM_ERROR$1; + } + + state = strm.state; + + if (state.wrap !== 0 && state.mode !== DICT) { + return Z_STREAM_ERROR$1; + } + /* check for correct dictionary identifier */ + + + if (state.mode === DICT) { + dictid = 1; + /* adler32(0, null, 0)*/ + + /* dictid = adler32(dictid, dictionary, dictLength); */ + + dictid = adler32_1(dictid, dictionary, dictLength, 0); + + if (dictid !== state.check) { + return Z_DATA_ERROR$1; + } + } + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + + + ret = updatewindow(strm, dictionary, dictLength, dictLength); + + if (ret) { + state.mode = MEM; + return Z_MEM_ERROR$1; + } + + state.havedict = 1; // Tracev((stderr, "inflate: dictionary set\n")); + + return Z_OK$1; +}; + +var inflateReset_1 = inflateReset; +var inflateReset2_1 = inflateReset2; +var inflateResetKeep_1 = inflateResetKeep; +var inflateInit_1 = inflateInit; +var inflateInit2_1 = inflateInit2; +var inflate_2$1 = inflate$2; +var inflateEnd_1 = inflateEnd; +var inflateGetHeader_1 = inflateGetHeader; +var inflateSetDictionary_1 = inflateSetDictionary; +var inflateInfo = 'pako inflate (from Nodeca project)'; +/* Not implemented +module.exports.inflateCopy = inflateCopy; +module.exports.inflateGetDictionary = inflateGetDictionary; +module.exports.inflateMark = inflateMark; +module.exports.inflatePrime = inflatePrime; +module.exports.inflateSync = inflateSync; +module.exports.inflateSyncPoint = inflateSyncPoint; +module.exports.inflateUndermine = inflateUndermine; +*/ + +var inflate_1$2 = { + inflateReset: inflateReset_1, + inflateReset2: inflateReset2_1, + inflateResetKeep: inflateResetKeep_1, + inflateInit: inflateInit_1, + inflateInit2: inflateInit2_1, + inflate: inflate_2$1, + inflateEnd: inflateEnd_1, + inflateGetHeader: inflateGetHeader_1, + inflateSetDictionary: inflateSetDictionary_1, + inflateInfo: inflateInfo +}; // (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + + this.xflags = 0; + /* operating system */ + + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + + /* pointer to zero-terminated file name or Z_NULL */ + + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + + /* pointer to zero-terminated comment or Z_NULL */ + + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + + /* true if there was or will be a header crc */ + + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + + this.done = false; +} + +var gzheader = GZheader; +const toString = Object.prototype.toString; +/* Public constants ==========================================================*/ + +/* ===========================================================================*/ + +const { + Z_NO_FLUSH, + Z_FINISH, + Z_OK, + Z_STREAM_END, + Z_NEED_DICT, + Z_STREAM_ERROR, + Z_DATA_ERROR, + Z_MEM_ERROR +} = constants$2; +/* ===========================================================================*/ + +/** + * class Inflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[inflate]] + * and [[inflateRaw]]. + **/ + +/* internal + * inflate.chunks -> Array + * + * Chunks of output data, if [[Inflate#onData]] not overridden. + **/ + +/** + * Inflate.result -> Uint8Array|String + * + * Uncompressed result, generated by default [[Inflate#onData]] + * and [[Inflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Inflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Inflate.err -> Number + * + * Error code after inflate finished. 0 (Z_OK) on success. + * Should be checked if broken data possible. + **/ + +/** + * Inflate.msg -> String + * + * Error message, if [[Inflate.err]] != 0 + **/ + +/** + * new Inflate(options) + * - options (Object): zlib inflate options. + * + * Creates new inflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `windowBits` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw inflate + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * By default, when no options set, autodetect deflate/gzip data format via + * wrapper header. + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) + * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * const inflate = new pako.Inflate({ level: 3}); + * + * inflate.push(chunk1, false); + * inflate.push(chunk2, true); // true -> last chunk + * + * if (inflate.err) { throw new Error(inflate.err); } + * + * console.log(inflate.result); + * ``` + **/ + +function Inflate$1(options) { + this.options = common.assign({ + chunkSize: 1024 * 64, + windowBits: 15, + to: '' + }, options || {}); + const opt = this.options; // Force window size for `raw` data, if not set directly, + // because we have no header for autodetect. + + if (opt.raw && opt.windowBits >= 0 && opt.windowBits < 16) { + opt.windowBits = -opt.windowBits; + + if (opt.windowBits === 0) { + opt.windowBits = -15; + } + } // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate + + + if (opt.windowBits >= 0 && opt.windowBits < 16 && !(options && options.windowBits)) { + opt.windowBits += 32; + } // Gzip header has no info about windows size, we can do autodetect only + // for deflate. So, if window size not set, force it to max when gzip possible + + + if (opt.windowBits > 15 && opt.windowBits < 48) { + // bit 3 (16) -> gzipped data + // bit 4 (32) -> autodetect gzip/deflate + if ((opt.windowBits & 15) === 0) { + opt.windowBits |= 15; + } + } + + this.err = 0; // error code, if happens (0 = Z_OK) + + this.msg = ''; // error message + + this.ended = false; // used to avoid multiple onEnd() calls + + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + let status = inflate_1$2.inflateInit2(this.strm, opt.windowBits); + + if (status !== Z_OK) { + throw new Error(messages[status]); + } + + this.header = new gzheader(); + inflate_1$2.inflateGetHeader(this.strm, this.header); // Setup dictionary + + if (opt.dictionary) { + // Convert data if needed + if (typeof opt.dictionary === 'string') { + opt.dictionary = strings.string2buf(opt.dictionary); + } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { + opt.dictionary = new Uint8Array(opt.dictionary); + } + + if (opt.raw) { + //In raw mode we need to set the dictionary early + status = inflate_1$2.inflateSetDictionary(this.strm, opt.dictionary); + + if (status !== Z_OK) { + throw new Error(messages[status]); + } + } + } +} +/** + * Inflate#push(data[, flush_mode]) -> Boolean + * - data (Uint8Array|ArrayBuffer): input data + * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE + * flush modes. See constants. Skipped or `false` means Z_NO_FLUSH, + * `true` means Z_FINISH. + * + * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with + * new output chunks. Returns `true` on success. If end of stream detected, + * [[Inflate#onEnd]] will be called. + * + * `flush_mode` is not needed for normal operation, because end of stream + * detected automatically. You may try to use it for advanced things, but + * this functionality was not tested. + * + * On fail call [[Inflate#onEnd]] with error code and return false. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ + + +Inflate$1.prototype.push = function (data, flush_mode) { + const strm = this.strm; + const chunkSize = this.options.chunkSize; + const dictionary = this.options.dictionary; + + let status, _flush_mode, last_avail_out; + + if (this.ended) return false; + if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;else _flush_mode = flush_mode === true ? Z_FINISH : Z_NO_FLUSH; // Convert data if needed + + if (toString.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + for (;;) { + if (strm.avail_out === 0) { + strm.output = new Uint8Array(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + status = inflate_1$2.inflate(strm, _flush_mode); + + if (status === Z_NEED_DICT && dictionary) { + status = inflate_1$2.inflateSetDictionary(strm, dictionary); + + if (status === Z_OK) { + status = inflate_1$2.inflate(strm, _flush_mode); + } else if (status === Z_DATA_ERROR) { + // Replace code with more verbose + status = Z_NEED_DICT; + } + } // Skip snyc markers if more data follows and not raw mode + + + while (strm.avail_in > 0 && status === Z_STREAM_END && strm.state.wrap > 0 && data[strm.next_in] !== 0) { + inflate_1$2.inflateReset(strm); + status = inflate_1$2.inflate(strm, _flush_mode); + } + + switch (status) { + case Z_STREAM_ERROR: + case Z_DATA_ERROR: + case Z_NEED_DICT: + case Z_MEM_ERROR: + this.onEnd(status); + this.ended = true; + return false; + } // Remember real `avail_out` value, because we may patch out buffer content + // to align utf8 strings boundaries. + + + last_avail_out = strm.avail_out; + + if (strm.next_out) { + if (strm.avail_out === 0 || status === Z_STREAM_END) { + if (this.options.to === 'string') { + let next_out_utf8 = strings.utf8border(strm.output, strm.next_out); + let tail = strm.next_out - next_out_utf8; + let utf8str = strings.buf2string(strm.output, next_out_utf8); // move tail & realign counters + + strm.next_out = tail; + strm.avail_out = chunkSize - tail; + if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0); + this.onData(utf8str); + } else { + this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out)); + } + } + } // Must repeat iteration if out buffer is full + + + if (status === Z_OK && last_avail_out === 0) continue; // Finalize if end of stream reached. + + if (status === Z_STREAM_END) { + status = inflate_1$2.inflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return true; + } + + if (strm.avail_in === 0) break; + } + + return true; +}; +/** + * Inflate#onData(chunk) -> Void + * - chunk (Uint8Array|String): output data. When string output requested, + * each chunk will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ + + +Inflate$1.prototype.onData = function (chunk) { + this.chunks.push(chunk); +}; +/** + * Inflate#onEnd(status) -> Void + * - status (Number): inflate status. 0 (Z_OK) on success, + * other if not. + * + * Called either after you tell inflate that the input stream is + * complete (Z_FINISH). By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ + + +Inflate$1.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK) { + if (this.options.to === 'string') { + this.result = this.chunks.join(''); + } else { + this.result = common.flattenChunks(this.chunks); + } + } + + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; +/** + * inflate(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * Decompress `data` with inflate/ungzip and `options`. Autodetect + * format via wrapper header by default. That's why we don't provide + * separate `ungzip` method. + * + * Supported options are: + * + * - windowBits + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * + * ##### Example: + * + * ```javascript + * const pako = require('pako'); + * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9])); + * let output; + * + * try { + * output = pako.inflate(input); + * } catch (err) { + * console.log(err); + * } + * ``` + **/ + + +function inflate$1(input, options) { + const inflator = new Inflate$1(options); + inflator.push(input); // That will never happens, if you don't cheat with options :) + + if (inflator.err) throw inflator.msg || messages[inflator.err]; + return inflator.result; +} +/** + * inflateRaw(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * The same as [[inflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + + +function inflateRaw$1(input, options) { + options = options || {}; + options.raw = true; + return inflate$1(input, options); +} +/** + * ungzip(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * Just shortcut to [[inflate]], because it autodetects format + * by header.content. Done for convenience. + **/ + + +var Inflate_1$1 = Inflate$1; +var inflate_2 = inflate$1; +var inflateRaw_1$1 = inflateRaw$1; +var ungzip$1 = inflate$1; +var constants = constants$2; +var inflate_1$1 = { + Inflate: Inflate_1$1, + inflate: inflate_2, + inflateRaw: inflateRaw_1$1, + ungzip: ungzip$1, + constants: constants +}; +const { + Deflate, + deflate, + deflateRaw, + gzip +} = deflate_1$1; +const { + Inflate, + inflate, + inflateRaw, + ungzip +} = inflate_1$1; +var Deflate_1 = Deflate; +exports.Deflate = Deflate_1; +var deflate_1 = deflate; +exports.deflate = deflate_1; +var deflateRaw_1 = deflateRaw; +exports.deflateRaw = deflateRaw_1; +var gzip_1 = gzip; +exports.gzip = gzip_1; +var Inflate_1 = Inflate; +exports.Inflate = Inflate_1; +var inflate_1 = inflate; +exports.inflate = inflate_1; +var inflateRaw_1 = inflateRaw; +exports.inflateRaw = inflateRaw_1; +var ungzip_1 = ungzip; +exports.ungzip = ungzip_1; +var constants_1 = constants$2; +exports.constants = constants_1; +var pako = { + Deflate: Deflate_1, + deflate: deflate_1, + deflateRaw: deflateRaw_1, + gzip: gzip_1, + Inflate: Inflate_1, + inflate: inflate_1, + inflateRaw: inflateRaw_1, + ungzip: ungzip_1, + constants: constants_1 +}; +exports.default = pako; + +},{}],19:[function(require,module,exports){ +(function (Buffer){(function (){ +(function() { + var crypt = require('crypt'), + utf8 = require('charenc').utf8, + bin = require('charenc').bin, + + // The core + sha1 = function (message) { + // Convert to byte array + if (message.constructor == String) + message = utf8.stringToBytes(message); + else if (typeof Buffer !== 'undefined' && typeof Buffer.isBuffer == 'function' && Buffer.isBuffer(message)) + message = Array.prototype.slice.call(message, 0); + else if (!Array.isArray(message)) + message = message.toString(); + + // otherwise assume byte array + + var m = crypt.bytesToWords(message), + l = message.length * 8, + w = [], + H0 = 1732584193, + H1 = -271733879, + H2 = -1732584194, + H3 = 271733878, + H4 = -1009589776; + + // Padding + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >>> 9) << 4) + 15] = l; + + for (var i = 0; i < m.length; i += 16) { + var a = H0, + b = H1, + c = H2, + d = H3, + e = H4; + + for (var j = 0; j < 80; j++) { + + if (j < 16) + w[j] = m[i + j]; + else { + var n = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16]; + w[j] = (n << 1) | (n >>> 31); + } + + var t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + ( + j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 : + j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 : + j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 : + (H1 ^ H2 ^ H3) - 899497514); + + H4 = H3; + H3 = H2; + H2 = (H1 << 30) | (H1 >>> 2); + H1 = H0; + H0 = t; + } + + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += e; + } + + return [H0, H1, H2, H3, H4]; + }, + + // Public API + api = function (message, options) { + var digestbytes = crypt.wordsToBytes(sha1(message)); + return options && options.asBytes ? digestbytes : + options && options.asString ? bin.bytesToString(digestbytes) : + crypt.bytesToHex(digestbytes); + }; + + api._blocksize = 16; + api._digestsize = 20; + + module.exports = api; +})(); + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":4,"charenc":5,"crypt":6}],20:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.addExtensionsToContext = addExtensionsToContext; +exports.attributes = void 0; +exports.bindFramebufferInfo = bindFramebufferInfo; +exports.bindTransformFeedbackInfo = bindTransformFeedbackInfo; +exports.bindUniformBlock = bindUniformBlock; +exports.canFilter = canFilter; +exports.canGenerateMipmap = canGenerateMipmap; +exports.createAttribsFromArrays = createAttribsFromArrays; +exports.createAttributeSetters = createAttributeSetters; +exports.createBufferFromArray = createBufferFromArray; +exports.createBufferFromTypedArray = createBufferFromTypedArray; +exports.createBufferInfoFromArrays = createBufferInfoFromArrays; +exports.createBuffersFromArrays = createBuffersFromArrays; +exports.createFramebufferInfo = createFramebufferInfo; +exports.createProgram = createProgram; +exports.createProgramFromScripts = createProgramFromScripts; +exports.createProgramFromSources = createProgramFromSources; +exports.createProgramInfo = createProgramInfo; +exports.createProgramInfoFromProgram = createProgramInfoFromProgram; +exports.createSampler = createSampler; +exports.createSamplers = createSamplers; +exports.createTexture = createTexture; +exports.createTextures = createTextures; +exports.createTransformFeedback = createTransformFeedback; +exports.createTransformFeedbackInfo = createTransformFeedbackInfo; +exports.createUniformBlockInfo = createUniformBlockInfo; +exports.createUniformBlockInfoFromProgram = createUniformBlockInfoFromProgram; +exports.createUniformBlockSpecFromProgram = createUniformBlockSpecFromProgram; +exports.createUniformSetters = createUniformSetters; +exports.createVAOAndSetAttributes = createVAOAndSetAttributes; +exports.createVAOFromBufferInfo = createVAOFromBufferInfo; +exports.createVertexArrayInfo = createVertexArrayInfo; +exports.draw = void 0; +exports.drawBufferInfo = drawBufferInfo; +exports.drawObjectList = drawObjectList; +exports.framebuffers = void 0; +exports.getArray_ = getArray; +exports.getBytesPerElementForInternalFormat = getBytesPerElementForInternalFormat; +exports.getContext = getContext; +exports.getFormatAndTypeForInternalFormat = getFormatAndTypeForInternalFormat; +exports.getGLTypeForTypedArray = getGLTypeForTypedArray; +exports.getGLTypeForTypedArrayType = getGLTypeForTypedArrayType; +exports.getNumComponentsForFormat = getNumComponentsForFormat; +exports.getNumComponents_ = getNumComponents; +exports.getTypedArrayTypeForGLType = getTypedArrayTypeForGLType; +exports.getWebGLContext = getWebGLContext; +exports.isArrayBuffer = exports.glEnumToString = void 0; +exports.isWebGL1 = isWebGL1; +exports.isWebGL2 = isWebGL2; +exports.loadTextureFromUrl = loadTextureFromUrl; +exports.programs = exports.primitives = exports.m4 = void 0; +exports.resizeCanvasToDisplaySize = resizeCanvasToDisplaySize; +exports.resizeFramebufferInfo = resizeFramebufferInfo; +exports.resizeTexture = resizeTexture; +exports.setAttribInfoBufferFromArray = setAttribInfoBufferFromArray; +exports.setAttributeDefaults_ = setDefaults; +exports.setAttributePrefix = setAttributePrefix; +exports.setAttributes = setAttributes; +exports.setBlockUniforms = setBlockUniforms; +exports.setBuffersAndAttributes = setBuffersAndAttributes; +exports.setDefaultTextureColor = setDefaultTextureColor; +exports.setDefaults = setDefaults$2; +exports.setEmptyTexture = setEmptyTexture; +exports.setSamplerParameters = setSamplerParameters; +exports.setTextureDefaults_ = setDefaults$1; +exports.setTextureFilteringForSize = setTextureFilteringForSize; +exports.setTextureFromArray = setTextureFromArray; +exports.setTextureFromElement = setTextureFromElement; +exports.setTextureParameters = setTextureParameters; +exports.setUniformBlock = setUniformBlock; +exports.setUniforms = setUniforms; +exports.vertexArrays = exports.v3 = exports.utils = exports.typedarrays = exports.textures = exports.setUniformsAndBindTextures = void 0; + +/* @license twgl.js 4.19.1 Copyright (c) 2015, Gregg Tavares All Rights Reserved. +Available via the MIT license. +see: http://github.com/greggman/twgl.js for details */ + +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * + * Vec3 math math functions. + * + * Almost all functions take an optional `dst` argument. If it is not passed in the + * functions will create a new Vec3. In other words you can do this + * + * var v = v3.cross(v1, v2); // Creates a new Vec3 with the cross product of v1 x v2. + * + * or + * + * var v = v3.create(); + * v3.cross(v1, v2, v); // Puts the cross product of v1 x v2 in v + * + * The first style is often easier but depending on where it's used it generates garbage where + * as there is almost never allocation with the second style. + * + * It is always save to pass any vector as the destination. So for example + * + * v3.cross(v1, v2, v1); // Puts the cross product of v1 x v2 in v1 + * + * @module twgl/v3 + */ +let VecType = Float32Array; +/** + * A JavaScript array with 3 values or a Float32Array with 3 values. + * When created by the library will create the default type which is `Float32Array` + * but can be set by calling {@link module:twgl/v3.setDefaultType}. + * @typedef {(number[]|Float32Array)} Vec3 + * @memberOf module:twgl/v3 + */ + +/** + * Sets the type this library creates for a Vec3 + * @param {constructor} ctor the constructor for the type. Either `Float32Array` or `Array` + * @return {constructor} previous constructor for Vec3 + * @memberOf module:twgl/v3 + */ + +function setDefaultType(ctor) { + const oldType = VecType; + VecType = ctor; + return oldType; +} +/** + * Creates a vec3; may be called with x, y, z to set initial values. + * @param {number} [x] Initial x value. + * @param {number} [y] Initial y value. + * @param {number} [z] Initial z value. + * @return {module:twgl/v3.Vec3} the created vector + * @memberOf module:twgl/v3 + */ + + +function create(x, y, z) { + const dst = new VecType(3); + + if (x) { + dst[0] = x; + } + + if (y) { + dst[1] = y; + } + + if (z) { + dst[2] = z; + } + + return dst; +} +/** + * Adds two vectors; assumes a and b have the same dimension. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} A vector tha tis the sum of a and b. + * @memberOf module:twgl/v3 + */ + + +function add(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] + b[0]; + dst[1] = a[1] + b[1]; + dst[2] = a[2] + b[2]; + return dst; +} +/** + * Subtracts two vectors. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} A vector that is the difference of a and b. + * @memberOf module:twgl/v3 + */ + + +function subtract(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] - b[0]; + dst[1] = a[1] - b[1]; + dst[2] = a[2] - b[2]; + return dst; +} +/** + * Performs linear interpolation on two vectors. + * Given vectors a and b and interpolation coefficient t, returns + * a + t * (b - a). + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {number} t Interpolation coefficient. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The linear interpolated result. + * @memberOf module:twgl/v3 + */ + + +function lerp(a, b, t, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] + t * (b[0] - a[0]); + dst[1] = a[1] + t * (b[1] - a[1]); + dst[2] = a[2] + t * (b[2] - a[2]); + return dst; +} +/** + * Performs linear interpolation on two vectors. + * Given vectors a and b and interpolation coefficient vector t, returns + * a + t * (b - a). + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} t Interpolation coefficients vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} the linear interpolated result. + * @memberOf module:twgl/v3 + */ + + +function lerpV(a, b, t, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] + t[0] * (b[0] - a[0]); + dst[1] = a[1] + t[1] * (b[1] - a[1]); + dst[2] = a[2] + t[2] * (b[2] - a[2]); + return dst; +} +/** + * Return max values of two vectors. + * Given vectors a and b returns + * [max(a[0], b[0]), max(a[1], b[1]), max(a[2], b[2])]. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The max components vector. + * @memberOf module:twgl/v3 + */ + + +function max(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = Math.max(a[0], b[0]); + dst[1] = Math.max(a[1], b[1]); + dst[2] = Math.max(a[2], b[2]); + return dst; +} +/** + * Return min values of two vectors. + * Given vectors a and b returns + * [min(a[0], b[0]), min(a[1], b[1]), min(a[2], b[2])]. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The min components vector. + * @memberOf module:twgl/v3 + */ + + +function min(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = Math.min(a[0], b[0]); + dst[1] = Math.min(a[1], b[1]); + dst[2] = Math.min(a[2], b[2]); + return dst; +} +/** + * Multiplies a vector by a scalar. + * @param {module:twgl/v3.Vec3} v The vector. + * @param {number} k The scalar. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The scaled vector. + * @memberOf module:twgl/v3 + */ + + +function mulScalar(v, k, dst) { + dst = dst || new VecType(3); + dst[0] = v[0] * k; + dst[1] = v[1] * k; + dst[2] = v[2] * k; + return dst; +} +/** + * Divides a vector by a scalar. + * @param {module:twgl/v3.Vec3} v The vector. + * @param {number} k The scalar. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The scaled vector. + * @memberOf module:twgl/v3 + */ + + +function divScalar(v, k, dst) { + dst = dst || new VecType(3); + dst[0] = v[0] / k; + dst[1] = v[1] / k; + dst[2] = v[2] / k; + return dst; +} +/** + * Computes the cross product of two vectors; assumes both vectors have + * three entries. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The vector of a cross b. + * @memberOf module:twgl/v3 + */ + + +function cross(a, b, dst) { + dst = dst || new VecType(3); + const t1 = a[2] * b[0] - a[0] * b[2]; + const t2 = a[0] * b[1] - a[1] * b[0]; + dst[0] = a[1] * b[2] - a[2] * b[1]; + dst[1] = t1; + dst[2] = t2; + return dst; +} +/** + * Computes the dot product of two vectors; assumes both vectors have + * three entries. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @return {number} dot product + * @memberOf module:twgl/v3 + */ + + +function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} +/** + * Computes the length of vector + * @param {module:twgl/v3.Vec3} v vector. + * @return {number} length of vector. + * @memberOf module:twgl/v3 + */ + + +function length$1(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} +/** + * Computes the square of the length of vector + * @param {module:twgl/v3.Vec3} v vector. + * @return {number} square of the length of vector. + * @memberOf module:twgl/v3 + */ + + +function lengthSq(v) { + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; +} +/** + * Computes the distance between 2 points + * @param {module:twgl/v3.Vec3} a vector. + * @param {module:twgl/v3.Vec3} b vector. + * @return {number} distance between a and b + * @memberOf module:twgl/v3 + */ + + +function distance(a, b) { + const dx = a[0] - b[0]; + const dy = a[1] - b[1]; + const dz = a[2] - b[2]; + return Math.sqrt(dx * dx + dy * dy + dz * dz); +} +/** + * Computes the square of the distance between 2 points + * @param {module:twgl/v3.Vec3} a vector. + * @param {module:twgl/v3.Vec3} b vector. + * @return {number} square of the distance between a and b + * @memberOf module:twgl/v3 + */ + + +function distanceSq(a, b) { + const dx = a[0] - b[0]; + const dy = a[1] - b[1]; + const dz = a[2] - b[2]; + return dx * dx + dy * dy + dz * dz; +} +/** + * Divides a vector by its Euclidean length and returns the quotient. + * @param {module:twgl/v3.Vec3} a The vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The normalized vector. + * @memberOf module:twgl/v3 + */ + + +function normalize(a, dst) { + dst = dst || new VecType(3); + const lenSq = a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; + const len = Math.sqrt(lenSq); + + if (len > 0.00001) { + dst[0] = a[0] / len; + dst[1] = a[1] / len; + dst[2] = a[2] / len; + } else { + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + } + + return dst; +} +/** + * Negates a vector. + * @param {module:twgl/v3.Vec3} v The vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} -v. + * @memberOf module:twgl/v3 + */ + + +function negate(v, dst) { + dst = dst || new VecType(3); + dst[0] = -v[0]; + dst[1] = -v[1]; + dst[2] = -v[2]; + return dst; +} +/** + * Copies a vector. + * @param {module:twgl/v3.Vec3} v The vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} A copy of v. + * @memberOf module:twgl/v3 + */ + + +function copy(v, dst) { + dst = dst || new VecType(3); + dst[0] = v[0]; + dst[1] = v[1]; + dst[2] = v[2]; + return dst; +} +/** + * Multiplies a vector by another vector (component-wise); assumes a and + * b have the same length. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The vector of products of entries of a and + * b. + * @memberOf module:twgl/v3 + */ + + +function multiply(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] * b[0]; + dst[1] = a[1] * b[1]; + dst[2] = a[2] * b[2]; + return dst; +} +/** + * Divides a vector by another vector (component-wise); assumes a and + * b have the same length. + * @param {module:twgl/v3.Vec3} a Operand vector. + * @param {module:twgl/v3.Vec3} b Operand vector. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not new one is created. + * @return {module:twgl/v3.Vec3} The vector of quotients of entries of a and + * b. + * @memberOf module:twgl/v3 + */ + + +function divide(a, b, dst) { + dst = dst || new VecType(3); + dst[0] = a[0] / b[0]; + dst[1] = a[1] / b[1]; + dst[2] = a[2] / b[2]; + return dst; +} + +var v3 = /*#__PURE__*/Object.freeze({ + __proto__: null, + add: add, + copy: copy, + create: create, + cross: cross, + distance: distance, + distanceSq: distanceSq, + divide: divide, + divScalar: divScalar, + dot: dot, + lerp: lerp, + lerpV: lerpV, + length: length$1, + lengthSq: lengthSq, + max: max, + min: min, + mulScalar: mulScalar, + multiply: multiply, + negate: negate, + normalize: normalize, + setDefaultType: setDefaultType, + subtract: subtract +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * 4x4 Matrix math math functions. + * + * Almost all functions take an optional `dst` argument. If it is not passed in the + * functions will create a new matrix. In other words you can do this + * + * const mat = m4.translation([1, 2, 3]); // Creates a new translation matrix + * + * or + * + * const mat = m4.create(); + * m4.translation([1, 2, 3], mat); // Puts translation matrix in mat. + * + * The first style is often easier but depending on where it's used it generates garbage where + * as there is almost never allocation with the second style. + * + * It is always save to pass any matrix as the destination. So for example + * + * const mat = m4.identity(); + * const trans = m4.translation([1, 2, 3]); + * m4.multiply(mat, trans, mat); // Multiplies mat * trans and puts result in mat. + * + * @module twgl/m4 + */ + +exports.v3 = v3; +let MatType = Float32Array; +/** + * A JavaScript array with 16 values or a Float32Array with 16 values. + * When created by the library will create the default type which is `Float32Array` + * but can be set by calling {@link module:twgl/m4.setDefaultType}. + * @typedef {(number[]|Float32Array)} Mat4 + * @memberOf module:twgl/m4 + */ + +/** + * Sets the type this library creates for a Mat4 + * @param {constructor} ctor the constructor for the type. Either `Float32Array` or `Array` + * @return {constructor} previous constructor for Mat4 + * @memberOf module:twgl/m4 + */ + +function setDefaultType$1(ctor) { + const oldType = MatType; + MatType = ctor; + return oldType; +} +/** + * Negates a matrix. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} -m. + * @memberOf module:twgl/m4 + */ + + +function negate$1(m, dst) { + dst = dst || new MatType(16); + dst[0] = -m[0]; + dst[1] = -m[1]; + dst[2] = -m[2]; + dst[3] = -m[3]; + dst[4] = -m[4]; + dst[5] = -m[5]; + dst[6] = -m[6]; + dst[7] = -m[7]; + dst[8] = -m[8]; + dst[9] = -m[9]; + dst[10] = -m[10]; + dst[11] = -m[11]; + dst[12] = -m[12]; + dst[13] = -m[13]; + dst[14] = -m[14]; + dst[15] = -m[15]; + return dst; +} +/** + * Copies a matrix. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/m4.Mat4} [dst] The matrix. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} A copy of m. + * @memberOf module:twgl/m4 + */ + + +function copy$1(m, dst) { + dst = dst || new MatType(16); + dst[0] = m[0]; + dst[1] = m[1]; + dst[2] = m[2]; + dst[3] = m[3]; + dst[4] = m[4]; + dst[5] = m[5]; + dst[6] = m[6]; + dst[7] = m[7]; + dst[8] = m[8]; + dst[9] = m[9]; + dst[10] = m[10]; + dst[11] = m[11]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + return dst; +} +/** + * Creates an n-by-n identity matrix. + * + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} An n-by-n identity matrix. + * @memberOf module:twgl/m4 + */ + + +function identity(dst) { + dst = dst || new MatType(16); + dst[0] = 1; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = 1; + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Takes the transpose of a matrix. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The transpose of m. + * @memberOf module:twgl/m4 + */ + + +function transpose(m, dst) { + dst = dst || new MatType(16); + + if (dst === m) { + let t; + t = m[1]; + m[1] = m[4]; + m[4] = t; + t = m[2]; + m[2] = m[8]; + m[8] = t; + t = m[3]; + m[3] = m[12]; + m[12] = t; + t = m[6]; + m[6] = m[9]; + m[9] = t; + t = m[7]; + m[7] = m[13]; + m[13] = t; + t = m[11]; + m[11] = m[14]; + m[14] = t; + return dst; + } + + const m00 = m[0 * 4 + 0]; + const m01 = m[0 * 4 + 1]; + const m02 = m[0 * 4 + 2]; + const m03 = m[0 * 4 + 3]; + const m10 = m[1 * 4 + 0]; + const m11 = m[1 * 4 + 1]; + const m12 = m[1 * 4 + 2]; + const m13 = m[1 * 4 + 3]; + const m20 = m[2 * 4 + 0]; + const m21 = m[2 * 4 + 1]; + const m22 = m[2 * 4 + 2]; + const m23 = m[2 * 4 + 3]; + const m30 = m[3 * 4 + 0]; + const m31 = m[3 * 4 + 1]; + const m32 = m[3 * 4 + 2]; + const m33 = m[3 * 4 + 3]; + dst[0] = m00; + dst[1] = m10; + dst[2] = m20; + dst[3] = m30; + dst[4] = m01; + dst[5] = m11; + dst[6] = m21; + dst[7] = m31; + dst[8] = m02; + dst[9] = m12; + dst[10] = m22; + dst[11] = m32; + dst[12] = m03; + dst[13] = m13; + dst[14] = m23; + dst[15] = m33; + return dst; +} +/** + * Computes the inverse of a 4-by-4 matrix. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The inverse of m. + * @memberOf module:twgl/m4 + */ + + +function inverse(m, dst) { + dst = dst || new MatType(16); + const m00 = m[0 * 4 + 0]; + const m01 = m[0 * 4 + 1]; + const m02 = m[0 * 4 + 2]; + const m03 = m[0 * 4 + 3]; + const m10 = m[1 * 4 + 0]; + const m11 = m[1 * 4 + 1]; + const m12 = m[1 * 4 + 2]; + const m13 = m[1 * 4 + 3]; + const m20 = m[2 * 4 + 0]; + const m21 = m[2 * 4 + 1]; + const m22 = m[2 * 4 + 2]; + const m23 = m[2 * 4 + 3]; + const m30 = m[3 * 4 + 0]; + const m31 = m[3 * 4 + 1]; + const m32 = m[3 * 4 + 2]; + const m33 = m[3 * 4 + 3]; + const tmp_0 = m22 * m33; + const tmp_1 = m32 * m23; + const tmp_2 = m12 * m33; + const tmp_3 = m32 * m13; + const tmp_4 = m12 * m23; + const tmp_5 = m22 * m13; + const tmp_6 = m02 * m33; + const tmp_7 = m32 * m03; + const tmp_8 = m02 * m23; + const tmp_9 = m22 * m03; + const tmp_10 = m02 * m13; + const tmp_11 = m12 * m03; + const tmp_12 = m20 * m31; + const tmp_13 = m30 * m21; + const tmp_14 = m10 * m31; + const tmp_15 = m30 * m11; + const tmp_16 = m10 * m21; + const tmp_17 = m20 * m11; + const tmp_18 = m00 * m31; + const tmp_19 = m30 * m01; + const tmp_20 = m00 * m21; + const tmp_21 = m20 * m01; + const tmp_22 = m00 * m11; + const tmp_23 = m10 * m01; + const t0 = tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31 - (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); + const t1 = tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31 - (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); + const t2 = tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31 - (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); + const t3 = tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21 - (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); + const d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); + dst[0] = d * t0; + dst[1] = d * t1; + dst[2] = d * t2; + dst[3] = d * t3; + dst[4] = d * (tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30 - (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)); + dst[5] = d * (tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30 - (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)); + dst[6] = d * (tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30 - (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)); + dst[7] = d * (tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20 - (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)); + dst[8] = d * (tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33 - (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)); + dst[9] = d * (tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33 - (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)); + dst[10] = d * (tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33 - (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)); + dst[11] = d * (tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23 - (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)); + dst[12] = d * (tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12 - (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)); + dst[13] = d * (tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22 - (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)); + dst[14] = d * (tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02 - (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)); + dst[15] = d * (tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12 - (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02)); + return dst; +} +/** + * Multiplies two 4-by-4 matrices with a on the left and b on the right + * @param {module:twgl/m4.Mat4} a The matrix on the left. + * @param {module:twgl/m4.Mat4} b The matrix on the right. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The matrix product of a and b. + * @memberOf module:twgl/m4 + */ + + +function multiply$1(a, b, dst) { + dst = dst || new MatType(16); + const a00 = a[0]; + const a01 = a[1]; + const a02 = a[2]; + const a03 = a[3]; + const a10 = a[4 + 0]; + const a11 = a[4 + 1]; + const a12 = a[4 + 2]; + const a13 = a[4 + 3]; + const a20 = a[8 + 0]; + const a21 = a[8 + 1]; + const a22 = a[8 + 2]; + const a23 = a[8 + 3]; + const a30 = a[12 + 0]; + const a31 = a[12 + 1]; + const a32 = a[12 + 2]; + const a33 = a[12 + 3]; + const b00 = b[0]; + const b01 = b[1]; + const b02 = b[2]; + const b03 = b[3]; + const b10 = b[4 + 0]; + const b11 = b[4 + 1]; + const b12 = b[4 + 2]; + const b13 = b[4 + 3]; + const b20 = b[8 + 0]; + const b21 = b[8 + 1]; + const b22 = b[8 + 2]; + const b23 = b[8 + 3]; + const b30 = b[12 + 0]; + const b31 = b[12 + 1]; + const b32 = b[12 + 2]; + const b33 = b[12 + 3]; + dst[0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; + dst[1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; + dst[2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; + dst[3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; + dst[4] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; + dst[5] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; + dst[6] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; + dst[7] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; + dst[8] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; + dst[9] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; + dst[10] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; + dst[11] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; + dst[12] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + dst[13] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + dst[14] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + dst[15] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; + return dst; +} +/** + * Sets the translation component of a 4-by-4 matrix to the given + * vector. + * @param {module:twgl/m4.Mat4} a The matrix. + * @param {module:twgl/v3.Vec3} v The vector. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The matrix with translation set. + * @memberOf module:twgl/m4 + */ + + +function setTranslation(a, v, dst) { + dst = dst || identity(); + + if (a !== dst) { + dst[0] = a[0]; + dst[1] = a[1]; + dst[2] = a[2]; + dst[3] = a[3]; + dst[4] = a[4]; + dst[5] = a[5]; + dst[6] = a[6]; + dst[7] = a[7]; + dst[8] = a[8]; + dst[9] = a[9]; + dst[10] = a[10]; + dst[11] = a[11]; + } + + dst[12] = v[0]; + dst[13] = v[1]; + dst[14] = v[2]; + dst[15] = 1; + return dst; +} +/** + * Returns the translation component of a 4-by-4 matrix as a vector with 3 + * entries. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} [dst] vector to hold result. If not passed a new one is created. + * @return {module:twgl/v3.Vec3} The translation component of m. + * @memberOf module:twgl/m4 + */ + + +function getTranslation(m, dst) { + dst = dst || create(); + dst[0] = m[12]; + dst[1] = m[13]; + dst[2] = m[14]; + return dst; +} +/** + * Returns an axis of a 4x4 matrix as a vector with 3 entries + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {number} axis The axis 0 = x, 1 = y, 2 = z; + * @return {module:twgl/v3.Vec3} [dst] vector. + * @return {module:twgl/v3.Vec3} The axis component of m. + * @memberOf module:twgl/m4 + */ + + +function getAxis(m, axis, dst) { + dst = dst || create(); + const off = axis * 4; + dst[0] = m[off + 0]; + dst[1] = m[off + 1]; + dst[2] = m[off + 2]; + return dst; +} +/** + * Sets an axis of a 4x4 matrix as a vector with 3 entries + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} v the axis vector + * @param {number} axis The axis 0 = x, 1 = y, 2 = z; + * @param {module:twgl/m4.Mat4} [dst] The matrix to set. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The matrix with axis set. + * @memberOf module:twgl/m4 + */ + + +function setAxis(a, v, axis, dst) { + if (dst !== a) { + dst = copy$1(a, dst); + } + + const off = axis * 4; + dst[off + 0] = v[0]; + dst[off + 1] = v[1]; + dst[off + 2] = v[2]; + return dst; +} +/** + * Computes a 4-by-4 perspective transformation matrix given the angular height + * of the frustum, the aspect ratio, and the near and far clipping planes. The + * arguments define a frustum extending in the negative z direction. The given + * angle is the vertical angle of the frustum, and the horizontal angle is + * determined to produce the given aspect ratio. The arguments near and far are + * the distances to the near and far clipping planes. Note that near and far + * are not z coordinates, but rather they are distances along the negative + * z-axis. The matrix generated sends the viewing frustum to the unit box. + * We assume a unit box extending from -1 to 1 in the x and y dimensions and + * from 0 to 1 in the z dimension. + * @param {number} fieldOfViewYInRadians The camera angle from top to bottom (in radians). + * @param {number} aspect The aspect ratio width / height. + * @param {number} zNear The depth (negative z coordinate) + * of the near clipping plane. + * @param {number} zFar The depth (negative z coordinate) + * of the far clipping plane. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The perspective matrix. + * @memberOf module:twgl/m4 + */ + + +function perspective(fieldOfViewYInRadians, aspect, zNear, zFar, dst) { + dst = dst || new MatType(16); + const f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewYInRadians); + const rangeInv = 1.0 / (zNear - zFar); + dst[0] = f / aspect; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = f; + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = (zNear + zFar) * rangeInv; + dst[11] = -1; + dst[12] = 0; + dst[13] = 0; + dst[14] = zNear * zFar * rangeInv * 2; + dst[15] = 0; + return dst; +} +/** + * Computes a 4-by-4 orthogonal transformation matrix given the left, right, + * bottom, and top dimensions of the near clipping plane as well as the + * near and far clipping plane distances. + * @param {number} left Left side of the near clipping plane viewport. + * @param {number} right Right side of the near clipping plane viewport. + * @param {number} bottom Bottom of the near clipping plane viewport. + * @param {number} top Top of the near clipping plane viewport. + * @param {number} near The depth (negative z coordinate) + * of the near clipping plane. + * @param {number} far The depth (negative z coordinate) + * of the far clipping plane. + * @param {module:twgl/m4.Mat4} [dst] Output matrix. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The perspective matrix. + * @memberOf module:twgl/m4 + */ + + +function ortho(left, right, bottom, top, near, far, dst) { + dst = dst || new MatType(16); + dst[0] = 2 / (right - left); + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = 2 / (top - bottom); + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = 2 / (near - far); + dst[11] = 0; + dst[12] = (right + left) / (left - right); + dst[13] = (top + bottom) / (bottom - top); + dst[14] = (far + near) / (near - far); + dst[15] = 1; + return dst; +} +/** + * Computes a 4-by-4 perspective transformation matrix given the left, right, + * top, bottom, near and far clipping planes. The arguments define a frustum + * extending in the negative z direction. The arguments near and far are the + * distances to the near and far clipping planes. Note that near and far are not + * z coordinates, but rather they are distances along the negative z-axis. The + * matrix generated sends the viewing frustum to the unit box. We assume a unit + * box extending from -1 to 1 in the x and y dimensions and from 0 to 1 in the z + * dimension. + * @param {number} left The x coordinate of the left plane of the box. + * @param {number} right The x coordinate of the right plane of the box. + * @param {number} bottom The y coordinate of the bottom plane of the box. + * @param {number} top The y coordinate of the right plane of the box. + * @param {number} near The negative z coordinate of the near plane of the box. + * @param {number} far The negative z coordinate of the far plane of the box. + * @param {module:twgl/m4.Mat4} [dst] Output matrix. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The perspective projection matrix. + * @memberOf module:twgl/m4 + */ + + +function frustum(left, right, bottom, top, near, far, dst) { + dst = dst || new MatType(16); + const dx = right - left; + const dy = top - bottom; + const dz = near - far; + dst[0] = 2 * near / dx; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = 2 * near / dy; + dst[6] = 0; + dst[7] = 0; + dst[8] = (left + right) / dx; + dst[9] = (top + bottom) / dy; + dst[10] = far / dz; + dst[11] = -1; + dst[12] = 0; + dst[13] = 0; + dst[14] = near * far / dz; + dst[15] = 0; + return dst; +} + +let xAxis; +let yAxis; +let zAxis; +/** + * Computes a 4-by-4 look-at transformation. + * + * This is a matrix which positions the camera itself. If you want + * a view matrix (a matrix which moves things in front of the camera) + * take the inverse of this. + * + * @param {module:twgl/v3.Vec3} eye The position of the eye. + * @param {module:twgl/v3.Vec3} target The position meant to be viewed. + * @param {module:twgl/v3.Vec3} up A vector pointing up. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The look-at matrix. + * @memberOf module:twgl/m4 + */ + +function lookAt(eye, target, up, dst) { + dst = dst || new MatType(16); + xAxis = xAxis || create(); + yAxis = yAxis || create(); + zAxis = zAxis || create(); + normalize(subtract(eye, target, zAxis), zAxis); + normalize(cross(up, zAxis, xAxis), xAxis); + normalize(cross(zAxis, xAxis, yAxis), yAxis); + dst[0] = xAxis[0]; + dst[1] = xAxis[1]; + dst[2] = xAxis[2]; + dst[3] = 0; + dst[4] = yAxis[0]; + dst[5] = yAxis[1]; + dst[6] = yAxis[2]; + dst[7] = 0; + dst[8] = zAxis[0]; + dst[9] = zAxis[1]; + dst[10] = zAxis[2]; + dst[11] = 0; + dst[12] = eye[0]; + dst[13] = eye[1]; + dst[14] = eye[2]; + dst[15] = 1; + return dst; +} +/** + * Creates a 4-by-4 matrix which translates by the given vector v. + * @param {module:twgl/v3.Vec3} v The vector by + * which to translate. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The translation matrix. + * @memberOf module:twgl/m4 + */ + + +function translation(v, dst) { + dst = dst || new MatType(16); + dst[0] = 1; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = 1; + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = v[0]; + dst[13] = v[1]; + dst[14] = v[2]; + dst[15] = 1; + return dst; +} +/** + * Translates the given 4-by-4 matrix by the given vector v. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} v The vector by + * which to translate. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The translated matrix. + * @memberOf module:twgl/m4 + */ + + +function translate(m, v, dst) { + dst = dst || new MatType(16); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + const m00 = m[0]; + const m01 = m[1]; + const m02 = m[2]; + const m03 = m[3]; + const m10 = m[1 * 4 + 0]; + const m11 = m[1 * 4 + 1]; + const m12 = m[1 * 4 + 2]; + const m13 = m[1 * 4 + 3]; + const m20 = m[2 * 4 + 0]; + const m21 = m[2 * 4 + 1]; + const m22 = m[2 * 4 + 2]; + const m23 = m[2 * 4 + 3]; + const m30 = m[3 * 4 + 0]; + const m31 = m[3 * 4 + 1]; + const m32 = m[3 * 4 + 2]; + const m33 = m[3 * 4 + 3]; + + if (m !== dst) { + dst[0] = m00; + dst[1] = m01; + dst[2] = m02; + dst[3] = m03; + dst[4] = m10; + dst[5] = m11; + dst[6] = m12; + dst[7] = m13; + dst[8] = m20; + dst[9] = m21; + dst[10] = m22; + dst[11] = m23; + } + + dst[12] = m00 * v0 + m10 * v1 + m20 * v2 + m30; + dst[13] = m01 * v0 + m11 * v1 + m21 * v2 + m31; + dst[14] = m02 * v0 + m12 * v1 + m22 * v2 + m32; + dst[15] = m03 * v0 + m13 * v1 + m23 * v2 + m33; + return dst; +} +/** + * Creates a 4-by-4 matrix which rotates around the x-axis by the given angle. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotation matrix. + * @memberOf module:twgl/m4 + */ + + +function rotationX(angleInRadians, dst) { + dst = dst || new MatType(16); + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[0] = 1; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = c; + dst[6] = s; + dst[7] = 0; + dst[8] = 0; + dst[9] = -s; + dst[10] = c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Rotates the given 4-by-4 matrix around the x-axis by the given + * angle. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotated matrix. + * @memberOf module:twgl/m4 + */ + + +function rotateX(m, angleInRadians, dst) { + dst = dst || new MatType(16); + const m10 = m[4]; + const m11 = m[5]; + const m12 = m[6]; + const m13 = m[7]; + const m20 = m[8]; + const m21 = m[9]; + const m22 = m[10]; + const m23 = m[11]; + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[4] = c * m10 + s * m20; + dst[5] = c * m11 + s * m21; + dst[6] = c * m12 + s * m22; + dst[7] = c * m13 + s * m23; + dst[8] = c * m20 - s * m10; + dst[9] = c * m21 - s * m11; + dst[10] = c * m22 - s * m12; + dst[11] = c * m23 - s * m13; + + if (m !== dst) { + dst[0] = m[0]; + dst[1] = m[1]; + dst[2] = m[2]; + dst[3] = m[3]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; +} +/** + * Creates a 4-by-4 matrix which rotates around the y-axis by the given angle. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotation matrix. + * @memberOf module:twgl/m4 + */ + + +function rotationY(angleInRadians, dst) { + dst = dst || new MatType(16); + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[0] = c; + dst[1] = 0; + dst[2] = -s; + dst[3] = 0; + dst[4] = 0; + dst[5] = 1; + dst[6] = 0; + dst[7] = 0; + dst[8] = s; + dst[9] = 0; + dst[10] = c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Rotates the given 4-by-4 matrix around the y-axis by the given + * angle. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotated matrix. + * @memberOf module:twgl/m4 + */ + + +function rotateY(m, angleInRadians, dst) { + dst = dst || new MatType(16); + const m00 = m[0 * 4 + 0]; + const m01 = m[0 * 4 + 1]; + const m02 = m[0 * 4 + 2]; + const m03 = m[0 * 4 + 3]; + const m20 = m[2 * 4 + 0]; + const m21 = m[2 * 4 + 1]; + const m22 = m[2 * 4 + 2]; + const m23 = m[2 * 4 + 3]; + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[0] = c * m00 - s * m20; + dst[1] = c * m01 - s * m21; + dst[2] = c * m02 - s * m22; + dst[3] = c * m03 - s * m23; + dst[8] = c * m20 + s * m00; + dst[9] = c * m21 + s * m01; + dst[10] = c * m22 + s * m02; + dst[11] = c * m23 + s * m03; + + if (m !== dst) { + dst[4] = m[4]; + dst[5] = m[5]; + dst[6] = m[6]; + dst[7] = m[7]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; +} +/** + * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotation matrix. + * @memberOf module:twgl/m4 + */ + + +function rotationZ(angleInRadians, dst) { + dst = dst || new MatType(16); + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[0] = c; + dst[1] = s; + dst[2] = 0; + dst[3] = 0; + dst[4] = -s; + dst[5] = c; + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = 1; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Rotates the given 4-by-4 matrix around the z-axis by the given + * angle. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotated matrix. + * @memberOf module:twgl/m4 + */ + + +function rotateZ(m, angleInRadians, dst) { + dst = dst || new MatType(16); + const m00 = m[0 * 4 + 0]; + const m01 = m[0 * 4 + 1]; + const m02 = m[0 * 4 + 2]; + const m03 = m[0 * 4 + 3]; + const m10 = m[1 * 4 + 0]; + const m11 = m[1 * 4 + 1]; + const m12 = m[1 * 4 + 2]; + const m13 = m[1 * 4 + 3]; + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + dst[0] = c * m00 + s * m10; + dst[1] = c * m01 + s * m11; + dst[2] = c * m02 + s * m12; + dst[3] = c * m03 + s * m13; + dst[4] = c * m10 - s * m00; + dst[5] = c * m11 - s * m01; + dst[6] = c * m12 - s * m02; + dst[7] = c * m13 - s * m03; + + if (m !== dst) { + dst[8] = m[8]; + dst[9] = m[9]; + dst[10] = m[10]; + dst[11] = m[11]; + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; +} +/** + * Creates a 4-by-4 matrix which rotates around the given axis by the given + * angle. + * @param {module:twgl/v3.Vec3} axis The axis + * about which to rotate. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} A matrix which rotates angle radians + * around the axis. + * @memberOf module:twgl/m4 + */ + + +function axisRotation(axis, angleInRadians, dst) { + dst = dst || new MatType(16); + let x = axis[0]; + let y = axis[1]; + let z = axis[2]; + const n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + const xx = x * x; + const yy = y * y; + const zz = z * z; + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + const oneMinusCosine = 1 - c; + dst[0] = xx + (1 - xx) * c; + dst[1] = x * y * oneMinusCosine + z * s; + dst[2] = x * z * oneMinusCosine - y * s; + dst[3] = 0; + dst[4] = x * y * oneMinusCosine - z * s; + dst[5] = yy + (1 - yy) * c; + dst[6] = y * z * oneMinusCosine + x * s; + dst[7] = 0; + dst[8] = x * z * oneMinusCosine + y * s; + dst[9] = y * z * oneMinusCosine - x * s; + dst[10] = zz + (1 - zz) * c; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Rotates the given 4-by-4 matrix around the given axis by the + * given angle. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} axis The axis + * about which to rotate. + * @param {number} angleInRadians The angle by which to rotate (in radians). + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The rotated matrix. + * @memberOf module:twgl/m4 + */ + + +function axisRotate(m, axis, angleInRadians, dst) { + dst = dst || new MatType(16); + let x = axis[0]; + let y = axis[1]; + let z = axis[2]; + const n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + const xx = x * x; + const yy = y * y; + const zz = z * z; + const c = Math.cos(angleInRadians); + const s = Math.sin(angleInRadians); + const oneMinusCosine = 1 - c; + const r00 = xx + (1 - xx) * c; + const r01 = x * y * oneMinusCosine + z * s; + const r02 = x * z * oneMinusCosine - y * s; + const r10 = x * y * oneMinusCosine - z * s; + const r11 = yy + (1 - yy) * c; + const r12 = y * z * oneMinusCosine + x * s; + const r20 = x * z * oneMinusCosine + y * s; + const r21 = y * z * oneMinusCosine - x * s; + const r22 = zz + (1 - zz) * c; + const m00 = m[0]; + const m01 = m[1]; + const m02 = m[2]; + const m03 = m[3]; + const m10 = m[4]; + const m11 = m[5]; + const m12 = m[6]; + const m13 = m[7]; + const m20 = m[8]; + const m21 = m[9]; + const m22 = m[10]; + const m23 = m[11]; + dst[0] = r00 * m00 + r01 * m10 + r02 * m20; + dst[1] = r00 * m01 + r01 * m11 + r02 * m21; + dst[2] = r00 * m02 + r01 * m12 + r02 * m22; + dst[3] = r00 * m03 + r01 * m13 + r02 * m23; + dst[4] = r10 * m00 + r11 * m10 + r12 * m20; + dst[5] = r10 * m01 + r11 * m11 + r12 * m21; + dst[6] = r10 * m02 + r11 * m12 + r12 * m22; + dst[7] = r10 * m03 + r11 * m13 + r12 * m23; + dst[8] = r20 * m00 + r21 * m10 + r22 * m20; + dst[9] = r20 * m01 + r21 * m11 + r22 * m21; + dst[10] = r20 * m02 + r21 * m12 + r22 * m22; + dst[11] = r20 * m03 + r21 * m13 + r22 * m23; + + if (m !== dst) { + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; +} +/** + * Creates a 4-by-4 matrix which scales in each dimension by an amount given by + * the corresponding entry in the given vector; assumes the vector has three + * entries. + * @param {module:twgl/v3.Vec3} v A vector of + * three entries specifying the factor by which to scale in each dimension. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The scaling matrix. + * @memberOf module:twgl/m4 + */ + + +function scaling(v, dst) { + dst = dst || new MatType(16); + dst[0] = v[0]; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + dst[4] = 0; + dst[5] = v[1]; + dst[6] = 0; + dst[7] = 0; + dst[8] = 0; + dst[9] = 0; + dst[10] = v[2]; + dst[11] = 0; + dst[12] = 0; + dst[13] = 0; + dst[14] = 0; + dst[15] = 1; + return dst; +} +/** + * Scales the given 4-by-4 matrix in each dimension by an amount + * given by the corresponding entry in the given vector; assumes the vector has + * three entries. + * @param {module:twgl/m4.Mat4} m The matrix to be modified. + * @param {module:twgl/v3.Vec3} v A vector of three entries specifying the + * factor by which to scale in each dimension. + * @param {module:twgl/m4.Mat4} [dst] matrix to hold result. If not passed a new one is created. + * @return {module:twgl/m4.Mat4} The scaled matrix. + * @memberOf module:twgl/m4 + */ + + +function scale(m, v, dst) { + dst = dst || new MatType(16); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + dst[0] = v0 * m[0 * 4 + 0]; + dst[1] = v0 * m[0 * 4 + 1]; + dst[2] = v0 * m[0 * 4 + 2]; + dst[3] = v0 * m[0 * 4 + 3]; + dst[4] = v1 * m[1 * 4 + 0]; + dst[5] = v1 * m[1 * 4 + 1]; + dst[6] = v1 * m[1 * 4 + 2]; + dst[7] = v1 * m[1 * 4 + 3]; + dst[8] = v2 * m[2 * 4 + 0]; + dst[9] = v2 * m[2 * 4 + 1]; + dst[10] = v2 * m[2 * 4 + 2]; + dst[11] = v2 * m[2 * 4 + 3]; + + if (m !== dst) { + dst[12] = m[12]; + dst[13] = m[13]; + dst[14] = m[14]; + dst[15] = m[15]; + } + + return dst; +} +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, + * interprets the vector as a point, transforms that point by the matrix, and + * returns the result as a vector with 3 entries. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} v The point. + * @param {module:twgl/v3.Vec3} [dst] optional vec3 to store result. If not passed a new one is created. + * @return {module:twgl/v3.Vec3} The transformed point. + * @memberOf module:twgl/m4 + */ + + +function transformPoint(m, v, dst) { + dst = dst || create(); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + const d = v0 * m[0 * 4 + 3] + v1 * m[1 * 4 + 3] + v2 * m[2 * 4 + 3] + m[3 * 4 + 3]; + dst[0] = (v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0] + m[3 * 4 + 0]) / d; + dst[1] = (v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1] + m[3 * 4 + 1]) / d; + dst[2] = (v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2] + m[3 * 4 + 2]) / d; + return dst; +} +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, interprets the vector as a + * direction, transforms that direction by the matrix, and returns the result; + * assumes the transformation of 3-dimensional space represented by the matrix + * is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} v The direction. + * @param {module:twgl/v3.Vec3} [dst] optional Vec3 to store result. If not passed a new one is created. + * @return {module:twgl/v3.Vec3} The transformed direction. + * @memberOf module:twgl/m4 + */ + + +function transformDirection(m, v, dst) { + dst = dst || create(); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + dst[0] = v0 * m[0 * 4 + 0] + v1 * m[1 * 4 + 0] + v2 * m[2 * 4 + 0]; + dst[1] = v0 * m[0 * 4 + 1] + v1 * m[1 * 4 + 1] + v2 * m[2 * 4 + 1]; + dst[2] = v0 * m[0 * 4 + 2] + v1 * m[1 * 4 + 2] + v2 * m[2 * 4 + 2]; + return dst; +} +/** + * Takes a 4-by-4 matrix m and a vector v with 3 entries, interprets the vector + * as a normal to a surface, and computes a vector which is normal upon + * transforming that surface by the matrix. The effect of this function is the + * same as transforming v (as a direction) by the inverse-transpose of m. This + * function assumes the transformation of 3-dimensional space represented by the + * matrix is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {module:twgl/m4.Mat4} m The matrix. + * @param {module:twgl/v3.Vec3} v The normal. + * @param {module:twgl/v3.Vec3} [dst] The direction. If not passed a new one is created. + * @return {module:twgl/v3.Vec3} The transformed normal. + * @memberOf module:twgl/m4 + */ + + +function transformNormal(m, v, dst) { + dst = dst || create(); + const mi = inverse(m); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + dst[0] = v0 * mi[0 * 4 + 0] + v1 * mi[0 * 4 + 1] + v2 * mi[0 * 4 + 2]; + dst[1] = v0 * mi[1 * 4 + 0] + v1 * mi[1 * 4 + 1] + v2 * mi[1 * 4 + 2]; + dst[2] = v0 * mi[2 * 4 + 0] + v1 * mi[2 * 4 + 1] + v2 * mi[2 * 4 + 2]; + return dst; +} + +var m4 = /*#__PURE__*/Object.freeze({ + __proto__: null, + axisRotate: axisRotate, + axisRotation: axisRotation, + copy: copy$1, + frustum: frustum, + getAxis: getAxis, + getTranslation: getTranslation, + identity: identity, + inverse: inverse, + lookAt: lookAt, + multiply: multiply$1, + negate: negate$1, + ortho: ortho, + perspective: perspective, + rotateX: rotateX, + rotateY: rotateY, + rotateZ: rotateZ, + rotationX: rotationX, + rotationY: rotationY, + rotationZ: rotationZ, + scale: scale, + scaling: scaling, + setAxis: setAxis, + setDefaultType: setDefaultType$1, + setTranslation: setTranslation, + transformDirection: transformDirection, + transformNormal: transformNormal, + transformPoint: transformPoint, + translate: translate, + translation: translation, + transpose: transpose +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* DataType */ + +exports.m4 = m4; +const BYTE = 0x1400; +const UNSIGNED_BYTE = 0x1401; +const SHORT = 0x1402; +const UNSIGNED_SHORT = 0x1403; +const INT = 0x1404; +const UNSIGNED_INT = 0x1405; +const FLOAT = 0x1406; +const UNSIGNED_SHORT_4_4_4_4 = 0x8033; +const UNSIGNED_SHORT_5_5_5_1 = 0x8034; +const UNSIGNED_SHORT_5_6_5 = 0x8363; +const HALF_FLOAT = 0x140B; +const UNSIGNED_INT_2_10_10_10_REV = 0x8368; +const UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B; +const UNSIGNED_INT_5_9_9_9_REV = 0x8C3E; +const FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD; +const UNSIGNED_INT_24_8 = 0x84FA; +const glTypeToTypedArray = {}; +{ + const tt = glTypeToTypedArray; + tt[BYTE] = Int8Array; + tt[UNSIGNED_BYTE] = Uint8Array; + tt[SHORT] = Int16Array; + tt[UNSIGNED_SHORT] = Uint16Array; + tt[INT] = Int32Array; + tt[UNSIGNED_INT] = Uint32Array; + tt[FLOAT] = Float32Array; + tt[UNSIGNED_SHORT_4_4_4_4] = Uint16Array; + tt[UNSIGNED_SHORT_5_5_5_1] = Uint16Array; + tt[UNSIGNED_SHORT_5_6_5] = Uint16Array; + tt[HALF_FLOAT] = Uint16Array; + tt[UNSIGNED_INT_2_10_10_10_REV] = Uint32Array; + tt[UNSIGNED_INT_10F_11F_11F_REV] = Uint32Array; + tt[UNSIGNED_INT_5_9_9_9_REV] = Uint32Array; + tt[FLOAT_32_UNSIGNED_INT_24_8_REV] = Uint32Array; + tt[UNSIGNED_INT_24_8] = Uint32Array; +} +/** + * Get the GL type for a typedArray + * @param {ArrayBufferView} typedArray a typedArray + * @return {number} the GL type for array. For example pass in an `Int8Array` and `gl.BYTE` will + * be returned. Pass in a `Uint32Array` and `gl.UNSIGNED_INT` will be returned + * @memberOf module:twgl/typedArray + */ + +function getGLTypeForTypedArray(typedArray) { + if (typedArray instanceof Int8Array) { + return BYTE; + } // eslint-disable-line + + + if (typedArray instanceof Uint8Array) { + return UNSIGNED_BYTE; + } // eslint-disable-line + + + if (typedArray instanceof Uint8ClampedArray) { + return UNSIGNED_BYTE; + } // eslint-disable-line + + + if (typedArray instanceof Int16Array) { + return SHORT; + } // eslint-disable-line + + + if (typedArray instanceof Uint16Array) { + return UNSIGNED_SHORT; + } // eslint-disable-line + + + if (typedArray instanceof Int32Array) { + return INT; + } // eslint-disable-line + + + if (typedArray instanceof Uint32Array) { + return UNSIGNED_INT; + } // eslint-disable-line + + + if (typedArray instanceof Float32Array) { + return FLOAT; + } // eslint-disable-line + + + throw new Error('unsupported typed array type'); +} +/** + * Get the GL type for a typedArray type + * @param {ArrayBufferView} typedArrayType a typedArray constructor + * @return {number} the GL type for type. For example pass in `Int8Array` and `gl.BYTE` will + * be returned. Pass in `Uint32Array` and `gl.UNSIGNED_INT` will be returned + * @memberOf module:twgl/typedArray + */ + + +function getGLTypeForTypedArrayType(typedArrayType) { + if (typedArrayType === Int8Array) { + return BYTE; + } // eslint-disable-line + + + if (typedArrayType === Uint8Array) { + return UNSIGNED_BYTE; + } // eslint-disable-line + + + if (typedArrayType === Uint8ClampedArray) { + return UNSIGNED_BYTE; + } // eslint-disable-line + + + if (typedArrayType === Int16Array) { + return SHORT; + } // eslint-disable-line + + + if (typedArrayType === Uint16Array) { + return UNSIGNED_SHORT; + } // eslint-disable-line + + + if (typedArrayType === Int32Array) { + return INT; + } // eslint-disable-line + + + if (typedArrayType === Uint32Array) { + return UNSIGNED_INT; + } // eslint-disable-line + + + if (typedArrayType === Float32Array) { + return FLOAT; + } // eslint-disable-line + + + throw new Error('unsupported typed array type'); +} +/** + * Get the typed array constructor for a given GL type + * @param {number} type the GL type. (eg: `gl.UNSIGNED_INT`) + * @return {function} the constructor for a the corresponding typed array. (eg. `Uint32Array`). + * @memberOf module:twgl/typedArray + */ + + +function getTypedArrayTypeForGLType(type) { + const CTOR = glTypeToTypedArray[type]; + + if (!CTOR) { + throw new Error('unknown gl type'); + } + + return CTOR; +} + +const isArrayBuffer = typeof SharedArrayBuffer !== 'undefined' ? function isArrayBufferOrSharedArrayBuffer(a) { + return a && a.buffer && a.buffer.toString && (a.buffer.toString() === "[object ArrayBuffer]" || a.buffer.toString() === "[object SharedArrayBuffer]"); +} : function isArrayBuffer(a) { + return a && a.buffer && a.buffer.toString && a.buffer.toString() === "[object ArrayBuffer]"; +}; +exports.isArrayBuffer = isArrayBuffer; +var typedarrays = /*#__PURE__*/Object.freeze({ + __proto__: null, + getGLTypeForTypedArray: getGLTypeForTypedArray, + getGLTypeForTypedArrayType: getGLTypeForTypedArrayType, + getTypedArrayTypeForGLType: getTypedArrayTypeForGLType, + isArrayBuffer: isArrayBuffer +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* eslint no-console: "off" */ + +/** + * Copy named properties + * + * @param {string[]} names names of properties to copy + * @param {object} src object to copy properties from + * @param {object} dst object to copy properties to + * @private + */ + +exports.typedarrays = typedarrays; + +function copyNamedProperties(names, src, dst) { + names.forEach(function (name) { + const value = src[name]; + + if (value !== undefined) { + dst[name] = value; + } + }); +} +/** + * Copies properties from source to dest only if a matching key is in dest + * + * @param {Object.} src the source + * @param {Object.} dst the dest + * @private + */ + + +function copyExistingProperties(src, dst) { + Object.keys(dst).forEach(function (key) { + if (dst.hasOwnProperty(key) && src.hasOwnProperty(key)) { + /* eslint no-prototype-builtins: 0 */ + dst[key] = src[key]; + } + }); +} + +function error(...args) { + console.error(...args); +} + +function warn(...args) { + console.warn(...args); +} + +function isBuffer(gl, t) { + return typeof WebGLBuffer !== 'undefined' && t instanceof WebGLBuffer; +} + +function isRenderbuffer(gl, t) { + return typeof WebGLRenderbuffer !== 'undefined' && t instanceof WebGLRenderbuffer; +} + +function isShader(gl, t) { + return typeof WebGLShader !== 'undefined' && t instanceof WebGLShader; +} + +function isTexture(gl, t) { + return typeof WebGLTexture !== 'undefined' && t instanceof WebGLTexture; +} + +function isSampler(gl, t) { + return typeof WebGLSampler !== 'undefined' && t instanceof WebGLSampler; +} +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +const STATIC_DRAW = 0x88e4; +const ARRAY_BUFFER = 0x8892; +const ELEMENT_ARRAY_BUFFER = 0x8893; +const BUFFER_SIZE = 0x8764; +const BYTE$1 = 0x1400; +const UNSIGNED_BYTE$1 = 0x1401; +const SHORT$1 = 0x1402; +const UNSIGNED_SHORT$1 = 0x1403; +const INT$1 = 0x1404; +const UNSIGNED_INT$1 = 0x1405; +const FLOAT$1 = 0x1406; +const defaults = { + attribPrefix: "" +}; +/** + * Sets the default attrib prefix + * + * When writing shaders I prefer to name attributes with `a_`, uniforms with `u_` and varyings with `v_` + * as it makes it clear where they came from. But, when building geometry I prefer using un-prefixed names. + * + * In other words I'll create arrays of geometry like this + * + * var arrays = { + * position: ... + * normal: ... + * texcoord: ... + * }; + * + * But need those mapped to attributes and my attributes start with `a_`. + * + * @deprecated see {@link module:twgl.setDefaults} + * @param {string} prefix prefix for attribs + * @memberOf module:twgl/attributes + */ + +function setAttributePrefix(prefix) { + defaults.attribPrefix = prefix; +} + +function setDefaults(newDefaults) { + copyExistingProperties(newDefaults, defaults); +} + +function setBufferFromTypedArray(gl, type, buffer, array, drawType) { + gl.bindBuffer(type, buffer); + gl.bufferData(type, array, drawType || STATIC_DRAW); +} +/** + * Given typed array creates a WebGLBuffer and copies the typed array + * into it. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {ArrayBuffer|SharedArrayBuffer|ArrayBufferView|WebGLBuffer} typedArray the typed array. Note: If a WebGLBuffer is passed in it will just be returned. No action will be taken + * @param {number} [type] the GL bind type for the buffer. Default = `gl.ARRAY_BUFFER`. + * @param {number} [drawType] the GL draw type for the buffer. Default = 'gl.STATIC_DRAW`. + * @return {WebGLBuffer} the created WebGLBuffer + * @memberOf module:twgl/attributes + */ + + +function createBufferFromTypedArray(gl, typedArray, type, drawType) { + if (isBuffer(gl, typedArray)) { + return typedArray; + } + + type = type || ARRAY_BUFFER; + const buffer = gl.createBuffer(); + setBufferFromTypedArray(gl, type, buffer, typedArray, drawType); + return buffer; +} + +function isIndices(name) { + return name === "indices"; +} // This is really just a guess. Though I can't really imagine using +// anything else? Maybe for some compression? + + +function getNormalizationForTypedArray(typedArray) { + if (typedArray instanceof Int8Array) { + return true; + } // eslint-disable-line + + + if (typedArray instanceof Uint8Array) { + return true; + } // eslint-disable-line + + + return false; +} // This is really just a guess. Though I can't really imagine using +// anything else? Maybe for some compression? + + +function getNormalizationForTypedArrayType(typedArrayType) { + if (typedArrayType === Int8Array) { + return true; + } // eslint-disable-line + + + if (typedArrayType === Uint8Array) { + return true; + } // eslint-disable-line + + + return false; +} + +function getArray(array) { + return array.length ? array : array.data; +} + +const texcoordRE = /coord|texture/i; +const colorRE = /color|colour/i; + +function guessNumComponentsFromName(name, length) { + let numComponents; + + if (texcoordRE.test(name)) { + numComponents = 2; + } else if (colorRE.test(name)) { + numComponents = 4; + } else { + numComponents = 3; // position, normals, indices ... + } + + if (length % numComponents > 0) { + throw new Error(`Can not guess numComponents for attribute '${name}'. Tried ${numComponents} but ${length} values is not evenly divisible by ${numComponents}. You should specify it.`); + } + + return numComponents; +} + +function getNumComponents(array, arrayName) { + return array.numComponents || array.size || guessNumComponentsFromName(arrayName, getArray(array).length); +} + +function makeTypedArray(array, name) { + if (isArrayBuffer(array)) { + return array; + } + + if (isArrayBuffer(array.data)) { + return array.data; + } + + if (Array.isArray(array)) { + array = { + data: array + }; + } + + let Type = array.type; + + if (!Type) { + if (isIndices(name)) { + Type = Uint16Array; + } else { + Type = Float32Array; + } + } + + return new Type(array.data); +} +/** + * The info for an attribute. This is effectively just the arguments to `gl.vertexAttribPointer` plus the WebGLBuffer + * for the attribute. + * + * @typedef {Object} AttribInfo + * @property {number[]|ArrayBufferView} [value] a constant value for the attribute. Note: if this is set the attribute will be + * disabled and set to this constant value and all other values will be ignored. + * @property {number} [numComponents] the number of components for this attribute. + * @property {number} [size] synonym for `numComponents`. + * @property {number} [type] the type of the attribute (eg. `gl.FLOAT`, `gl.UNSIGNED_BYTE`, etc...) Default = `gl.FLOAT` + * @property {boolean} [normalize] whether or not to normalize the data. Default = false + * @property {number} [offset] offset into buffer in bytes. Default = 0 + * @property {number} [stride] the stride in bytes per element. Default = 0 + * @property {number} [divisor] the divisor in instances. Default = undefined. Note: undefined = don't call gl.vertexAttribDivisor + * where as anything else = do call it with this value + * @property {WebGLBuffer} buffer the buffer that contains the data for this attribute + * @property {number} [drawType] the draw type passed to gl.bufferData. Default = gl.STATIC_DRAW + * @memberOf module:twgl + */ + +/** + * Use this type of array spec when TWGL can't guess the type or number of components of an array + * @typedef {Object} FullArraySpec + * @property {number[]|ArrayBufferView} [value] a constant value for the attribute. Note: if this is set the attribute will be + * disabled and set to this constant value and all other values will be ignored. + * @property {(number|number[]|ArrayBufferView)} data The data of the array. A number alone becomes the number of elements of type. + * @property {number} [numComponents] number of components for `vertexAttribPointer`. Default is based on the name of the array. + * If `coord` is in the name assumes `numComponents = 2`. + * If `color` is in the name assumes `numComponents = 4`. + * otherwise assumes `numComponents = 3` + * @property {constructor} [type] type. This is only used if `data` is a JavaScript array. It is the constructor for the typedarray. (eg. `Uint8Array`). + * For example if you want colors in a `Uint8Array` you might have a `FullArraySpec` like `{ type: Uint8Array, data: [255,0,255,255, ...], }`. + * @property {number} [size] synonym for `numComponents`. + * @property {boolean} [normalize] normalize for `vertexAttribPointer`. Default is true if type is `Int8Array` or `Uint8Array` otherwise false. + * @property {number} [stride] stride for `vertexAttribPointer`. Default = 0 + * @property {number} [offset] offset for `vertexAttribPointer`. Default = 0 + * @property {number} [divisor] divisor for `vertexAttribDivisor`. Default = undefined. Note: undefined = don't call gl.vertexAttribDivisor + * where as anything else = do call it with this value + * @property {string} [attrib] name of attribute this array maps to. Defaults to same name as array prefixed by the default attribPrefix. + * @property {string} [name] synonym for `attrib`. + * @property {string} [attribName] synonym for `attrib`. + * @property {WebGLBuffer} [buffer] Buffer to use for this attribute. This lets you use your own buffer + * but you will need to supply `numComponents` and `type`. You can effectively pass an `AttribInfo` + * to provide this. Example: + * + * const bufferInfo1 = twgl.createBufferInfoFromArrays(gl, { + * position: [1, 2, 3, ... ], + * }); + * const bufferInfo2 = twgl.createBufferInfoFromArrays(gl, { + * position: bufferInfo1.attribs.position, // use the same buffer from bufferInfo1 + * }); + * + * @memberOf module:twgl + */ + +/** + * An individual array in {@link module:twgl.Arrays} + * + * When passed to {@link module:twgl.createBufferInfoFromArrays} if an ArraySpec is `number[]` or `ArrayBufferView` + * the types will be guessed based on the name. `indices` will be `Uint16Array`, everything else will + * be `Float32Array`. If an ArraySpec is a number it's the number of floats for an empty (zeroed) buffer. + * + * @typedef {(number|number[]|ArrayBufferView|module:twgl.FullArraySpec)} ArraySpec + * @memberOf module:twgl + */ + +/** + * This is a JavaScript object of arrays by name. The names should match your shader's attributes. If your + * attributes have a common prefix you can specify it by calling {@link module:twgl.setAttributePrefix}. + * + * Bare JavaScript Arrays + * + * var arrays = { + * position: [-1, 1, 0], + * normal: [0, 1, 0], + * ... + * } + * + * Bare TypedArrays + * + * var arrays = { + * position: new Float32Array([-1, 1, 0]), + * color: new Uint8Array([255, 128, 64, 255]), + * ... + * } + * + * * Will guess at `numComponents` if not specified based on name. + * + * If `coord` is in the name assumes `numComponents = 2` + * + * If `color` is in the name assumes `numComponents = 4` + * + * otherwise assumes `numComponents = 3` + * + * Objects with various fields. See {@link module:twgl.FullArraySpec}. + * + * var arrays = { + * position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], }, + * texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], }, + * normal: { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], }, + * indices: { numComponents: 3, data: [0, 1, 2, 1, 2, 3], }, + * }; + * + * @typedef {Object.} Arrays + * @memberOf module:twgl + */ + +/** + * Creates a set of attribute data and WebGLBuffers from set of arrays + * + * Given + * + * var arrays = { + * position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], }, + * texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], }, + * normal: { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], }, + * color: { numComponents: 4, data: [255, 255, 255, 255, 255, 0, 0, 255, 0, 0, 255, 255], type: Uint8Array, }, + * indices: { numComponents: 3, data: [0, 1, 2, 1, 2, 3], }, + * }; + * + * returns something like + * + * var attribs = { + * position: { numComponents: 3, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, }, + * texcoord: { numComponents: 2, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, }, + * normal: { numComponents: 3, type: gl.FLOAT, normalize: false, buffer: WebGLBuffer, }, + * color: { numComponents: 4, type: gl.UNSIGNED_BYTE, normalize: true, buffer: WebGLBuffer, }, + * }; + * + * notes: + * + * * Arrays can take various forms + * + * Bare JavaScript Arrays + * + * var arrays = { + * position: [-1, 1, 0], + * normal: [0, 1, 0], + * ... + * } + * + * Bare TypedArrays + * + * var arrays = { + * position: new Float32Array([-1, 1, 0]), + * color: new Uint8Array([255, 128, 64, 255]), + * ... + * } + * + * * Will guess at `numComponents` if not specified based on name. + * + * If `coord` is in the name assumes `numComponents = 2` + * + * If `color` is in the name assumes `numComponents = 4` + * + * otherwise assumes `numComponents = 3` + * + * @param {WebGLRenderingContext} gl The webgl rendering context. + * @param {module:twgl.Arrays} arrays The arrays + * @param {module:twgl.BufferInfo} [srcBufferInfo] a BufferInfo to copy from + * This lets you share buffers. Any arrays you supply will override + * the buffers from srcBufferInfo. + * @return {Object.} the attribs + * @memberOf module:twgl/attributes + */ + + +function createAttribsFromArrays(gl, arrays) { + const attribs = {}; + Object.keys(arrays).forEach(function (arrayName) { + if (!isIndices(arrayName)) { + const array = arrays[arrayName]; + const attribName = array.attrib || array.name || array.attribName || defaults.attribPrefix + arrayName; + + if (array.value) { + if (!Array.isArray(array.value) && !isArrayBuffer(array.value)) { + throw new Error('array.value is not array or typedarray'); + } + + attribs[attribName] = { + value: array.value + }; + } else { + let buffer; + let type; + let normalization; + let numComponents; + + if (array.buffer && array.buffer instanceof WebGLBuffer) { + buffer = array.buffer; + numComponents = array.numComponents || array.size; + type = array.type; + normalization = array.normalize; + } else if (typeof array === "number" || typeof array.data === "number") { + const numValues = array.data || array; + const arrayType = array.type || Float32Array; + const numBytes = numValues * arrayType.BYTES_PER_ELEMENT; + type = getGLTypeForTypedArrayType(arrayType); + normalization = array.normalize !== undefined ? array.normalize : getNormalizationForTypedArrayType(arrayType); + numComponents = array.numComponents || array.size || guessNumComponentsFromName(arrayName, numValues); + buffer = gl.createBuffer(); + gl.bindBuffer(ARRAY_BUFFER, buffer); + gl.bufferData(ARRAY_BUFFER, numBytes, array.drawType || STATIC_DRAW); + } else { + const typedArray = makeTypedArray(array, arrayName); + buffer = createBufferFromTypedArray(gl, typedArray, undefined, array.drawType); + type = getGLTypeForTypedArray(typedArray); + normalization = array.normalize !== undefined ? array.normalize : getNormalizationForTypedArray(typedArray); + numComponents = getNumComponents(array, arrayName); + } + + attribs[attribName] = { + buffer: buffer, + numComponents: numComponents, + type: type, + normalize: normalization, + stride: array.stride || 0, + offset: array.offset || 0, + divisor: array.divisor === undefined ? undefined : array.divisor, + drawType: array.drawType + }; + } + } + }); + gl.bindBuffer(ARRAY_BUFFER, null); + return attribs; +} +/** + * Sets the contents of a buffer attached to an attribInfo + * + * This is helper function to dynamically update a buffer. + * + * Let's say you make a bufferInfo + * + * var arrays = { + * position: new Float32Array([0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0]), + * texcoord: new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]), + * normal: new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]), + * indices: new Uint16Array([0, 1, 2, 1, 2, 3]), + * }; + * var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays); + * + * And you want to dynamically update the positions. You could do this + * + * // assuming arrays.position has already been updated with new data. + * twgl.setAttribInfoBufferFromArray(gl, bufferInfo.attribs.position, arrays.position); + * + * @param {WebGLRenderingContext} gl + * @param {AttribInfo} attribInfo The attribInfo who's buffer contents to set. NOTE: If you have an attribute prefix + * the name of the attribute will include the prefix. + * @param {ArraySpec} array Note: it is arguably inefficient to pass in anything but a typed array because anything + * else will have to be converted to a typed array before it can be used by WebGL. During init time that + * inefficiency is usually not important but if you're updating data dynamically best to be efficient. + * @param {number} [offset] an optional offset into the buffer. This is only an offset into the WebGL buffer + * not the array. To pass in an offset into the array itself use a typed array and create an `ArrayBufferView` + * for the portion of the array you want to use. + * + * var someArray = new Float32Array(1000); // an array with 1000 floats + * var someSubArray = new Float32Array(someArray.buffer, offsetInBytes, sizeInUnits); // a view into someArray + * + * Now you can pass `someSubArray` into setAttribInfoBufferFromArray` + * @memberOf module:twgl/attributes + */ + + +function setAttribInfoBufferFromArray(gl, attribInfo, array, offset) { + array = makeTypedArray(array); + + if (offset !== undefined) { + gl.bindBuffer(ARRAY_BUFFER, attribInfo.buffer); + gl.bufferSubData(ARRAY_BUFFER, offset, array); + } else { + setBufferFromTypedArray(gl, ARRAY_BUFFER, attribInfo.buffer, array, attribInfo.drawType); + } +} + +function getBytesPerValueForGLType(gl, type) { + if (type === BYTE$1) return 1; // eslint-disable-line + + if (type === UNSIGNED_BYTE$1) return 1; // eslint-disable-line + + if (type === SHORT$1) return 2; // eslint-disable-line + + if (type === UNSIGNED_SHORT$1) return 2; // eslint-disable-line + + if (type === INT$1) return 4; // eslint-disable-line + + if (type === UNSIGNED_INT$1) return 4; // eslint-disable-line + + if (type === FLOAT$1) return 4; // eslint-disable-line + + return 0; +} // Tries to get the number of elements from a set of arrays. + + +const positionKeys = ['position', 'positions', 'a_position']; + +function getNumElementsFromNonIndexedArrays(arrays) { + let key; + let ii; + + for (ii = 0; ii < positionKeys.length; ++ii) { + key = positionKeys[ii]; + + if (key in arrays) { + break; + } + } + + if (ii === positionKeys.length) { + key = Object.keys(arrays)[0]; + } + + const array = arrays[key]; + const length = getArray(array).length; + const numComponents = getNumComponents(array, key); + const numElements = length / numComponents; + + if (length % numComponents > 0) { + throw new Error(`numComponents ${numComponents} not correct for length ${length}`); + } + + return numElements; +} + +function getNumElementsFromAttributes(gl, attribs) { + let key; + let ii; + + for (ii = 0; ii < positionKeys.length; ++ii) { + key = positionKeys[ii]; + + if (key in attribs) { + break; + } + + key = defaults.attribPrefix + key; + + if (key in attribs) { + break; + } + } + + if (ii === positionKeys.length) { + key = Object.keys(attribs)[0]; + } + + const attrib = attribs[key]; + gl.bindBuffer(ARRAY_BUFFER, attrib.buffer); + const numBytes = gl.getBufferParameter(ARRAY_BUFFER, BUFFER_SIZE); + gl.bindBuffer(ARRAY_BUFFER, null); + const bytesPerValue = getBytesPerValueForGLType(gl, attrib.type); + const totalElements = numBytes / bytesPerValue; + const numComponents = attrib.numComponents || attrib.size; // TODO: check stride + + const numElements = totalElements / numComponents; + + if (numElements % 1 !== 0) { + throw new Error(`numComponents ${numComponents} not correct for length ${length}`); + } + + return numElements; +} +/** + * @typedef {Object} BufferInfo + * @property {number} numElements The number of elements to pass to `gl.drawArrays` or `gl.drawElements`. + * @property {number} [elementType] The type of indices `UNSIGNED_BYTE`, `UNSIGNED_SHORT` etc.. + * @property {WebGLBuffer} [indices] The indices `ELEMENT_ARRAY_BUFFER` if any indices exist. + * @property {Object.} [attribs] The attribs appropriate to call `setAttributes` + * @memberOf module:twgl + */ + +/** + * Creates a BufferInfo from an object of arrays. + * + * This can be passed to {@link module:twgl.setBuffersAndAttributes} and to + * {@link module:twgl:drawBufferInfo}. + * + * Given an object like + * + * var arrays = { + * position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], }, + * texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], }, + * normal: { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], }, + * indices: { numComponents: 3, data: [0, 1, 2, 1, 2, 3], }, + * }; + * + * Creates an BufferInfo like this + * + * bufferInfo = { + * numElements: 4, // or whatever the number of elements is + * indices: WebGLBuffer, // this property will not exist if there are no indices + * attribs: { + * position: { buffer: WebGLBuffer, numComponents: 3, }, + * normal: { buffer: WebGLBuffer, numComponents: 3, }, + * texcoord: { buffer: WebGLBuffer, numComponents: 2, }, + * }, + * }; + * + * The properties of arrays can be JavaScript arrays in which case the number of components + * will be guessed. + * + * var arrays = { + * position: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], + * texcoord: [0, 0, 0, 1, 1, 0, 1, 1], + * normal: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], + * indices: [0, 1, 2, 1, 2, 3], + * }; + * + * They can also be TypedArrays + * + * var arrays = { + * position: new Float32Array([0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0]), + * texcoord: new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]), + * normal: new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]), + * indices: new Uint16Array([0, 1, 2, 1, 2, 3]), + * }; + * + * Or AugmentedTypedArrays + * + * var positions = createAugmentedTypedArray(3, 4); + * var texcoords = createAugmentedTypedArray(2, 4); + * var normals = createAugmentedTypedArray(3, 4); + * var indices = createAugmentedTypedArray(3, 2, Uint16Array); + * + * positions.push([0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0]); + * texcoords.push([0, 0, 0, 1, 1, 0, 1, 1]); + * normals.push([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); + * indices.push([0, 1, 2, 1, 2, 3]); + * + * var arrays = { + * position: positions, + * texcoord: texcoords, + * normal: normals, + * indices: indices, + * }; + * + * For the last example it is equivalent to + * + * var bufferInfo = { + * attribs: { + * position: { numComponents: 3, buffer: gl.createBuffer(), }, + * texcoord: { numComponents: 2, buffer: gl.createBuffer(), }, + * normal: { numComponents: 3, buffer: gl.createBuffer(), }, + * }, + * indices: gl.createBuffer(), + * numElements: 6, + * }; + * + * gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.position.buffer); + * gl.bufferData(gl.ARRAY_BUFFER, arrays.position, gl.STATIC_DRAW); + * gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.texcoord.buffer); + * gl.bufferData(gl.ARRAY_BUFFER, arrays.texcoord, gl.STATIC_DRAW); + * gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.attribs.normal.buffer); + * gl.bufferData(gl.ARRAY_BUFFER, arrays.normal, gl.STATIC_DRAW); + * gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferInfo.indices); + * gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, arrays.indices, gl.STATIC_DRAW); + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {module:twgl.Arrays} arrays Your data + * @param {module:twgl.BufferInfo} [srcBufferInfo] An existing + * buffer info to start from. WebGLBuffers etc specified + * in the srcBufferInfo will be used in a new BufferInfo + * with any arrays specified overriding the ones in + * srcBufferInfo. + * @return {module:twgl.BufferInfo} A BufferInfo + * @memberOf module:twgl/attributes + */ + + +function createBufferInfoFromArrays(gl, arrays, srcBufferInfo) { + const newAttribs = createAttribsFromArrays(gl, arrays); + const bufferInfo = Object.assign({}, srcBufferInfo ? srcBufferInfo : {}); + bufferInfo.attribs = Object.assign({}, srcBufferInfo ? srcBufferInfo.attribs : {}, newAttribs); + const indices = arrays.indices; + + if (indices) { + const newIndices = makeTypedArray(indices, "indices"); + bufferInfo.indices = createBufferFromTypedArray(gl, newIndices, ELEMENT_ARRAY_BUFFER); + bufferInfo.numElements = newIndices.length; + bufferInfo.elementType = getGLTypeForTypedArray(newIndices); + } else if (!bufferInfo.numElements) { + bufferInfo.numElements = getNumElementsFromAttributes(gl, bufferInfo.attribs); + } + + return bufferInfo; +} +/** + * Creates a buffer from an array, typed array, or array spec + * + * Given something like this + * + * [1, 2, 3], + * + * or + * + * new Uint16Array([1,2,3]); + * + * or + * + * { + * data: [1, 2, 3], + * type: Uint8Array, + * } + * + * returns a WebGLBuffer that contains the given data. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext. + * @param {module:twgl.ArraySpec} array an array, typed array, or array spec. + * @param {string} arrayName name of array. Used to guess the type if type can not be derived otherwise. + * @return {WebGLBuffer} a WebGLBuffer containing the data in array. + * @memberOf module:twgl/attributes + */ + + +function createBufferFromArray(gl, array, arrayName) { + const type = arrayName === "indices" ? ELEMENT_ARRAY_BUFFER : ARRAY_BUFFER; + const typedArray = makeTypedArray(array, arrayName); + return createBufferFromTypedArray(gl, typedArray, type); +} +/** + * Creates buffers from arrays or typed arrays + * + * Given something like this + * + * var arrays = { + * positions: [1, 2, 3], + * normals: [0, 0, 1], + * } + * + * returns something like + * + * buffers = { + * positions: WebGLBuffer, + * normals: WebGLBuffer, + * } + * + * If the buffer is named 'indices' it will be made an ELEMENT_ARRAY_BUFFER. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext. + * @param {module:twgl.Arrays} arrays + * @return {Object} returns an object with one WebGLBuffer per array + * @memberOf module:twgl/attributes + */ + + +function createBuffersFromArrays(gl, arrays) { + const buffers = {}; + Object.keys(arrays).forEach(function (key) { + buffers[key] = createBufferFromArray(gl, arrays[key], key); + }); // Ugh! + + if (arrays.indices) { + buffers.numElements = arrays.indices.length; + buffers.elementType = getGLTypeForTypedArray(makeTypedArray(arrays.indices)); + } else { + buffers.numElements = getNumElementsFromNonIndexedArrays(arrays); + } + + return buffers; +} + +var attributes = /*#__PURE__*/Object.freeze({ + __proto__: null, + createAttribsFromArrays: createAttribsFromArrays, + createBuffersFromArrays: createBuffersFromArrays, + createBufferFromArray: createBufferFromArray, + createBufferFromTypedArray: createBufferFromTypedArray, + createBufferInfoFromArrays: createBufferInfoFromArrays, + setAttribInfoBufferFromArray: setAttribInfoBufferFromArray, + setAttributePrefix: setAttributePrefix, + setAttributeDefaults_: setDefaults, + getNumComponents_: getNumComponents, + getArray_: getArray +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +exports.attributes = attributes; +const getArray$1 = getArray; // eslint-disable-line + +const getNumComponents$1 = getNumComponents; // eslint-disable-line + +/** + * @typedef {(Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array)} TypedArray + */ + +/** + * Add `push` to a typed array. It just keeps a 'cursor' + * and allows use to `push` values into the array so we + * don't have to manually compute offsets + * @param {TypedArray} typedArray TypedArray to augment + * @param {number} numComponents number of components. + * @private + */ + +function augmentTypedArray(typedArray, numComponents) { + let cursor = 0; + + typedArray.push = function () { + for (let ii = 0; ii < arguments.length; ++ii) { + const value = arguments[ii]; + + if (value instanceof Array || isArrayBuffer(value)) { + for (let jj = 0; jj < value.length; ++jj) { + typedArray[cursor++] = value[jj]; + } + } else { + typedArray[cursor++] = value; + } + } + }; + + typedArray.reset = function (opt_index) { + cursor = opt_index || 0; + }; + + typedArray.numComponents = numComponents; + Object.defineProperty(typedArray, 'numElements', { + get: function () { + return this.length / this.numComponents | 0; + } + }); + return typedArray; +} +/** + * creates a typed array with a `push` function attached + * so that you can easily *push* values. + * + * `push` can take multiple arguments. If an argument is an array each element + * of the array will be added to the typed array. + * + * Example: + * + * const array = createAugmentedTypedArray(3, 2); // creates a Float32Array with 6 values + * array.push(1, 2, 3); + * array.push([4, 5, 6]); + * // array now contains [1, 2, 3, 4, 5, 6] + * + * Also has `numComponents` and `numElements` properties. + * + * @param {number} numComponents number of components + * @param {number} numElements number of elements. The total size of the array will be `numComponents * numElements`. + * @param {constructor} opt_type A constructor for the type. Default = `Float32Array`. + * @return {ArrayBufferView} A typed array. + * @memberOf module:twgl/primitives + */ + + +function createAugmentedTypedArray(numComponents, numElements, opt_type) { + const Type = opt_type || Float32Array; + return augmentTypedArray(new Type(numComponents * numElements), numComponents); +} + +function allButIndices(name) { + return name !== "indices"; +} +/** + * Given indexed vertices creates a new set of vertices un-indexed by expanding the indexed vertices. + * @param {Object.} vertices The indexed vertices to deindex + * @return {Object.} The deindexed vertices + * @memberOf module:twgl/primitives + */ + + +function deindexVertices(vertices) { + const indices = vertices.indices; + const newVertices = {}; + const numElements = indices.length; + + function expandToUnindexed(channel) { + const srcBuffer = vertices[channel]; + const numComponents = srcBuffer.numComponents; + const dstBuffer = createAugmentedTypedArray(numComponents, numElements, srcBuffer.constructor); + + for (let ii = 0; ii < numElements; ++ii) { + const ndx = indices[ii]; + const offset = ndx * numComponents; + + for (let jj = 0; jj < numComponents; ++jj) { + dstBuffer.push(srcBuffer[offset + jj]); + } + } + + newVertices[channel] = dstBuffer; + } + + Object.keys(vertices).filter(allButIndices).forEach(expandToUnindexed); + return newVertices; +} +/** + * flattens the normals of deindexed vertices in place. + * @param {Object.} vertices The deindexed vertices who's normals to flatten + * @return {Object.} The flattened vertices (same as was passed in) + * @memberOf module:twgl/primitives + */ + + +function flattenNormals(vertices) { + if (vertices.indices) { + throw new Error('can not flatten normals of indexed vertices. deindex them first'); + } + + const normals = vertices.normal; + const numNormals = normals.length; + + for (let ii = 0; ii < numNormals; ii += 9) { + // pull out the 3 normals for this triangle + const nax = normals[ii + 0]; + const nay = normals[ii + 1]; + const naz = normals[ii + 2]; + const nbx = normals[ii + 3]; + const nby = normals[ii + 4]; + const nbz = normals[ii + 5]; + const ncx = normals[ii + 6]; + const ncy = normals[ii + 7]; + const ncz = normals[ii + 8]; // add them + + let nx = nax + nbx + ncx; + let ny = nay + nby + ncy; + let nz = naz + nbz + ncz; // normalize them + + const length = Math.sqrt(nx * nx + ny * ny + nz * nz); + nx /= length; + ny /= length; + nz /= length; // copy them back in + + normals[ii + 0] = nx; + normals[ii + 1] = ny; + normals[ii + 2] = nz; + normals[ii + 3] = nx; + normals[ii + 4] = ny; + normals[ii + 5] = nz; + normals[ii + 6] = nx; + normals[ii + 7] = ny; + normals[ii + 8] = nz; + } + + return vertices; +} + +function applyFuncToV3Array(array, matrix, fn) { + const len = array.length; + const tmp = new Float32Array(3); + + for (let ii = 0; ii < len; ii += 3) { + fn(matrix, [array[ii], array[ii + 1], array[ii + 2]], tmp); + array[ii] = tmp[0]; + array[ii + 1] = tmp[1]; + array[ii + 2] = tmp[2]; + } +} + +function transformNormal$1(mi, v, dst) { + dst = dst || create(); + const v0 = v[0]; + const v1 = v[1]; + const v2 = v[2]; + dst[0] = v0 * mi[0 * 4 + 0] + v1 * mi[0 * 4 + 1] + v2 * mi[0 * 4 + 2]; + dst[1] = v0 * mi[1 * 4 + 0] + v1 * mi[1 * 4 + 1] + v2 * mi[1 * 4 + 2]; + dst[2] = v0 * mi[2 * 4 + 0] + v1 * mi[2 * 4 + 1] + v2 * mi[2 * 4 + 2]; + return dst; +} +/** + * Reorients directions by the given matrix.. + * @param {(number[]|TypedArray)} array The array. Assumes value floats per element. + * @param {module:twgl/m4.Mat4} matrix A matrix to multiply by. + * @return {(number[]|TypedArray)} the same array that was passed in + * @memberOf module:twgl/primitives + */ + + +function reorientDirections(array, matrix) { + applyFuncToV3Array(array, matrix, transformDirection); + return array; +} +/** + * Reorients normals by the inverse-transpose of the given + * matrix.. + * @param {(number[]|TypedArray)} array The array. Assumes value floats per element. + * @param {module:twgl/m4.Mat4} matrix A matrix to multiply by. + * @return {(number[]|TypedArray)} the same array that was passed in + * @memberOf module:twgl/primitives + */ + + +function reorientNormals(array, matrix) { + applyFuncToV3Array(array, inverse(matrix), transformNormal$1); + return array; +} +/** + * Reorients positions by the given matrix. In other words, it + * multiplies each vertex by the given matrix. + * @param {(number[]|TypedArray)} array The array. Assumes value floats per element. + * @param {module:twgl/m4.Mat4} matrix A matrix to multiply by. + * @return {(number[]|TypedArray)} the same array that was passed in + * @memberOf module:twgl/primitives + */ + + +function reorientPositions(array, matrix) { + applyFuncToV3Array(array, matrix, transformPoint); + return array; +} +/** + * @typedef {(number[]|TypedArray)} NativeArrayOrTypedArray + */ + +/** + * Reorients arrays by the given matrix. Assumes arrays have + * names that contains 'pos' could be reoriented as positions, + * 'binorm' or 'tan' as directions, and 'norm' as normals. + * + * @param {Object.} arrays The vertices to reorient + * @param {module:twgl/m4.Mat4} matrix matrix to reorient by. + * @return {Object.} same arrays that were passed in. + * @memberOf module:twgl/primitives + */ + + +function reorientVertices(arrays, matrix) { + Object.keys(arrays).forEach(function (name) { + const array = arrays[name]; + + if (name.indexOf("pos") >= 0) { + reorientPositions(array, matrix); + } else if (name.indexOf("tan") >= 0 || name.indexOf("binorm") >= 0) { + reorientDirections(array, matrix); + } else if (name.indexOf("norm") >= 0) { + reorientNormals(array, matrix); + } + }); + return arrays; +} +/** + * Creates XY quad BufferInfo + * + * The default with no parameters will return a 2x2 quad with values from -1 to +1. + * If you want a unit quad with that goes from 0 to 1 you'd call it with + * + * twgl.primitives.createXYQuadBufferInfo(gl, 1, 0.5, 0.5); + * + * If you want a unit quad centered above 0,0 you'd call it with + * + * twgl.primitives.createXYQuadBufferInfo(gl, 1, 0, 0.5); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [size] the size across the quad. Defaults to 2 which means vertices will go from -1 to +1 + * @param {number} [xOffset] the amount to offset the quad in X + * @param {number} [yOffset] the amount to offset the quad in Y + * @return {Object.} the created XY Quad BufferInfo + * @memberOf module:twgl/primitives + * @function createXYQuadBuffers + */ + +/** + * Creates XY quad Buffers + * + * The default with no parameters will return a 2x2 quad with values from -1 to +1. + * If you want a unit quad with that goes from 0 to 1 you'd call it with + * + * twgl.primitives.createXYQuadBufferInfo(gl, 1, 0.5, 0.5); + * + * If you want a unit quad centered above 0,0 you'd call it with + * + * twgl.primitives.createXYQuadBufferInfo(gl, 1, 0, 0.5); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [size] the size across the quad. Defaults to 2 which means vertices will go from -1 to +1 + * @param {number} [xOffset] the amount to offset the quad in X + * @param {number} [yOffset] the amount to offset the quad in Y + * @return {module:twgl.BufferInfo} the created XY Quad buffers + * @memberOf module:twgl/primitives + * @function createXYQuadBufferInfo + */ + +/** + * Creates XY quad vertices + * + * The default with no parameters will return a 2x2 quad with values from -1 to +1. + * If you want a unit quad with that goes from 0 to 1 you'd call it with + * + * twgl.primitives.createXYQuadVertices(1, 0.5, 0.5); + * + * If you want a unit quad centered above 0,0 you'd call it with + * + * twgl.primitives.createXYQuadVertices(1, 0, 0.5); + * + * @param {number} [size] the size across the quad. Defaults to 2 which means vertices will go from -1 to +1 + * @param {number} [xOffset] the amount to offset the quad in X + * @param {number} [yOffset] the amount to offset the quad in Y + * @return {Object.} the created XY Quad vertices + * @memberOf module:twgl/primitives + */ + + +function createXYQuadVertices(size, xOffset, yOffset) { + size = size || 2; + xOffset = xOffset || 0; + yOffset = yOffset || 0; + size *= 0.5; + return { + position: { + numComponents: 2, + data: [xOffset + -1 * size, yOffset + -1 * size, xOffset + 1 * size, yOffset + -1 * size, xOffset + -1 * size, yOffset + 1 * size, xOffset + 1 * size, yOffset + 1 * size] + }, + normal: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1], + texcoord: [0, 0, 1, 0, 0, 1, 1, 1], + indices: [0, 1, 2, 2, 1, 3] + }; +} +/** + * Creates XZ plane BufferInfo. + * + * The created plane has position, normal, and texcoord data + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [width] Width of the plane. Default = 1 + * @param {number} [depth] Depth of the plane. Default = 1 + * @param {number} [subdivisionsWidth] Number of steps across the plane. Default = 1 + * @param {number} [subdivisionsDepth] Number of steps down the plane. Default = 1 + * @param {module:twgl/m4.Mat4} [matrix] A matrix by which to multiply all the vertices. + * @return {module:twgl.BufferInfo} The created plane BufferInfo. + * @memberOf module:twgl/primitives + * @function createPlaneBufferInfo + */ + +/** + * Creates XZ plane buffers. + * + * The created plane has position, normal, and texcoord data + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [width] Width of the plane. Default = 1 + * @param {number} [depth] Depth of the plane. Default = 1 + * @param {number} [subdivisionsWidth] Number of steps across the plane. Default = 1 + * @param {number} [subdivisionsDepth] Number of steps down the plane. Default = 1 + * @param {module:twgl/m4.Mat4} [matrix] A matrix by which to multiply all the vertices. + * @return {Object.} The created plane buffers. + * @memberOf module:twgl/primitives + * @function createPlaneBuffers + */ + +/** + * Creates XZ plane vertices. + * + * The created plane has position, normal, and texcoord data + * + * @param {number} [width] Width of the plane. Default = 1 + * @param {number} [depth] Depth of the plane. Default = 1 + * @param {number} [subdivisionsWidth] Number of steps across the plane. Default = 1 + * @param {number} [subdivisionsDepth] Number of steps down the plane. Default = 1 + * @param {module:twgl/m4.Mat4} [matrix] A matrix by which to multiply all the vertices. + * @return {Object.} The created plane vertices. + * @memberOf module:twgl/primitives + */ + + +function createPlaneVertices(width, depth, subdivisionsWidth, subdivisionsDepth, matrix) { + width = width || 1; + depth = depth || 1; + subdivisionsWidth = subdivisionsWidth || 1; + subdivisionsDepth = subdivisionsDepth || 1; + matrix = matrix || identity(); + const numVertices = (subdivisionsWidth + 1) * (subdivisionsDepth + 1); + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + + for (let z = 0; z <= subdivisionsDepth; z++) { + for (let x = 0; x <= subdivisionsWidth; x++) { + const u = x / subdivisionsWidth; + const v = z / subdivisionsDepth; + positions.push(width * u - width * 0.5, 0, depth * v - depth * 0.5); + normals.push(0, 1, 0); + texcoords.push(u, v); + } + } + + const numVertsAcross = subdivisionsWidth + 1; + const indices = createAugmentedTypedArray(3, subdivisionsWidth * subdivisionsDepth * 2, Uint16Array); + + for (let z = 0; z < subdivisionsDepth; z++) { + // eslint-disable-line + for (let x = 0; x < subdivisionsWidth; x++) { + // eslint-disable-line + // Make triangle 1 of quad. + indices.push((z + 0) * numVertsAcross + x, (z + 1) * numVertsAcross + x, (z + 0) * numVertsAcross + x + 1); // Make triangle 2 of quad. + + indices.push((z + 1) * numVertsAcross + x, (z + 1) * numVertsAcross + x + 1, (z + 0) * numVertsAcross + x + 1); + } + } + + const arrays = reorientVertices({ + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }, matrix); + return arrays; +} +/** + * Creates sphere BufferInfo. + * + * The created sphere has position, normal, and texcoord data + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius radius of the sphere. + * @param {number} subdivisionsAxis number of steps around the sphere. + * @param {number} subdivisionsHeight number of vertically on the sphere. + * @param {number} [opt_startLatitudeInRadians] where to start the + * top of the sphere. Default = 0. + * @param {number} [opt_endLatitudeInRadians] Where to end the + * bottom of the sphere. Default = Math.PI. + * @param {number} [opt_startLongitudeInRadians] where to start + * wrapping the sphere. Default = 0. + * @param {number} [opt_endLongitudeInRadians] where to end + * wrapping the sphere. Default = 2 * Math.PI. + * @return {module:twgl.BufferInfo} The created sphere BufferInfo. + * @memberOf module:twgl/primitives + * @function createSphereBufferInfo + */ + +/** + * Creates sphere buffers. + * + * The created sphere has position, normal, and texcoord data + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius radius of the sphere. + * @param {number} subdivisionsAxis number of steps around the sphere. + * @param {number} subdivisionsHeight number of vertically on the sphere. + * @param {number} [opt_startLatitudeInRadians] where to start the + * top of the sphere. Default = 0. + * @param {number} [opt_endLatitudeInRadians] Where to end the + * bottom of the sphere. Default = Math.PI. + * @param {number} [opt_startLongitudeInRadians] where to start + * wrapping the sphere. Default = 0. + * @param {number} [opt_endLongitudeInRadians] where to end + * wrapping the sphere. Default = 2 * Math.PI. + * @return {Object.} The created sphere buffers. + * @memberOf module:twgl/primitives + * @function createSphereBuffers + */ + +/** + * Creates sphere vertices. + * + * The created sphere has position, normal, and texcoord data + * + * @param {number} radius radius of the sphere. + * @param {number} subdivisionsAxis number of steps around the sphere. + * @param {number} subdivisionsHeight number of vertically on the sphere. + * @param {number} [opt_startLatitudeInRadians] where to start the + * top of the sphere. Default = 0. + * @param {number} [opt_endLatitudeInRadians] Where to end the + * bottom of the sphere. Default = Math.PI. + * @param {number} [opt_startLongitudeInRadians] where to start + * wrapping the sphere. Default = 0. + * @param {number} [opt_endLongitudeInRadians] where to end + * wrapping the sphere. Default = 2 * Math.PI. + * @return {Object.} The created sphere vertices. + * @memberOf module:twgl/primitives + */ + + +function createSphereVertices(radius, subdivisionsAxis, subdivisionsHeight, opt_startLatitudeInRadians, opt_endLatitudeInRadians, opt_startLongitudeInRadians, opt_endLongitudeInRadians) { + if (subdivisionsAxis <= 0 || subdivisionsHeight <= 0) { + throw new Error('subdivisionAxis and subdivisionHeight must be > 0'); + } + + opt_startLatitudeInRadians = opt_startLatitudeInRadians || 0; + opt_endLatitudeInRadians = opt_endLatitudeInRadians || Math.PI; + opt_startLongitudeInRadians = opt_startLongitudeInRadians || 0; + opt_endLongitudeInRadians = opt_endLongitudeInRadians || Math.PI * 2; + const latRange = opt_endLatitudeInRadians - opt_startLatitudeInRadians; + const longRange = opt_endLongitudeInRadians - opt_startLongitudeInRadians; // We are going to generate our sphere by iterating through its + // spherical coordinates and generating 2 triangles for each quad on a + // ring of the sphere. + + const numVertices = (subdivisionsAxis + 1) * (subdivisionsHeight + 1); + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); // Generate the individual vertices in our vertex buffer. + + for (let y = 0; y <= subdivisionsHeight; y++) { + for (let x = 0; x <= subdivisionsAxis; x++) { + // Generate a vertex based on its spherical coordinates + const u = x / subdivisionsAxis; + const v = y / subdivisionsHeight; + const theta = longRange * u + opt_startLongitudeInRadians; + const phi = latRange * v + opt_startLatitudeInRadians; + const sinTheta = Math.sin(theta); + const cosTheta = Math.cos(theta); + const sinPhi = Math.sin(phi); + const cosPhi = Math.cos(phi); + const ux = cosTheta * sinPhi; + const uy = cosPhi; + const uz = sinTheta * sinPhi; + positions.push(radius * ux, radius * uy, radius * uz); + normals.push(ux, uy, uz); + texcoords.push(1 - u, v); + } + } + + const numVertsAround = subdivisionsAxis + 1; + const indices = createAugmentedTypedArray(3, subdivisionsAxis * subdivisionsHeight * 2, Uint16Array); + + for (let x = 0; x < subdivisionsAxis; x++) { + // eslint-disable-line + for (let y = 0; y < subdivisionsHeight; y++) { + // eslint-disable-line + // Make triangle 1 of quad. + indices.push((y + 0) * numVertsAround + x, (y + 0) * numVertsAround + x + 1, (y + 1) * numVertsAround + x); // Make triangle 2 of quad. + + indices.push((y + 1) * numVertsAround + x, (y + 0) * numVertsAround + x + 1, (y + 1) * numVertsAround + x + 1); + } + } + + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * Array of the indices of corners of each face of a cube. + * @type {Array.} + * @private + */ + + +const CUBE_FACE_INDICES = [[3, 7, 5, 1], // right +[6, 2, 0, 4], // left +[6, 7, 3, 2], // ?? +[0, 1, 5, 4], // ?? +[7, 6, 4, 5], // front +[2, 3, 1, 0] // back +]; +/** + * Creates a BufferInfo for a cube. + * + * The cube is created around the origin. (-size / 2, size / 2). + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [size] width, height and depth of the cube. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createCubeBufferInfo + */ + +/** + * Creates the buffers and indices for a cube. + * + * The cube is created around the origin. (-size / 2, size / 2). + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} [size] width, height and depth of the cube. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createCubeBuffers + */ + +/** + * Creates the vertices and indices for a cube. + * + * The cube is created around the origin. (-size / 2, size / 2). + * + * @param {number} [size] width, height and depth of the cube. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + +function createCubeVertices(size) { + size = size || 1; + const k = size / 2; + const cornerVertices = [[-k, -k, -k], [+k, -k, -k], [-k, +k, -k], [+k, +k, -k], [-k, -k, +k], [+k, -k, +k], [-k, +k, +k], [+k, +k, +k]]; + const faceNormals = [[+1, +0, +0], [-1, +0, +0], [+0, +1, +0], [+0, -1, +0], [+0, +0, +1], [+0, +0, -1]]; + const uvCoords = [[1, 0], [0, 0], [0, 1], [1, 1]]; + const numVertices = 6 * 4; + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + const indices = createAugmentedTypedArray(3, 6 * 2, Uint16Array); + + for (let f = 0; f < 6; ++f) { + const faceIndices = CUBE_FACE_INDICES[f]; + + for (let v = 0; v < 4; ++v) { + const position = cornerVertices[faceIndices[v]]; + const normal = faceNormals[f]; + const uv = uvCoords[v]; // Each face needs all four vertices because the normals and texture + // coordinates are not all the same. + + positions.push(position); + normals.push(normal); + texcoords.push(uv); + } // Two triangles make a square face. + + + const offset = 4 * f; + indices.push(offset + 0, offset + 1, offset + 2); + indices.push(offset + 0, offset + 2, offset + 3); + } + + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * Creates a BufferInfo for a truncated cone, which is like a cylinder + * except that it has different top and bottom radii. A truncated cone + * can also be used to create cylinders and regular cones. The + * truncated cone will be created centered about the origin, with the + * y axis as its vertical axis. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} bottomRadius Bottom radius of truncated cone. + * @param {number} topRadius Top radius of truncated cone. + * @param {number} height Height of truncated cone. + * @param {number} radialSubdivisions The number of subdivisions around the + * truncated cone. + * @param {number} verticalSubdivisions The number of subdivisions down the + * truncated cone. + * @param {boolean} [opt_topCap] Create top cap. Default = true. + * @param {boolean} [opt_bottomCap] Create bottom cap. Default = true. + * @return {module:twgl.BufferInfo} The created cone BufferInfo. + * @memberOf module:twgl/primitives + * @function createTruncatedConeBufferInfo + */ + +/** + * Creates buffers for a truncated cone, which is like a cylinder + * except that it has different top and bottom radii. A truncated cone + * can also be used to create cylinders and regular cones. The + * truncated cone will be created centered about the origin, with the + * y axis as its vertical axis. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} bottomRadius Bottom radius of truncated cone. + * @param {number} topRadius Top radius of truncated cone. + * @param {number} height Height of truncated cone. + * @param {number} radialSubdivisions The number of subdivisions around the + * truncated cone. + * @param {number} verticalSubdivisions The number of subdivisions down the + * truncated cone. + * @param {boolean} [opt_topCap] Create top cap. Default = true. + * @param {boolean} [opt_bottomCap] Create bottom cap. Default = true. + * @return {Object.} The created cone buffers. + * @memberOf module:twgl/primitives + * @function createTruncatedConeBuffers + */ + +/** + * Creates vertices for a truncated cone, which is like a cylinder + * except that it has different top and bottom radii. A truncated cone + * can also be used to create cylinders and regular cones. The + * truncated cone will be created centered about the origin, with the + * y axis as its vertical axis. . + * + * @param {number} bottomRadius Bottom radius of truncated cone. + * @param {number} topRadius Top radius of truncated cone. + * @param {number} height Height of truncated cone. + * @param {number} radialSubdivisions The number of subdivisions around the + * truncated cone. + * @param {number} verticalSubdivisions The number of subdivisions down the + * truncated cone. + * @param {boolean} [opt_topCap] Create top cap. Default = true. + * @param {boolean} [opt_bottomCap] Create bottom cap. Default = true. + * @return {Object.} The created cone vertices. + * @memberOf module:twgl/primitives + */ + + +function createTruncatedConeVertices(bottomRadius, topRadius, height, radialSubdivisions, verticalSubdivisions, opt_topCap, opt_bottomCap) { + if (radialSubdivisions < 3) { + throw new Error('radialSubdivisions must be 3 or greater'); + } + + if (verticalSubdivisions < 1) { + throw new Error('verticalSubdivisions must be 1 or greater'); + } + + const topCap = opt_topCap === undefined ? true : opt_topCap; + const bottomCap = opt_bottomCap === undefined ? true : opt_bottomCap; + const extra = (topCap ? 2 : 0) + (bottomCap ? 2 : 0); + const numVertices = (radialSubdivisions + 1) * (verticalSubdivisions + 1 + extra); + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + const indices = createAugmentedTypedArray(3, radialSubdivisions * (verticalSubdivisions + extra / 2) * 2, Uint16Array); + const vertsAroundEdge = radialSubdivisions + 1; // The slant of the cone is constant across its surface + + const slant = Math.atan2(bottomRadius - topRadius, height); + const cosSlant = Math.cos(slant); + const sinSlant = Math.sin(slant); + const start = topCap ? -2 : 0; + const end = verticalSubdivisions + (bottomCap ? 2 : 0); + + for (let yy = start; yy <= end; ++yy) { + let v = yy / verticalSubdivisions; + let y = height * v; + let ringRadius; + + if (yy < 0) { + y = 0; + v = 1; + ringRadius = bottomRadius; + } else if (yy > verticalSubdivisions) { + y = height; + v = 1; + ringRadius = topRadius; + } else { + ringRadius = bottomRadius + (topRadius - bottomRadius) * (yy / verticalSubdivisions); + } + + if (yy === -2 || yy === verticalSubdivisions + 2) { + ringRadius = 0; + v = 0; + } + + y -= height / 2; + + for (let ii = 0; ii < vertsAroundEdge; ++ii) { + const sin = Math.sin(ii * Math.PI * 2 / radialSubdivisions); + const cos = Math.cos(ii * Math.PI * 2 / radialSubdivisions); + positions.push(sin * ringRadius, y, cos * ringRadius); + + if (yy < 0) { + normals.push(0, -1, 0); + } else if (yy > verticalSubdivisions) { + normals.push(0, 1, 0); + } else if (ringRadius === 0.0) { + normals.push(0, 0, 0); + } else { + normals.push(sin * cosSlant, sinSlant, cos * cosSlant); + } + + texcoords.push(ii / radialSubdivisions, 1 - v); + } + } + + for (let yy = 0; yy < verticalSubdivisions + extra; ++yy) { + // eslint-disable-line + if (yy === 1 && topCap || yy === verticalSubdivisions + extra - 2 && bottomCap) { + continue; + } + + for (let ii = 0; ii < radialSubdivisions; ++ii) { + // eslint-disable-line + indices.push(vertsAroundEdge * (yy + 0) + 0 + ii, vertsAroundEdge * (yy + 0) + 1 + ii, vertsAroundEdge * (yy + 1) + 1 + ii); + indices.push(vertsAroundEdge * (yy + 0) + 0 + ii, vertsAroundEdge * (yy + 1) + 1 + ii, vertsAroundEdge * (yy + 1) + 0 + ii); + } + } + + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * Expands RLE data + * @param {number[]} rleData data in format of run-length, x, y, z, run-length, x, y, z + * @param {number[]} [padding] value to add each entry with. + * @return {number[]} the expanded rleData + * @private + */ + + +function expandRLEData(rleData, padding) { + padding = padding || []; + const data = []; + + for (let ii = 0; ii < rleData.length; ii += 4) { + const runLength = rleData[ii]; + const element = rleData.slice(ii + 1, ii + 4); + element.push.apply(element, padding); + + for (let jj = 0; jj < runLength; ++jj) { + data.push.apply(data, element); + } + } + + return data; +} +/** + * Creates 3D 'F' BufferInfo. + * An 'F' is useful because you can easily tell which way it is oriented. + * The created 'F' has position, normal, texcoord, and color buffers. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function create3DFBufferInfo + */ + +/** + * Creates 3D 'F' buffers. + * An 'F' is useful because you can easily tell which way it is oriented. + * The created 'F' has position, normal, texcoord, and color buffers. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function create3DFBuffers + */ + +/** + * Creates 3D 'F' vertices. + * An 'F' is useful because you can easily tell which way it is oriented. + * The created 'F' has position, normal, texcoord, and color arrays. + * + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + + +function create3DFVertices() { + const positions = [// left column front + 0, 0, 0, 0, 150, 0, 30, 0, 0, 0, 150, 0, 30, 150, 0, 30, 0, 0, // top rung front + 30, 0, 0, 30, 30, 0, 100, 0, 0, 30, 30, 0, 100, 30, 0, 100, 0, 0, // middle rung front + 30, 60, 0, 30, 90, 0, 67, 60, 0, 30, 90, 0, 67, 90, 0, 67, 60, 0, // left column back + 0, 0, 30, 30, 0, 30, 0, 150, 30, 0, 150, 30, 30, 0, 30, 30, 150, 30, // top rung back + 30, 0, 30, 100, 0, 30, 30, 30, 30, 30, 30, 30, 100, 0, 30, 100, 30, 30, // middle rung back + 30, 60, 30, 67, 60, 30, 30, 90, 30, 30, 90, 30, 67, 60, 30, 67, 90, 30, // top + 0, 0, 0, 100, 0, 0, 100, 0, 30, 0, 0, 0, 100, 0, 30, 0, 0, 30, // top rung front + 100, 0, 0, 100, 30, 0, 100, 30, 30, 100, 0, 0, 100, 30, 30, 100, 0, 30, // under top rung + 30, 30, 0, 30, 30, 30, 100, 30, 30, 30, 30, 0, 100, 30, 30, 100, 30, 0, // between top rung and middle + 30, 30, 0, 30, 60, 30, 30, 30, 30, 30, 30, 0, 30, 60, 0, 30, 60, 30, // top of middle rung + 30, 60, 0, 67, 60, 30, 30, 60, 30, 30, 60, 0, 67, 60, 0, 67, 60, 30, // front of middle rung + 67, 60, 0, 67, 90, 30, 67, 60, 30, 67, 60, 0, 67, 90, 0, 67, 90, 30, // bottom of middle rung. + 30, 90, 0, 30, 90, 30, 67, 90, 30, 30, 90, 0, 67, 90, 30, 67, 90, 0, // front of bottom + 30, 90, 0, 30, 150, 30, 30, 90, 30, 30, 90, 0, 30, 150, 0, 30, 150, 30, // bottom + 0, 150, 0, 0, 150, 30, 30, 150, 30, 0, 150, 0, 30, 150, 30, 30, 150, 0, // left side + 0, 0, 0, 0, 0, 30, 0, 150, 30, 0, 0, 0, 0, 150, 30, 0, 150, 0]; + const texcoords = [// left column front + 0.22, 0.19, 0.22, 0.79, 0.34, 0.19, 0.22, 0.79, 0.34, 0.79, 0.34, 0.19, // top rung front + 0.34, 0.19, 0.34, 0.31, 0.62, 0.19, 0.34, 0.31, 0.62, 0.31, 0.62, 0.19, // middle rung front + 0.34, 0.43, 0.34, 0.55, 0.49, 0.43, 0.34, 0.55, 0.49, 0.55, 0.49, 0.43, // left column back + 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, // top rung back + 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, // middle rung back + 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, // top + 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, // top rung front + 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, // under top rung + 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, // between top rung and middle + 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // top of middle rung + 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // front of middle rung + 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // bottom of middle rung. + 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, // front of bottom + 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // bottom + 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, // left side + 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0]; + const normals = expandRLEData([// left column front + // top rung front + // middle rung front + 18, 0, 0, 1, // left column back + // top rung back + // middle rung back + 18, 0, 0, -1, // top + 6, 0, 1, 0, // top rung front + 6, 1, 0, 0, // under top rung + 6, 0, -1, 0, // between top rung and middle + 6, 1, 0, 0, // top of middle rung + 6, 0, 1, 0, // front of middle rung + 6, 1, 0, 0, // bottom of middle rung. + 6, 0, -1, 0, // front of bottom + 6, 1, 0, 0, // bottom + 6, 0, -1, 0, // left side + 6, -1, 0, 0]); + const colors = expandRLEData([// left column front + // top rung front + // middle rung front + 18, 200, 70, 120, // left column back + // top rung back + // middle rung back + 18, 80, 70, 200, // top + 6, 70, 200, 210, // top rung front + 6, 200, 200, 70, // under top rung + 6, 210, 100, 70, // between top rung and middle + 6, 210, 160, 70, // top of middle rung + 6, 70, 180, 210, // front of middle rung + 6, 100, 70, 210, // bottom of middle rung. + 6, 76, 210, 100, // front of bottom + 6, 140, 210, 80, // bottom + 6, 90, 130, 110, // left side + 6, 160, 160, 220], [255]); + const numVerts = positions.length / 3; + const arrays = { + position: createAugmentedTypedArray(3, numVerts), + texcoord: createAugmentedTypedArray(2, numVerts), + normal: createAugmentedTypedArray(3, numVerts), + color: createAugmentedTypedArray(4, numVerts, Uint8Array), + indices: createAugmentedTypedArray(3, numVerts / 3, Uint16Array) + }; + arrays.position.push(positions); + arrays.texcoord.push(texcoords); + arrays.normal.push(normals); + arrays.color.push(colors); + + for (let ii = 0; ii < numVerts; ++ii) { + arrays.indices.push(ii); + } + + return arrays; +} +/** + * Creates crescent BufferInfo. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createCresentBufferInfo + */ + +/** + * Creates crescent buffers. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createCresentBuffers + */ + +/** + * Creates crescent vertices. + * + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + * @function createCresentBuffers + */ + +/** + * Creates crescent BufferInfo. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createCrescentBufferInfo + */ + +/** + * Creates crescent buffers. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createCrescentBuffers + */ + +/** + * Creates crescent vertices. + * + * @param {number} verticalRadius The vertical radius of the crescent. + * @param {number} outerRadius The outer radius of the crescent. + * @param {number} innerRadius The inner radius of the crescent. + * @param {number} thickness The thickness of the crescent. + * @param {number} subdivisionsDown number of steps around the crescent. + * @param {number} [startOffset] Where to start arc. Default 0. + * @param {number} [endOffset] Where to end arg. Default 1. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + + +function createCrescentVertices(verticalRadius, outerRadius, innerRadius, thickness, subdivisionsDown, startOffset, endOffset) { + if (subdivisionsDown <= 0) { + throw new Error('subdivisionDown must be > 0'); + } + + startOffset = startOffset || 0; + endOffset = endOffset || 1; + const subdivisionsThick = 2; + const offsetRange = endOffset - startOffset; + const numVertices = (subdivisionsDown + 1) * 2 * (2 + subdivisionsThick); + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + + function lerp(a, b, s) { + return a + (b - a) * s; + } + + function createArc(arcRadius, x, normalMult, normalAdd, uMult, uAdd) { + for (let z = 0; z <= subdivisionsDown; z++) { + const uBack = x / (subdivisionsThick - 1); + const v = z / subdivisionsDown; + const xBack = (uBack - 0.5) * 2; + const angle = (startOffset + v * offsetRange) * Math.PI; + const s = Math.sin(angle); + const c = Math.cos(angle); + const radius = lerp(verticalRadius, arcRadius, s); + const px = xBack * thickness; + const py = c * verticalRadius; + const pz = s * radius; + positions.push(px, py, pz); + const n = add(multiply([0, s, c], normalMult), normalAdd); + normals.push(n); + texcoords.push(uBack * uMult + uAdd, v); + } + } // Generate the individual vertices in our vertex buffer. + + + for (let x = 0; x < subdivisionsThick; x++) { + const uBack = (x / (subdivisionsThick - 1) - 0.5) * 2; + createArc(outerRadius, x, [1, 1, 1], [0, 0, 0], 1, 0); + createArc(outerRadius, x, [0, 0, 0], [uBack, 0, 0], 0, 0); + createArc(innerRadius, x, [1, 1, 1], [0, 0, 0], 1, 0); + createArc(innerRadius, x, [0, 0, 0], [uBack, 0, 0], 0, 1); + } // Do outer surface. + + + const indices = createAugmentedTypedArray(3, subdivisionsDown * 2 * (2 + subdivisionsThick), Uint16Array); + + function createSurface(leftArcOffset, rightArcOffset) { + for (let z = 0; z < subdivisionsDown; ++z) { + // Make triangle 1 of quad. + indices.push(leftArcOffset + z + 0, leftArcOffset + z + 1, rightArcOffset + z + 0); // Make triangle 2 of quad. + + indices.push(leftArcOffset + z + 1, rightArcOffset + z + 1, rightArcOffset + z + 0); + } + } + + const numVerticesDown = subdivisionsDown + 1; // front + + createSurface(numVerticesDown * 0, numVerticesDown * 4); // right + + createSurface(numVerticesDown * 5, numVerticesDown * 7); // back + + createSurface(numVerticesDown * 6, numVerticesDown * 2); // left + + createSurface(numVerticesDown * 3, numVerticesDown * 1); + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * Creates cylinder BufferInfo. The cylinder will be created around the origin + * along the y-axis. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius Radius of cylinder. + * @param {number} height Height of cylinder. + * @param {number} radialSubdivisions The number of subdivisions around the cylinder. + * @param {number} verticalSubdivisions The number of subdivisions down the cylinder. + * @param {boolean} [topCap] Create top cap. Default = true. + * @param {boolean} [bottomCap] Create bottom cap. Default = true. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createCylinderBufferInfo + */ + +/** + * Creates cylinder buffers. The cylinder will be created around the origin + * along the y-axis. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius Radius of cylinder. + * @param {number} height Height of cylinder. + * @param {number} radialSubdivisions The number of subdivisions around the cylinder. + * @param {number} verticalSubdivisions The number of subdivisions down the cylinder. + * @param {boolean} [topCap] Create top cap. Default = true. + * @param {boolean} [bottomCap] Create bottom cap. Default = true. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createCylinderBuffers + */ + +/** + * Creates cylinder vertices. The cylinder will be created around the origin + * along the y-axis. + * + * @param {number} radius Radius of cylinder. + * @param {number} height Height of cylinder. + * @param {number} radialSubdivisions The number of subdivisions around the cylinder. + * @param {number} verticalSubdivisions The number of subdivisions down the cylinder. + * @param {boolean} [topCap] Create top cap. Default = true. + * @param {boolean} [bottomCap] Create bottom cap. Default = true. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + + +function createCylinderVertices(radius, height, radialSubdivisions, verticalSubdivisions, topCap, bottomCap) { + return createTruncatedConeVertices(radius, radius, height, radialSubdivisions, verticalSubdivisions, topCap, bottomCap); +} +/** + * Creates BufferInfo for a torus + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius radius of center of torus circle. + * @param {number} thickness radius of torus ring. + * @param {number} radialSubdivisions The number of subdivisions around the torus. + * @param {number} bodySubdivisions The number of subdivisions around the body torus. + * @param {boolean} [startAngle] start angle in radians. Default = 0. + * @param {boolean} [endAngle] end angle in radians. Default = Math.PI * 2. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createTorusBufferInfo + */ + +/** + * Creates buffers for a torus + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius radius of center of torus circle. + * @param {number} thickness radius of torus ring. + * @param {number} radialSubdivisions The number of subdivisions around the torus. + * @param {number} bodySubdivisions The number of subdivisions around the body torus. + * @param {boolean} [startAngle] start angle in radians. Default = 0. + * @param {boolean} [endAngle] end angle in radians. Default = Math.PI * 2. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createTorusBuffers + */ + +/** + * Creates vertices for a torus + * + * @param {number} radius radius of center of torus circle. + * @param {number} thickness radius of torus ring. + * @param {number} radialSubdivisions The number of subdivisions around the torus. + * @param {number} bodySubdivisions The number of subdivisions around the body torus. + * @param {boolean} [startAngle] start angle in radians. Default = 0. + * @param {boolean} [endAngle] end angle in radians. Default = Math.PI * 2. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + + +function createTorusVertices(radius, thickness, radialSubdivisions, bodySubdivisions, startAngle, endAngle) { + if (radialSubdivisions < 3) { + throw new Error('radialSubdivisions must be 3 or greater'); + } + + if (bodySubdivisions < 3) { + throw new Error('verticalSubdivisions must be 3 or greater'); + } + + startAngle = startAngle || 0; + endAngle = endAngle || Math.PI * 2; + const range = endAngle - startAngle; + const radialParts = radialSubdivisions + 1; + const bodyParts = bodySubdivisions + 1; + const numVertices = radialParts * bodyParts; + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + const indices = createAugmentedTypedArray(3, radialSubdivisions * bodySubdivisions * 2, Uint16Array); + + for (let slice = 0; slice < bodyParts; ++slice) { + const v = slice / bodySubdivisions; + const sliceAngle = v * Math.PI * 2; + const sliceSin = Math.sin(sliceAngle); + const ringRadius = radius + sliceSin * thickness; + const ny = Math.cos(sliceAngle); + const y = ny * thickness; + + for (let ring = 0; ring < radialParts; ++ring) { + const u = ring / radialSubdivisions; + const ringAngle = startAngle + u * range; + const xSin = Math.sin(ringAngle); + const zCos = Math.cos(ringAngle); + const x = xSin * ringRadius; + const z = zCos * ringRadius; + const nx = xSin * sliceSin; + const nz = zCos * sliceSin; + positions.push(x, y, z); + normals.push(nx, ny, nz); + texcoords.push(u, 1 - v); + } + } + + for (let slice = 0; slice < bodySubdivisions; ++slice) { + // eslint-disable-line + for (let ring = 0; ring < radialSubdivisions; ++ring) { + // eslint-disable-line + const nextRingIndex = 1 + ring; + const nextSliceIndex = 1 + slice; + indices.push(radialParts * slice + ring, radialParts * nextSliceIndex + ring, radialParts * slice + nextRingIndex); + indices.push(radialParts * nextSliceIndex + ring, radialParts * nextSliceIndex + nextRingIndex, radialParts * slice + nextRingIndex); + } + } + + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * Creates a disc BufferInfo. The disc will be in the xz plane, centered at + * the origin. When creating, at least 3 divisions, or pie + * pieces, need to be specified, otherwise the triangles making + * up the disc will be degenerate. You can also specify the + * number of radial pieces `stacks`. A value of 1 for + * stacks will give you a simple disc of pie pieces. If you + * want to create an annulus you can set `innerRadius` to a + * value > 0. Finally, `stackPower` allows you to have the widths + * increase or decrease as you move away from the center. This + * is particularly useful when using the disc as a ground plane + * with a fixed camera such that you don't need the resolution + * of small triangles near the perimeter. For example, a value + * of 2 will produce stacks whose outside radius increases with + * the square of the stack index. A value of 1 will give uniform + * stacks. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius Radius of the ground plane. + * @param {number} divisions Number of triangles in the ground plane (at least 3). + * @param {number} [stacks] Number of radial divisions (default=1). + * @param {number} [innerRadius] Default 0. + * @param {number} [stackPower] Power to raise stack size to for decreasing width. + * @return {module:twgl.BufferInfo} The created BufferInfo. + * @memberOf module:twgl/primitives + * @function createDiscBufferInfo + */ + +/** + * Creates disc buffers. The disc will be in the xz plane, centered at + * the origin. When creating, at least 3 divisions, or pie + * pieces, need to be specified, otherwise the triangles making + * up the disc will be degenerate. You can also specify the + * number of radial pieces `stacks`. A value of 1 for + * stacks will give you a simple disc of pie pieces. If you + * want to create an annulus you can set `innerRadius` to a + * value > 0. Finally, `stackPower` allows you to have the widths + * increase or decrease as you move away from the center. This + * is particularly useful when using the disc as a ground plane + * with a fixed camera such that you don't need the resolution + * of small triangles near the perimeter. For example, a value + * of 2 will produce stacks whose outside radius increases with + * the square of the stack index. A value of 1 will give uniform + * stacks. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext. + * @param {number} radius Radius of the ground plane. + * @param {number} divisions Number of triangles in the ground plane (at least 3). + * @param {number} [stacks] Number of radial divisions (default=1). + * @param {number} [innerRadius] Default 0. + * @param {number} [stackPower] Power to raise stack size to for decreasing width. + * @return {Object.} The created buffers. + * @memberOf module:twgl/primitives + * @function createDiscBuffers + */ + +/** + * Creates disc vertices. The disc will be in the xz plane, centered at + * the origin. When creating, at least 3 divisions, or pie + * pieces, need to be specified, otherwise the triangles making + * up the disc will be degenerate. You can also specify the + * number of radial pieces `stacks`. A value of 1 for + * stacks will give you a simple disc of pie pieces. If you + * want to create an annulus you can set `innerRadius` to a + * value > 0. Finally, `stackPower` allows you to have the widths + * increase or decrease as you move away from the center. This + * is particularly useful when using the disc as a ground plane + * with a fixed camera such that you don't need the resolution + * of small triangles near the perimeter. For example, a value + * of 2 will produce stacks whose outside radius increases with + * the square of the stack index. A value of 1 will give uniform + * stacks. + * + * @param {number} radius Radius of the ground plane. + * @param {number} divisions Number of triangles in the ground plane (at least 3). + * @param {number} [stacks] Number of radial divisions (default=1). + * @param {number} [innerRadius] Default 0. + * @param {number} [stackPower] Power to raise stack size to for decreasing width. + * @return {Object.} The created vertices. + * @memberOf module:twgl/primitives + */ + + +function createDiscVertices(radius, divisions, stacks, innerRadius, stackPower) { + if (divisions < 3) { + throw new Error('divisions must be at least 3'); + } + + stacks = stacks ? stacks : 1; + stackPower = stackPower ? stackPower : 1; + innerRadius = innerRadius ? innerRadius : 0; // Note: We don't share the center vertex because that would + // mess up texture coordinates. + + const numVertices = (divisions + 1) * (stacks + 1); + const positions = createAugmentedTypedArray(3, numVertices); + const normals = createAugmentedTypedArray(3, numVertices); + const texcoords = createAugmentedTypedArray(2, numVertices); + const indices = createAugmentedTypedArray(3, stacks * divisions * 2, Uint16Array); + let firstIndex = 0; + const radiusSpan = radius - innerRadius; + const pointsPerStack = divisions + 1; // Build the disk one stack at a time. + + for (let stack = 0; stack <= stacks; ++stack) { + const stackRadius = innerRadius + radiusSpan * Math.pow(stack / stacks, stackPower); + + for (let i = 0; i <= divisions; ++i) { + const theta = 2.0 * Math.PI * i / divisions; + const x = stackRadius * Math.cos(theta); + const z = stackRadius * Math.sin(theta); + positions.push(x, 0, z); + normals.push(0, 1, 0); + texcoords.push(1 - i / divisions, stack / stacks); + + if (stack > 0 && i !== divisions) { + // a, b, c and d are the indices of the vertices of a quad. unless + // the current stack is the one closest to the center, in which case + // the vertices a and b connect to the center vertex. + const a = firstIndex + (i + 1); + const b = firstIndex + i; + const c = firstIndex + i - pointsPerStack; + const d = firstIndex + (i + 1) - pointsPerStack; // Make a quad of the vertices a, b, c, d. + + indices.push(a, b, c); + indices.push(a, c, d); + } + } + + firstIndex += divisions + 1; + } + + return { + position: positions, + normal: normals, + texcoord: texcoords, + indices: indices + }; +} +/** + * creates a random integer between 0 and range - 1 inclusive. + * @param {number} range + * @return {number} random value between 0 and range - 1 inclusive. + * @private + */ + + +function randInt(range) { + return Math.random() * range | 0; +} +/** + * Used to supply random colors + * @callback RandomColorFunc + * @param {number} ndx index of triangle/quad if unindexed or index of vertex if indexed + * @param {number} channel 0 = red, 1 = green, 2 = blue, 3 = alpha + * @return {number} a number from 0 to 255 + * @memberOf module:twgl/primitives + */ + +/** + * @typedef {Object} RandomVerticesOptions + * @property {number} [vertsPerColor] Defaults to 3 for non-indexed vertices + * @property {module:twgl/primitives.RandomColorFunc} [rand] A function to generate random numbers + * @memberOf module:twgl/primitives + */ + +/** + * Creates an augmentedTypedArray of random vertex colors. + * If the vertices are indexed (have an indices array) then will + * just make random colors. Otherwise assumes they are triangles + * and makes one random color for every 3 vertices. + * @param {Object.} vertices Vertices as returned from one of the createXXXVertices functions. + * @param {module:twgl/primitives.RandomVerticesOptions} [options] options. + * @return {Object.} same vertices as passed in with `color` added. + * @memberOf module:twgl/primitives + */ + + +function makeRandomVertexColors(vertices, options) { + options = options || {}; + const numElements = vertices.position.numElements; + const vColors = createAugmentedTypedArray(4, numElements, Uint8Array); + + const rand = options.rand || function (ndx, channel) { + return channel < 3 ? randInt(256) : 255; + }; + + vertices.color = vColors; + + if (vertices.indices) { + // just make random colors if index + for (let ii = 0; ii < numElements; ++ii) { + vColors.push(rand(ii, 0), rand(ii, 1), rand(ii, 2), rand(ii, 3)); + } + } else { + // make random colors per triangle + const numVertsPerColor = options.vertsPerColor || 3; + const numSets = numElements / numVertsPerColor; + + for (let ii = 0; ii < numSets; ++ii) { + // eslint-disable-line + const color = [rand(ii, 0), rand(ii, 1), rand(ii, 2), rand(ii, 3)]; + + for (let jj = 0; jj < numVertsPerColor; ++jj) { + vColors.push(color); + } + } + } + + return vertices; +} +/** + * creates a function that calls fn to create vertices and then + * creates a buffers for them + * @private + */ + + +function createBufferFunc(fn) { + return function (gl) { + const arrays = fn.apply(this, Array.prototype.slice.call(arguments, 1)); + return createBuffersFromArrays(gl, arrays); + }; +} +/** + * creates a function that calls fn to create vertices and then + * creates a bufferInfo object for them + * @private + */ + + +function createBufferInfoFunc(fn) { + return function (gl) { + const arrays = fn.apply(null, Array.prototype.slice.call(arguments, 1)); + return createBufferInfoFromArrays(gl, arrays); + }; +} + +const arraySpecPropertyNames = ["numComponents", "size", "type", "normalize", "stride", "offset", "attrib", "name", "attribName"]; +/** + * Copy elements from one array to another + * + * @param {Array|TypedArray} src source array + * @param {Array|TypedArray} dst dest array + * @param {number} dstNdx index in dest to copy src + * @param {number} [offset] offset to add to copied values + * @private + */ + +function copyElements(src, dst, dstNdx, offset) { + offset = offset || 0; + const length = src.length; + + for (let ii = 0; ii < length; ++ii) { + dst[dstNdx + ii] = src[ii] + offset; + } +} +/** + * Creates an array of the same time + * + * @param {(number[]|ArrayBufferView|module:twgl.FullArraySpec)} srcArray array who's type to copy + * @param {number} length size of new array + * @return {(number[]|ArrayBufferView|module:twgl.FullArraySpec)} array with same type as srcArray + * @private + */ + + +function createArrayOfSameType(srcArray, length) { + const arraySrc = getArray$1(srcArray); + const newArray = new arraySrc.constructor(length); + let newArraySpec = newArray; // If it appears to have been augmented make new one augmented + + if (arraySrc.numComponents && arraySrc.numElements) { + augmentTypedArray(newArray, arraySrc.numComponents); + } // If it was a full spec make new one a full spec + + + if (srcArray.data) { + newArraySpec = { + data: newArray + }; + copyNamedProperties(arraySpecPropertyNames, srcArray, newArraySpec); + } + + return newArraySpec; +} +/** + * Concatenates sets of vertices + * + * Assumes the vertices match in composition. For example + * if one set of vertices has positions, normals, and indices + * all sets of vertices must have positions, normals, and indices + * and of the same type. + * + * Example: + * + * const cubeVertices = twgl.primitives.createCubeVertices(2); + * const sphereVertices = twgl.primitives.createSphereVertices(1, 10, 10); + * // move the sphere 2 units up + * twgl.primitives.reorientVertices( + * sphereVertices, twgl.m4.translation([0, 2, 0])); + * // merge the sphere with the cube + * const cubeSphereVertices = twgl.primitives.concatVertices( + * [cubeVertices, sphereVertices]); + * // turn them into WebGL buffers and attrib data + * const bufferInfo = twgl.createBufferInfoFromArrays(gl, cubeSphereVertices); + * + * @param {module:twgl.Arrays[]} arrays Array of arrays of vertices + * @return {module:twgl.Arrays} The concatenated vertices. + * @memberOf module:twgl/primitives + */ + + +function concatVertices(arrayOfArrays) { + const names = {}; + let baseName; // get names of all arrays. + // and numElements for each set of vertices + + for (let ii = 0; ii < arrayOfArrays.length; ++ii) { + const arrays = arrayOfArrays[ii]; + Object.keys(arrays).forEach(function (name) { + // eslint-disable-line + if (!names[name]) { + names[name] = []; + } + + if (!baseName && name !== 'indices') { + baseName = name; + } + + const arrayInfo = arrays[name]; + const numComponents = getNumComponents$1(arrayInfo, name); + const array = getArray$1(arrayInfo); + const numElements = array.length / numComponents; + names[name].push(numElements); + }); + } // compute length of combined array + // and return one for reference + + + function getLengthOfCombinedArrays(name) { + let length = 0; + let arraySpec; + + for (let ii = 0; ii < arrayOfArrays.length; ++ii) { + const arrays = arrayOfArrays[ii]; + const arrayInfo = arrays[name]; + const array = getArray$1(arrayInfo); + length += array.length; + + if (!arraySpec || arrayInfo.data) { + arraySpec = arrayInfo; + } + } + + return { + length: length, + spec: arraySpec + }; + } + + function copyArraysToNewArray(name, base, newArray) { + let baseIndex = 0; + let offset = 0; + + for (let ii = 0; ii < arrayOfArrays.length; ++ii) { + const arrays = arrayOfArrays[ii]; + const arrayInfo = arrays[name]; + const array = getArray$1(arrayInfo); + + if (name === 'indices') { + copyElements(array, newArray, offset, baseIndex); + baseIndex += base[ii]; + } else { + copyElements(array, newArray, offset); + } + + offset += array.length; + } + } + + const base = names[baseName]; + const newArrays = {}; + Object.keys(names).forEach(function (name) { + const info = getLengthOfCombinedArrays(name); + const newArraySpec = createArrayOfSameType(info.spec, info.length); + copyArraysToNewArray(name, base, getArray$1(newArraySpec)); + newArrays[name] = newArraySpec; + }); + return newArrays; +} +/** + * Creates a duplicate set of vertices + * + * This is useful for calling reorientVertices when you + * also want to keep the original available + * + * @param {module:twgl.Arrays} arrays of vertices + * @return {module:twgl.Arrays} The duplicated vertices. + * @memberOf module:twgl/primitives + */ + + +function duplicateVertices(arrays) { + const newArrays = {}; + Object.keys(arrays).forEach(function (name) { + const arraySpec = arrays[name]; + const srcArray = getArray$1(arraySpec); + const newArraySpec = createArrayOfSameType(arraySpec, srcArray.length); + copyElements(srcArray, getArray$1(newArraySpec), 0); + newArrays[name] = newArraySpec; + }); + return newArrays; +} + +const create3DFBufferInfo = createBufferInfoFunc(create3DFVertices); +const create3DFBuffers = createBufferFunc(create3DFVertices); +const createCubeBufferInfo = createBufferInfoFunc(createCubeVertices); +const createCubeBuffers = createBufferFunc(createCubeVertices); +const createPlaneBufferInfo = createBufferInfoFunc(createPlaneVertices); +const createPlaneBuffers = createBufferFunc(createPlaneVertices); +const createSphereBufferInfo = createBufferInfoFunc(createSphereVertices); +const createSphereBuffers = createBufferFunc(createSphereVertices); +const createTruncatedConeBufferInfo = createBufferInfoFunc(createTruncatedConeVertices); +const createTruncatedConeBuffers = createBufferFunc(createTruncatedConeVertices); +const createXYQuadBufferInfo = createBufferInfoFunc(createXYQuadVertices); +const createXYQuadBuffers = createBufferFunc(createXYQuadVertices); +const createCrescentBufferInfo = createBufferInfoFunc(createCrescentVertices); +const createCrescentBuffers = createBufferFunc(createCrescentVertices); +const createCylinderBufferInfo = createBufferInfoFunc(createCylinderVertices); +const createCylinderBuffers = createBufferFunc(createCylinderVertices); +const createTorusBufferInfo = createBufferInfoFunc(createTorusVertices); +const createTorusBuffers = createBufferFunc(createTorusVertices); +const createDiscBufferInfo = createBufferInfoFunc(createDiscVertices); +const createDiscBuffers = createBufferFunc(createDiscVertices); // these were mis-spelled until 4.12 + +const createCresentBufferInfo = createCrescentBufferInfo; +const createCresentBuffers = createCrescentBuffers; +const createCresentVertices = createCrescentVertices; +var primitives = /*#__PURE__*/Object.freeze({ + __proto__: null, + create3DFBufferInfo: create3DFBufferInfo, + create3DFBuffers: create3DFBuffers, + create3DFVertices: create3DFVertices, + createAugmentedTypedArray: createAugmentedTypedArray, + createCubeBufferInfo: createCubeBufferInfo, + createCubeBuffers: createCubeBuffers, + createCubeVertices: createCubeVertices, + createPlaneBufferInfo: createPlaneBufferInfo, + createPlaneBuffers: createPlaneBuffers, + createPlaneVertices: createPlaneVertices, + createSphereBufferInfo: createSphereBufferInfo, + createSphereBuffers: createSphereBuffers, + createSphereVertices: createSphereVertices, + createTruncatedConeBufferInfo: createTruncatedConeBufferInfo, + createTruncatedConeBuffers: createTruncatedConeBuffers, + createTruncatedConeVertices: createTruncatedConeVertices, + createXYQuadBufferInfo: createXYQuadBufferInfo, + createXYQuadBuffers: createXYQuadBuffers, + createXYQuadVertices: createXYQuadVertices, + createCresentBufferInfo: createCresentBufferInfo, + createCresentBuffers: createCresentBuffers, + createCresentVertices: createCresentVertices, + createCrescentBufferInfo: createCrescentBufferInfo, + createCrescentBuffers: createCrescentBuffers, + createCrescentVertices: createCrescentVertices, + createCylinderBufferInfo: createCylinderBufferInfo, + createCylinderBuffers: createCylinderBuffers, + createCylinderVertices: createCylinderVertices, + createTorusBufferInfo: createTorusBufferInfo, + createTorusBuffers: createTorusBuffers, + createTorusVertices: createTorusVertices, + createDiscBufferInfo: createDiscBufferInfo, + createDiscBuffers: createDiscBuffers, + createDiscVertices: createDiscVertices, + deindexVertices: deindexVertices, + flattenNormals: flattenNormals, + makeRandomVertexColors: makeRandomVertexColors, + reorientDirections: reorientDirections, + reorientNormals: reorientNormals, + reorientPositions: reorientPositions, + reorientVertices: reorientVertices, + concatVertices: concatVertices, + duplicateVertices: duplicateVertices +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * Gets the gl version as a number + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @return {number} version of gl + * @private + */ +//function getVersionAsNumber(gl) { +// return parseFloat(gl.getParameter(gl.VERSION).substr(6)); +//} + +/** + * Check if context is WebGL 2.0 + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @return {bool} true if it's WebGL 2.0 + * @memberOf module:twgl + */ + +exports.primitives = primitives; + +function isWebGL2(gl) { + // This is the correct check but it's slow + // return gl.getParameter(gl.VERSION).indexOf("WebGL 2.0") === 0; + // This might also be the correct check but I'm assuming it's slow-ish + // return gl instanceof WebGL2RenderingContext; + return !!gl.texStorage2D; +} +/** + * Check if context is WebGL 1.0 + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @return {bool} true if it's WebGL 1.0 + * @memberOf module:twgl + */ + + +function isWebGL1(gl) { + // This is the correct check but it's slow + // const version = getVersionAsNumber(gl); + // return version <= 1.0 && version > 0.0; // because as of 2016/5 Edge returns 0.96 + // This might also be the correct check but I'm assuming it's slow-ish + // return gl instanceof WebGLRenderingContext; + return !gl.texStorage2D; +} +/** + * Gets a string for WebGL enum + * + * Note: Several enums are the same. Without more + * context (which function) it's impossible to always + * give the correct enum. As it is, for matching values + * it gives all enums. Checking the WebGL2RenderingContext + * that means + * + * 0 = ZERO | POINT | NONE | NO_ERROR + * 1 = ONE | LINES | SYNC_FLUSH_COMMANDS_BIT + * 32777 = BLEND_EQUATION_RGB | BLEND_EQUATION_RGB + * 36662 = COPY_READ_BUFFER | COPY_READ_BUFFER_BINDING + * 36663 = COPY_WRITE_BUFFER | COPY_WRITE_BUFFER_BINDING + * 36006 = FRAMEBUFFER_BINDING | DRAW_FRAMEBUFFER_BINDING + * + * It's also not useful for bits really unless you pass in individual bits. + * In other words + * + * const bits = gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT; + * twgl.glEnumToString(gl, bits); // not going to work + * + * Note that some enums only exist on extensions. If you + * want them to show up you need to pass the extension at least + * once. For example + * + * const ext = gl.getExtension('WEBGL_compressed_texture_s3tc'); + * if (ext) { + * twgl.glEnumToString(ext, 0); // just prime the function + * + * ..later.. + * + * const internalFormat = ext.COMPRESSED_RGB_S3TC_DXT1_EXT; + * console.log(twgl.glEnumToString(gl, internalFormat)); + * + * Notice I didn't have to pass the extension the second time. This means + * you can have place that generically gets an enum for texture formats for example. + * and as long as you primed the function with the extensions + * + * If you're using `twgl.addExtensionsToContext` to enable your extensions + * then twgl will automatically get the extension's enums. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext or any extension object + * @param {number} value the value of the enum you want to look up. + * @return {string} enum string or hex value + * @memberOf module:twgl + * @function glEnumToString + */ + + +const glEnumToString = function () { + const haveEnumsForType = {}; + const enums = {}; + + function addEnums(gl) { + const type = gl.constructor.name; + + if (!haveEnumsForType[type]) { + for (const key in gl) { + if (typeof gl[key] === 'number') { + const existing = enums[gl[key]]; + enums[gl[key]] = existing ? `${existing} | ${key}` : key; + } + } + + haveEnumsForType[type] = true; + } + } + + return function glEnumToString(gl, value) { + addEnums(gl); + return enums[value] || (typeof value === 'number' ? `0x${value.toString(16)}` : value); + }; +}(); + +exports.glEnumToString = glEnumToString; +var utils = /*#__PURE__*/Object.freeze({ + __proto__: null, + glEnumToString: glEnumToString, + isWebGL1: isWebGL1, + isWebGL2: isWebGL2 +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +exports.utils = utils; +const defaults$1 = { + textureColor: new Uint8Array([128, 192, 255, 255]), + textureOptions: {}, + crossOrigin: undefined +}; +const isArrayBuffer$1 = isArrayBuffer; // Should we make this on demand? + +const getShared2DContext = function () { + let s_ctx; + return function getShared2DContext() { + s_ctx = s_ctx || (typeof document !== 'undefined' && document.createElement ? document.createElement("canvas").getContext("2d") : null); + return s_ctx; + }; +}(); // NOTE: Chrome supports 2D canvas in a Worker (behind flag as of v64 but +// not only does Firefox NOT support it but Firefox freezes immediately +// if you try to create one instead of just returning null and continuing. +// : (global.OffscreenCanvas && (new global.OffscreenCanvas(1, 1)).getContext("2d")); // OffscreenCanvas may not support 2d +// NOTE: We can maybe remove some of the need for the 2d canvas. In WebGL2 +// we can use the various unpack settings. Otherwise we could try using +// the ability of an ImageBitmap to be cut. Unfortunately cutting an ImageBitmap +// is async and the current TWGL code expects a non-Async result though that +// might not be a problem. ImageBitmap though is not available in Edge or Safari +// as of 2018-01-02 + +/* PixelFormat */ + + +const ALPHA = 0x1906; +const RGB = 0x1907; +const RGBA = 0x1908; +const LUMINANCE = 0x1909; +const LUMINANCE_ALPHA = 0x190A; +const DEPTH_COMPONENT = 0x1902; +const DEPTH_STENCIL = 0x84F9; +/* TextureWrapMode */ +// const REPEAT = 0x2901; +// const MIRRORED_REPEAT = 0x8370; + +const CLAMP_TO_EDGE = 0x812f; +/* TextureMagFilter */ + +const NEAREST = 0x2600; +const LINEAR = 0x2601; +/* TextureMinFilter */ +// const NEAREST_MIPMAP_NEAREST = 0x2700; +// const LINEAR_MIPMAP_NEAREST = 0x2701; +// const NEAREST_MIPMAP_LINEAR = 0x2702; +// const LINEAR_MIPMAP_LINEAR = 0x2703; + +/* Texture Target */ + +const TEXTURE_2D = 0x0de1; +const TEXTURE_CUBE_MAP = 0x8513; +const TEXTURE_3D = 0x806f; +const TEXTURE_2D_ARRAY = 0x8c1a; +/* Cubemap Targets */ + +const TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; +const TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; +const TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; +const TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; +const TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; +const TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851a; +/* Texture Parameters */ + +const TEXTURE_MIN_FILTER = 0x2801; +const TEXTURE_MAG_FILTER = 0x2800; +const TEXTURE_WRAP_S = 0x2802; +const TEXTURE_WRAP_T = 0x2803; +const TEXTURE_WRAP_R = 0x8072; +const TEXTURE_MIN_LOD = 0x813a; +const TEXTURE_MAX_LOD = 0x813b; +const TEXTURE_BASE_LEVEL = 0x813c; +const TEXTURE_MAX_LEVEL = 0x813d; +/* Pixel store */ + +const UNPACK_ALIGNMENT = 0x0cf5; +const UNPACK_ROW_LENGTH = 0x0cf2; +const UNPACK_IMAGE_HEIGHT = 0x806e; +const UNPACK_SKIP_PIXELS = 0x0cf4; +const UNPACK_SKIP_ROWS = 0x0cf3; +const UNPACK_SKIP_IMAGES = 0x806d; +const UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; +const UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; +const UNPACK_FLIP_Y_WEBGL = 0x9240; +const R8 = 0x8229; +const R8_SNORM = 0x8F94; +const R16F = 0x822D; +const R32F = 0x822E; +const R8UI = 0x8232; +const R8I = 0x8231; +const RG16UI = 0x823A; +const RG16I = 0x8239; +const RG32UI = 0x823C; +const RG32I = 0x823B; +const RG8 = 0x822B; +const RG8_SNORM = 0x8F95; +const RG16F = 0x822F; +const RG32F = 0x8230; +const RG8UI = 0x8238; +const RG8I = 0x8237; +const R16UI = 0x8234; +const R16I = 0x8233; +const R32UI = 0x8236; +const R32I = 0x8235; +const RGB8 = 0x8051; +const SRGB8 = 0x8C41; +const RGB565 = 0x8D62; +const RGB8_SNORM = 0x8F96; +const R11F_G11F_B10F = 0x8C3A; +const RGB9_E5 = 0x8C3D; +const RGB16F = 0x881B; +const RGB32F = 0x8815; +const RGB8UI = 0x8D7D; +const RGB8I = 0x8D8F; +const RGB16UI = 0x8D77; +const RGB16I = 0x8D89; +const RGB32UI = 0x8D71; +const RGB32I = 0x8D83; +const RGBA8 = 0x8058; +const SRGB8_ALPHA8 = 0x8C43; +const RGBA8_SNORM = 0x8F97; +const RGB5_A1 = 0x8057; +const RGBA4 = 0x8056; +const RGB10_A2 = 0x8059; +const RGBA16F = 0x881A; +const RGBA32F = 0x8814; +const RGBA8UI = 0x8D7C; +const RGBA8I = 0x8D8E; +const RGB10_A2UI = 0x906F; +const RGBA16UI = 0x8D76; +const RGBA16I = 0x8D88; +const RGBA32I = 0x8D82; +const RGBA32UI = 0x8D70; +const DEPTH_COMPONENT16 = 0x81A5; +const DEPTH_COMPONENT24 = 0x81A6; +const DEPTH_COMPONENT32F = 0x8CAC; +const DEPTH32F_STENCIL8 = 0x8CAD; +const DEPTH24_STENCIL8 = 0x88F0; +/* DataType */ + +const BYTE$2 = 0x1400; +const UNSIGNED_BYTE$2 = 0x1401; +const SHORT$2 = 0x1402; +const UNSIGNED_SHORT$2 = 0x1403; +const INT$2 = 0x1404; +const UNSIGNED_INT$2 = 0x1405; +const FLOAT$2 = 0x1406; +const UNSIGNED_SHORT_4_4_4_4$1 = 0x8033; +const UNSIGNED_SHORT_5_5_5_1$1 = 0x8034; +const UNSIGNED_SHORT_5_6_5$1 = 0x8363; +const HALF_FLOAT$1 = 0x140B; +const HALF_FLOAT_OES = 0x8D61; // Thanks Khronos for making this different >:( + +const UNSIGNED_INT_2_10_10_10_REV$1 = 0x8368; +const UNSIGNED_INT_10F_11F_11F_REV$1 = 0x8C3B; +const UNSIGNED_INT_5_9_9_9_REV$1 = 0x8C3E; +const FLOAT_32_UNSIGNED_INT_24_8_REV$1 = 0x8DAD; +const UNSIGNED_INT_24_8$1 = 0x84FA; +const RG = 0x8227; +const RG_INTEGER = 0x8228; +const RED = 0x1903; +const RED_INTEGER = 0x8D94; +const RGB_INTEGER = 0x8D98; +const RGBA_INTEGER = 0x8D99; +const formatInfo = {}; +{ + // NOTE: this is named `numColorComponents` vs `numComponents` so we can let Uglify mangle + // the name. + const f = formatInfo; + f[ALPHA] = { + numColorComponents: 1 + }; + f[LUMINANCE] = { + numColorComponents: 1 + }; + f[LUMINANCE_ALPHA] = { + numColorComponents: 2 + }; + f[RGB] = { + numColorComponents: 3 + }; + f[RGBA] = { + numColorComponents: 4 + }; + f[RED] = { + numColorComponents: 1 + }; + f[RED_INTEGER] = { + numColorComponents: 1 + }; + f[RG] = { + numColorComponents: 2 + }; + f[RG_INTEGER] = { + numColorComponents: 2 + }; + f[RGB] = { + numColorComponents: 3 + }; + f[RGB_INTEGER] = { + numColorComponents: 3 + }; + f[RGBA] = { + numColorComponents: 4 + }; + f[RGBA_INTEGER] = { + numColorComponents: 4 + }; + f[DEPTH_COMPONENT] = { + numColorComponents: 1 + }; + f[DEPTH_STENCIL] = { + numColorComponents: 2 + }; +} +/** + * @typedef {Object} TextureFormatDetails + * @property {number} textureFormat format to pass texImage2D and similar functions. + * @property {boolean} colorRenderable true if you can render to this format of texture. + * @property {boolean} textureFilterable true if you can filter the texture, false if you can ony use `NEAREST`. + * @property {number[]} type Array of possible types you can pass to texImage2D and similar function + * @property {Object.} bytesPerElementMap A map of types to bytes per element + * @private + */ + +let s_textureInternalFormatInfo; + +function getTextureInternalFormatInfo(internalFormat) { + if (!s_textureInternalFormatInfo) { + // NOTE: these properties need unique names so we can let Uglify mangle the name. + const t = {}; // unsized formats + + t[ALPHA] = { + textureFormat: ALPHA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [1, 2, 2, 4], + type: [UNSIGNED_BYTE$2, HALF_FLOAT$1, HALF_FLOAT_OES, FLOAT$2] + }; + t[LUMINANCE] = { + textureFormat: LUMINANCE, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [1, 2, 2, 4], + type: [UNSIGNED_BYTE$2, HALF_FLOAT$1, HALF_FLOAT_OES, FLOAT$2] + }; + t[LUMINANCE_ALPHA] = { + textureFormat: LUMINANCE_ALPHA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [2, 4, 4, 8], + type: [UNSIGNED_BYTE$2, HALF_FLOAT$1, HALF_FLOAT_OES, FLOAT$2] + }; + t[RGB] = { + textureFormat: RGB, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [3, 6, 6, 12, 2], + type: [UNSIGNED_BYTE$2, HALF_FLOAT$1, HALF_FLOAT_OES, FLOAT$2, UNSIGNED_SHORT_5_6_5$1] + }; + t[RGBA] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4, 8, 8, 16, 2, 2], + type: [UNSIGNED_BYTE$2, HALF_FLOAT$1, HALF_FLOAT_OES, FLOAT$2, UNSIGNED_SHORT_4_4_4_4$1, UNSIGNED_SHORT_5_5_5_1$1] + }; + t[DEPTH_COMPONENT] = { + textureFormat: DEPTH_COMPONENT, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2, 4], + type: [UNSIGNED_INT$2, UNSIGNED_SHORT$2] + }; // sized formats + + t[R8] = { + textureFormat: RED, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [1], + type: [UNSIGNED_BYTE$2] + }; + t[R8_SNORM] = { + textureFormat: RED, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [1], + type: [BYTE$2] + }; + t[R16F] = { + textureFormat: RED, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [4, 2], + type: [FLOAT$2, HALF_FLOAT$1] + }; + t[R32F] = { + textureFormat: RED, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [4], + type: [FLOAT$2] + }; + t[R8UI] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [1], + type: [UNSIGNED_BYTE$2] + }; + t[R8I] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [1], + type: [BYTE$2] + }; + t[R16UI] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2], + type: [UNSIGNED_SHORT$2] + }; + t[R16I] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2], + type: [SHORT$2] + }; + t[R32UI] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_INT$2] + }; + t[R32I] = { + textureFormat: RED_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [INT$2] + }; + t[RG8] = { + textureFormat: RG, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [2], + type: [UNSIGNED_BYTE$2] + }; + t[RG8_SNORM] = { + textureFormat: RG, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [2], + type: [BYTE$2] + }; + t[RG16F] = { + textureFormat: RG, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [8, 4], + type: [FLOAT$2, HALF_FLOAT$1] + }; + t[RG32F] = { + textureFormat: RG, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [8], + type: [FLOAT$2] + }; + t[RG8UI] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2], + type: [UNSIGNED_BYTE$2] + }; + t[RG8I] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2], + type: [BYTE$2] + }; + t[RG16UI] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_SHORT$2] + }; + t[RG16I] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [SHORT$2] + }; + t[RG32UI] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [8], + type: [UNSIGNED_INT$2] + }; + t[RG32I] = { + textureFormat: RG_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [8], + type: [INT$2] + }; + t[RGB8] = { + textureFormat: RGB, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [3], + type: [UNSIGNED_BYTE$2] + }; + t[SRGB8] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [3], + type: [UNSIGNED_BYTE$2] + }; + t[RGB565] = { + textureFormat: RGB, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [3, 2], + type: [UNSIGNED_BYTE$2, UNSIGNED_SHORT_5_6_5$1] + }; + t[RGB8_SNORM] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [3], + type: [BYTE$2] + }; + t[R11F_G11F_B10F] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [12, 6, 4], + type: [FLOAT$2, HALF_FLOAT$1, UNSIGNED_INT_10F_11F_11F_REV$1] + }; + t[RGB9_E5] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [12, 6, 4], + type: [FLOAT$2, HALF_FLOAT$1, UNSIGNED_INT_5_9_9_9_REV$1] + }; + t[RGB16F] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [12, 6], + type: [FLOAT$2, HALF_FLOAT$1] + }; + t[RGB32F] = { + textureFormat: RGB, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [12], + type: [FLOAT$2] + }; + t[RGB8UI] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [3], + type: [UNSIGNED_BYTE$2] + }; + t[RGB8I] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [3], + type: [BYTE$2] + }; + t[RGB16UI] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [6], + type: [UNSIGNED_SHORT$2] + }; + t[RGB16I] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [6], + type: [SHORT$2] + }; + t[RGB32UI] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [12], + type: [UNSIGNED_INT$2] + }; + t[RGB32I] = { + textureFormat: RGB_INTEGER, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [12], + type: [INT$2] + }; + t[RGBA8] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4], + type: [UNSIGNED_BYTE$2] + }; + t[SRGB8_ALPHA8] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4], + type: [UNSIGNED_BYTE$2] + }; + t[RGBA8_SNORM] = { + textureFormat: RGBA, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [4], + type: [BYTE$2] + }; + t[RGB5_A1] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4, 2, 4], + type: [UNSIGNED_BYTE$2, UNSIGNED_SHORT_5_5_5_1$1, UNSIGNED_INT_2_10_10_10_REV$1] + }; + t[RGBA4] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4, 2], + type: [UNSIGNED_BYTE$2, UNSIGNED_SHORT_4_4_4_4$1] + }; + t[RGB10_A2] = { + textureFormat: RGBA, + colorRenderable: true, + textureFilterable: true, + bytesPerElement: [4], + type: [UNSIGNED_INT_2_10_10_10_REV$1] + }; + t[RGBA16F] = { + textureFormat: RGBA, + colorRenderable: false, + textureFilterable: true, + bytesPerElement: [16, 8], + type: [FLOAT$2, HALF_FLOAT$1] + }; + t[RGBA32F] = { + textureFormat: RGBA, + colorRenderable: false, + textureFilterable: false, + bytesPerElement: [16], + type: [FLOAT$2] + }; + t[RGBA8UI] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_BYTE$2] + }; + t[RGBA8I] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [BYTE$2] + }; + t[RGB10_A2UI] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_INT_2_10_10_10_REV$1] + }; + t[RGBA16UI] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [8], + type: [UNSIGNED_SHORT$2] + }; + t[RGBA16I] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [8], + type: [SHORT$2] + }; + t[RGBA32I] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [16], + type: [INT$2] + }; + t[RGBA32UI] = { + textureFormat: RGBA_INTEGER, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [16], + type: [UNSIGNED_INT$2] + }; // Sized Internal + + t[DEPTH_COMPONENT16] = { + textureFormat: DEPTH_COMPONENT, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [2, 4], + type: [UNSIGNED_SHORT$2, UNSIGNED_INT$2] + }; + t[DEPTH_COMPONENT24] = { + textureFormat: DEPTH_COMPONENT, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_INT$2] + }; + t[DEPTH_COMPONENT32F] = { + textureFormat: DEPTH_COMPONENT, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [FLOAT$2] + }; + t[DEPTH24_STENCIL8] = { + textureFormat: DEPTH_STENCIL, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [UNSIGNED_INT_24_8$1] + }; + t[DEPTH32F_STENCIL8] = { + textureFormat: DEPTH_STENCIL, + colorRenderable: true, + textureFilterable: false, + bytesPerElement: [4], + type: [FLOAT_32_UNSIGNED_INT_24_8_REV$1] + }; + Object.keys(t).forEach(function (internalFormat) { + const info = t[internalFormat]; + info.bytesPerElementMap = {}; + info.bytesPerElement.forEach(function (bytesPerElement, ndx) { + const type = info.type[ndx]; + info.bytesPerElementMap[type] = bytesPerElement; + }); + }); + s_textureInternalFormatInfo = t; + } + + return s_textureInternalFormatInfo[internalFormat]; +} +/** + * Gets the number of bytes per element for a given internalFormat / type + * @param {number} internalFormat The internalFormat parameter from texImage2D etc.. + * @param {number} type The type parameter for texImage2D etc.. + * @return {number} the number of bytes per element for the given internalFormat, type combo + * @memberOf module:twgl/textures + */ + + +function getBytesPerElementForInternalFormat(internalFormat, type) { + const info = getTextureInternalFormatInfo(internalFormat); + + if (!info) { + throw "unknown internal format"; + } + + const bytesPerElement = info.bytesPerElementMap[type]; + + if (bytesPerElement === undefined) { + throw "unknown internal format"; + } + + return bytesPerElement; +} +/** + * Info related to a specific texture internalFormat as returned + * from {@link module:twgl/textures.getFormatAndTypeForInternalFormat}. + * + * @typedef {Object} TextureFormatInfo + * @property {number} format Format to pass to texImage2D and related functions + * @property {number} type Type to pass to texImage2D and related functions + * @memberOf module:twgl/textures + */ + +/** + * Gets the format and type for a given internalFormat + * + * @param {number} internalFormat The internal format + * @return {module:twgl/textures.TextureFormatInfo} the corresponding format and type, + * @memberOf module:twgl/textures + */ + + +function getFormatAndTypeForInternalFormat(internalFormat) { + const info = getTextureInternalFormatInfo(internalFormat); + + if (!info) { + throw "unknown internal format"; + } + + return { + format: info.textureFormat, + type: info.type[0] + }; +} +/** + * Returns true if value is power of 2 + * @param {number} value number to check. + * @return true if value is power of 2 + * @private + */ + + +function isPowerOf2(value) { + return (value & value - 1) === 0; +} +/** + * Gets whether or not we can generate mips for the given + * internal format. + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {number} width The width parameter from texImage2D etc.. + * @param {number} height The height parameter from texImage2D etc.. + * @param {number} internalFormat The internalFormat parameter from texImage2D etc.. + * @return {boolean} true if we can generate mips + * @memberOf module:twgl/textures + */ + + +function canGenerateMipmap(gl, width, height, internalFormat) { + if (!isWebGL2(gl)) { + return isPowerOf2(width) && isPowerOf2(height); + } + + const info = getTextureInternalFormatInfo(internalFormat); + + if (!info) { + throw "unknown internal format"; + } + + return info.colorRenderable && info.textureFilterable; +} +/** + * Gets whether or not we can generate mips for the given format + * @param {number} internalFormat The internalFormat parameter from texImage2D etc.. + * @return {boolean} true if we can generate mips + * @memberOf module:twgl/textures + */ + + +function canFilter(internalFormat) { + const info = getTextureInternalFormatInfo(internalFormat); + + if (!info) { + throw "unknown internal format"; + } + + return info.textureFilterable; +} +/** + * Gets the number of components for a given image format. + * @param {number} format the format. + * @return {number} the number of components for the format. + * @memberOf module:twgl/textures + */ + + +function getNumComponentsForFormat(format) { + const info = formatInfo[format]; + + if (!info) { + throw "unknown format: " + format; + } + + return info.numColorComponents; +} +/** + * Gets the texture type for a given array type. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @return {number} the gl texture type + * @private + */ + + +function getTextureTypeForArrayType(gl, src, defaultType) { + if (isArrayBuffer$1(src)) { + return getGLTypeForTypedArray(src); + } + + return defaultType || UNSIGNED_BYTE$2; +} + +function guessDimensions(gl, target, width, height, numElements) { + if (numElements % 1 !== 0) { + throw "can't guess dimensions"; + } + + if (!width && !height) { + const size = Math.sqrt(numElements / (target === TEXTURE_CUBE_MAP ? 6 : 1)); + + if (size % 1 === 0) { + width = size; + height = size; + } else { + width = numElements; + height = 1; + } + } else if (!height) { + height = numElements / width; + + if (height % 1) { + throw "can't guess dimensions"; + } + } else if (!width) { + width = numElements / height; + + if (width % 1) { + throw "can't guess dimensions"; + } + } + + return { + width: width, + height: height + }; +} +/** + * Sets the default texture color. + * + * The default texture color is used when loading textures from + * urls. Because the URL will be loaded async we'd like to be + * able to use the texture immediately. By putting a 1x1 pixel + * color in the texture we can start using the texture before + * the URL has loaded. + * + * @param {number[]} color Array of 4 values in the range 0 to 1 + * @deprecated see {@link module:twgl.setDefaults} + * @memberOf module:twgl/textures + */ + + +function setDefaultTextureColor(color) { + defaults$1.textureColor = new Uint8Array([color[0] * 255, color[1] * 255, color[2] * 255, color[3] * 255]); +} + +function setDefaults$1(newDefaults) { + copyExistingProperties(newDefaults, defaults$1); + + if (newDefaults.textureColor) { + setDefaultTextureColor(newDefaults.textureColor); + } +} +/** + * A function to generate the source for a texture. + * @callback TextureFunc + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {module:twgl.TextureOptions} options the texture options + * @return {*} Returns any of the things documented for `src` for {@link module:twgl.TextureOptions}. + * @memberOf module:twgl + */ + +/** + * Texture options passed to most texture functions. Each function will use whatever options + * are appropriate for its needs. This lets you pass the same options to all functions. + * + * Note: A `TexImageSource` is defined in the WebGL spec as a `HTMLImageElement`, `HTMLVideoElement`, + * `HTMLCanvasElement`, `ImageBitmap`, or `ImageData`. + * + * @typedef {Object} TextureOptions + * @property {number} [target] the type of texture `gl.TEXTURE_2D` or `gl.TEXTURE_CUBE_MAP`. Defaults to `gl.TEXTURE_2D`. + * @property {number} [level] the mip level to affect. Defaults to 0. Note, if set auto will be considered false unless explicitly set to true. + * @property {number} [width] the width of the texture. Only used if src is an array or typed array or null. + * @property {number} [height] the height of a texture. Only used if src is an array or typed array or null. + * @property {number} [depth] the depth of a texture. Only used if src is an array or type array or null and target is `TEXTURE_3D` . + * @property {number} [min] the min filter setting (eg. `gl.LINEAR`). Defaults to `gl.NEAREST_MIPMAP_LINEAR` + * or if texture is not a power of 2 on both dimensions then defaults to `gl.LINEAR`. + * @property {number} [mag] the mag filter setting (eg. `gl.LINEAR`). Defaults to `gl.LINEAR` + * @property {number} [minMag] both the min and mag filter settings. + * @property {number} [internalFormat] internal format for texture. Defaults to `gl.RGBA` + * @property {number} [format] format for texture. Defaults to `gl.RGBA`. + * @property {number} [type] type for texture. Defaults to `gl.UNSIGNED_BYTE` unless `src` is ArrayBufferView. If `src` + * is ArrayBufferView defaults to type that matches ArrayBufferView type. + * @property {number} [wrap] Texture wrapping for both S and T (and R if TEXTURE_3D or WebGLSampler). Defaults to `gl.REPEAT` for 2D unless src is WebGL1 and src not npot and `gl.CLAMP_TO_EDGE` for cube + * @property {number} [wrapS] Texture wrapping for S. Defaults to `gl.REPEAT` and `gl.CLAMP_TO_EDGE` for cube. If set takes precedence over `wrap`. + * @property {number} [wrapT] Texture wrapping for T. Defaults to `gl.REPEAT` and `gl.CLAMP_TO_EDGE` for cube. If set takes precedence over `wrap`. + * @property {number} [wrapR] Texture wrapping for R. Defaults to `gl.REPEAT` and `gl.CLAMP_TO_EDGE` for cube. If set takes precedence over `wrap`. + * @property {number} [minLod] TEXTURE_MIN_LOD setting + * @property {number} [maxLod] TEXTURE_MAX_LOD setting + * @property {number} [baseLevel] TEXTURE_BASE_LEVEL setting + * @property {number} [maxLevel] TEXTURE_MAX_LEVEL setting + * @property {number} [unpackAlignment] The `gl.UNPACK_ALIGNMENT` used when uploading an array. Defaults to 1. + * @property {number[]|ArrayBufferView} [color] Color to initialize this texture with if loading an image asynchronously. + * The default use a blue 1x1 pixel texture. You can set another default by calling `twgl.setDefaults` + * or you can set an individual texture's initial color by setting this property. Example: `[1, .5, .5, 1]` = pink + * @property {number} [premultiplyAlpha] Whether or not to premultiply alpha. Defaults to whatever the current setting is. + * This lets you set it once before calling `twgl.createTexture` or `twgl.createTextures` and only override + * the current setting for specific textures. + * @property {number} [flipY] Whether or not to flip the texture vertically on upload. Defaults to whatever the current setting is. + * This lets you set it once before calling `twgl.createTexture` or `twgl.createTextures` and only override + * the current setting for specific textures. + * @property {number} [colorspaceConversion] Whether or not to let the browser do colorspace conversion of the texture on upload. Defaults to whatever the current setting is. + * This lets you set it once before calling `twgl.createTexture` or `twgl.createTextures` and only override + * the current setting for specific textures. + * @property {boolean} [auto] If `undefined` or `true`, in WebGL1, texture filtering is set automatically for non-power of 2 images and + * mips are generated for power of 2 images. In WebGL2 mips are generated if they can be. Note: if `level` is set above + * then then `auto` is assumed to be `false` unless explicity set to `true`. + * @property {number[]} [cubeFaceOrder] The order that cube faces are pulled out of an img or set of images. The default is + * + * [gl.TEXTURE_CUBE_MAP_POSITIVE_X, + * gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + * gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + * gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + * gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + * gl.TEXTURE_CUBE_MAP_NEGATIVE_Z] + * + * @property {(number[]|ArrayBufferView|TexImageSource|TexImageSource[]|string|string[]|module:twgl.TextureFunc)} [src] source for texture + * + * If `string` then it's assumed to be a URL to an image. The image will be downloaded async. A usable + * 1x1 pixel texture will be returned immediately. The texture will be updated once the image has downloaded. + * If `target` is `gl.TEXTURE_CUBE_MAP` will attempt to divide image into 6 square pieces. 1x6, 6x1, 3x2, 2x3. + * The pieces will be uploaded in `cubeFaceOrder` + * + * If `string[]` or `TexImageSource[]` and target is `gl.TEXTURE_CUBE_MAP` then it must have 6 entries, one for each face of a cube map. + * + * If `string[]` or `TexImageSource[]` and target is `gl.TEXTURE_2D_ARRAY` then each entry is a slice of the a 2d array texture + * and will be scaled to the specified width and height OR to the size of the first image that loads. + * + * If `TexImageSource` then it wil be used immediately to create the contents of the texture. Examples `HTMLImageElement`, + * `HTMLCanvasElement`, `HTMLVideoElement`. + * + * If `number[]` or `ArrayBufferView` it's assumed to be data for a texture. If `width` or `height` is + * not specified it is guessed as follows. First the number of elements is computed by `src.length / numComponents` + * where `numComponents` is derived from `format`. If `target` is `gl.TEXTURE_CUBE_MAP` then `numElements` is divided + * by 6. Then + * + * * If neither `width` nor `height` are specified and `sqrt(numElements)` is an integer then width and height + * are set to `sqrt(numElements)`. Otherwise `width = numElements` and `height = 1`. + * + * * If only one of `width` or `height` is specified then the other equals `numElements / specifiedDimension`. + * + * If `number[]` will be converted to `type`. + * + * If `src` is a function it will be called with a `WebGLRenderingContext` and these options. + * Whatever it returns is subject to these rules. So it can return a string url, an `HTMLElement` + * an array etc... + * + * If `src` is undefined then an empty texture will be created of size `width` by `height`. + * + * @property {string} [crossOrigin] What to set the crossOrigin property of images when they are downloaded. + * default: undefined. Also see {@link module:twgl.setDefaults}. + * + * @memberOf module:twgl + */ + +/** + * Sets any packing state that will be set based on the options. + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @private + */ + + +function setPackState(gl, options) { + if (options.colorspaceConversion !== undefined) { + gl.pixelStorei(UNPACK_COLORSPACE_CONVERSION_WEBGL, options.colorspaceConversion); + } + + if (options.premultiplyAlpha !== undefined) { + gl.pixelStorei(UNPACK_PREMULTIPLY_ALPHA_WEBGL, options.premultiplyAlpha); + } + + if (options.flipY !== undefined) { + gl.pixelStorei(UNPACK_FLIP_Y_WEBGL, options.flipY); + } +} +/** + * Set skip state to defaults + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @private + */ + + +function setSkipStateToDefault(gl) { + gl.pixelStorei(UNPACK_ALIGNMENT, 4); + + if (isWebGL2(gl)) { + gl.pixelStorei(UNPACK_ROW_LENGTH, 0); + gl.pixelStorei(UNPACK_IMAGE_HEIGHT, 0); + gl.pixelStorei(UNPACK_SKIP_PIXELS, 0); + gl.pixelStorei(UNPACK_SKIP_ROWS, 0); + gl.pixelStorei(UNPACK_SKIP_IMAGES, 0); + } +} +/** + * Sets the parameters of a texture or sampler + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {number|WebGLSampler} target texture target or sampler + * @param {function()} parameteriFn texParameteri or samplerParameteri fn + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @private + */ + + +function setTextureSamplerParameters(gl, target, parameteriFn, options) { + if (options.minMag) { + parameteriFn.call(gl, target, TEXTURE_MIN_FILTER, options.minMag); + parameteriFn.call(gl, target, TEXTURE_MAG_FILTER, options.minMag); + } + + if (options.min) { + parameteriFn.call(gl, target, TEXTURE_MIN_FILTER, options.min); + } + + if (options.mag) { + parameteriFn.call(gl, target, TEXTURE_MAG_FILTER, options.mag); + } + + if (options.wrap) { + parameteriFn.call(gl, target, TEXTURE_WRAP_S, options.wrap); + parameteriFn.call(gl, target, TEXTURE_WRAP_T, options.wrap); + + if (target === TEXTURE_3D || isSampler(gl, target)) { + parameteriFn.call(gl, target, TEXTURE_WRAP_R, options.wrap); + } + } + + if (options.wrapR) { + parameteriFn.call(gl, target, TEXTURE_WRAP_R, options.wrapR); + } + + if (options.wrapS) { + parameteriFn.call(gl, target, TEXTURE_WRAP_S, options.wrapS); + } + + if (options.wrapT) { + parameteriFn.call(gl, target, TEXTURE_WRAP_T, options.wrapT); + } + + if (options.minLod) { + parameteriFn.call(gl, target, TEXTURE_MIN_LOD, options.minLod); + } + + if (options.maxLod) { + parameteriFn.call(gl, target, TEXTURE_MAX_LOD, options.maxLod); + } + + if (options.baseLevel) { + parameteriFn.call(gl, target, TEXTURE_BASE_LEVEL, options.baseLevel); + } + + if (options.maxLevel) { + parameteriFn.call(gl, target, TEXTURE_MAX_LEVEL, options.maxLevel); + } +} +/** + * Sets the texture parameters of a texture. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @memberOf module:twgl/textures + */ + + +function setTextureParameters(gl, tex, options) { + const target = options.target || TEXTURE_2D; + gl.bindTexture(target, tex); + setTextureSamplerParameters(gl, target, gl.texParameteri, options); +} +/** + * Sets the sampler parameters of a sampler. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLSampler} sampler the WebGLSampler to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @memberOf module:twgl/textures + */ + + +function setSamplerParameters(gl, sampler, options) { + setTextureSamplerParameters(gl, sampler, gl.samplerParameteri, options); +} +/** + * Creates a new sampler object and sets parameters. + * + * Example: + * + * const sampler = twgl.createSampler(gl, { + * minMag: gl.NEAREST, // sets both TEXTURE_MIN_FILTER and TEXTURE_MAG_FILTER + * wrap: gl.CLAMP_TO_NEAREST, // sets both TEXTURE_WRAP_S and TEXTURE_WRAP_T and TEXTURE_WRAP_R + * }); + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {Object.} options A object of TextureOptions one per sampler. + * @return {Object.} the created samplers by name + * @private + */ + + +function createSampler(gl, options) { + const sampler = gl.createSampler(); + setSamplerParameters(gl, sampler, options); + return sampler; +} +/** + * Creates a multiple sampler objects and sets parameters on each. + * + * Example: + * + * const samplers = twgl.createSamplers(gl, { + * nearest: { + * minMag: gl.NEAREST, + * }, + * nearestClampS: { + * minMag: gl.NEAREST, + * wrapS: gl.CLAMP_TO_NEAREST, + * }, + * linear: { + * minMag: gl.LINEAR, + * }, + * nearestClamp: { + * minMag: gl.NEAREST, + * wrap: gl.CLAMP_TO_EDGE, + * }, + * linearClamp: { + * minMag: gl.LINEAR, + * wrap: gl.CLAMP_TO_EDGE, + * }, + * linearClampT: { + * minMag: gl.LINEAR, + * wrapT: gl.CLAMP_TO_EDGE, + * }, + * }); + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set on the sampler + * @private + */ + + +function createSamplers(gl, samplerOptions) { + const samplers = {}; + Object.keys(samplerOptions).forEach(function (name) { + samplers[name] = createSampler(gl, samplerOptions[name]); + }); + return samplers; +} +/** + * Makes a 1x1 pixel + * If no color is passed in uses the default color which can be set by calling `setDefaultTextureColor`. + * @param {(number[]|ArrayBufferView)} [color] The color using 0-1 values + * @return {Uint8Array} Unit8Array with color. + * @private + */ + + +function make1Pixel(color) { + color = color || defaults$1.textureColor; + + if (isArrayBuffer$1(color)) { + return color; + } + + return new Uint8Array([color[0] * 255, color[1] * 255, color[2] * 255, color[3] * 255]); +} +/** + * Sets filtering or generates mips for texture based on width or height + * If width or height is not passed in uses `options.width` and//or `options.height` + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @param {number} [width] width of texture + * @param {number} [height] height of texture + * @param {number} [internalFormat] The internalFormat parameter from texImage2D etc.. + * @memberOf module:twgl/textures + */ + + +function setTextureFilteringForSize(gl, tex, options, width, height, internalFormat) { + options = options || defaults$1.textureOptions; + internalFormat = internalFormat || RGBA; + const target = options.target || TEXTURE_2D; + width = width || options.width; + height = height || options.height; + gl.bindTexture(target, tex); + + if (canGenerateMipmap(gl, width, height, internalFormat)) { + gl.generateMipmap(target); + } else { + const filtering = canFilter(internalFormat) ? LINEAR : NEAREST; + gl.texParameteri(target, TEXTURE_MIN_FILTER, filtering); + gl.texParameteri(target, TEXTURE_MAG_FILTER, filtering); + gl.texParameteri(target, TEXTURE_WRAP_S, CLAMP_TO_EDGE); + gl.texParameteri(target, TEXTURE_WRAP_T, CLAMP_TO_EDGE); + } +} + +function shouldAutomaticallySetTextureFilteringForSize(options) { + return options.auto === true || options.auto === undefined && options.level === undefined; +} +/** + * Gets an array of cubemap face enums + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @return {number[]} cubemap face enums + * @private + */ + + +function getCubeFaceOrder(gl, options) { + options = options || {}; + return options.cubeFaceOrder || [TEXTURE_CUBE_MAP_POSITIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_NEGATIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z, TEXTURE_CUBE_MAP_NEGATIVE_Z]; +} +/** + * @typedef {Object} FaceInfo + * @property {number} face gl enum for texImage2D + * @property {number} ndx face index (0 - 5) into source data + * @ignore + */ + +/** + * Gets an array of FaceInfos + * There's a bug in some NVidia drivers that will crash the driver if + * `gl.TEXTURE_CUBE_MAP_POSITIVE_X` is not uploaded first. So, we take + * the user's desired order from his faces to WebGL and make sure we + * do the faces in WebGL order + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @return {FaceInfo[]} cubemap face infos. Arguably the `face` property of each element is redundant but + * it's needed internally to sort the array of `ndx` properties by `face`. + * @private + */ + + +function getCubeFacesWithNdx(gl, options) { + const faces = getCubeFaceOrder(gl, options); // work around bug in NVidia drivers. We have to upload the first face first else the driver crashes :( + + const facesWithNdx = faces.map(function (face, ndx) { + return { + face: face, + ndx: ndx + }; + }); + facesWithNdx.sort(function (a, b) { + return a.face - b.face; + }); + return facesWithNdx; +} +/** + * Set a texture from the contents of an element. Will also set + * texture filtering or generate mips based on the dimensions of the element + * unless `options.auto === false`. If `target === gl.TEXTURE_CUBE_MAP` will + * attempt to slice image into 1x6, 2x3, 3x2, or 6x1 images, one for each face. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {HTMLElement} element a canvas, img, or video element. + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @memberOf module:twgl/textures + * @kind function + */ + + +function setTextureFromElement(gl, tex, element, options) { + options = options || defaults$1.textureOptions; + const target = options.target || TEXTURE_2D; + const level = options.level || 0; + let width = element.width; + let height = element.height; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + const type = options.type || formatType.type; + setPackState(gl, options); + gl.bindTexture(target, tex); + + if (target === TEXTURE_CUBE_MAP) { + // guess the parts + const imgWidth = element.width; + const imgHeight = element.height; + let size; + let slices; + + if (imgWidth / 6 === imgHeight) { + // It's 6x1 + size = imgHeight; + slices = [0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0]; + } else if (imgHeight / 6 === imgWidth) { + // It's 1x6 + size = imgWidth; + slices = [0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5]; + } else if (imgWidth / 3 === imgHeight / 2) { + // It's 3x2 + size = imgWidth / 3; + slices = [0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1]; + } else if (imgWidth / 2 === imgHeight / 3) { + // It's 2x3 + size = imgWidth / 2; + slices = [0, 0, 1, 0, 0, 1, 1, 1, 0, 2, 1, 2]; + } else { + throw "can't figure out cube map from element: " + (element.src ? element.src : element.nodeName); + } + + const ctx = getShared2DContext(); + + if (ctx) { + ctx.canvas.width = size; + ctx.canvas.height = size; + width = size; + height = size; + getCubeFacesWithNdx(gl, options).forEach(function (f) { + const xOffset = slices[f.ndx * 2 + 0] * size; + const yOffset = slices[f.ndx * 2 + 1] * size; + ctx.drawImage(element, xOffset, yOffset, size, size, 0, 0, size, size); + gl.texImage2D(f.face, level, internalFormat, format, type, ctx.canvas); + }); // Free up the canvas memory + + ctx.canvas.width = 1; + ctx.canvas.height = 1; + } else if (typeof createImageBitmap !== 'undefined') { + // NOTE: It seems like we should prefer ImageBitmap because unlike canvas it's + // note lossy? (alpha is not premultiplied? although I'm not sure what + width = size; + height = size; + getCubeFacesWithNdx(gl, options).forEach(function (f) { + const xOffset = slices[f.ndx * 2 + 0] * size; + const yOffset = slices[f.ndx * 2 + 1] * size; // We can't easily use a default texture color here as it would have to match + // the type across all faces where as with a 2D one there's only one face + // so we're replacing everything all at once. It also has to be the correct size. + // On the other hand we need all faces to be the same size so as one face loads + // the rest match else the texture will be un-renderable. + + gl.texImage2D(f.face, level, internalFormat, size, size, 0, format, type, null); + createImageBitmap(element, xOffset, yOffset, size, size, { + premultiplyAlpha: 'none', + colorSpaceConversion: 'none' + }).then(function (imageBitmap) { + setPackState(gl, options); + gl.bindTexture(target, tex); + gl.texImage2D(f.face, level, internalFormat, format, type, imageBitmap); + + if (shouldAutomaticallySetTextureFilteringForSize(options)) { + setTextureFilteringForSize(gl, tex, options, width, height, internalFormat); + } + }); + }); + } + } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + const smallest = Math.min(element.width, element.height); + const largest = Math.max(element.width, element.height); + const depth = largest / smallest; + + if (depth % 1 !== 0) { + throw "can not compute 3D dimensions of element"; + } + + const xMult = element.width === largest ? 1 : 0; + const yMult = element.height === largest ? 1 : 0; + gl.pixelStorei(UNPACK_ALIGNMENT, 1); + gl.pixelStorei(UNPACK_ROW_LENGTH, element.width); + gl.pixelStorei(UNPACK_IMAGE_HEIGHT, 0); + gl.pixelStorei(UNPACK_SKIP_IMAGES, 0); + gl.texImage3D(target, level, internalFormat, smallest, smallest, smallest, 0, format, type, null); + + for (let d = 0; d < depth; ++d) { + const srcX = d * smallest * xMult; + const srcY = d * smallest * yMult; + gl.pixelStorei(UNPACK_SKIP_PIXELS, srcX); + gl.pixelStorei(UNPACK_SKIP_ROWS, srcY); + gl.texSubImage3D(target, level, 0, 0, d, smallest, smallest, 1, format, type, element); + } + + setSkipStateToDefault(gl); + } else { + gl.texImage2D(target, level, internalFormat, format, type, element); + } + + if (shouldAutomaticallySetTextureFilteringForSize(options)) { + setTextureFilteringForSize(gl, tex, options, width, height, internalFormat); + } + + setTextureParameters(gl, tex, options); +} + +function noop() {} +/** + * Checks whether the url's origin is the same so that we can set the `crossOrigin` + * @param {string} url url to image + * @returns {boolean} true if the window's origin is the same as image's url + * @private + */ + + +function urlIsSameOrigin(url) { + if (typeof document !== 'undefined') { + // for IE really + const a = document.createElement('a'); + a.href = url; + return a.hostname === location.hostname && a.port === location.port && a.protocol === location.protocol; + } else { + const localOrigin = new URL(location.href).origin; + const urlOrigin = new URL(url, location.href).origin; + return urlOrigin === localOrigin; + } +} + +function setToAnonymousIfUndefinedAndURLIsNotSameOrigin(url, crossOrigin) { + return crossOrigin === undefined && !urlIsSameOrigin(url) ? 'anonymous' : crossOrigin; +} +/** + * Loads an image + * @param {string} url url to image + * @param {string} crossOrigin + * @param {function(err, img)} [callback] a callback that's passed an error and the image. The error will be non-null + * if there was an error + * @return {HTMLImageElement} the image being loaded. + * @private + */ + + +function loadImage(url, crossOrigin, callback) { + callback = callback || noop; + let img; + crossOrigin = crossOrigin !== undefined ? crossOrigin : defaults$1.crossOrigin; + crossOrigin = setToAnonymousIfUndefinedAndURLIsNotSameOrigin(url, crossOrigin); + + if (typeof Image !== 'undefined') { + img = new Image(); + + if (crossOrigin !== undefined) { + img.crossOrigin = crossOrigin; + } + + const clearEventHandlers = function clearEventHandlers() { + img.removeEventListener('error', onError); // eslint-disable-line + + img.removeEventListener('load', onLoad); // eslint-disable-line + + img = null; + }; + + const onError = function onError() { + const msg = "couldn't load image: " + url; + error(msg); + callback(msg, img); + clearEventHandlers(); + }; + + const onLoad = function onLoad() { + callback(null, img); + clearEventHandlers(); + }; + + img.addEventListener('error', onError); + img.addEventListener('load', onLoad); + img.src = url; + return img; + } else if (typeof ImageBitmap !== 'undefined') { + let err; + let bm; + + const cb = function cb() { + callback(err, bm); + }; + + const options = {}; + + if (crossOrigin) { + options.mode = 'cors'; // TODO: not sure how to translate image.crossOrigin + } + + fetch(url, options).then(function (response) { + if (!response.ok) { + throw response; + } + + return response.blob(); + }).then(function (blob) { + return createImageBitmap(blob, { + premultiplyAlpha: 'none', + colorSpaceConversion: 'none' + }); + }).then(function (bitmap) { + // not sure if this works. We don't want + // to catch the user's error. So, call + // the callback in a timeout so we're + // not in this scope inside the promise. + bm = bitmap; + setTimeout(cb); + }).catch(function (e) { + err = e; + setTimeout(cb); + }); + img = null; + } + + return img; +} +/** + * check if object is a TexImageSource + * + * @param {Object} obj Object to test + * @return {boolean} true if object is a TexImageSource + * @private + */ + + +function isTexImageSource(obj) { + return typeof ImageBitmap !== 'undefined' && obj instanceof ImageBitmap || typeof ImageData !== 'undefined' && obj instanceof ImageData || typeof HTMLElement !== 'undefined' && obj instanceof HTMLElement; +} +/** + * if obj is an TexImageSource then just + * uses it otherwise if obj is a string + * then load it first. + * + * @param {string|TexImageSource} obj + * @param {string} crossOrigin + * @param {function(err, img)} [callback] a callback that's passed an error and the image. The error will be non-null + * if there was an error + * @private + */ + + +function loadAndUseImage(obj, crossOrigin, callback) { + if (isTexImageSource(obj)) { + setTimeout(function () { + callback(null, obj); + }); + return obj; + } + + return loadImage(obj, crossOrigin, callback); +} +/** + * Sets a texture to a 1x1 pixel color. If `options.color === false` is nothing happens. If it's not set + * the default texture color is used which can be set by calling `setDefaultTextureColor`. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @memberOf module:twgl/textures + */ + + +function setTextureTo1PixelColor(gl, tex, options) { + options = options || defaults$1.textureOptions; + const target = options.target || TEXTURE_2D; + gl.bindTexture(target, tex); + + if (options.color === false) { + return; + } // Assume it's a URL + // Put 1x1 pixels in texture. That makes it renderable immediately regardless of filtering. + + + const color = make1Pixel(options.color); + + if (target === TEXTURE_CUBE_MAP) { + for (let ii = 0; ii < 6; ++ii) { + gl.texImage2D(TEXTURE_CUBE_MAP_POSITIVE_X + ii, 0, RGBA, 1, 1, 0, RGBA, UNSIGNED_BYTE$2, color); + } + } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + gl.texImage3D(target, 0, RGBA, 1, 1, 1, 0, RGBA, UNSIGNED_BYTE$2, color); + } else { + gl.texImage2D(target, 0, RGBA, 1, 1, 0, RGBA, UNSIGNED_BYTE$2, color); + } +} +/** + * The src image(s) used to create a texture. + * + * When you call {@link module:twgl.createTexture} or {@link module:twgl.createTextures} + * you can pass in urls for images to load into the textures. If it's a single url + * then this will be a single HTMLImageElement. If it's an array of urls used for a cubemap + * this will be a corresponding array of images for the cubemap. + * + * @typedef {HTMLImageElement|HTMLImageElement[]} TextureSrc + * @memberOf module:twgl + */ + +/** + * A callback for when an image finished downloading and been uploaded into a texture + * @callback TextureReadyCallback + * @param {*} err If truthy there was an error. + * @param {WebGLTexture} texture the texture. + * @param {module:twgl.TextureSrc} source image(s) used to as the src for the texture + * @memberOf module:twgl + */ + +/** + * A callback for when all images have finished downloading and been uploaded into their respective textures + * @callback TexturesReadyCallback + * @param {*} err If truthy there was an error. + * @param {Object.} textures the created textures by name. Same as returned by {@link module:twgl.createTextures}. + * @param {Object.} sources the image(s) used for the texture by name. + * @memberOf module:twgl + */ + +/** + * A callback for when an image finished downloading and been uploaded into a texture + * @callback CubemapReadyCallback + * @param {*} err If truthy there was an error. + * @param {WebGLTexture} tex the texture. + * @param {HTMLImageElement[]} imgs the images for each face. + * @memberOf module:twgl + */ + +/** + * A callback for when an image finished downloading and been uploaded into a texture + * @callback ThreeDReadyCallback + * @param {*} err If truthy there was an error. + * @param {WebGLTexture} tex the texture. + * @param {HTMLImageElement[]} imgs the images for each slice. + * @memberOf module:twgl + */ + +/** + * Loads a texture from an image from a Url as specified in `options.src` + * If `options.color !== false` will set the texture to a 1x1 pixel color so that the texture is + * immediately useable. It will be updated with the contents of the image once the image has finished + * downloading. Filtering options will be set as appropriate for image unless `options.auto === false`. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * @param {module:twgl.TextureReadyCallback} [callback] A function to be called when the image has finished loading. err will + * be non null if there was an error. + * @return {HTMLImageElement} the image being downloaded. + * @memberOf module:twgl/textures + */ + + +function loadTextureFromUrl(gl, tex, options, callback) { + callback = callback || noop; + options = options || defaults$1.textureOptions; + setTextureTo1PixelColor(gl, tex, options); // Because it's async we need to copy the options. + + options = Object.assign({}, options); + const img = loadAndUseImage(options.src, options.crossOrigin, function (err, img) { + if (err) { + callback(err, tex, img); + } else { + setTextureFromElement(gl, tex, img, options); + callback(null, tex, img); + } + }); + return img; +} +/** + * Loads a cubemap from 6 urls or TexImageSources as specified in `options.src`. Will set the cubemap to a 1x1 pixel color + * so that it is usable immediately unless `option.color === false`. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @param {module:twgl.CubemapReadyCallback} [callback] A function to be called when all the images have finished loading. err will + * be non null if there was an error. + * @memberOf module:twgl/textures + */ + + +function loadCubemapFromUrls(gl, tex, options, callback) { + callback = callback || noop; + const urls = options.src; + + if (urls.length !== 6) { + throw "there must be 6 urls for a cubemap"; + } + + const level = options.level || 0; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + const type = options.type || UNSIGNED_BYTE$2; + const target = options.target || TEXTURE_2D; + + if (target !== TEXTURE_CUBE_MAP) { + throw "target must be TEXTURE_CUBE_MAP"; + } + + setTextureTo1PixelColor(gl, tex, options); // Because it's async we need to copy the options. + + options = Object.assign({}, options); + let numToLoad = 6; + const errors = []; + const faces = getCubeFaceOrder(gl, options); + let imgs; // eslint-disable-line + + function uploadImg(faceTarget) { + return function (err, img) { + --numToLoad; + + if (err) { + errors.push(err); + } else { + if (img.width !== img.height) { + errors.push("cubemap face img is not a square: " + img.src); + } else { + setPackState(gl, options); + gl.bindTexture(target, tex); // So assuming this is the first image we now have one face that's img sized + // and 5 faces that are 1x1 pixel so size the other faces + + if (numToLoad === 5) { + // use the default order + getCubeFaceOrder().forEach(function (otherTarget) { + // Should we re-use the same face or a color? + gl.texImage2D(otherTarget, level, internalFormat, format, type, img); + }); + } else { + gl.texImage2D(faceTarget, level, internalFormat, format, type, img); + } + + if (shouldAutomaticallySetTextureFilteringForSize(options)) { + gl.generateMipmap(target); + } + } + } + + if (numToLoad === 0) { + callback(errors.length ? errors : undefined, tex, imgs); + } + }; + } + + imgs = urls.map(function (url, ndx) { + return loadAndUseImage(url, options.crossOrigin, uploadImg(faces[ndx])); + }); +} +/** + * Loads a 2d array or 3d texture from urls OR TexImageSources as specified in `options.src`. + * Will set the texture to a 1x1 pixel color + * so that it is usable immediately unless `option.color === false`. + * + * If the width and height is not specified the width and height of the first + * image loaded will be used. Note that since images are loaded async + * which image downloads first is unknown. + * + * If an image is not the same size as the width and height it will be scaled + * to that width and height. + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @param {module:twgl.ThreeDReadyCallback} [callback] A function to be called when all the images have finished loading. err will + * be non null if there was an error. + * @memberOf module:twgl/textures + */ + + +function loadSlicesFromUrls(gl, tex, options, callback) { + callback = callback || noop; + const urls = options.src; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + const type = options.type || UNSIGNED_BYTE$2; + const target = options.target || TEXTURE_2D_ARRAY; + + if (target !== TEXTURE_3D && target !== TEXTURE_2D_ARRAY) { + throw "target must be TEXTURE_3D or TEXTURE_2D_ARRAY"; + } + + setTextureTo1PixelColor(gl, tex, options); // Because it's async we need to copy the options. + + options = Object.assign({}, options); + let numToLoad = urls.length; + const errors = []; + let imgs; // eslint-disable-line + + const level = options.level || 0; + let width = options.width; + let height = options.height; + const depth = urls.length; + let firstImage = true; + + function uploadImg(slice) { + return function (err, img) { + --numToLoad; + + if (err) { + errors.push(err); + } else { + setPackState(gl, options); + gl.bindTexture(target, tex); + + if (firstImage) { + firstImage = false; + width = options.width || img.width; + height = options.height || img.height; + gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, null); // put it in every slice otherwise some slices will be 0,0,0,0 + + for (let s = 0; s < depth; ++s) { + gl.texSubImage3D(target, level, 0, 0, s, width, height, 1, format, type, img); + } + } else { + let src = img; + let ctx; + + if (img.width !== width || img.height !== height) { + // Size the image to fix + ctx = getShared2DContext(); + src = ctx.canvas; + ctx.canvas.width = width; + ctx.canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + } + + gl.texSubImage3D(target, level, 0, 0, slice, width, height, 1, format, type, src); // free the canvas memory + + if (ctx && src === ctx.canvas) { + ctx.canvas.width = 0; + ctx.canvas.height = 0; + } + } + + if (shouldAutomaticallySetTextureFilteringForSize(options)) { + gl.generateMipmap(target); + } + } + + if (numToLoad === 0) { + callback(errors.length ? errors : undefined, tex, imgs); + } + }; + } + + imgs = urls.map(function (url, ndx) { + return loadAndUseImage(url, options.crossOrigin, uploadImg(ndx)); + }); +} +/** + * Sets a texture from an array or typed array. If the width or height is not provided will attempt to + * guess the size. See {@link module:twgl.TextureOptions}. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {(number[]|ArrayBufferView)} src An array or typed arry with texture data. + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * This is often the same options you passed in when you created the texture. + * @memberOf module:twgl/textures + */ + + +function setTextureFromArray(gl, tex, src, options) { + options = options || defaults$1.textureOptions; + const target = options.target || TEXTURE_2D; + gl.bindTexture(target, tex); + let width = options.width; + let height = options.height; + let depth = options.depth; + const level = options.level || 0; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + const type = options.type || getTextureTypeForArrayType(gl, src, formatType.type); + + if (!isArrayBuffer$1(src)) { + const Type = getTypedArrayTypeForGLType(type); + src = new Type(src); + } else if (src instanceof Uint8ClampedArray) { + src = new Uint8Array(src.buffer); + } + + const bytesPerElement = getBytesPerElementForInternalFormat(internalFormat, type); + const numElements = src.byteLength / bytesPerElement; // TODO: check UNPACK_ALIGNMENT? + + if (numElements % 1) { + throw "length wrong size for format: " + glEnumToString(gl, format); + } + + let dimensions; + + if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + if (!width && !height && !depth) { + const size = Math.cbrt(numElements); + + if (size % 1 !== 0) { + throw "can't guess cube size of array of numElements: " + numElements; + } + + width = size; + height = size; + depth = size; + } else if (width && (!height || !depth)) { + dimensions = guessDimensions(gl, target, height, depth, numElements / width); + height = dimensions.width; + depth = dimensions.height; + } else if (height && (!width || !depth)) { + dimensions = guessDimensions(gl, target, width, depth, numElements / height); + width = dimensions.width; + depth = dimensions.height; + } else { + dimensions = guessDimensions(gl, target, width, height, numElements / depth); + width = dimensions.width; + height = dimensions.height; + } + } else { + dimensions = guessDimensions(gl, target, width, height, numElements); + width = dimensions.width; + height = dimensions.height; + } + + setSkipStateToDefault(gl); + gl.pixelStorei(UNPACK_ALIGNMENT, options.unpackAlignment || 1); + setPackState(gl, options); + + if (target === TEXTURE_CUBE_MAP) { + const elementsPerElement = bytesPerElement / src.BYTES_PER_ELEMENT; + const faceSize = numElements / 6 * elementsPerElement; + getCubeFacesWithNdx(gl, options).forEach(f => { + const offset = faceSize * f.ndx; + const data = src.subarray(offset, offset + faceSize); + gl.texImage2D(f.face, level, internalFormat, width, height, 0, format, type, data); + }); + } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, src); + } else { + gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, src); + } + + return { + width: width, + height: height, + depth: depth, + type: type + }; +} +/** + * Sets a texture with no contents of a certain size. In other words calls `gl.texImage2D` with `null`. + * You must set `options.width` and `options.height`. + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the WebGLTexture to set parameters for + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @memberOf module:twgl/textures + */ + + +function setEmptyTexture(gl, tex, options) { + const target = options.target || TEXTURE_2D; + gl.bindTexture(target, tex); + const level = options.level || 0; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + const type = options.type || formatType.type; + setPackState(gl, options); + + if (target === TEXTURE_CUBE_MAP) { + for (let ii = 0; ii < 6; ++ii) { + gl.texImage2D(TEXTURE_CUBE_MAP_POSITIVE_X + ii, level, internalFormat, options.width, options.height, 0, format, type, null); + } + } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + gl.texImage3D(target, level, internalFormat, options.width, options.height, options.depth, 0, format, type, null); + } else { + gl.texImage2D(target, level, internalFormat, options.width, options.height, 0, format, type, null); + } +} +/** + * Creates a texture based on the options passed in. + * + * Note: may reset UNPACK_ALIGNMENT, UNPACK_ROW_LENGTH, UNPACK_IMAGE_HEIGHT, UNPACK_SKIP_IMAGES + * UNPACK_SKIP_PIXELS, and UNPACK_SKIP_ROWS + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set. + * @param {module:twgl.TextureReadyCallback} [callback] A callback called when an image has been downloaded and uploaded to the texture. + * @return {WebGLTexture} the created texture. + * @memberOf module:twgl/textures + */ + + +function createTexture(gl, options, callback) { + callback = callback || noop; + options = options || defaults$1.textureOptions; + const tex = gl.createTexture(); + const target = options.target || TEXTURE_2D; + let width = options.width || 1; + let height = options.height || 1; + const internalFormat = options.internalFormat || RGBA; + gl.bindTexture(target, tex); + + if (target === TEXTURE_CUBE_MAP) { + // this should have been the default for cubemaps :( + gl.texParameteri(target, TEXTURE_WRAP_S, CLAMP_TO_EDGE); + gl.texParameteri(target, TEXTURE_WRAP_T, CLAMP_TO_EDGE); + } + + let src = options.src; + + if (src) { + if (typeof src === "function") { + src = src(gl, options); + } + + if (typeof src === "string") { + loadTextureFromUrl(gl, tex, options, callback); + } else if (isArrayBuffer$1(src) || Array.isArray(src) && (typeof src[0] === 'number' || Array.isArray(src[0]) || isArrayBuffer$1(src[0]))) { + const dimensions = setTextureFromArray(gl, tex, src, options); + width = dimensions.width; + height = dimensions.height; + } else if (Array.isArray(src) && (typeof src[0] === 'string' || isTexImageSource(src[0]))) { + if (target === TEXTURE_CUBE_MAP) { + loadCubemapFromUrls(gl, tex, options, callback); + } else { + loadSlicesFromUrls(gl, tex, options, callback); + } + } else { + // if (isTexImageSource(src)) + setTextureFromElement(gl, tex, src, options); + width = src.width; + height = src.height; + } + } else { + setEmptyTexture(gl, tex, options); + } + + if (shouldAutomaticallySetTextureFilteringForSize(options)) { + setTextureFilteringForSize(gl, tex, options, width, height, internalFormat); + } + + setTextureParameters(gl, tex, options); + return tex; +} +/** + * Resizes a texture based on the options passed in. + * + * Note: This is not a generic resize anything function. + * It's mostly used by {@link module:twgl.resizeFramebufferInfo} + * It will use `options.src` if it exists to try to determine a `type` + * otherwise it will assume `gl.UNSIGNED_BYTE`. No data is provided + * for the texture. Texture parameters will be set accordingly + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {WebGLTexture} tex the texture to resize + * @param {module:twgl.TextureOptions} options A TextureOptions object with whatever parameters you want set. + * @param {number} [width] the new width. If not passed in will use `options.width` + * @param {number} [height] the new height. If not passed in will use `options.height` + * @param {number} [depth] the new depth. If not passed in will use `options.depth` + * @memberOf module:twgl/textures + */ + + +function resizeTexture(gl, tex, options, width, height, depth) { + width = width || options.width; + height = height || options.height; + depth = depth || options.depth; + const target = options.target || TEXTURE_2D; + gl.bindTexture(target, tex); + const level = options.level || 0; + const internalFormat = options.internalFormat || options.format || RGBA; + const formatType = getFormatAndTypeForInternalFormat(internalFormat); + const format = options.format || formatType.format; + let type; + const src = options.src; + + if (!src) { + type = options.type || formatType.type; + } else if (isArrayBuffer$1(src) || Array.isArray(src) && typeof src[0] === 'number') { + type = options.type || getTextureTypeForArrayType(gl, src, formatType.type); + } else { + type = options.type || formatType.type; + } + + if (target === TEXTURE_CUBE_MAP) { + for (let ii = 0; ii < 6; ++ii) { + gl.texImage2D(TEXTURE_CUBE_MAP_POSITIVE_X + ii, level, internalFormat, width, height, 0, format, type, null); + } + } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { + gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, null); + } else { + gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null); + } +} +/** + * Check if a src is an async request. + * if src is a string we're going to download an image + * if src is an array of strings we're going to download cubemap images + * @param {*} src The src from a TextureOptions + * @returns {bool} true if src is async. + * @private + */ + + +function isAsyncSrc(src) { + return typeof src === 'string' || Array.isArray(src) && typeof src[0] === 'string'; +} +/** + * Creates a bunch of textures based on the passed in options. + * + * Example: + * + * const textures = twgl.createTextures(gl, { + * // a power of 2 image + * hftIcon: { src: "images/hft-icon-16.png", mag: gl.NEAREST }, + * // a non-power of 2 image + * clover: { src: "images/clover.jpg" }, + * // From a canvas + * fromCanvas: { src: ctx.canvas }, + * // A cubemap from 6 images + * yokohama: { + * target: gl.TEXTURE_CUBE_MAP, + * src: [ + * 'images/yokohama/posx.jpg', + * 'images/yokohama/negx.jpg', + * 'images/yokohama/posy.jpg', + * 'images/yokohama/negy.jpg', + * 'images/yokohama/posz.jpg', + * 'images/yokohama/negz.jpg', + * ], + * }, + * // A cubemap from 1 image (can be 1x6, 2x3, 3x2, 6x1) + * goldengate: { + * target: gl.TEXTURE_CUBE_MAP, + * src: 'images/goldengate.jpg', + * }, + * // A 2x2 pixel texture from a JavaScript array + * checker: { + * mag: gl.NEAREST, + * min: gl.LINEAR, + * src: [ + * 255,255,255,255, + * 192,192,192,255, + * 192,192,192,255, + * 255,255,255,255, + * ], + * }, + * // a 1x2 pixel texture from a typed array. + * stripe: { + * mag: gl.NEAREST, + * min: gl.LINEAR, + * format: gl.LUMINANCE, + * src: new Uint8Array([ + * 255, + * 128, + * 255, + * 128, + * 255, + * 128, + * 255, + * 128, + * ]), + * width: 1, + * }, + * }); + * + * Now + * + * * `textures.hftIcon` will be a 2d texture + * * `textures.clover` will be a 2d texture + * * `textures.fromCanvas` will be a 2d texture + * * `textures.yohohama` will be a cubemap texture + * * `textures.goldengate` will be a cubemap texture + * * `textures.checker` will be a 2d texture + * * `textures.stripe` will be a 2d texture + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {Object.} options A object of TextureOptions one per texture. + * @param {module:twgl.TexturesReadyCallback} [callback] A callback called when all textures have been downloaded. + * @return {Object.} the created textures by name + * @memberOf module:twgl/textures + */ + + +function createTextures(gl, textureOptions, callback) { + callback = callback || noop; + let numDownloading = 0; + const errors = []; + const textures = {}; + const images = {}; + + function callCallbackIfReady() { + if (numDownloading === 0) { + setTimeout(function () { + callback(errors.length ? errors : undefined, textures, images); + }, 0); + } + } + + Object.keys(textureOptions).forEach(function (name) { + const options = textureOptions[name]; + let onLoadFn; + + if (isAsyncSrc(options.src)) { + onLoadFn = function (err, tex, img) { + images[name] = img; + --numDownloading; + + if (err) { + errors.push(err); + } + + callCallbackIfReady(); + }; + + ++numDownloading; + } + + textures[name] = createTexture(gl, options, onLoadFn); + }); // queue the callback if there are no images to download. + // We do this because if your code is structured to wait for + // images to download but then you comment out all the async + // images your code would break. + + callCallbackIfReady(); + return textures; +} + +var textures = /*#__PURE__*/Object.freeze({ + __proto__: null, + setTextureDefaults_: setDefaults$1, + createSampler: createSampler, + createSamplers: createSamplers, + setSamplerParameters: setSamplerParameters, + createTexture: createTexture, + setEmptyTexture: setEmptyTexture, + setTextureFromArray: setTextureFromArray, + loadTextureFromUrl: loadTextureFromUrl, + setTextureFromElement: setTextureFromElement, + setTextureFilteringForSize: setTextureFilteringForSize, + setTextureParameters: setTextureParameters, + setDefaultTextureColor: setDefaultTextureColor, + createTextures: createTextures, + resizeTexture: resizeTexture, + canGenerateMipmap: canGenerateMipmap, + canFilter: canFilter, + getNumComponentsForFormat: getNumComponentsForFormat, + getBytesPerElementForInternalFormat: getBytesPerElementForInternalFormat, + getFormatAndTypeForInternalFormat: getFormatAndTypeForInternalFormat +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * Low level shader program related functions + * + * You should generally not need to use these functions. They are provided + * for those cases where you're doing something out of the ordinary + * and you need lower level access. + * + * For backward compatibility they are available at both `twgl.programs` and `twgl` + * itself + * + * See {@link module:twgl} for core functions + * + * @module twgl/programs + */ + +exports.textures = textures; +const error$1 = error; +const warn$1 = warn; + +function getElementById(id) { + return typeof document !== 'undefined' && document.getElementById ? document.getElementById(id) : null; +} + +const TEXTURE0 = 0x84c0; +const DYNAMIC_DRAW = 0x88e8; +const ARRAY_BUFFER$1 = 0x8892; +const ELEMENT_ARRAY_BUFFER$1 = 0x8893; +const UNIFORM_BUFFER = 0x8a11; +const TRANSFORM_FEEDBACK_BUFFER = 0x8c8e; +const TRANSFORM_FEEDBACK = 0x8e22; +const COMPILE_STATUS = 0x8b81; +const LINK_STATUS = 0x8b82; +const FRAGMENT_SHADER = 0x8b30; +const VERTEX_SHADER = 0x8b31; +const SEPARATE_ATTRIBS = 0x8c8d; +const ACTIVE_UNIFORMS = 0x8b86; +const ACTIVE_ATTRIBUTES = 0x8b89; +const TRANSFORM_FEEDBACK_VARYINGS = 0x8c83; +const ACTIVE_UNIFORM_BLOCKS = 0x8a36; +const UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8a44; +const UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8a46; +const UNIFORM_BLOCK_DATA_SIZE = 0x8a40; +const UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8a43; +const FLOAT$3 = 0x1406; +const FLOAT_VEC2 = 0x8B50; +const FLOAT_VEC3 = 0x8B51; +const FLOAT_VEC4 = 0x8B52; +const INT$3 = 0x1404; +const INT_VEC2 = 0x8B53; +const INT_VEC3 = 0x8B54; +const INT_VEC4 = 0x8B55; +const BOOL = 0x8B56; +const BOOL_VEC2 = 0x8B57; +const BOOL_VEC3 = 0x8B58; +const BOOL_VEC4 = 0x8B59; +const FLOAT_MAT2 = 0x8B5A; +const FLOAT_MAT3 = 0x8B5B; +const FLOAT_MAT4 = 0x8B5C; +const SAMPLER_2D = 0x8B5E; +const SAMPLER_CUBE = 0x8B60; +const SAMPLER_3D = 0x8B5F; +const SAMPLER_2D_SHADOW = 0x8B62; +const FLOAT_MAT2x3 = 0x8B65; +const FLOAT_MAT2x4 = 0x8B66; +const FLOAT_MAT3x2 = 0x8B67; +const FLOAT_MAT3x4 = 0x8B68; +const FLOAT_MAT4x2 = 0x8B69; +const FLOAT_MAT4x3 = 0x8B6A; +const SAMPLER_2D_ARRAY = 0x8DC1; +const SAMPLER_2D_ARRAY_SHADOW = 0x8DC4; +const SAMPLER_CUBE_SHADOW = 0x8DC5; +const UNSIGNED_INT$3 = 0x1405; +const UNSIGNED_INT_VEC2 = 0x8DC6; +const UNSIGNED_INT_VEC3 = 0x8DC7; +const UNSIGNED_INT_VEC4 = 0x8DC8; +const INT_SAMPLER_2D = 0x8DCA; +const INT_SAMPLER_3D = 0x8DCB; +const INT_SAMPLER_CUBE = 0x8DCC; +const INT_SAMPLER_2D_ARRAY = 0x8DCF; +const UNSIGNED_INT_SAMPLER_2D = 0x8DD2; +const UNSIGNED_INT_SAMPLER_3D = 0x8DD3; +const UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4; +const UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7; +const TEXTURE_2D$1 = 0x0DE1; +const TEXTURE_CUBE_MAP$1 = 0x8513; +const TEXTURE_3D$1 = 0x806F; +const TEXTURE_2D_ARRAY$1 = 0x8C1A; +const typeMap = {}; +/** + * Returns the corresponding bind point for a given sampler type + */ + +function getBindPointForSamplerType(gl, type) { + return typeMap[type].bindPoint; +} // This kind of sucks! If you could compose functions as in `var fn = gl[name];` +// this code could be a lot smaller but that is sadly really slow (T_T) + + +function floatSetter(gl, location) { + return function (v) { + gl.uniform1f(location, v); + }; +} + +function floatArraySetter(gl, location) { + return function (v) { + gl.uniform1fv(location, v); + }; +} + +function floatVec2Setter(gl, location) { + return function (v) { + gl.uniform2fv(location, v); + }; +} + +function floatVec3Setter(gl, location) { + return function (v) { + gl.uniform3fv(location, v); + }; +} + +function floatVec4Setter(gl, location) { + return function (v) { + gl.uniform4fv(location, v); + }; +} + +function intSetter(gl, location) { + return function (v) { + gl.uniform1i(location, v); + }; +} + +function intArraySetter(gl, location) { + return function (v) { + gl.uniform1iv(location, v); + }; +} + +function intVec2Setter(gl, location) { + return function (v) { + gl.uniform2iv(location, v); + }; +} + +function intVec3Setter(gl, location) { + return function (v) { + gl.uniform3iv(location, v); + }; +} + +function intVec4Setter(gl, location) { + return function (v) { + gl.uniform4iv(location, v); + }; +} + +function uintSetter(gl, location) { + return function (v) { + gl.uniform1ui(location, v); + }; +} + +function uintArraySetter(gl, location) { + return function (v) { + gl.uniform1uiv(location, v); + }; +} + +function uintVec2Setter(gl, location) { + return function (v) { + gl.uniform2uiv(location, v); + }; +} + +function uintVec3Setter(gl, location) { + return function (v) { + gl.uniform3uiv(location, v); + }; +} + +function uintVec4Setter(gl, location) { + return function (v) { + gl.uniform4uiv(location, v); + }; +} + +function floatMat2Setter(gl, location) { + return function (v) { + gl.uniformMatrix2fv(location, false, v); + }; +} + +function floatMat3Setter(gl, location) { + return function (v) { + gl.uniformMatrix3fv(location, false, v); + }; +} + +function floatMat4Setter(gl, location) { + return function (v) { + gl.uniformMatrix4fv(location, false, v); + }; +} + +function floatMat23Setter(gl, location) { + return function (v) { + gl.uniformMatrix2x3fv(location, false, v); + }; +} + +function floatMat32Setter(gl, location) { + return function (v) { + gl.uniformMatrix3x2fv(location, false, v); + }; +} + +function floatMat24Setter(gl, location) { + return function (v) { + gl.uniformMatrix2x4fv(location, false, v); + }; +} + +function floatMat42Setter(gl, location) { + return function (v) { + gl.uniformMatrix4x2fv(location, false, v); + }; +} + +function floatMat34Setter(gl, location) { + return function (v) { + gl.uniformMatrix3x4fv(location, false, v); + }; +} + +function floatMat43Setter(gl, location) { + return function (v) { + gl.uniformMatrix4x3fv(location, false, v); + }; +} + +function samplerSetter(gl, type, unit, location) { + const bindPoint = getBindPointForSamplerType(gl, type); + return isWebGL2(gl) ? function (textureOrPair) { + let texture; + let sampler; + + if (isTexture(gl, textureOrPair)) { + texture = textureOrPair; + sampler = null; + } else { + texture = textureOrPair.texture; + sampler = textureOrPair.sampler; + } + + gl.uniform1i(location, unit); + gl.activeTexture(TEXTURE0 + unit); + gl.bindTexture(bindPoint, texture); + gl.bindSampler(unit, sampler); + } : function (texture) { + gl.uniform1i(location, unit); + gl.activeTexture(TEXTURE0 + unit); + gl.bindTexture(bindPoint, texture); + }; +} + +function samplerArraySetter(gl, type, unit, location, size) { + const bindPoint = getBindPointForSamplerType(gl, type); + const units = new Int32Array(size); + + for (let ii = 0; ii < size; ++ii) { + units[ii] = unit + ii; + } + + return isWebGL2(gl) ? function (textures) { + gl.uniform1iv(location, units); + textures.forEach(function (textureOrPair, index) { + gl.activeTexture(TEXTURE0 + units[index]); + let texture; + let sampler; + + if (isTexture(gl, textureOrPair)) { + texture = textureOrPair; + sampler = null; + } else { + texture = textureOrPair.texture; + sampler = textureOrPair.sampler; + } + + gl.bindSampler(unit, sampler); + gl.bindTexture(bindPoint, texture); + }); + } : function (textures) { + gl.uniform1iv(location, units); + textures.forEach(function (texture, index) { + gl.activeTexture(TEXTURE0 + units[index]); + gl.bindTexture(bindPoint, texture); + }); + }; +} + +typeMap[FLOAT$3] = { + Type: Float32Array, + size: 4, + setter: floatSetter, + arraySetter: floatArraySetter +}; +typeMap[FLOAT_VEC2] = { + Type: Float32Array, + size: 8, + setter: floatVec2Setter +}; +typeMap[FLOAT_VEC3] = { + Type: Float32Array, + size: 12, + setter: floatVec3Setter +}; +typeMap[FLOAT_VEC4] = { + Type: Float32Array, + size: 16, + setter: floatVec4Setter +}; +typeMap[INT$3] = { + Type: Int32Array, + size: 4, + setter: intSetter, + arraySetter: intArraySetter +}; +typeMap[INT_VEC2] = { + Type: Int32Array, + size: 8, + setter: intVec2Setter +}; +typeMap[INT_VEC3] = { + Type: Int32Array, + size: 12, + setter: intVec3Setter +}; +typeMap[INT_VEC4] = { + Type: Int32Array, + size: 16, + setter: intVec4Setter +}; +typeMap[UNSIGNED_INT$3] = { + Type: Uint32Array, + size: 4, + setter: uintSetter, + arraySetter: uintArraySetter +}; +typeMap[UNSIGNED_INT_VEC2] = { + Type: Uint32Array, + size: 8, + setter: uintVec2Setter +}; +typeMap[UNSIGNED_INT_VEC3] = { + Type: Uint32Array, + size: 12, + setter: uintVec3Setter +}; +typeMap[UNSIGNED_INT_VEC4] = { + Type: Uint32Array, + size: 16, + setter: uintVec4Setter +}; +typeMap[BOOL] = { + Type: Uint32Array, + size: 4, + setter: intSetter, + arraySetter: intArraySetter +}; +typeMap[BOOL_VEC2] = { + Type: Uint32Array, + size: 8, + setter: intVec2Setter +}; +typeMap[BOOL_VEC3] = { + Type: Uint32Array, + size: 12, + setter: intVec3Setter +}; +typeMap[BOOL_VEC4] = { + Type: Uint32Array, + size: 16, + setter: intVec4Setter +}; +typeMap[FLOAT_MAT2] = { + Type: Float32Array, + size: 16, + setter: floatMat2Setter +}; +typeMap[FLOAT_MAT3] = { + Type: Float32Array, + size: 36, + setter: floatMat3Setter +}; +typeMap[FLOAT_MAT4] = { + Type: Float32Array, + size: 64, + setter: floatMat4Setter +}; +typeMap[FLOAT_MAT2x3] = { + Type: Float32Array, + size: 24, + setter: floatMat23Setter +}; +typeMap[FLOAT_MAT2x4] = { + Type: Float32Array, + size: 32, + setter: floatMat24Setter +}; +typeMap[FLOAT_MAT3x2] = { + Type: Float32Array, + size: 24, + setter: floatMat32Setter +}; +typeMap[FLOAT_MAT3x4] = { + Type: Float32Array, + size: 48, + setter: floatMat34Setter +}; +typeMap[FLOAT_MAT4x2] = { + Type: Float32Array, + size: 32, + setter: floatMat42Setter +}; +typeMap[FLOAT_MAT4x3] = { + Type: Float32Array, + size: 48, + setter: floatMat43Setter +}; +typeMap[SAMPLER_2D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D$1 +}; +typeMap[SAMPLER_CUBE] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_CUBE_MAP$1 +}; +typeMap[SAMPLER_3D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_3D$1 +}; +typeMap[SAMPLER_2D_SHADOW] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D$1 +}; +typeMap[SAMPLER_2D_ARRAY] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D_ARRAY$1 +}; +typeMap[SAMPLER_2D_ARRAY_SHADOW] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D_ARRAY$1 +}; +typeMap[SAMPLER_CUBE_SHADOW] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_CUBE_MAP$1 +}; +typeMap[INT_SAMPLER_2D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D$1 +}; +typeMap[INT_SAMPLER_3D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_3D$1 +}; +typeMap[INT_SAMPLER_CUBE] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_CUBE_MAP$1 +}; +typeMap[INT_SAMPLER_2D_ARRAY] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D_ARRAY$1 +}; +typeMap[UNSIGNED_INT_SAMPLER_2D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D$1 +}; +typeMap[UNSIGNED_INT_SAMPLER_3D] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_3D$1 +}; +typeMap[UNSIGNED_INT_SAMPLER_CUBE] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_CUBE_MAP$1 +}; +typeMap[UNSIGNED_INT_SAMPLER_2D_ARRAY] = { + Type: null, + size: 0, + setter: samplerSetter, + arraySetter: samplerArraySetter, + bindPoint: TEXTURE_2D_ARRAY$1 +}; + +function floatAttribSetter(gl, index) { + return function (b) { + if (b.value) { + gl.disableVertexAttribArray(index); + + switch (b.value.length) { + case 4: + gl.vertexAttrib4fv(index, b.value); + break; + + case 3: + gl.vertexAttrib3fv(index, b.value); + break; + + case 2: + gl.vertexAttrib2fv(index, b.value); + break; + + case 1: + gl.vertexAttrib1fv(index, b.value); + break; + + default: + throw new Error('the length of a float constant value must be between 1 and 4!'); + } + } else { + gl.bindBuffer(ARRAY_BUFFER$1, b.buffer); + gl.enableVertexAttribArray(index); + gl.vertexAttribPointer(index, b.numComponents || b.size, b.type || FLOAT$3, b.normalize || false, b.stride || 0, b.offset || 0); + + if (b.divisor !== undefined) { + gl.vertexAttribDivisor(index, b.divisor); + } + } + }; +} + +function intAttribSetter(gl, index) { + return function (b) { + if (b.value) { + gl.disableVertexAttribArray(index); + + if (b.value.length === 4) { + gl.vertexAttrib4iv(index, b.value); + } else { + throw new Error('The length of an integer constant value must be 4!'); + } + } else { + gl.bindBuffer(ARRAY_BUFFER$1, b.buffer); + gl.enableVertexAttribArray(index); + gl.vertexAttribIPointer(index, b.numComponents || b.size, b.type || INT$3, b.stride || 0, b.offset || 0); + + if (b.divisor !== undefined) { + gl.vertexAttribDivisor(index, b.divisor); + } + } + }; +} + +function uintAttribSetter(gl, index) { + return function (b) { + if (b.value) { + gl.disableVertexAttribArray(index); + + if (b.value.length === 4) { + gl.vertexAttrib4uiv(index, b.value); + } else { + throw new Error('The length of an unsigned integer constant value must be 4!'); + } + } else { + gl.bindBuffer(ARRAY_BUFFER$1, b.buffer); + gl.enableVertexAttribArray(index); + gl.vertexAttribIPointer(index, b.numComponents || b.size, b.type || UNSIGNED_INT$3, b.stride || 0, b.offset || 0); + + if (b.divisor !== undefined) { + gl.vertexAttribDivisor(index, b.divisor); + } + } + }; +} + +function matAttribSetter(gl, index, typeInfo) { + const defaultSize = typeInfo.size; + const count = typeInfo.count; + return function (b) { + gl.bindBuffer(ARRAY_BUFFER$1, b.buffer); + const numComponents = b.size || b.numComponents || defaultSize; + const size = numComponents / count; + const type = b.type || FLOAT$3; + const typeInfo = typeMap[type]; + const stride = typeInfo.size * numComponents; + const normalize = b.normalize || false; + const offset = b.offset || 0; + const rowOffset = stride / count; + + for (let i = 0; i < count; ++i) { + gl.enableVertexAttribArray(index + i); + gl.vertexAttribPointer(index + i, size, type, normalize, stride, offset + rowOffset * i); + + if (b.divisor !== undefined) { + gl.vertexAttribDivisor(index + i, b.divisor); + } + } + }; +} + +const attrTypeMap = {}; +attrTypeMap[FLOAT$3] = { + size: 4, + setter: floatAttribSetter +}; +attrTypeMap[FLOAT_VEC2] = { + size: 8, + setter: floatAttribSetter +}; +attrTypeMap[FLOAT_VEC3] = { + size: 12, + setter: floatAttribSetter +}; +attrTypeMap[FLOAT_VEC4] = { + size: 16, + setter: floatAttribSetter +}; +attrTypeMap[INT$3] = { + size: 4, + setter: intAttribSetter +}; +attrTypeMap[INT_VEC2] = { + size: 8, + setter: intAttribSetter +}; +attrTypeMap[INT_VEC3] = { + size: 12, + setter: intAttribSetter +}; +attrTypeMap[INT_VEC4] = { + size: 16, + setter: intAttribSetter +}; +attrTypeMap[UNSIGNED_INT$3] = { + size: 4, + setter: uintAttribSetter +}; +attrTypeMap[UNSIGNED_INT_VEC2] = { + size: 8, + setter: uintAttribSetter +}; +attrTypeMap[UNSIGNED_INT_VEC3] = { + size: 12, + setter: uintAttribSetter +}; +attrTypeMap[UNSIGNED_INT_VEC4] = { + size: 16, + setter: uintAttribSetter +}; +attrTypeMap[BOOL] = { + size: 4, + setter: intAttribSetter +}; +attrTypeMap[BOOL_VEC2] = { + size: 8, + setter: intAttribSetter +}; +attrTypeMap[BOOL_VEC3] = { + size: 12, + setter: intAttribSetter +}; +attrTypeMap[BOOL_VEC4] = { + size: 16, + setter: intAttribSetter +}; +attrTypeMap[FLOAT_MAT2] = { + size: 4, + setter: matAttribSetter, + count: 2 +}; +attrTypeMap[FLOAT_MAT3] = { + size: 9, + setter: matAttribSetter, + count: 3 +}; +attrTypeMap[FLOAT_MAT4] = { + size: 16, + setter: matAttribSetter, + count: 4 +}; +const errorRE = /ERROR:\s*\d+:(\d+)/gi; + +function addLineNumbersWithError(src, log = '', lineOffset = 0) { + // Note: Error message formats are not defined by any spec so this may or may not work. + const matches = [...log.matchAll(errorRE)]; + const lineNoToErrorMap = new Map(matches.map((m, ndx) => { + const lineNo = parseInt(m[1]); + const next = matches[ndx + 1]; + const end = next ? next.index : log.length; + const msg = log.substring(m.index, end); + return [lineNo - 1, msg]; + })); + return src.split('\n').map((line, lineNo) => { + const err = lineNoToErrorMap.get(lineNo); + return `${lineNo + 1 + lineOffset}: ${line}${err ? `\n\n^^^ ${err}` : ''}`; + }).join('\n'); +} +/** + * Error Callback + * @callback ErrorCallback + * @param {string} msg error message. + * @param {number} [lineOffset] amount to add to line number + * @memberOf module:twgl + */ + + +const spaceRE = /^[ \t]*\n/; +/** + * Loads a shader. + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {string} shaderSource The shader source. + * @param {number} shaderType The type of shader. + * @param {module:twgl.ErrorCallback} opt_errorCallback callback for errors. + * @return {WebGLShader} The created shader. + * @private + */ + +function loadShader(gl, shaderSource, shaderType, opt_errorCallback) { + const errFn = opt_errorCallback || error$1; // Create the shader object + + const shader = gl.createShader(shaderType); // Remove the first end of line because WebGL 2.0 requires + // #version 300 es + // as the first line. No whitespace allowed before that line + // so + // + // + // + // Has one line before it which is invalid according to GLSL ES 3.00 + // + + let lineOffset = 0; + + if (spaceRE.test(shaderSource)) { + lineOffset = 1; + shaderSource = shaderSource.replace(spaceRE, ''); + } // Load the shader source + + + gl.shaderSource(shader, shaderSource); // Compile the shader + + gl.compileShader(shader); // Check the compile status + + const compiled = gl.getShaderParameter(shader, COMPILE_STATUS); + + if (!compiled) { + // Something went wrong during compilation; get the error + const lastError = gl.getShaderInfoLog(shader); + errFn(`${addLineNumbersWithError(shaderSource, lastError, lineOffset)}\nError compiling ${glEnumToString(gl, shaderType)}: ${lastError}`); + gl.deleteShader(shader); + return null; + } + + return shader; +} +/** + * @typedef {Object} ProgramOptions + * @property {function(string)} [errorCallback] callback for errors + * @property {Object.} [attribLocations] a attribute name to location map + * @property {(module:twgl.BufferInfo|Object.|string[])} [transformFeedbackVaryings] If passed + * a BufferInfo will use the attribs names inside. If passed an object of AttribInfos will use the names from that object. Otherwise + * you can pass an array of names. + * @property {number} [transformFeedbackMode] the mode to pass `gl.transformFeedbackVaryings`. Defaults to `SEPARATE_ATTRIBS`. + * @memberOf module:twgl + */ + +/** + * Gets the program options based on all these optional arguments + * @param {module:twgl.ProgramOptions|string[]} [opt_attribs] Options for the program or an array of attribs names. Locations will be assigned by index if not passed in + * @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console + * on error. If you want something else pass an callback. It's passed an error message. + * @return {module:twgl.ProgramOptions} an instance of ProgramOptions based on the arguments passed in + * @private + */ + + +function getProgramOptions(opt_attribs, opt_locations, opt_errorCallback) { + let transformFeedbackVaryings; + let transformFeedbackMode; + + if (typeof opt_locations === 'function') { + opt_errorCallback = opt_locations; + opt_locations = undefined; + } + + if (typeof opt_attribs === 'function') { + opt_errorCallback = opt_attribs; + opt_attribs = undefined; + } else if (opt_attribs && !Array.isArray(opt_attribs)) { + // If we have an errorCallback we can just return this object + // Otherwise we need to construct one with default errorCallback + if (opt_attribs.errorCallback) { + return opt_attribs; + } + + const opt = opt_attribs; + opt_errorCallback = opt.errorCallback; + opt_attribs = opt.attribLocations; + transformFeedbackVaryings = opt.transformFeedbackVaryings; + transformFeedbackMode = opt.transformFeedbackMode; + } + + const options = { + errorCallback: opt_errorCallback || error$1, + transformFeedbackVaryings: transformFeedbackVaryings, + transformFeedbackMode: transformFeedbackMode + }; + + if (opt_attribs) { + let attribLocations = {}; + + if (Array.isArray(opt_attribs)) { + opt_attribs.forEach(function (attrib, ndx) { + attribLocations[attrib] = opt_locations ? opt_locations[ndx] : ndx; + }); + } else { + attribLocations = opt_attribs; + } + + options.attribLocations = attribLocations; + } + + return options; +} + +const defaultShaderType = ["VERTEX_SHADER", "FRAGMENT_SHADER"]; + +function getShaderTypeFromScriptType(gl, scriptType) { + if (scriptType.indexOf("frag") >= 0) { + return FRAGMENT_SHADER; + } else if (scriptType.indexOf("vert") >= 0) { + return VERTEX_SHADER; + } + + return undefined; +} + +function deleteShaders(gl, shaders) { + shaders.forEach(function (shader) { + gl.deleteShader(shader); + }); +} +/** + * Creates a program, attaches (and/or compiles) shaders, binds attrib locations, links the + * program and calls useProgram. + * + * NOTE: There are 4 signatures for this function + * + * twgl.createProgram(gl, [vs, fs], options); + * twgl.createProgram(gl, [vs, fs], opt_errFunc); + * twgl.createProgram(gl, [vs, fs], opt_attribs, opt_errFunc); + * twgl.createProgram(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {WebGLShader[]|string[]} shaders The shaders to attach, or element ids for their source, or strings that contain their source + * @param {module:twgl.ProgramOptions|string[]|module:twgl.ErrorCallback} [opt_attribs] Options for the program or an array of attribs names or an error callback. Locations will be assigned by index if not passed in + * @param {number[]} [opt_locations|module:twgl.ErrorCallback] The locations for the. A parallel array to opt_attribs letting you assign locations or an error callback. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console + * on error. If you want something else pass an callback. It's passed an error message. + * @return {WebGLProgram?} the created program or null if error. + * @memberOf module:twgl/programs + */ + + +function createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback) { + const progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback); + const realShaders = []; + const newShaders = []; + + for (let ndx = 0; ndx < shaders.length; ++ndx) { + let shader = shaders[ndx]; + + if (typeof shader === 'string') { + const elem = getElementById(shader); + const src = elem ? elem.text : shader; + let type = gl[defaultShaderType[ndx]]; + + if (elem && elem.type) { + type = getShaderTypeFromScriptType(gl, elem.type) || type; + } + + shader = loadShader(gl, src, type, progOptions.errorCallback); + newShaders.push(shader); + } + + if (isShader(gl, shader)) { + realShaders.push(shader); + } + } + + if (realShaders.length !== shaders.length) { + progOptions.errorCallback("not enough shaders for program"); + deleteShaders(gl, newShaders); + return null; + } + + const program = gl.createProgram(); + realShaders.forEach(function (shader) { + gl.attachShader(program, shader); + }); + + if (progOptions.attribLocations) { + Object.keys(progOptions.attribLocations).forEach(function (attrib) { + gl.bindAttribLocation(program, progOptions.attribLocations[attrib], attrib); + }); + } + + let varyings = progOptions.transformFeedbackVaryings; + + if (varyings) { + if (varyings.attribs) { + varyings = varyings.attribs; + } + + if (!Array.isArray(varyings)) { + varyings = Object.keys(varyings); + } + + gl.transformFeedbackVaryings(program, varyings, progOptions.transformFeedbackMode || SEPARATE_ATTRIBS); + } + + gl.linkProgram(program); // Check the link status + + const linked = gl.getProgramParameter(program, LINK_STATUS); + + if (!linked) { + // something went wrong with the link + const lastError = gl.getProgramInfoLog(program); + progOptions.errorCallback(`${realShaders.map(shader => { + const src = addLineNumbersWithError(gl.getShaderSource(shader), '', 0); + const type = gl.getShaderParameter(shader, gl.SHADER_TYPE); + return `${glEnumToString(gl, type)}\n${src}}`; + }).join('\n')}\nError in program linking: ${lastError}`); + gl.deleteProgram(program); + deleteShaders(gl, newShaders); + return null; + } + + return program; +} +/** + * Loads a shader from a script tag. + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {string} scriptId The id of the script tag. + * @param {number} [opt_shaderType] The type of shader. If not passed in it will + * be derived from the type of the script tag. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. + * @return {WebGLShader?} The created shader or null if error. + * @private + */ + + +function createShaderFromScript(gl, scriptId, opt_shaderType, opt_errorCallback) { + let shaderSource = ""; + const shaderScript = getElementById(scriptId); + + if (!shaderScript) { + throw new Error(`unknown script element: ${scriptId}`); + } + + shaderSource = shaderScript.text; + const shaderType = opt_shaderType || getShaderTypeFromScriptType(gl, shaderScript.type); + + if (!shaderType) { + throw new Error('unknown shader type'); + } + + return loadShader(gl, shaderSource, shaderType, opt_errorCallback); +} +/** + * Creates a program from 2 script tags. + * + * NOTE: There are 4 signatures for this function + * + * twgl.createProgramFromScripts(gl, [vs, fs], opt_options); + * twgl.createProgramFromScripts(gl, [vs, fs], opt_errFunc); + * twgl.createProgramFromScripts(gl, [vs, fs], opt_attribs, opt_errFunc); + * twgl.createProgramFromScripts(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext + * to use. + * @param {string[]} shaderScriptIds Array of ids of the script + * tags for the shaders. The first is assumed to be the + * vertex shader, the second the fragment shader. + * @param {module:twgl.ProgramOptions|string[]|module:twgl.ErrorCallback} [opt_attribs] Options for the program or an array of attribs names or an error callback. Locations will be assigned by index if not passed in + * @param {number[]} [opt_locations|module:twgl.ErrorCallback] The locations for the. A parallel array to opt_attribs letting you assign locations or an error callback. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console + * on error. If you want something else pass an callback. It's passed an error message. + * @return {WebGLProgram?} the created program or null if error. + * @memberOf module:twgl/programs + */ + + +function createProgramFromScripts(gl, shaderScriptIds, opt_attribs, opt_locations, opt_errorCallback) { + const progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback); + const shaders = []; + + for (let ii = 0; ii < shaderScriptIds.length; ++ii) { + const shader = createShaderFromScript(gl, shaderScriptIds[ii], gl[defaultShaderType[ii]], progOptions.errorCallback); + + if (!shader) { + return null; + } + + shaders.push(shader); + } + + return createProgram(gl, shaders, progOptions); +} +/** + * Creates a program from 2 sources. + * + * NOTE: There are 4 signatures for this function + * + * twgl.createProgramFromSource(gl, [vs, fs], opt_options); + * twgl.createProgramFromSource(gl, [vs, fs], opt_errFunc); + * twgl.createProgramFromSource(gl, [vs, fs], opt_attribs, opt_errFunc); + * twgl.createProgramFromSource(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext + * to use. + * @param {string[]} shaderSources Array of sources for the + * shaders. The first is assumed to be the vertex shader, + * the second the fragment shader. + * @param {module:twgl.ProgramOptions|string[]|module:twgl.ErrorCallback} [opt_attribs] Options for the program or an array of attribs names or an error callback. Locations will be assigned by index if not passed in + * @param {number[]} [opt_locations|module:twgl.ErrorCallback] The locations for the. A parallel array to opt_attribs letting you assign locations or an error callback. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console + * on error. If you want something else pass an callback. It's passed an error message. + * @return {WebGLProgram?} the created program or null if error. + * @memberOf module:twgl/programs + */ + + +function createProgramFromSources(gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) { + const progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback); + const shaders = []; + + for (let ii = 0; ii < shaderSources.length; ++ii) { + const shader = loadShader(gl, shaderSources[ii], gl[defaultShaderType[ii]], progOptions.errorCallback); + + if (!shader) { + return null; + } + + shaders.push(shader); + } + + return createProgram(gl, shaders, progOptions); +} +/** + * Returns true if attribute/uniform is a reserved/built in + * + * It makes no sense to me why GL returns these because it's + * illegal to call `gl.getUniformLocation` and `gl.getAttribLocation` + * with names that start with `gl_` (and `webgl_` in WebGL) + * + * I can only assume they are there because they might count + * when computing the number of uniforms/attributes used when you want to + * know if you are near the limit. That doesn't really make sense + * to me but the fact that these get returned are in the spec. + * + * @param {WebGLActiveInfo} info As returned from `gl.getActiveUniform` or + * `gl.getActiveAttrib`. + * @return {bool} true if it's reserved + * @private + */ + + +function isBuiltIn(info) { + const name = info.name; + return name.startsWith("gl_") || name.startsWith("webgl_"); +} +/** + * Creates setter functions for all uniforms of a shader + * program. + * + * @see {@link module:twgl.setUniforms} + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {WebGLProgram} program the program to create setters for. + * @returns {Object.} an object with a setter by name for each uniform + * @memberOf module:twgl/programs + */ + + +function createUniformSetters(gl, program) { + let textureUnit = 0; + /** + * Creates a setter for a uniform of the given program with it's + * location embedded in the setter. + * @param {WebGLProgram} program + * @param {WebGLUniformInfo} uniformInfo + * @returns {function} the created setter. + */ + + function createUniformSetter(program, uniformInfo, location) { + const isArray = uniformInfo.name.endsWith("[0]"); + const type = uniformInfo.type; + const typeInfo = typeMap[type]; + + if (!typeInfo) { + throw new Error(`unknown type: 0x${type.toString(16)}`); // we should never get here. + } + + let setter; + + if (typeInfo.bindPoint) { + // it's a sampler + const unit = textureUnit; + textureUnit += uniformInfo.size; + + if (isArray) { + setter = typeInfo.arraySetter(gl, type, unit, location, uniformInfo.size); + } else { + setter = typeInfo.setter(gl, type, unit, location, uniformInfo.size); + } + } else { + if (typeInfo.arraySetter && isArray) { + setter = typeInfo.arraySetter(gl, location); + } else { + setter = typeInfo.setter(gl, location); + } + } + + setter.location = location; + return setter; + } + + const uniformSetters = {}; + const numUniforms = gl.getProgramParameter(program, ACTIVE_UNIFORMS); + + for (let ii = 0; ii < numUniforms; ++ii) { + const uniformInfo = gl.getActiveUniform(program, ii); + + if (isBuiltIn(uniformInfo)) { + continue; + } + + let name = uniformInfo.name; // remove the array suffix. + + if (name.endsWith("[0]")) { + name = name.substr(0, name.length - 3); + } + + const location = gl.getUniformLocation(program, uniformInfo.name); // the uniform will have no location if it's in a uniform block + + if (location) { + uniformSetters[name] = createUniformSetter(program, uniformInfo, location); + } + } + + return uniformSetters; +} +/** + * @typedef {Object} TransformFeedbackInfo + * @property {number} index index of transform feedback + * @property {number} type GL type + * @property {number} size 1 - 4 + * @memberOf module:twgl + */ + +/** + * Create TransformFeedbackInfo for passing to bindTransformFeedbackInfo. + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {WebGLProgram} program an existing WebGLProgram. + * @return {Object} + * @memberOf module:twgl + */ + + +function createTransformFeedbackInfo(gl, program) { + const info = {}; + const numVaryings = gl.getProgramParameter(program, TRANSFORM_FEEDBACK_VARYINGS); + + for (let ii = 0; ii < numVaryings; ++ii) { + const varying = gl.getTransformFeedbackVarying(program, ii); + info[varying.name] = { + index: ii, + type: varying.type, + size: varying.size + }; + } + + return info; +} +/** + * Binds buffers for transform feedback. + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {(module:twgl.ProgramInfo|Object)} transformFeedbackInfo A ProgramInfo or TransformFeedbackInfo. + * @param {(module:twgl.BufferInfo|Object)} [bufferInfo] A BufferInfo or set of AttribInfos. + * @memberOf module:twgl + */ + + +function bindTransformFeedbackInfo(gl, transformFeedbackInfo, bufferInfo) { + if (transformFeedbackInfo.transformFeedbackInfo) { + transformFeedbackInfo = transformFeedbackInfo.transformFeedbackInfo; + } + + if (bufferInfo.attribs) { + bufferInfo = bufferInfo.attribs; + } + + for (const name in bufferInfo) { + const varying = transformFeedbackInfo[name]; + + if (varying) { + const buf = bufferInfo[name]; + + if (buf.offset) { + gl.bindBufferRange(TRANSFORM_FEEDBACK_BUFFER, varying.index, buf.buffer, buf.offset, buf.size); + } else { + gl.bindBufferBase(TRANSFORM_FEEDBACK_BUFFER, varying.index, buf.buffer); + } + } + } +} +/** + * Creates a transform feedback and sets the buffers + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {module:twgl.ProgramInfo} programInfo A ProgramInfo as returned from {@link module:twgl.createProgramInfo} + * @param {(module:twgl.BufferInfo|Object)} [bufferInfo] A BufferInfo or set of AttribInfos. + * @return {WebGLTransformFeedback} the created transform feedback + * @memberOf module:twgl + */ + + +function createTransformFeedback(gl, programInfo, bufferInfo) { + const tf = gl.createTransformFeedback(); + gl.bindTransformFeedback(TRANSFORM_FEEDBACK, tf); + gl.useProgram(programInfo.program); + bindTransformFeedbackInfo(gl, programInfo, bufferInfo); + gl.bindTransformFeedback(TRANSFORM_FEEDBACK, null); + return tf; +} +/** + * @typedef {Object} UniformData + * @property {number} type The WebGL type enum for this uniform + * @property {number} size The number of elements for this uniform + * @property {number} blockNdx The block index this uniform appears in + * @property {number} offset The byte offset in the block for this uniform's value + * @memberOf module:twgl + */ + +/** + * The specification for one UniformBlockObject + * + * @typedef {Object} BlockSpec + * @property {number} index The index of the block. + * @property {number} size The size in bytes needed for the block + * @property {number[]} uniformIndices The indices of the uniforms used by the block. These indices + * correspond to entries in a UniformData array in the {@link module:twgl.UniformBlockSpec}. + * @property {bool} usedByVertexShader Self explanatory + * @property {bool} usedByFragmentShader Self explanatory + * @property {bool} used Self explanatory + * @memberOf module:twgl + */ + +/** + * A `UniformBlockSpec` represents the data needed to create and bind + * UniformBlockObjects for a given program + * + * @typedef {Object} UniformBlockSpec + * @property {Object. blockSpecs The BlockSpec for each block by block name + * @property {UniformData[]} uniformData An array of data for each uniform by uniform index. + * @memberOf module:twgl + */ + +/** + * Creates a UniformBlockSpec for the given program. + * + * A UniformBlockSpec represents the data needed to create and bind + * UniformBlockObjects + * + * @param {WebGL2RenderingContext} gl A WebGL2 Rendering Context + * @param {WebGLProgram} program A WebGLProgram for a successfully linked program + * @return {module:twgl.UniformBlockSpec} The created UniformBlockSpec + * @memberOf module:twgl/programs + */ + + +function createUniformBlockSpecFromProgram(gl, program) { + const numUniforms = gl.getProgramParameter(program, ACTIVE_UNIFORMS); + const uniformData = []; + const uniformIndices = []; + + for (let ii = 0; ii < numUniforms; ++ii) { + uniformIndices.push(ii); + uniformData.push({}); + const uniformInfo = gl.getActiveUniform(program, ii); + + if (isBuiltIn(uniformInfo)) { + break; + } + + uniformData[ii].name = uniformInfo.name; + } + + [["UNIFORM_TYPE", "type"], ["UNIFORM_SIZE", "size"], // num elements + ["UNIFORM_BLOCK_INDEX", "blockNdx"], ["UNIFORM_OFFSET", "offset"]].forEach(function (pair) { + const pname = pair[0]; + const key = pair[1]; + gl.getActiveUniforms(program, uniformIndices, gl[pname]).forEach(function (value, ndx) { + uniformData[ndx][key] = value; + }); + }); + const blockSpecs = {}; + const numUniformBlocks = gl.getProgramParameter(program, ACTIVE_UNIFORM_BLOCKS); + + for (let ii = 0; ii < numUniformBlocks; ++ii) { + const name = gl.getActiveUniformBlockName(program, ii); + const blockSpec = { + index: gl.getUniformBlockIndex(program, name), + usedByVertexShader: gl.getActiveUniformBlockParameter(program, ii, UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER), + usedByFragmentShader: gl.getActiveUniformBlockParameter(program, ii, UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER), + size: gl.getActiveUniformBlockParameter(program, ii, UNIFORM_BLOCK_DATA_SIZE), + uniformIndices: gl.getActiveUniformBlockParameter(program, ii, UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) + }; + blockSpec.used = blockSpec.usedByVertexShader || blockSpec.usedByFragmentShader; + blockSpecs[name] = blockSpec; + } + + return { + blockSpecs: blockSpecs, + uniformData: uniformData + }; +} + +const arraySuffixRE = /\[\d+\]\.$/; // better way to check? + +const pad = (v, padding) => ((v + (padding - 1)) / padding | 0) * padding; + +function createUniformBlockUniformSetter(view, Type, typeSize, paddedSize, isArray) { + if (isArray) { + const numElements = typeSize / Type.BYTES_PER_ELEMENT; + const numPaddedElements = paddedSize / Type.BYTES_PER_ELEMENT; + return function (value) { + let dst = 0; + + for (let src = 0; src < value.length; src += numElements) { + for (let i = 0; i < numElements; ++i) { + view[dst + i] = value[src + i]; + } + + dst += numPaddedElements; + } + }; + } else { + return function (value) { + if (value.length) { + view.set(value); + } else { + view[0] = value; + } + }; + } +} +/** + * Represents a UniformBlockObject including an ArrayBuffer with all the uniform values + * and a corresponding WebGLBuffer to hold those values on the GPU + * + * @typedef {Object} UniformBlockInfo + * @property {string} name The name of the block + * @property {ArrayBuffer} array The array buffer that contains the uniform values + * @property {Float32Array} asFloat A float view on the array buffer. This is useful + * inspecting the contents of the buffer in the debugger. + * @property {WebGLBuffer} buffer A WebGL buffer that will hold a copy of the uniform values for rendering. + * @property {number} [offset] offset into buffer + * @property {Object} uniforms A uniform name to ArrayBufferView map. + * each Uniform has a correctly typed `ArrayBufferView` into array at the correct offset + * and length of that uniform. So for example a float uniform would have a 1 float `Float32Array` + * view. A single mat4 would have a 16 element `Float32Array` view. An ivec2 would have an + * `Int32Array` view, etc. + * @property {Object} setters A setter for this uniform. + * The reason to use setters is elements of arrays are padded to vec4 sizes which + * means if you want to set an array of 4 floats you'd need to set 16 values + * (or set elements 0, 4, 8, 12). In other words + * `someBlockInfo.uniforms.some4FloatArrayUniform.set([0, , , , 1, , , , 2, , , , 3])` + * where as the setter handles just passing in [0, 1, 2, 3] either directly as in + * `someBlockInfo.setter.some4FloatArrayUniform.set([0, 1, 2, 3])` (not recommended) + * or via {@link module:twgl.setBlockUniforms} + * @memberOf module:twgl + */ + +/** + * Creates a `UniformBlockInfo` for the specified block + * + * Note: **If the blockName matches no existing blocks a warning is printed to the console and a dummy + * `UniformBlockInfo` is returned**. This is because when debugging GLSL + * it is common to comment out large portions of a shader or for example set + * the final output to a constant. When that happens blocks get optimized out. + * If this function did not create dummy blocks your code would crash when debugging. + * + * @param {WebGL2RenderingContext} gl A WebGL2RenderingContext + * @param {WebGLProgram} program A WebGLProgram + * @param {module:twgl.UniformBlockSpec} uniformBlockSpec. A UniformBlockSpec as returned + * from {@link module:twgl.createUniformBlockSpecFromProgram}. + * @param {string} blockName The name of the block. + * @return {module:twgl.UniformBlockInfo} The created UniformBlockInfo + * @memberOf module:twgl/programs + */ + + +function createUniformBlockInfoFromProgram(gl, program, uniformBlockSpec, blockName) { + const blockSpecs = uniformBlockSpec.blockSpecs; + const uniformData = uniformBlockSpec.uniformData; + const blockSpec = blockSpecs[blockName]; + + if (!blockSpec) { + warn$1("no uniform block object named:", blockName); + return { + name: blockName, + uniforms: {} + }; + } + + const array = new ArrayBuffer(blockSpec.size); + const buffer = gl.createBuffer(); + const uniformBufferIndex = blockSpec.index; + gl.bindBuffer(UNIFORM_BUFFER, buffer); + gl.uniformBlockBinding(program, blockSpec.index, uniformBufferIndex); + let prefix = blockName + "."; + + if (arraySuffixRE.test(prefix)) { + prefix = prefix.replace(arraySuffixRE, "."); + } + + const uniforms = {}; + const setters = {}; + blockSpec.uniformIndices.forEach(function (uniformNdx) { + const data = uniformData[uniformNdx]; + const typeInfo = typeMap[data.type]; + const Type = typeInfo.Type; + const paddedSize = pad(typeInfo.size, 16); + const length = typeInfo.size + (data.size - 1) * paddedSize; + let name = data.name; + + if (name.startsWith(prefix)) { + name = name.substr(prefix.length); + } + + const isArray = name.endsWith('[0]'); + + if (isArray) { + name = name.substr(0, name.length - 3); + } + + const uniformView = new Type(array, data.offset, length / Type.BYTES_PER_ELEMENT); + uniforms[name] = uniformView; + setters[name] = createUniformBlockUniformSetter(uniformView, Type, typeInfo.size, paddedSize, isArray); + }); + return { + name: blockName, + array, + asFloat: new Float32Array(array), + // for debugging + buffer, + uniforms, + setters + }; +} +/** + * Creates a `UniformBlockInfo` for the specified block + * + * Note: **If the blockName matches no existing blocks a warning is printed to the console and a dummy + * `UniformBlockInfo` is returned**. This is because when debugging GLSL + * it is common to comment out large portions of a shader or for example set + * the final output to a constant. When that happens blocks get optimized out. + * If this function did not create dummy blocks your code would crash when debugging. + * + * @param {WebGL2RenderingContext} gl A WebGL2RenderingContext + * @param {module:twgl.ProgramInfo} programInfo a `ProgramInfo` + * as returned from {@link module:twgl.createProgramInfo} + * @param {string} blockName The name of the block. + * @return {module:twgl.UniformBlockInfo} The created UniformBlockInfo + * @memberOf module:twgl/programs + */ + + +function createUniformBlockInfo(gl, programInfo, blockName) { + return createUniformBlockInfoFromProgram(gl, programInfo.program, programInfo.uniformBlockSpec, blockName); +} +/** + * Binds a uniform block to the matching uniform block point. + * Matches by blocks by name so blocks must have the same name not just the same + * structure. + * + * If you have changed any values and you upload the values into the corresponding WebGLBuffer + * call {@link module:twgl.setUniformBlock} instead. + * + * @param {WebGL2RenderingContext} gl A WebGL 2 rendering context. + * @param {(module:twgl.ProgramInfo|module:twgl.UniformBlockSpec)} programInfo a `ProgramInfo` + * as returned from {@link module:twgl.createProgramInfo} or or `UniformBlockSpec` as + * returned from {@link module:twgl.createUniformBlockSpecFromProgram}. + * @param {module:twgl.UniformBlockInfo} uniformBlockInfo a `UniformBlockInfo` as returned from + * {@link module:twgl.createUniformBlockInfo}. + * @return {bool} true if buffer was bound. If the programInfo has no block with the same block name + * no buffer is bound. + * @memberOf module:twgl/programs + */ + + +function bindUniformBlock(gl, programInfo, uniformBlockInfo) { + const uniformBlockSpec = programInfo.uniformBlockSpec || programInfo; + const blockSpec = uniformBlockSpec.blockSpecs[uniformBlockInfo.name]; + + if (blockSpec) { + const bufferBindIndex = blockSpec.index; + gl.bindBufferRange(UNIFORM_BUFFER, bufferBindIndex, uniformBlockInfo.buffer, uniformBlockInfo.offset || 0, uniformBlockInfo.array.byteLength); + return true; + } + + return false; +} +/** + * Uploads the current uniform values to the corresponding WebGLBuffer + * and binds that buffer to the program's corresponding bind point for the uniform block object. + * + * If you haven't changed any values and you only need to bind the uniform block object + * call {@link module:twgl.bindUniformBlock} instead. + * + * @param {WebGL2RenderingContext} gl A WebGL 2 rendering context. + * @param {(module:twgl.ProgramInfo|module:twgl.UniformBlockSpec)} programInfo a `ProgramInfo` + * as returned from {@link module:twgl.createProgramInfo} or or `UniformBlockSpec` as + * returned from {@link module:twgl.createUniformBlockSpecFromProgram}. + * @param {module:twgl.UniformBlockInfo} uniformBlockInfo a `UniformBlockInfo` as returned from + * {@link module:twgl.createUniformBlockInfo}. + * @memberOf module:twgl/programs + */ + + +function setUniformBlock(gl, programInfo, uniformBlockInfo) { + if (bindUniformBlock(gl, programInfo, uniformBlockInfo)) { + gl.bufferData(UNIFORM_BUFFER, uniformBlockInfo.array, DYNAMIC_DRAW); + } +} +/** + * Sets values of a uniform block object + * + * @param {module:twgl.UniformBlockInfo} uniformBlockInfo A UniformBlockInfo as returned by {@link module:twgl.createUniformBlockInfo}. + * @param {Object.} values A uniform name to value map where the value is correct for the given + * type of uniform. So for example given a block like + * + * uniform SomeBlock { + * float someFloat; + * vec2 someVec2; + * vec3 someVec3Array[2]; + * int someInt; + * } + * + * You can set the values of the uniform block with + * + * twgl.setBlockUniforms(someBlockInfo, { + * someFloat: 12.3, + * someVec2: [1, 2], + * someVec3Array: [1, 2, 3, 4, 5, 6], + * someInt: 5, + * } + * + * Arrays can be JavaScript arrays or typed arrays + * + * Any name that doesn't match will be ignored + * @memberOf module:twgl/programs + */ + + +function setBlockUniforms(uniformBlockInfo, values) { + const setters = uniformBlockInfo.setters; + + for (const name in values) { + const setter = setters[name]; + + if (setter) { + const value = values[name]; + setter(value); + } + } +} +/** + * Set uniforms and binds related textures. + * + * example: + * + * const programInfo = createProgramInfo( + * gl, ["some-vs", "some-fs"]); + * + * const tex1 = gl.createTexture(); + * const tex2 = gl.createTexture(); + * + * ... assume we setup the textures with data ... + * + * const uniforms = { + * u_someSampler: tex1, + * u_someOtherSampler: tex2, + * u_someColor: [1,0,0,1], + * u_somePosition: [0,1,1], + * u_someMatrix: [ + * 1,0,0,0, + * 0,1,0,0, + * 0,0,1,0, + * 0,0,0,0, + * ], + * }; + * + * gl.useProgram(program); + * + * This will automatically bind the textures AND set the + * uniforms. + * + * twgl.setUniforms(programInfo, uniforms); + * + * For the example above it is equivalent to + * + * var texUnit = 0; + * gl.activeTexture(gl.TEXTURE0 + texUnit); + * gl.bindTexture(gl.TEXTURE_2D, tex1); + * gl.uniform1i(u_someSamplerLocation, texUnit++); + * gl.activeTexture(gl.TEXTURE0 + texUnit); + * gl.bindTexture(gl.TEXTURE_2D, tex2); + * gl.uniform1i(u_someSamplerLocation, texUnit++); + * gl.uniform4fv(u_someColorLocation, [1, 0, 0, 1]); + * gl.uniform3fv(u_somePositionLocation, [0, 1, 1]); + * gl.uniformMatrix4fv(u_someMatrix, false, [ + * 1,0,0,0, + * 0,1,0,0, + * 0,0,1,0, + * 0,0,0,0, + * ]); + * + * Note it is perfectly reasonable to call `setUniforms` multiple times. For example + * + * const uniforms = { + * u_someSampler: tex1, + * u_someOtherSampler: tex2, + * }; + * + * const moreUniforms { + * u_someColor: [1,0,0,1], + * u_somePosition: [0,1,1], + * u_someMatrix: [ + * 1,0,0,0, + * 0,1,0,0, + * 0,0,1,0, + * 0,0,0,0, + * ], + * }; + * + * twgl.setUniforms(programInfo, uniforms); + * twgl.setUniforms(programInfo, moreUniforms); + * + * You can also add WebGLSamplers to uniform samplers as in + * + * const uniforms = { + * u_someSampler: { + * texture: someWebGLTexture, + * sampler: someWebGLSampler, + * }, + * }; + * + * In which case both the sampler and texture will be bound to the + * same unit. + * + * @param {(module:twgl.ProgramInfo|Object.)} setters a `ProgramInfo` as returned from `createProgramInfo` or the setters returned from + * `createUniformSetters`. + * @param {Object.} values an object with values for the + * uniforms. + * You can pass multiple objects by putting them in an array or by calling with more arguments.For example + * + * const sharedUniforms = { + * u_fogNear: 10, + * u_projection: ... + * ... + * }; + * + * const localUniforms = { + * u_world: ... + * u_diffuseColor: ... + * }; + * + * twgl.setUniforms(programInfo, sharedUniforms, localUniforms); + * + * // is the same as + * + * twgl.setUniforms(programInfo, [sharedUniforms, localUniforms]); + * + * // is the same as + * + * twgl.setUniforms(programInfo, sharedUniforms); + * twgl.setUniforms(programInfo, localUniforms}; + * + * @memberOf module:twgl/programs + */ + + +function setUniforms(setters, values) { + // eslint-disable-line + const actualSetters = setters.uniformSetters || setters; + const numArgs = arguments.length; + + for (let aNdx = 1; aNdx < numArgs; ++aNdx) { + const values = arguments[aNdx]; + + if (Array.isArray(values)) { + const numValues = values.length; + + for (let ii = 0; ii < numValues; ++ii) { + setUniforms(actualSetters, values[ii]); + } + } else { + for (const name in values) { + const setter = actualSetters[name]; + + if (setter) { + setter(values[name]); + } + } + } + } +} +/** + * Alias for `setUniforms` + * @function + * @param {(module:twgl.ProgramInfo|Object.)} setters a `ProgramInfo` as returned from `createProgramInfo` or the setters returned from + * `createUniformSetters`. + * @param {Object.} values an object with values for the + * @memberOf module:twgl/programs + */ + + +const setUniformsAndBindTextures = setUniforms; +/** + * Creates setter functions for all attributes of a shader + * program. You can pass this to {@link module:twgl.setBuffersAndAttributes} to set all your buffers and attributes. + * + * @see {@link module:twgl.setAttributes} for example + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {WebGLProgram} program the program to create setters for. + * @return {Object.} an object with a setter for each attribute by name. + * @memberOf module:twgl/programs + */ + +exports.setUniformsAndBindTextures = setUniformsAndBindTextures; + +function createAttributeSetters(gl, program) { + const attribSetters = {}; + const numAttribs = gl.getProgramParameter(program, ACTIVE_ATTRIBUTES); + + for (let ii = 0; ii < numAttribs; ++ii) { + const attribInfo = gl.getActiveAttrib(program, ii); + + if (isBuiltIn(attribInfo)) { + continue; + } + + const index = gl.getAttribLocation(program, attribInfo.name); + const typeInfo = attrTypeMap[attribInfo.type]; + const setter = typeInfo.setter(gl, index, typeInfo); + setter.location = index; + attribSetters[attribInfo.name] = setter; + } + + return attribSetters; +} +/** + * Sets attributes and binds buffers (deprecated... use {@link module:twgl.setBuffersAndAttributes}) + * + * Example: + * + * const program = createProgramFromScripts( + * gl, ["some-vs", "some-fs"); + * + * const attribSetters = createAttributeSetters(program); + * + * const positionBuffer = gl.createBuffer(); + * const texcoordBuffer = gl.createBuffer(); + * + * const attribs = { + * a_position: {buffer: positionBuffer, numComponents: 3}, + * a_texcoord: {buffer: texcoordBuffer, numComponents: 2}, + * }; + * + * gl.useProgram(program); + * + * This will automatically bind the buffers AND set the + * attributes. + * + * setAttributes(attribSetters, attribs); + * + * Properties of attribs. For each attrib you can add + * properties: + * + * * type: the type of data in the buffer. Default = gl.FLOAT + * * normalize: whether or not to normalize the data. Default = false + * * stride: the stride. Default = 0 + * * offset: offset into the buffer. Default = 0 + * * divisor: the divisor for instances. Default = undefined + * + * For example if you had 3 value float positions, 2 value + * float texcoord and 4 value uint8 colors you'd setup your + * attribs like this + * + * const attribs = { + * a_position: {buffer: positionBuffer, numComponents: 3}, + * a_texcoord: {buffer: texcoordBuffer, numComponents: 2}, + * a_color: { + * buffer: colorBuffer, + * numComponents: 4, + * type: gl.UNSIGNED_BYTE, + * normalize: true, + * }, + * }; + * + * @param {Object.} setters Attribute setters as returned from createAttributeSetters + * @param {Object.} buffers AttribInfos mapped by attribute name. + * @memberOf module:twgl/programs + * @deprecated use {@link module:twgl.setBuffersAndAttributes} + */ + + +function setAttributes(setters, buffers) { + for (const name in buffers) { + const setter = setters[name]; + + if (setter) { + setter(buffers[name]); + } + } +} +/** + * Sets attributes and buffers including the `ELEMENT_ARRAY_BUFFER` if appropriate + * + * Example: + * + * const programInfo = createProgramInfo( + * gl, ["some-vs", "some-fs"); + * + * const arrays = { + * position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], }, + * texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1], }, + * }; + * + * const bufferInfo = createBufferInfoFromArrays(gl, arrays); + * + * gl.useProgram(programInfo.program); + * + * This will automatically bind the buffers AND set the + * attributes. + * + * setBuffersAndAttributes(gl, programInfo, bufferInfo); + * + * For the example above it is equivalent to + * + * gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + * gl.enableVertexAttribArray(a_positionLocation); + * gl.vertexAttribPointer(a_positionLocation, 3, gl.FLOAT, false, 0, 0); + * gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); + * gl.enableVertexAttribArray(a_texcoordLocation); + * gl.vertexAttribPointer(a_texcoordLocation, 4, gl.FLOAT, false, 0, 0); + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext. + * @param {(module:twgl.ProgramInfo|Object.)} setters A `ProgramInfo` as returned from {@link module:twgl.createProgramInfo} or Attribute setters as returned from {@link module:twgl.createAttributeSetters} + * @param {(module:twgl.BufferInfo|module:twgl.VertexArrayInfo)} buffers a `BufferInfo` as returned from {@link module:twgl.createBufferInfoFromArrays}. + * or a `VertexArrayInfo` as returned from {@link module:twgl.createVertexArrayInfo} + * @memberOf module:twgl/programs + */ + + +function setBuffersAndAttributes(gl, programInfo, buffers) { + if (buffers.vertexArrayObject) { + gl.bindVertexArray(buffers.vertexArrayObject); + } else { + setAttributes(programInfo.attribSetters || programInfo, buffers.attribs); + + if (buffers.indices) { + gl.bindBuffer(ELEMENT_ARRAY_BUFFER$1, buffers.indices); + } + } +} +/** + * @typedef {Object} ProgramInfo + * @property {WebGLProgram} program A shader program + * @property {Object} uniformSetters object of setters as returned from createUniformSetters, + * @property {Object} attribSetters object of setters as returned from createAttribSetters, + * @property {module:twgl.UniformBlockSpec} [uniformBlockSpace] a uniform block spec for making UniformBlockInfos with createUniformBlockInfo etc.. + * @property {Object} [transformFeedbackInfo] info for transform feedbacks + * @memberOf module:twgl + */ + +/** + * Creates a ProgramInfo from an existing program. + * + * A ProgramInfo contains + * + * programInfo = { + * program: WebGLProgram, + * uniformSetters: object of setters as returned from createUniformSetters, + * attribSetters: object of setters as returned from createAttribSetters, + * } + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext + * to use. + * @param {WebGLProgram} program an existing WebGLProgram. + * @return {module:twgl.ProgramInfo} The created ProgramInfo. + * @memberOf module:twgl/programs + */ + + +function createProgramInfoFromProgram(gl, program) { + const uniformSetters = createUniformSetters(gl, program); + const attribSetters = createAttributeSetters(gl, program); + const programInfo = { + program: program, + uniformSetters: uniformSetters, + attribSetters: attribSetters + }; + + if (isWebGL2(gl)) { + programInfo.uniformBlockSpec = createUniformBlockSpecFromProgram(gl, program); + programInfo.transformFeedbackInfo = createTransformFeedbackInfo(gl, program); + } + + return programInfo; +} +/** + * Creates a ProgramInfo from 2 sources. + * + * A ProgramInfo contains + * + * programInfo = { + * program: WebGLProgram, + * uniformSetters: object of setters as returned from createUniformSetters, + * attribSetters: object of setters as returned from createAttribSetters, + * } + * + * NOTE: There are 4 signatures for this function + * + * twgl.createProgramInfo(gl, [vs, fs], options); + * twgl.createProgramInfo(gl, [vs, fs], opt_errFunc); + * twgl.createProgramInfo(gl, [vs, fs], opt_attribs, opt_errFunc); + * twgl.createProgramInfo(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc); + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext + * to use. + * @param {string[]} shaderSources Array of sources for the + * shaders or ids. The first is assumed to be the vertex shader, + * the second the fragment shader. + * @param {module:twgl.ProgramOptions|string[]|module:twgl.ErrorCallback} [opt_attribs] Options for the program or an array of attribs names or an error callback. Locations will be assigned by index if not passed in + * @param {number[]} [opt_locations|module:twgl.ErrorCallback] The locations for the. A parallel array to opt_attribs letting you assign locations or an error callback. + * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console + * on error. If you want something else pass an callback. It's passed an error message. + * @return {module:twgl.ProgramInfo?} The created ProgramInfo or null if it failed to link or compile + * @memberOf module:twgl/programs + */ + + +function createProgramInfo(gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) { + const progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback); + let good = true; + shaderSources = shaderSources.map(function (source) { + // Lets assume if there is no \n it's an id + if (source.indexOf("\n") < 0) { + const script = getElementById(source); + + if (!script) { + progOptions.errorCallback("no element with id: " + source); + good = false; + } else { + source = script.text; + } + } + + return source; + }); + + if (!good) { + return null; + } + + const program = createProgramFromSources(gl, shaderSources, progOptions); + + if (!program) { + return null; + } + + return createProgramInfoFromProgram(gl, program); +} + +var programs = /*#__PURE__*/Object.freeze({ + __proto__: null, + createAttributeSetters: createAttributeSetters, + createProgram: createProgram, + createProgramFromScripts: createProgramFromScripts, + createProgramFromSources: createProgramFromSources, + createProgramInfo: createProgramInfo, + createProgramInfoFromProgram: createProgramInfoFromProgram, + createUniformSetters: createUniformSetters, + createUniformBlockSpecFromProgram: createUniformBlockSpecFromProgram, + createUniformBlockInfoFromProgram: createUniformBlockInfoFromProgram, + createUniformBlockInfo: createUniformBlockInfo, + createTransformFeedback: createTransformFeedback, + createTransformFeedbackInfo: createTransformFeedbackInfo, + bindTransformFeedbackInfo: bindTransformFeedbackInfo, + setAttributes: setAttributes, + setBuffersAndAttributes: setBuffersAndAttributes, + setUniforms: setUniforms, + setUniformsAndBindTextures: setUniformsAndBindTextures, + setUniformBlock: setUniformBlock, + setBlockUniforms: setBlockUniforms, + bindUniformBlock: bindUniformBlock +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +exports.programs = programs; +const TRIANGLES = 0x0004; +const UNSIGNED_SHORT$3 = 0x1403; +/** + * Drawing related functions + * + * For backward compatibility they are available at both `twgl.draw` and `twgl` + * itself + * + * See {@link module:twgl} for core functions + * + * @module twgl/draw + */ + +/** + * Calls `gl.drawElements` or `gl.drawArrays`, whichever is appropriate + * + * normally you'd call `gl.drawElements` or `gl.drawArrays` yourself + * but calling this means if you switch from indexed data to non-indexed + * data you don't have to remember to update your draw call. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {(module:twgl.BufferInfo|module:twgl.VertexArrayInfo)} bufferInfo A BufferInfo as returned from {@link module:twgl.createBufferInfoFromArrays} or + * a VertexArrayInfo as returned from {@link module:twgl.createVertexArrayInfo} + * @param {number} [type] eg (gl.TRIANGLES, gl.LINES, gl.POINTS, gl.TRIANGLE_STRIP, ...). Defaults to `gl.TRIANGLES` + * @param {number} [count] An optional count. Defaults to bufferInfo.numElements + * @param {number} [offset] An optional offset. Defaults to 0. + * @param {number} [instanceCount] An optional instanceCount. if set then `drawArraysInstanced` or `drawElementsInstanced` will be called + * @memberOf module:twgl/draw + */ + +function drawBufferInfo(gl, bufferInfo, type, count, offset, instanceCount) { + type = type === undefined ? TRIANGLES : type; + const indices = bufferInfo.indices; + const elementType = bufferInfo.elementType; + const numElements = count === undefined ? bufferInfo.numElements : count; + offset = offset === undefined ? 0 : offset; + + if (elementType || indices) { + if (instanceCount !== undefined) { + gl.drawElementsInstanced(type, numElements, elementType === undefined ? UNSIGNED_SHORT$3 : bufferInfo.elementType, offset, instanceCount); + } else { + gl.drawElements(type, numElements, elementType === undefined ? UNSIGNED_SHORT$3 : bufferInfo.elementType, offset); + } + } else { + if (instanceCount !== undefined) { + gl.drawArraysInstanced(type, offset, numElements, instanceCount); + } else { + gl.drawArrays(type, offset, numElements); + } + } +} +/** + * A DrawObject is useful for putting objects in to an array and passing them to {@link module:twgl.drawObjectList}. + * + * You need either a `BufferInfo` or a `VertexArrayInfo`. + * + * @typedef {Object} DrawObject + * @property {boolean} [active] whether or not to draw. Default = `true` (must be `false` to be not true). In other words `undefined` = `true` + * @property {number} [type] type to draw eg. `gl.TRIANGLES`, `gl.LINES`, etc... + * @property {module:twgl.ProgramInfo} programInfo A ProgramInfo as returned from {@link module:twgl.createProgramInfo} + * @property {module:twgl.BufferInfo} [bufferInfo] A BufferInfo as returned from {@link module:twgl.createBufferInfoFromArrays} + * @property {module:twgl.VertexArrayInfo} [vertexArrayInfo] A VertexArrayInfo as returned from {@link module:twgl.createVertexArrayInfo} + * @property {Object} uniforms The values for the uniforms. + * You can pass multiple objects by putting them in an array. For example + * + * var sharedUniforms = { + * u_fogNear: 10, + * u_projection: ... + * ... + * }; + * + * var localUniforms = { + * u_world: ... + * u_diffuseColor: ... + * }; + * + * var drawObj = { + * ... + * uniforms: [sharedUniforms, localUniforms], + * }; + * + * @property {number} [offset] the offset to pass to `gl.drawArrays` or `gl.drawElements`. Defaults to 0. + * @property {number} [count] the count to pass to `gl.drawArrays` or `gl.drawElements`. Defaults to bufferInfo.numElements. + * @property {number} [instanceCount] the number of instances. Defaults to undefined. + * @memberOf module:twgl + */ + +/** + * Draws a list of objects + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {DrawObject[]} objectsToDraw an array of objects to draw. + * @memberOf module:twgl/draw + */ + + +function drawObjectList(gl, objectsToDraw) { + let lastUsedProgramInfo = null; + let lastUsedBufferInfo = null; + objectsToDraw.forEach(function (object) { + if (object.active === false) { + return; + } + + const programInfo = object.programInfo; + const bufferInfo = object.vertexArrayInfo || object.bufferInfo; + let bindBuffers = false; + const type = object.type === undefined ? TRIANGLES : object.type; + + if (programInfo !== lastUsedProgramInfo) { + lastUsedProgramInfo = programInfo; + gl.useProgram(programInfo.program); // We have to rebind buffers when changing programs because we + // only bind buffers the program uses. So if 2 programs use the same + // bufferInfo but the 1st one uses only positions the when the + // we switch to the 2nd one some of the attributes will not be on. + + bindBuffers = true; + } // Setup all the needed attributes. + + + if (bindBuffers || bufferInfo !== lastUsedBufferInfo) { + if (lastUsedBufferInfo && lastUsedBufferInfo.vertexArrayObject && !bufferInfo.vertexArrayObject) { + gl.bindVertexArray(null); + } + + lastUsedBufferInfo = bufferInfo; + setBuffersAndAttributes(gl, programInfo, bufferInfo); + } // Set the uniforms. + + + setUniforms(programInfo, object.uniforms); // Draw + + drawBufferInfo(gl, bufferInfo, type, object.count, object.offset, object.instanceCount); + }); + + if (lastUsedBufferInfo && lastUsedBufferInfo.vertexArrayObject) { + gl.bindVertexArray(null); + } +} + +var draw = /*#__PURE__*/Object.freeze({ + __proto__: null, + drawBufferInfo: drawBufferInfo, + drawObjectList: drawObjectList +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +exports.draw = draw; +const FRAMEBUFFER = 0x8d40; +const RENDERBUFFER = 0x8d41; +const TEXTURE_2D$2 = 0x0de1; +const UNSIGNED_BYTE$3 = 0x1401; +/* PixelFormat */ + +const DEPTH_COMPONENT$1 = 0x1902; +const RGBA$1 = 0x1908; +const DEPTH_COMPONENT24$1 = 0x81a6; +const DEPTH_COMPONENT32F$1 = 0x8cac; +const DEPTH24_STENCIL8$1 = 0x88f0; +const DEPTH32F_STENCIL8$1 = 0x8cad; +/* Framebuffer Object. */ + +const RGBA4$1 = 0x8056; +const RGB5_A1$1 = 0x8057; +const RGB565$1 = 0x8D62; +const DEPTH_COMPONENT16$1 = 0x81A5; +const STENCIL_INDEX = 0x1901; +const STENCIL_INDEX8 = 0x8D48; +const DEPTH_STENCIL$1 = 0x84F9; +const COLOR_ATTACHMENT0 = 0x8CE0; +const DEPTH_ATTACHMENT = 0x8D00; +const STENCIL_ATTACHMENT = 0x8D20; +const DEPTH_STENCIL_ATTACHMENT = 0x821A; +/* TextureWrapMode */ + +const CLAMP_TO_EDGE$1 = 0x812F; +/* TextureMagFilter */ + +const LINEAR$1 = 0x2601; +/** + * The options for a framebuffer attachment. + * + * Note: For a `format` that is a texture include all the texture + * options from {@link module:twgl.TextureOptions} for example + * `min`, `mag`, `clamp`, etc... Note that unlike {@link module:twgl.TextureOptions} + * `auto` defaults to `false` for attachment textures but `min` and `mag` default + * to `gl.LINEAR` and `wrap` defaults to `CLAMP_TO_EDGE` + * + * @typedef {Object} AttachmentOptions + * @property {number} [attachmentPoint] The attachment point. Defaults + * to `gl.COLOR_ATTACHMENT0 + ndx` unless type is a depth or stencil type + * then it's gl.DEPTH_ATTACHMENT or `gl.DEPTH_STENCIL_ATTACHMENT` depending + * on the format or attachment type. + * @property {number} [format] The format. If one of `gl.RGBA4`, + * `gl.RGB565`, `gl.RGB5_A1`, `gl.DEPTH_COMPONENT16`, + * `gl.STENCIL_INDEX8` or `gl.DEPTH_STENCIL` then will create a + * renderbuffer. Otherwise will create a texture. Default = `gl.RGBA` + * @property {number} [type] The type. Used for texture. Default = `gl.UNSIGNED_BYTE`. + * @property {number} [target] The texture target for `gl.framebufferTexture2D`. + * Defaults to `gl.TEXTURE_2D`. Set to appropriate face for cube maps. + * @property {number} [level] level for `gl.framebufferTexture2D`. Defaults to 0. + * @property {number} [layer] layer for `gl.framebufferTextureLayer`. Defaults to undefined. + * If set then `gl.framebufferTextureLayer` is called, if not then `gl.framebufferTexture2D` + * @property {WebGLObject} [attachment] An existing renderbuffer or texture. + * If provided will attach this Object. This allows you to share + * attachments across framebuffers. + * @memberOf module:twgl + * @mixes module:twgl.TextureOptions + */ + +const defaultAttachments = [{ + format: RGBA$1, + type: UNSIGNED_BYTE$3, + min: LINEAR$1, + wrap: CLAMP_TO_EDGE$1 +}, { + format: DEPTH_STENCIL$1 +}]; +const attachmentsByFormat = {}; +attachmentsByFormat[DEPTH_STENCIL$1] = DEPTH_STENCIL_ATTACHMENT; +attachmentsByFormat[STENCIL_INDEX] = STENCIL_ATTACHMENT; +attachmentsByFormat[STENCIL_INDEX8] = STENCIL_ATTACHMENT; +attachmentsByFormat[DEPTH_COMPONENT$1] = DEPTH_ATTACHMENT; +attachmentsByFormat[DEPTH_COMPONENT16$1] = DEPTH_ATTACHMENT; +attachmentsByFormat[DEPTH_COMPONENT24$1] = DEPTH_ATTACHMENT; +attachmentsByFormat[DEPTH_COMPONENT32F$1] = DEPTH_ATTACHMENT; +attachmentsByFormat[DEPTH24_STENCIL8$1] = DEPTH_STENCIL_ATTACHMENT; +attachmentsByFormat[DEPTH32F_STENCIL8$1] = DEPTH_STENCIL_ATTACHMENT; + +function getAttachmentPointForFormat(format, internalFormat) { + return attachmentsByFormat[format] || attachmentsByFormat[internalFormat]; +} + +const renderbufferFormats = {}; +renderbufferFormats[RGBA4$1] = true; +renderbufferFormats[RGB5_A1$1] = true; +renderbufferFormats[RGB565$1] = true; +renderbufferFormats[DEPTH_STENCIL$1] = true; +renderbufferFormats[DEPTH_COMPONENT16$1] = true; +renderbufferFormats[STENCIL_INDEX] = true; +renderbufferFormats[STENCIL_INDEX8] = true; + +function isRenderbufferFormat(format) { + return renderbufferFormats[format]; +} +/** + * @typedef {Object} FramebufferInfo + * @property {WebGLFramebuffer} framebuffer The WebGLFramebuffer for this framebufferInfo + * @property {WebGLObject[]} attachments The created attachments in the same order as passed in to {@link module:twgl.createFramebufferInfo}. + * @property {number} width The width of the framebuffer and its attachments + * @property {number} height The width of the framebuffer and its attachments + * @memberOf module:twgl + */ + +/** + * Creates a framebuffer and attachments. + * + * This returns a {@link module:twgl.FramebufferInfo} because it needs to return the attachments as well as the framebuffer. + * + * The simplest usage + * + * // create an RGBA/UNSIGNED_BYTE texture and DEPTH_STENCIL renderbuffer + * const fbi = twgl.createFramebufferInfo(gl); + * + * More complex usage + * + * // create an RGB565 renderbuffer and a STENCIL_INDEX8 renderbuffer + * const attachments = [ + * { format: RGB565, mag: NEAREST }, + * { format: STENCIL_INDEX8 }, + * ] + * const fbi = twgl.createFramebufferInfo(gl, attachments); + * + * Passing in a specific size + * + * const width = 256; + * const height = 256; + * const fbi = twgl.createFramebufferInfo(gl, attachments, width, height); + * + * **Note!!** It is up to you to check if the framebuffer is renderable by calling `gl.checkFramebufferStatus`. + * [WebGL1 only guarantees 3 combinations of attachments work](https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6). + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.AttachmentOptions[]} [attachments] which attachments to create. If not provided the default is a framebuffer with an + * `RGBA`, `UNSIGNED_BYTE` texture `COLOR_ATTACHMENT0` and a `DEPTH_STENCIL` renderbuffer `DEPTH_STENCIL_ATTACHMENT`. + * @param {number} [width] the width for the attachments. Default = size of drawingBuffer + * @param {number} [height] the height for the attachments. Default = size of drawingBuffer + * @return {module:twgl.FramebufferInfo} the framebuffer and attachments. + * @memberOf module:twgl/framebuffers + */ + + +function createFramebufferInfo(gl, attachments, width, height) { + const target = FRAMEBUFFER; + const fb = gl.createFramebuffer(); + gl.bindFramebuffer(target, fb); + width = width || gl.drawingBufferWidth; + height = height || gl.drawingBufferHeight; + attachments = attachments || defaultAttachments; + let colorAttachmentCount = 0; + const framebufferInfo = { + framebuffer: fb, + attachments: [], + width: width, + height: height + }; + attachments.forEach(function (attachmentOptions) { + let attachment = attachmentOptions.attachment; + const format = attachmentOptions.format; + let attachmentPoint = attachmentOptions.attachmentPoint || getAttachmentPointForFormat(format, attachmentOptions.internalFormat); + + if (!attachmentPoint) { + attachmentPoint = COLOR_ATTACHMENT0 + colorAttachmentCount++; + } + + if (!attachment) { + if (isRenderbufferFormat(format)) { + attachment = gl.createRenderbuffer(); + gl.bindRenderbuffer(RENDERBUFFER, attachment); + gl.renderbufferStorage(RENDERBUFFER, format, width, height); + } else { + const textureOptions = Object.assign({}, attachmentOptions); + textureOptions.width = width; + textureOptions.height = height; + + if (textureOptions.auto === undefined) { + textureOptions.auto = false; + textureOptions.min = textureOptions.min || textureOptions.minMag || LINEAR$1; + textureOptions.mag = textureOptions.mag || textureOptions.minMag || LINEAR$1; + textureOptions.wrapS = textureOptions.wrapS || textureOptions.wrap || CLAMP_TO_EDGE$1; + textureOptions.wrapT = textureOptions.wrapT || textureOptions.wrap || CLAMP_TO_EDGE$1; + } + + attachment = createTexture(gl, textureOptions); + } + } + + if (isRenderbuffer(gl, attachment)) { + gl.framebufferRenderbuffer(target, attachmentPoint, RENDERBUFFER, attachment); + } else if (isTexture(gl, attachment)) { + if (attachmentOptions.layer !== undefined) { + gl.framebufferTextureLayer(target, attachmentPoint, attachment, attachmentOptions.level || 0, attachmentOptions.layer); + } else { + gl.framebufferTexture2D(target, attachmentPoint, attachmentOptions.target || TEXTURE_2D$2, attachment, attachmentOptions.level || 0); + } + } else { + throw new Error('unknown attachment type'); + } + + framebufferInfo.attachments.push(attachment); + }); + return framebufferInfo; +} +/** + * Resizes the attachments of a framebuffer. + * + * You need to pass in the same `attachments` as you passed in {@link module:twgl.createFramebufferInfo} + * because TWGL has no idea the format/type of each attachment. + * + * The simplest usage + * + * // create an RGBA/UNSIGNED_BYTE texture and DEPTH_STENCIL renderbuffer + * const fbi = twgl.createFramebufferInfo(gl); + * + * ... + * + * function render() { + * if (twgl.resizeCanvasToDisplaySize(gl.canvas)) { + * // resize the attachments + * twgl.resizeFramebufferInfo(gl, fbi); + * } + * + * More complex usage + * + * // create an RGB565 renderbuffer and a STENCIL_INDEX8 renderbuffer + * const attachments = [ + * { format: RGB565, mag: NEAREST }, + * { format: STENCIL_INDEX8 }, + * ] + * const fbi = twgl.createFramebufferInfo(gl, attachments); + * + * ... + * + * function render() { + * if (twgl.resizeCanvasToDisplaySize(gl.canvas)) { + * // resize the attachments to match + * twgl.resizeFramebufferInfo(gl, fbi, attachments); + * } + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.FramebufferInfo} framebufferInfo a framebufferInfo as returned from {@link module:twgl.createFramebufferInfo}. + * @param {module:twgl.AttachmentOptions[]} [attachments] the same attachments options as passed to {@link module:twgl.createFramebufferInfo}. + * @param {number} [width] the width for the attachments. Default = size of drawingBuffer + * @param {number} [height] the height for the attachments. Default = size of drawingBuffer + * @memberOf module:twgl/framebuffers + */ + + +function resizeFramebufferInfo(gl, framebufferInfo, attachments, width, height) { + width = width || gl.drawingBufferWidth; + height = height || gl.drawingBufferHeight; + framebufferInfo.width = width; + framebufferInfo.height = height; + attachments = attachments || defaultAttachments; + attachments.forEach(function (attachmentOptions, ndx) { + const attachment = framebufferInfo.attachments[ndx]; + const format = attachmentOptions.format; + + if (isRenderbuffer(gl, attachment)) { + gl.bindRenderbuffer(RENDERBUFFER, attachment); + gl.renderbufferStorage(RENDERBUFFER, format, width, height); + } else if (isTexture(gl, attachment)) { + resizeTexture(gl, attachment, attachmentOptions, width, height); + } else { + throw new Error('unknown attachment type'); + } + }); +} +/** + * Binds a framebuffer + * + * This function pretty much solely exists because I spent hours + * trying to figure out why something I wrote wasn't working only + * to realize I forget to set the viewport dimensions. + * My hope is this function will fix that. + * + * It is effectively the same as + * + * gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebufferInfo.framebuffer); + * gl.viewport(0, 0, someFramebufferInfo.width, someFramebufferInfo.height); + * + * @param {WebGLRenderingContext} gl the WebGLRenderingContext + * @param {module:twgl.FramebufferInfo|null} [framebufferInfo] a framebufferInfo as returned from {@link module:twgl.createFramebufferInfo}. + * If falsy will bind the canvas. + * @param {number} [target] The target. If not passed `gl.FRAMEBUFFER` will be used. + * @memberOf module:twgl/framebuffers + */ + + +function bindFramebufferInfo(gl, framebufferInfo, target) { + target = target || FRAMEBUFFER; + + if (framebufferInfo) { + gl.bindFramebuffer(target, framebufferInfo.framebuffer); + gl.viewport(0, 0, framebufferInfo.width, framebufferInfo.height); + } else { + gl.bindFramebuffer(target, null); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + } +} + +var framebuffers = /*#__PURE__*/Object.freeze({ + __proto__: null, + bindFramebufferInfo: bindFramebufferInfo, + createFramebufferInfo: createFramebufferInfo, + resizeFramebufferInfo: resizeFramebufferInfo +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * vertex array object related functions + * + * You should generally not need to use these functions. They are provided + * for those cases where you're doing something out of the ordinary + * and you need lower level access. + * + * For backward compatibility they are available at both `twgl.attributes` and `twgl` + * itself + * + * See {@link module:twgl} for core functions + * + * @module twgl/vertexArrays + */ + +exports.framebuffers = framebuffers; +const ELEMENT_ARRAY_BUFFER$2 = 0x8893; +/** + * @typedef {Object} VertexArrayInfo + * @property {number} numElements The number of elements to pass to `gl.drawArrays` or `gl.drawElements`. + * @property {number} [elementType] The type of indices `UNSIGNED_BYTE`, `UNSIGNED_SHORT` etc.. + * @property {WebGLVertexArrayObject} [vertexArrayObject] a vertex array object + * @memberOf module:twgl + */ + +/** + * Creates a VertexArrayInfo from a BufferInfo and one or more ProgramInfos + * + * This can be passed to {@link module:twgl.setBuffersAndAttributes} and to + * {@link module:twgl:drawBufferInfo}. + * + * > **IMPORTANT:** Vertex Array Objects are **not** a direct analog for a BufferInfo. Vertex Array Objects + * assign buffers to specific attributes at creation time. That means they can only be used with programs + * who's attributes use the same attribute locations for the same purposes. + * + * > Bind your attribute locations by passing an array of attribute names to {@link module:twgl.createProgramInfo} + * or use WebGL 2's GLSL ES 3's `layout(location = )` to make sure locations match. + * + * also + * + * > **IMPORTANT:** After calling twgl.setBuffersAndAttribute with a BufferInfo that uses a Vertex Array Object + * that Vertex Array Object will be bound. That means **ANY MANIPULATION OF ELEMENT_ARRAY_BUFFER or ATTRIBUTES** + * will affect the Vertex Array Object state. + * + * > Call `gl.bindVertexArray(null)` to get back manipulating the global attributes and ELEMENT_ARRAY_BUFFER. + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @param {module:twgl.ProgramInfo|module:twgl.ProgramInfo[]} programInfo a programInfo or array of programInfos + * @param {module:twgl.BufferInfo} bufferInfo BufferInfo as returned from createBufferInfoFromArrays etc... + * + * You need to make sure every attribute that will be used is bound. So for example assume shader 1 + * uses attributes A, B, C and shader 2 uses attributes A, B, D. If you only pass in the programInfo + * for shader 1 then only attributes A, B, and C will have their attributes set because TWGL doesn't + * now attribute D's location. + * + * So, you can pass in both shader 1 and shader 2's programInfo + * + * @return {module:twgl.VertexArrayInfo} The created VertexArrayInfo + * + * @memberOf module:twgl/vertexArrays + */ + +function createVertexArrayInfo(gl, programInfos, bufferInfo) { + const vao = gl.createVertexArray(); + gl.bindVertexArray(vao); + + if (!programInfos.length) { + programInfos = [programInfos]; + } + + programInfos.forEach(function (programInfo) { + setBuffersAndAttributes(gl, programInfo, bufferInfo); + }); + gl.bindVertexArray(null); + return { + numElements: bufferInfo.numElements, + elementType: bufferInfo.elementType, + vertexArrayObject: vao + }; +} +/** + * Creates a vertex array object and then sets the attributes on it + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use. + * @param {Object.} setters Attribute setters as returned from createAttributeSetters + * @param {Object.} attribs AttribInfos mapped by attribute name. + * @param {WebGLBuffer} [indices] an optional ELEMENT_ARRAY_BUFFER of indices + * @memberOf module:twgl/vertexArrays + */ + + +function createVAOAndSetAttributes(gl, setters, attribs, indices) { + const vao = gl.createVertexArray(); + gl.bindVertexArray(vao); + setAttributes(setters, attribs); + + if (indices) { + gl.bindBuffer(ELEMENT_ARRAY_BUFFER$2, indices); + } // We unbind this because otherwise any change to ELEMENT_ARRAY_BUFFER + // like when creating buffers for other stuff will mess up this VAO's binding + + + gl.bindVertexArray(null); + return vao; +} +/** + * Creates a vertex array object and then sets the attributes + * on it + * + * @param {WebGLRenderingContext} gl The WebGLRenderingContext + * to use. + * @param {Object.| module:twgl.ProgramInfo} programInfo as returned from createProgramInfo or Attribute setters as returned from createAttributeSetters + * @param {module:twgl.BufferInfo} bufferInfo BufferInfo as returned from createBufferInfoFromArrays etc... + * @param {WebGLBuffer} [indices] an optional ELEMENT_ARRAY_BUFFER of indices + * @memberOf module:twgl/vertexArrays + */ + + +function createVAOFromBufferInfo(gl, programInfo, bufferInfo) { + return createVAOAndSetAttributes(gl, programInfo.attribSetters || programInfo, bufferInfo.attribs, bufferInfo.indices); +} + +var vertexArrays = /*#__PURE__*/Object.freeze({ + __proto__: null, + createVertexArrayInfo: createVertexArrayInfo, + createVAOAndSetAttributes: createVAOAndSetAttributes, + createVAOFromBufferInfo: createVAOFromBufferInfo +}); +/* + * Copyright 2019 Gregg Tavares + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +exports.vertexArrays = vertexArrays; +const defaults$2 = { + addExtensionsToContext: true +}; +/** + * Various default settings for twgl. + * + * Note: You can call this any number of times. Example: + * + * twgl.setDefaults({ textureColor: [1, 0, 0, 1] }); + * twgl.setDefaults({ attribPrefix: 'a_' }); + * + * is equivalent to + * + * twgl.setDefaults({ + * textureColor: [1, 0, 0, 1], + * attribPrefix: 'a_', + * }); + * + * @typedef {Object} Defaults + * @property {string} [attribPrefix] The prefix to stick on attributes + * + * When writing shaders I prefer to name attributes with `a_`, uniforms with `u_` and varyings with `v_` + * as it makes it clear where they came from. But, when building geometry I prefer using un-prefixed names. + * + * In other words I'll create arrays of geometry like this + * + * const arrays = { + * position: ... + * normal: ... + * texcoord: ... + * }; + * + * But need those mapped to attributes and my attributes start with `a_`. + * + * Default: `""` + * + * @property {number[]} [textureColor] Array of 4 values in the range 0 to 1 + * + * The default texture color is used when loading textures from + * urls. Because the URL will be loaded async we'd like to be + * able to use the texture immediately. By putting a 1x1 pixel + * color in the texture we can start using the texture before + * the URL has loaded. + * + * Default: `[0.5, 0.75, 1, 1]` + * + * @property {string} [crossOrigin] + * + * If not undefined sets the crossOrigin attribute on images + * that twgl creates when downloading images for textures. + * + * Also see {@link module:twgl.TextureOptions}. + * + * @property {bool} [addExtensionsToContext] + * + * If true, then, when twgl will try to add any supported WebGL extensions + * directly to the context under their normal GL names. For example + * if ANGLE_instances_arrays exists then twgl would enable it, + * add the functions `vertexAttribDivisor`, `drawArraysInstanced`, + * `drawElementsInstanced`, and the constant `VERTEX_ATTRIB_ARRAY_DIVISOR` + * to the `WebGLRenderingContext`. + * + * @memberOf module:twgl + */ + +/** + * Sets various defaults for twgl. + * + * In the interest of terseness which is kind of the point + * of twgl I've integrated a few of the older functions here + * + * @param {module:twgl.Defaults} newDefaults The default settings. + * @memberOf module:twgl + */ + +function setDefaults$2(newDefaults) { + copyExistingProperties(newDefaults, defaults$2); + setDefaults(newDefaults); // eslint-disable-line + + setDefaults$1(newDefaults); // eslint-disable-line +} + +const prefixRE = /^(.*?)_/; + +function addExtensionToContext(gl, extensionName) { + glEnumToString(gl, 0); + const ext = gl.getExtension(extensionName); + + if (ext) { + const enums = {}; + const fnSuffix = prefixRE.exec(extensionName)[1]; + const enumSuffix = '_' + fnSuffix; + + for (const key in ext) { + const value = ext[key]; + const isFunc = typeof value === 'function'; + const suffix = isFunc ? fnSuffix : enumSuffix; + let name = key; // examples of where this is not true are WEBGL_compressed_texture_s3tc + // and WEBGL_compressed_texture_pvrtc + + if (key.endsWith(suffix)) { + name = key.substring(0, key.length - suffix.length); + } + + if (gl[name] !== undefined) { + if (!isFunc && gl[name] !== value) { + warn(name, gl[name], value, key); + } + } else { + if (isFunc) { + gl[name] = function (origFn) { + return function () { + return origFn.apply(ext, arguments); + }; + }(value); + } else { + gl[name] = value; + enums[name] = value; + } + } + } // pass the modified enums to glEnumToString + + + enums.constructor = { + name: ext.constructor.name + }; + glEnumToString(enums, 0); + } + + return ext; +} +/* + * If you're wondering why the code doesn't just iterate + * over all extensions using `gl.getExtensions` is that it's possible + * some future extension is incompatible with this code. Rather than + * have thing suddenly break it seems better to manually add to this + * list. + * + */ + + +const supportedExtensions = ['ANGLE_instanced_arrays', 'EXT_blend_minmax', 'EXT_color_buffer_float', 'EXT_color_buffer_half_float', 'EXT_disjoint_timer_query', 'EXT_disjoint_timer_query_webgl2', 'EXT_frag_depth', 'EXT_sRGB', 'EXT_shader_texture_lod', 'EXT_texture_filter_anisotropic', 'OES_element_index_uint', 'OES_standard_derivatives', 'OES_texture_float', 'OES_texture_float_linear', 'OES_texture_half_float', 'OES_texture_half_float_linear', 'OES_vertex_array_object', 'WEBGL_color_buffer_float', 'WEBGL_compressed_texture_atc', 'WEBGL_compressed_texture_etc1', 'WEBGL_compressed_texture_pvrtc', 'WEBGL_compressed_texture_s3tc', 'WEBGL_compressed_texture_s3tc_srgb', 'WEBGL_depth_texture', 'WEBGL_draw_buffers']; +/** + * Attempts to enable all of the following extensions + * and add their functions and constants to the + * `WebGLRenderingContext` using their normal non-extension like names. + * + * ANGLE_instanced_arrays + * EXT_blend_minmax + * EXT_color_buffer_float + * EXT_color_buffer_half_float + * EXT_disjoint_timer_query + * EXT_disjoint_timer_query_webgl2 + * EXT_frag_depth + * EXT_sRGB + * EXT_shader_texture_lod + * EXT_texture_filter_anisotropic + * OES_element_index_uint + * OES_standard_derivatives + * OES_texture_float + * OES_texture_float_linear + * OES_texture_half_float + * OES_texture_half_float_linear + * OES_vertex_array_object + * WEBGL_color_buffer_float + * WEBGL_compressed_texture_atc + * WEBGL_compressed_texture_etc1 + * WEBGL_compressed_texture_pvrtc + * WEBGL_compressed_texture_s3tc + * WEBGL_compressed_texture_s3tc_srgb + * WEBGL_depth_texture + * WEBGL_draw_buffers + * + * For example if `ANGLE_instanced_arrays` exists then the functions + * `drawArraysInstanced`, `drawElementsInstanced`, `vertexAttribDivisor` + * and the constant `VERTEX_ATTRIB_ARRAY_DIVISOR` are added to the + * `WebGLRenderingContext`. + * + * Note that if you want to know if the extension exists you should + * probably call `gl.getExtension` for each extension. Alternatively + * you can check for the existence of the functions or constants that + * are expected to be added. For example + * + * if (gl.drawBuffers) { + * // Either WEBGL_draw_buffers was enabled OR you're running in WebGL2 + * .... + * + * @param {WebGLRenderingContext} gl A WebGLRenderingContext + * @memberOf module:twgl + */ + +function addExtensionsToContext(gl) { + for (let ii = 0; ii < supportedExtensions.length; ++ii) { + addExtensionToContext(gl, supportedExtensions[ii]); + } +} +/** + * Creates a webgl context. + * @param {HTMLCanvasElement} canvas The canvas tag to get + * context from. If one is not passed in one will be + * created. + * @return {WebGLRenderingContext} The created context. + * @private + */ + + +function create3DContext(canvas, opt_attribs) { + const names = ["webgl", "experimental-webgl"]; + let context = null; + + for (let ii = 0; ii < names.length; ++ii) { + context = canvas.getContext(names[ii], opt_attribs); + + if (context) { + if (defaults$2.addExtensionsToContext) { + addExtensionsToContext(context); + } + + break; + } + } + + return context; +} +/** + * Gets a WebGL1 context. + * + * Note: Will attempt to enable Vertex Array Objects + * and add WebGL2 entry points. (unless you first set defaults with + * `twgl.setDefaults({enableVertexArrayObjects: false})`; + * + * @param {HTMLCanvasElement} canvas a canvas element. + * @param {WebGLContextAttributes} [opt_attribs] optional webgl context creation attributes + * @return {WebGLRenderingContext} The created context. + * @memberOf module:twgl + */ + + +function getWebGLContext(canvas, opt_attribs) { + const gl = create3DContext(canvas, opt_attribs); + return gl; +} +/** + * Creates a webgl context. + * + * Will return a WebGL2 context if possible. + * + * You can check if it's WebGL2 with + * + * twgl.isWebGL2(gl); + * + * @param {HTMLCanvasElement} canvas The canvas tag to get + * context from. If one is not passed in one will be + * created. + * @return {WebGLRenderingContext} The created context. + */ + + +function createContext(canvas, opt_attribs) { + const names = ["webgl2", "webgl", "experimental-webgl"]; + let context = null; + + for (let ii = 0; ii < names.length; ++ii) { + context = canvas.getContext(names[ii], opt_attribs); + + if (context) { + if (defaults$2.addExtensionsToContext) { + addExtensionsToContext(context); + } + + break; + } + } + + return context; +} +/** + * Gets a WebGL context. Will create a WebGL2 context if possible. + * + * You can check if it's WebGL2 with + * + * function isWebGL2(gl) { + * return gl.getParameter(gl.VERSION).indexOf("WebGL 2.0 ") == 0; + * } + * + * Note: For a WebGL1 context will attempt to enable Vertex Array Objects + * and add WebGL2 entry points. (unless you first set defaults with + * `twgl.setDefaults({enableVertexArrayObjects: false})`; + * + * @param {HTMLCanvasElement} canvas a canvas element. + * @param {WebGLContextAttributes} [opt_attribs] optional webgl context creation attributes + * @return {WebGLRenderingContext} The created context. + * @memberOf module:twgl + */ + + +function getContext(canvas, opt_attribs) { + const gl = createContext(canvas, opt_attribs); + return gl; +} +/** + * Resize a canvas to match the size it's displayed. + * @param {HTMLCanvasElement} canvas The canvas to resize. + * @param {number} [multiplier] So you can pass in `window.devicePixelRatio` or other scale value if you want to. + * @return {boolean} true if the canvas was resized. + * @memberOf module:twgl + */ + + +function resizeCanvasToDisplaySize(canvas, multiplier) { + multiplier = multiplier || 1; + multiplier = Math.max(0, multiplier); + const width = canvas.clientWidth * multiplier | 0; + const height = canvas.clientHeight * multiplier | 0; + + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + return true; + } + + return false; +} + +},{}]},{},[1])(1) +}); diff --git a/htdocs/adapter/view.dcm.html b/htdocs/adapter/view.dcm.html new file mode 100644 index 0000000..31deebc --- /dev/null +++ b/htdocs/adapter/view.dcm.html @@ -0,0 +1,64 @@ + + + + + DICOM + + + + + + + \ No newline at end of file