Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 428x | import type { Types } from '@cornerstonejs/core'; import { utilities } from '@cornerstonejs/core'; import { getOptions } from './options'; import type { LoaderXhrRequestError } from '../../types'; import extractMultipart from '../wadors/extractMultipart'; import { getImageQualityStatus } from '../wadors/getImageQualityStatus'; import type { CornerstoneWadoRsLoaderOptions, StreamingData, } from '../wadors/loadImage'; const { ProgressiveIterator } = utilities; /** * This function does a streaming parse from an http request, delivering * combined/subsequent parts of the result as iterations on a * ProgressiveIterator instance. * * @param url - to request and parse as either multipart or singlepart. * @param imageId - the imageId to be used in the returned detail object * @param defaultHeaders * @returns */ export default function streamRequest( url: string, imageId: string, defaultHeaders: Record<string, string> = {}, options: CornerstoneWadoRsLoaderOptions = {} ) { const globalOptions = getOptions(); const { retrieveOptions = {} as Types.RangeRetrieveOptions, streamingData = {} as StreamingData, } = options; // @ts-expect-error const minChunkSize = retrieveOptions.minChunkSize || 128 * 1024; const errorInterceptor = (err) => { if (typeof globalOptions.errorInterceptor === 'function') { const error = new Error('request failed') as LoaderXhrRequestError; globalOptions.errorInterceptor(error); } }; // Make the request for the streamable image frame (i.e. HTJ2K) const loadIterator = new ProgressiveIterator('streamRequest'); loadIterator.generate(async (iterator, reject) => { const beforeSendHeaders = await globalOptions.beforeSend?.( null, url, defaultHeaders, {} ); const headers = Object.assign({}, defaultHeaders, beforeSendHeaders); Object.keys(headers).forEach(function (key) { if (headers[key] === null) { headers[key] = undefined; } if (key === 'Accept' && url.indexOf('accept=') !== -1) { headers[key] = undefined; } }); try { const response = await fetch(url, { headers, signal: undefined, }); // Response is expected to be a 200 status response if (response.status !== 200) { throw new Error( `Couldn't retrieve ${url} got status ${response.status}` ); } const responseReader = response.body.getReader(); const responseHeaders = response.headers; const contentType = responseHeaders.get('content-type'); const totalBytes = Number(responseHeaders.get('Content-Length')); let readDone = false; let encodedData = streamingData.encodedData; // @ts-ignore let lastSize = streamingData.lastSize || 0; // @ts-ignore streamingData.isPartial = true; while (!readDone) { const { done, value } = await responseReader.read(); encodedData = appendChunk(encodedData, value); if (!encodedData) { if (readDone) { throw new Error(`Done but no image frame available ${imageId}`); } continue; } readDone = done || encodedData.byteLength === totalBytes; if (!readDone && encodedData.length < lastSize + minChunkSize) { continue; } lastSize = encodedData.length; // @ts-ignore streamingData.isPartial = !done; const extracted = extractMultipart( contentType, encodedData, streamingData ); const imageQualityStatus = getImageQualityStatus( retrieveOptions, readDone ); const detail = { url, imageId, ...extracted, percentComplete: done ? 100 : (extracted.pixelData?.length * 100) / totalBytes, imageQualityStatus, done: readDone, }; // All of the image load events will be handled by the imageLoader // this simply delivers the raw data as it becomes available. iterator.add(detail, readDone); } } catch (err) { errorInterceptor(err); console.error(err); reject(err); } }); return loadIterator.getNextPromise(); } function appendChunk(existing: Uint8Array, chunk?: Uint8Array) { // that imageId if (!existing) { return chunk; } if (!chunk) { return existing; } const newDataArray = new Uint8Array(existing.length + chunk.length); newDataArray.set(existing, 0); newDataArray.set(chunk, existing.length); return newDataArray; } |