# DICOM to PNG error

**URL:** <https://discourse.nodered.org/t/dicom-to-png-error/56708>\
**Category:** General\
**Tags:** function-node\
**Created:** [15 January 2022 19:48 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708 "2022-01-15T19:48:02Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![thejollypop](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thejollypop/32/36597_2.png) [@thejollypop](https://discourse.nodered.org/u/thejollypop)\
**Post date:** [15 January 2022 19:48 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708/1 "2022-01-15T19:48:02Z")

</div>

Hey everyone,

So I have DICOM medical images I want to convert and view as PNG, without cropping or resizing. It uses an [external function - npm](https://www.npmjs.com/package/dcmjs-imaging) , but I get a rendering error which indicates something is missing in the function, or maybe it is related to the `PhotometricInterpretation` DICOM [tag value](https://dicom.innolitics.com/ciods/rt-dose/image-pixel/00280004). However, it works fine over the `template` node.

Here's what I have so far:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/b/1/b13e7efe2df5460f23a61f3a51f700a36c7b6665.png)

Flow:

```auto
[{"id":"61dce39602934bc2","type":"tab","label":"Dicom Viewer","disabled":false,"info":""},{"id":"4762fc781032e120","type":"template","z":"61dce39602934bc2","name":"dcmjs-imaging","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"\n <style>\n html,\n body {\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n display: table;\n }\n .container {\n display: table-cell;\n text-align: center;\n vertical-align: middle;\n }\n .content {\n display: inline-block;\n text-align: center;\n }\n </style>\n </head>\n <body>\n <div id=\"dropZone\" class=\"container\">\n <div class=\"content\">\n <p id=\"infoText\">\n Drag and drop a DICOM Part 10 file to render it!<br />Nothing gets uploaded anywhere.\n </p>\n <canvas id=\"renderingcanvas\"></canvas>\n </div>\n </div>\n </body>\n <script src=\"https://unpkg.com/dcmjs-imaging@0.0.4/build/dcmjs-imaging.min.js\"></script>\n <script>\n const { DicomImage, WindowLevel } = window.dcmjsImaging;\n\n function renderFile(file) {\n const reader = new FileReader();\n reader.onload = function (file) {\n const arrayBuffer = reader.result;\n const canvasElement = document.getElementById('renderingcanvas');\n canvasElement.onwheel = undefined;\n canvasElement.onmousedown = undefined;\n canvasElement.onmousemove = undefined;\n canvasElement.onmouseup = undefined;\n const infoTextElement = document.getElementById('infoText');\n infoTextElement.innerText = '';\n\n const t0 = performance.now();\n\n let frame = 0;\n let windowing = false;\n let x = 0;\n let y = 0;\n\n const image = new DicomImage(arrayBuffer);\n const windowLevels = WindowLevel.fromDicomImage(image);\n const windowLevel =\n windowLevels.length > 0 ? windowLevels[0] : createDefaultWindowLevel(image);\n\n const t1 = performance.now();\n console.log('Parsing time: ' + (t1 - t0) + ' ms');\n console.log('Width: ', image.getWidth());\n console.log('Height: ', image.getHeight());\n console.log('Number of frames: ', image.getNumberOfFrames());\n console.log('Transfer syntax UID: ', image.getTransferSyntaxUid());\n\n if (image.getNumberOfFrames() > 1) {\n canvasElement.onwheel = (event) => {\n event.preventDefault();\n\n const next = event.deltaY > 0 ? 1 : -1;\n if (frame + next > image.getNumberOfFrames() - 1 || frame + next < 0) {\n return;\n }\n\n frame = frame + next;\n renderFrame(image, frame, windowLevel, canvasElement, infoTextElement);\n };\n }\n\n if (windowLevel) {\n canvasElement.onmousedown = (event) => {\n x = event.offsetX;\n y = event.offsetY;\n windowing = true;\n };\n canvasElement.onmousemove = (event) => {\n if (windowing) {\n const diffX = event.offsetX - x;\n const diffY = event.offsetY - y;\n x = event.offsetX;\n y = event.offsetY;\n\n const ww = windowLevel.getWindow();\n const wl = windowLevel.getLevel();\n windowLevel.setWindow(ww + diffX);\n windowLevel.setLevel(wl + diffY);\n renderFrame(image, frame, windowLevel, canvasElement, infoTextElement);\n }\n };\n canvasElement.onmouseup = (event) => {\n x = 0;\n y = 0;\n windowing = false;\n };\n }\n\n renderFrame(image, frame, windowLevel, canvasElement, infoTextElement);\n };\n reader.readAsArrayBuffer(file);\n }\n\n function renderFrame(image, frame, windowLevel, canvasElement, infoTextElement) {\n const ctx = canvasElement.getContext('2d');\n canvasElement.width = image.getWidth();\n canvasElement.height = image.getHeight();\n ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);\n\n try {\n const t0 = performance.now();\n const renderedPixels = new Uint8Array(image.render(frame, windowLevel));\n const t1 = performance.now();\n\n const imageData = ctx.createImageData(image.getWidth(), image.getHeight());\n const canvasPixels = imageData.data;\n for (let i = 0; i < 4 * image.getWidth() * image.getHeight(); i++) {\n canvasPixels[i] = renderedPixels[i];\n }\n ctx.putImageData(imageData, 0, 0);\n const t2 = performance.now();\n\n infoTextElement.innerHTML = '';\n console.log('Rendering frame: ' + frame);\n if (windowLevel) {\n console.log('Rendering window: ' + windowLevel.toString());\n }\n console.log('Rendering time: ' + (t1 - t0) + ' ms');\n console.log('Drawing time: ' + (t2 - t1) + ' ms');\n } catch (err) {\n infoTextElement.innerText = 'Error: ' + err.message;\n throw err;\n }\n }\n\n function createDefaultWindowLevel(image) {\n const photometricInterpretation = image.getElement('PhotometricInterpretation');\n if (!photometricInterpretation) {\n return;\n }\n if (['MONOCHROME1', 'MONOCHROME2'].indexOf(photometricInterpretation) == -1) {\n return;\n }\n const bitsStored = image.getElement('BitsStored');\n if (!bitsStored) {\n return;\n }\n const pixelRepresentation = image.getElement('PixelRepresentation') || 0;\n const signed = pixelRepresentation !== 0;\n\n const minValue = signed ? -(1 << (bitsStored - 1)) : 0;\n const maxValue = signed ? (1 << (bitsStored - 1)) - 1 : (1 << bitsStored) - 1;\n\n return new WindowLevel(maxValue - minValue, (minValue + maxValue) / 2);\n }\n\n function handleFileSelect(evt) {\n evt.stopPropagation();\n evt.preventDefault();\n const files = evt.dataTransfer.files;\n renderFile(files[0]);\n }\n\n function handleDragOver(evt) {\n evt.stopPropagation();\n evt.preventDefault();\n evt.dataTransfer.dropEffect = 'copy';\n }\n\n const dropZone = document.getElementById('dropZone');\n dropZone.addEventListener('dragover', handleDragOver, false);\n dropZone.addEventListener('drop', handleFileSelect, false);\n </script>\n\n<script> \n(function(scope) { \nscope.$watch('msg', function(msg) {\n if (msg) { \n// Do something when msg arrives \n$(scope.send)[0].src = msg.payload; \n} \n});\n})(scope);\n </script> \n","output":"str","x":320,"y":100,"wires":[["4f4e0f7ab3b3c744","b189c1910676197a"]]},{"id":"9aad85ab0f07e665","type":"inject","z":"61dce39602934bc2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":150,"y":400,"wires":[["afec55764d6f52d9"]]},{"id":"afec55764d6f52d9","type":"http request","z":"61dce39602934bc2","name":"DICOM2.dcm","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"credentials":{"user":"","password":""},"x":240,"y":340,"wires":[["ad5fee391ca75efb"]]},{"id":"5636e05a7f2a69ad","type":"http in","z":"61dce39602934bc2","name":"","url":"/dcmjs","method":"get","upload":false,"swaggerDoc":"","x":130,"y":100,"wires":[["4762fc781032e120"]]},{"id":"4f4e0f7ab3b3c744","type":"http response","z":"61dce39602934bc2","name":"","statusCode":"","headers":{},"x":490,"y":100,"wires":[]},{"id":"c024f1a485174791","type":"inject","z":"61dce39602934bc2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":130,"y":220,"wires":[["7095c0ff60104272"]]},{"id":"7095c0ff60104272","type":"http request","z":"61dce39602934bc2","name":"DICOM1.dcm","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://raw.githubusercontent.com/wearemothership/dicom-test-files/main/dicom-ts-issues/parse-issue-19.dcm","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"credentials":{"user":"","password":""},"x":320,"y":220,"wires":[["ad5fee391ca75efb"]]},{"id":"ad5fee391ca75efb","type":"function","z":"61dce39602934bc2","name":"dcmjs-imaging","func":"const arrayBuffer = msg.payload;\n\n// Create an ArrayBuffer with the contents of the DICOM P10 byte stream\n\nconst { DicomImage } = dcmjsImaging;\nconst image = new DicomImage(arrayBuffer);\n \n// Render image in an RGBA pixels ArrayBuffer\n// Optionally provide a frame index in case of multiframe datasets\n// const renderedPixels = image.render(); \n \nconst renderedPixels = Buffer.from(image.render());\n\n msg.payload = renderedPixels;\n return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"dcmjsImaging","module":"dcmjs-imaging"},{"var":"bmp","module":"bmp-js"},{"var":"fs","module":"fs"}],"x":380,"y":280,"wires":[["2d58ac109cd35ac7","ce16d978a4c669d7"]]},{"id":"2d58ac109cd35ac7","type":"debug","z":"61dce39602934bc2","name":"buffer","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":570,"y":280,"wires":[]},{"id":"141abd217a81f924","type":"fileinject","z":"61dce39602934bc2","name":"","x":180,"y":280,"wires":[["ad5fee391ca75efb"]]},{"id":"2a1d0cb53de651fa","type":"comment","z":"61dce39602934bc2","name":"NPMJS: dcmjs-imaging ","info":"https://www.npmjs.com/package/dcmjs-imaging\n\nhttps://github.com/PantelisGeorgiadis/dcmjs-imaging","x":160,"y":60,"wires":[]},{"id":"ce16d978a4c669d7","type":"image viewer","z":"61dce39602934bc2","name":"","width":160,"data":"payload","dataType":"msg","active":true,"x":570,"y":320,"wires":[[]]},{"id":"9f63577616220e9c","type":"comment","z":"61dce39602934bc2","name":"External Function: dcmjs-imaging ","info":"https://www.npmjs.com/package/dcmjs-imaging\n\nhttps://github.com/PantelisGeorgiadis/dcmjs-imaging","x":190,"y":180,"wires":[]},{"id":"b189c1910676197a","type":"debug","z":"61dce39602934bc2","d":true,"name":"buffer","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":490,"y":160,"wires":[]}]

```

Any help with this would be greatly appreciated!  
Thanks!

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [18 January 2022 12:10 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708/2 "2022-01-18T12:10:45Z")

</div>

If you want any help on this, you will need to provide DICOM1.dcm and DICOM2.dcm otherwise we cannot test and see what the issue is.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [18 January 2022 13:02 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708/3 "2022-01-18T13:02:13Z")

</div>

> [@Steve-Mcl](#):
>
> If you want any help on this, you will need to provide DICOM1.dcm and DICOM2.dcm

Never mind - I found a sample `dcm` file from your [other post](https://discourse.nodered.org/t/http-post-template-to-receive-json-payload/55963/9)

### Demo...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/e/aeb08f2737e00eca799b5a59ada46bcdba2036db.png)

### Flow...

```auto
[{"id":"ad5fee391ca75efb","type":"function","z":"61dce39602934bc2","name":"dcmjs-imaging","func":"const buf = msg.payload;\n\nconst { DicomImage, WindowLevel } = dcmjsImaging;\n\nmsg.payload = renderFile(buf.buffer);\nmsg.payload.jimp = {\n w: msg.payload.image.width, h: msg.payload.image.height, background: \"black\"\n}\nreturn msg;\n\n\n\nfunction renderFile(arrayBuffer) {\n // debugger\n let frame = 0;\n const image = new DicomImage(arrayBuffer);\n const windowLevels = WindowLevel.fromDicomImage(image);\n const windowLevel =\n windowLevels.length > 0 ? windowLevels[0] : createDefaultWindowLevel(image);\n\n const result = {\n framecount: image.getNumberOfFrames()\n }\n\n result.image = renderFrame(image, frame, windowLevel);\n return result;\n}\n\nfunction renderFrame(image, frame, windowLevel) {\n\n const result = {\n height: image.getHeight(),\n width: image.getWidth(),\n bitmap: null\n }\n \n try {\n\n const renderedPixels = new Uint8Array(image.render(frame, windowLevel));\n // const imageData = ctx.createImageData(image.getWidth(), image.getHeight());\n // const canvasPixels = imageData.data;\n const canvasPixels = [];\n for (let i = 0; i < 4 * image.getWidth() * image.getHeight(); i++) {\n canvasPixels[i] = renderedPixels[i];\n }\n // ctx.putImageData(imageData, 0, 0);\n result.bitmap = canvasPixels;\n return result;\n } catch (err) {\n throw err;\n }\n}\n\nfunction createDefaultWindowLevel(image) {\n const photometricInterpretation = image.getElement('PhotometricInterpretation');\n if (!photometricInterpretation) {\n return;\n }\n if (['MONOCHROME1', 'MONOCHROME2'].indexOf(photometricInterpretation) == -1) {\n return;\n }\n const bitsStored = image.getElement('BitsStored');\n if (!bitsStored) {\n return;\n }\n const pixelRepresentation = image.getElement('PixelRepresentation') || 0;\n const signed = pixelRepresentation !== 0;\n\n const minValue = signed ? -(1 << (bitsStored - 1)) : 0;\n const maxValue = signed ? (1 << (bitsStored - 1)) - 1 : (1 << bitsStored) - 1;\n\n return new WindowLevel(maxValue - minValue, (minValue + maxValue) / 2);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"dcmjsImaging","module":"dcmjs-imaging"}],"x":1900,"y":120,"wires":[["0559c20ace56b130"]]},{"id":"ce16d978a4c669d7","type":"image viewer","z":"61dce39602934bc2","name":"","width":"175","data":"image","dataType":"msg","active":true,"x":1870,"y":180,"wires":[[]]},{"id":"3faeb01f9beb7838","type":"inject","z":"61dce39602934bc2","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1440,"y":120,"wires":[["a48ea31d02b63d22"]]},{"id":"a48ea31d02b63d22","type":"http request","z":"61dce39602934bc2","name":"http get bbmri-53323851.dcm","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":1660,"y":120,"wires":[["ad5fee391ca75efb"]]},{"id":"0559c20ace56b130","type":"jimp-image","z":"61dce39602934bc2","name":"create blank image","data":"payload.jimp","dataType":"msg","ret":"img","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"image","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":1490,"y":180,"wires":[["d3710a9bf19f1a47"]]},{"id":"d3710a9bf19f1a47","type":"change","z":"61dce39602934bc2","name":"set image pixels","rules":[{"t":"set","p":"image.bitmap.data","pt":"msg","to":"payload.image.bitmap","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1700,"y":180,"wires":[["ce16d978a4c669d7"]]}]

```

  

If you want to save as PNG, add another image node set to "write" operation & it will save the internal JIMP object as a PNG (or whatever format you set)

  

#### NOTE:

For performance reasons, avoid creating branches as more than one wire leaving a node will generate LARGE duplicates of the image data (only process nodes in series when working with large data like images)

---

<div class="post-metadata">

**Author:** ![thejollypop](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thejollypop/32/36597_2.png) [@thejollypop](https://discourse.nodered.org/u/thejollypop)\
**Post date:** [18 January 2022 17:16 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708/4 "2022-01-18T17:16:58Z")

</div>

Thanks @Steve-Mcl so much:) You nailed it. I truly appreciate your help!

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [1 February 2022 17:17 UTC](https://discourse.nodered.org/t/dicom-to-png-error/56708/5 "2022-02-01T17:17:44Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
