Skip to content

Array buffer allocation #647

Description

@haghverdiNezhad

Describe the Bug

Hello, dear engineer. I hope you're doing well.
I am currently using an older version of Cornerstone (the one built with vanilla JavaScript), and I’ve run into an issue.
On 32-bit Windows systems with low RAM—say, 2GB—when I open a patient study in the browser and then try to open a second one (even after closing the tab for the first patient), I get an "Uncaught RangeError: Array buffer allocation" error.
I would appreciate your guidance on this.
Unfortunately, switching to the newer version of Cornerstone isn't an option for me right now.
Many hospitals and private clinics in Iran are using this version, and a lot of them aren't in a position to upgrade to more powerful hardware.

fixed this bug
i used cornerstoneWADOImageLoader.min.js version 3.0.3
change to
cornerstoneWADOImageLoader.min.js version 4.13.2

BUT

Another issue has come up; I'm currently testing on an older phone, like an iPhone 5s.
It's throwing an error and failing to load the image.
Here is my code.

` async function loadSeries(cornerstone, imageIds, element, stack, loaded = false) {
//stopCineLoop(); // جلوگیری از اجرای همزمان
deactivateCine();
var isLoaded = loaded;
const isLowEnd = isLowEndDevice();

 try {

     // لود و نمایش تصویر فعلی
     const image = await cornerstone.loadImage(imageIds[stack.currentImageIdIndex]);

     if (!isLowEnd) {
         // اگه سیستم قویه، همه عکس‌ها رو cache کن
         imageIds.forEach(imageId => cornerstone.loadAndCacheImage(imageId));
     }

     // ========== استخراج Image Orientation و اضافه کردن به element ==========
     try {
         if (image && image.data) {
             // دریافت Image Orientation (تگ 0020,0037)
             const imageOrientation = image.data.string('x00200037');
             if (imageOrientation) {
                 const values = imageOrientation.split('\\').map(parseFloat);
                 if (values.length === 6) {
                     // ذخیره در dataset عنصر
                     //element.dataset.imageOrientation = imageOrientation;
                     //element.dataset.imageOrientationRow = `${values[0]},${values[1]},${values[2]}`;
                     //element.dataset.imageOrientationCol = `${values[3]},${values[4]},${values[5]}`;

                     // محاسبه و ذخیره نوع صفحه (Axial/Coronal/Sagittal)
                     const planeType = detectPlaneTypeFromOrientation(values);
                     element.dataset.planeType = planeType; // 'axial', 'coronal', 'sagittal'
                 }
             }

             // همچنین Body Part Examined را هم بگیریم (مهم برای همگام‌سازی)
             //const bodyPartExamined = image.data.string('x00180015');
             //if (bodyPartExamined) {
             //    element.dataset.bodyPart = bodyPartExamined;
             //}

             // Frame of Reference UID
             //const frameOfReference = image.data.string('x00200052');
             //if (frameOfReference) {
             //    element.dataset.frameOfReference = frameOfReference;
             //}
         }
     } catch (err) {
         console.warn('Error extracting DICOM metadata:', err);
     }
     // ========== پایان اضافه کردن ==========

     //برای  overlay 1404/09/22
     lastImageWithOverlay = image;

     //1404/04/23 haghverdi چک کردن فریم های هر فایل دایکام -------------------------------------
     const numFrames = parseInt(image.data.string('x00280008'), 10);

     //1404/12/12 اگه مولتی فریم بود aa3DCursor غیرفعلا کنیم
     if (numFrames && numFrames >= 1) {
         document.getElementById("cursor3dToggle").disabled = true;
         document.getElementById("cursor3dToggle").style.cssText = "background: gray;cursor: no-drop;font-weight: 600;";
     }

     // محاسبه FPS  براساس فایل دایکام و ست کردن در FPS
     let fpsDicom = parseInt(image.data.string('x00180040'));
     cineLoop.fps = fpsDicom ? fpsDicom : 9;
     $("#cineFps").val(cineLoop.fps);

     //اگر تعداد فریم ها بیشتر از یک عدد بود یعنی چند فریم هست و باید CINE Loop براش فعال کنیم
     if (numFrames && numFrames > 1 && imageIds.length === 1) {
         // ریست فقط برای مولتی‌فریم جدید
         resetMultiFrame(element);
         multiFrame = true;
         //console.log(`این فایل ${numFrames} فریم دارد ✅`);
         const baseImageId = imageIds[0];
         const multiFrameIds = [];
         for (var i = 0; i < numFrames; i++) {
             multiFrameIds.push(`${baseImageId}?frame=${i}`);
         }
         stack.imageIds = multiFrameIds;
         stack.currentImageIdIndex = 0;
         loadSeries(cornerstone, multiFrameIds, element, stack, false);
         document.querySelector("#stack").classList.add("active", "is-active");
         document.querySelector("#pan").classList.remove("active", "is-active");
         cornerstoneTools.setToolActive('StackScroll', {
             mouseButtonMask: 1
         });
         cornerstoneTools.setToolActive('StackScrollMouseWheel', {});
         //cornerstoneTools.setToolDisabled('ScaleOverlay');// برای از بین بردن هشدار overlay
         return;

         //const newImage = await cornerstone.loadImage(stack.imageIds[0]);
         //cornerstone.displayImage(element, newImage);
     }
     cornerstone.displayImage(element, image);
     cornerstone.reset(element);

     // بررسی وجود Pixel Spacing (اگر نبود غیرفعال میکنیم)
     //1405/03/18
     //const rowSpacing = image.rowPixelSpacing;
     //const colSpacing = image.columnPixelSpacing;
     //if (!rowSpacing || !colSpacing) {
     //    console.warn("No Pixel Spacing found → Disabling ScaleOverlay.");
     //    cornerstoneTools.setToolDisabled('ScaleOverlay');
     //}
     //1405/03/18 گاهی اوقات مقدار pixelSpacing در imagerPixelSpacing هست
     let rowSpacing = image.rowPixelSpacing;
     let colSpacing = image.columnPixelSpacing;
     if (!rowSpacing || !colSpacing) {
         try {
             const imagerPixelSpacing = image.data.string('x00181164');
             //console.log(imagerPixelSpacing);
             if (imagerPixelSpacing && imagerPixelSpacing !== 'undefined') {
                 const parts = imagerPixelSpacing.split('\\');
                 if (parts.length >= 2) {
                     rowSpacing = parseFloat(parts[0]);
                     colSpacing = parseFloat(parts[1]);
                     // مقدار را به خود image هم اختصاص بدهید
                     image.rowPixelSpacing = rowSpacing;
                     image.columnPixelSpacing = colSpacing;
                     // فقط ست کردن در image کافی نیست درست کار نمیکنه باید تو متادیتا قرار بدیم
                     cornerstone.metaData.addProvider(function (type, imageId) {
                         if (type === 'imagePlaneModule') {
                             return {
                                 rowPixelSpacing: rowSpacing,
                                 columnPixelSpacing: colSpacing,
                                 rowImagePixelSpacing: rowSpacing,
                                 columnImagePixelSpacing: colSpacing
                             };
                         }
                     }, 999);
                 }
             } else {
                 console.warn("No Pixel Spacing found → Disabling ScaleOverlay.");
                 cornerstoneTools.setToolDisabled('ScaleOverlay');
             }
         } catch (error) {
             console.error('Error reading ImagerPixelSpacing:', error);
             cornerstoneTools.setToolDisabled('ScaleOverlay');
         }
     }

     // متغیرهای global را به‌روزرسانی کن:
     currentElement = element;
     currentStack = stack;

     // گرفتن viewport بعد از reset (که scale اولیه تنظیم شده)
     const viewport = cornerstone.getViewport(element);
     const initialScale = viewport.scale;
     // حالا تعریف minZoom و maxZoom
     const minZoom = initialScale / 2;
     const maxZoom = initialScale * 10;
     //تنظیم مجدد زوم روی دسکتاپ
     cornerstoneTools.getToolForElement(element, 'Zoom').configuration = {
         minScale: minZoom,
         maxScale: maxZoom
     };
     //تنظیم مجدد زوم روی موبایل
     const zoomTouchPinchTool = cornerstoneTools.getToolForElement(element, 'ZoomTouchPinch');
     if (zoomTouchPinchTool) {
         zoomTouchPinchTool.configuration = {
             minScale: minZoom,
             maxScale: maxZoom
         };
     }
     //1404/04/19
     // display on or off 3D button by check modality || images length smaller from 10
     var isCT_MRI = image.data.string('x00080060') === "CT" || image.data.string('x00080060') === "MR";
     $("body").attr("data-modality", image.data.string('x00080060'));
     //1404/12/12 3DCursor غیرفعلا کنیم
     if (!isCT_MRI) {
         document.getElementById("cursor3dToggle").disabled = true;
         document.getElementById("cursor3dToggle").style.cssText = "background: gray;cursor: no-drop;font-weight: 600;";
     }
     if (!isCT_MRI || stack.imageIds.length < 10) {
         document.getElementById("render3d").disabled = true;
         document.getElementById("render3d").style.cssText = "background: gray;cursor: no-drop;font-weight: 600;";
         //document.getElementById("render3d").setAttribute("style", "display: none !important;");
     } else {
         document.getElementById("render3d").disabled = false;
         document.getElementById("render3d").style.cssText = "background: #fff;cursor: pointer;font-weight: 600;";
         //document.getElementById("render3d").setAttribute("style", "font-size: 14px; font-weight: 600;");
     }

     //دکمه Cine Loop زده شده باشه
     //if (isCT_MRI && stack.imageIds.length > 1 && window.innerWidth > 580)
     //    activateCine();

     //1404/04/30 haghverdi  اگر تعداد عکس ها کمتر از دو تا بود غیرفعال شود
     if (stack.imageIds.length <= 1) {
         document.getElementById("Cine").style.cssText = "visibility: hidden;";
     } else {
         document.getElementById("Cine").style.cssText = "visibility: unset;";
     }

     // ابزارها
     cornerstoneTools.addStackStateManager(element, ['stack', toolName]);
     cornerstoneTools.addToolState(element, 'stack', stack);

     // وقتی تصویر تغییر کرد
     function onImageRendered(e) {
         const eventData = e.detail;
         const currentImageIdIndex = imageIds.indexOf(eventData.image.imageId);
         element.dataset.id = currentImageIdIndex;

         // آپدیت اطلاعات
         cornerstone.setToPixelCoordinateSystem(eventData.enabledElement, eventData.canvasContext);
         element.querySelector('.WW').textContent = Math.round(eventData.viewport.voi.windowWidth);
         element.querySelector('.WL').textContent = Math.round(eventData.viewport.voi.windowCenter);
         element.querySelector('.Scale').textContent = +eventData.viewport.scale.toFixed(2);
         element.querySelector(".FrameNum").textContent = `${currentImageIdIndex + 1} / ${imageIds.length}`;

         // Range Slider
         let rangeSlider = element.querySelector(".range-slider");
         rangeSlider.max = imageIds.length - 1;
         rangeSlider.value = currentImageIdIndex;
         rangeSlider.style.display = imageIds.length === 1 ? "none" : "block";

         // اگه سیستم ضعیف بود، نزدیک‌ترین عکس‌ها رو prefetch کن
         if (isLowEnd && !isLoaded) {
             isLoaded = true;
             loadImagesWithBreak(imageIds, element);
         }
     }
     element.addEventListener('cornerstoneimagerendered', onImageRendered);

     //برای  overlay 1404/09/22
     let lastImageKey = null;
     element.addEventListener('cornerstonenewimage', e => {
         const img = e.detail.image;
         const key = `${img.rows}x${img.columns}|${img.rowPixelSpacing}|${img.columnPixelSpacing}`;
         if (lastImageKey !== key) {
             cornerstone.fitToWindow(element);
             lastImageKey = key;
         }
         lastImageWithOverlay = img;
     });
     element.addEventListener('cornerstoneimagerendered', drawOverlay);

     //اگر مولتی فریم بود Cine loop فعال بشه
     //if (multiFrame && stack.imageIds.length > 1 && window.innerWidth > 580)
     //    activateCine();

     // متادیتا
     let dateUnFormated = image.data.string('x00080012');
     let dateFormated = dateUnFormated == undefined ? "no date" : `${dateUnFormated.slice(0, 4)}/${dateUnFormated.slice(4, 6)}/${dateUnFormated.slice(6, 8)}`;
     element.querySelector('.Date').textContent = dateFormated;

     //1405/04/02 تاریخ رو طبق زمان گرفتن تصویر تنظیم کردم که هر تصویر مشخص باشه چه تاریخی گرفته شده
     //let activeItem = document.querySelector(".tumbnail-item.active");
     //if (element.querySelector(".Date").textContent == "no date" && activeItem != null) {
     //    element.querySelector(".Date").textContent = `${activeItem.dataset.studydate.slice(0, 4)}/${activeItem.dataset.studydate.slice(4, 6)}/${activeItem.dataset.studydate.slice(6, 8)}`;
     //}
     let formattedDate;
     let activeItem = document.querySelector(".tumbnail-item.active");
     if (image.data.string('x00080022') == "" || image.data.string('x00080022') == null) {
         formattedDate = `${activeItem.dataset.studydate.slice(0, 4)}/${activeItem.dataset.studydate.slice(4, 6)}/${activeItem.dataset.studydate.slice(6, 8)}`;
     } else {
         let date = image.data.string('x00080022');
         let year = parseInt(date.slice(0, 4));
         let month = parseInt(date.slice(4, 6));
         let day = parseInt(date.slice(6, 8));
         let jalaliDate = jalaali.toJalaali(year, month, day);
         formattedDate = `${jalaliDate.jy}/${String(jalaliDate.jm).padStart(2, '0')}/${String(jalaliDate.jd).padStart(2, '0')}`;
     }
     if (element.querySelector(".Date").textContent == "no date" && activeItem != null) {
         element.querySelector(".Date").textContent = formattedDate;
     }

     //1405/03/24 ساعت رو طبق زمان گرفتن تصویر تنظیم کردم که هر تصویر مشخص باشه چه ساعتی گرفته شده
     //element.querySelector('.Time').textContent = activeItem != null ? activeItem.dataset.studytime : "";
     element.querySelector('.Time').textContent = formatDicomTime(image.data.string('x00080032'));
     element.querySelector('.left-right').textContent = image.data.string('x00204000') != "" ? image.data.string('x00204000') : "";
     element.querySelector('.left-right').setAttribute("title", image.data.string('x00204000') !== "" ? image.data.string('x00204000') : "");
     element.querySelector(".serieName").textContent = element.dataset.folder;
     element.querySelector('.ImageType').textContent = image.data.string('x00280008');
     element.querySelector('.InstitutionName').textContent = image.data.string('x00080080');
     element.querySelector('.ManufactureModel').textContent = image.data.string('x00081090') != "" ? image.data.string('x00081090') : "";
     element.querySelector('.StationName').textContent = image.data.string('x00081010') != "" ? image.data.string('x00081010') : "";
     element.querySelector('.CoilName').textContent = image.data.string('x00181250') != "" ? image.data.string('x00181250') : "";
     var patientName = image.data.string('x00100010');
     element.querySelector('.PatientName').textContent = patientName ? patientName.replace(/\^/g, " ").trim() : "";
     element.querySelector('.PatientID').textContent = image.data.string('x00100020');
     element.querySelector('.PatientAge').textContent = image.data.string('x00101010');
     element.querySelector('.Thk').textContent = image.data.string('x00180050') == undefined ? "" : image.data.string('x00180050').slice(0, 4).concat("mm");
     element.querySelector('.rows').textContent = image.data.uint16('x00280010');
     element.querySelector('.columns').textContent = image.data.uint16('x00280011');
     element.querySelector(".loading-badge").style.display = "none";
     element.querySelector(".top-right-details").style.display = "flex";
     if (hideInfo) {
         $("#info").trigger("click");
     }
 } catch (error) {
     // ❌ خطا در لود تصویر
     console.error('Failed to load DICOM:', error);

     // مخفی کردن لودر
     const loadingBadge = element.querySelector(".loading-badge");
     if (loadingBadge) loadingBadge.style.display = "none";

     // نمایش پیام ساده به کاربر
     element.innerHTML = `
                                                                                                     <div style="display: flex; justify-content: center; align-items: center; height: 100%; background: #1a1a1a; direction: rtl;">
                                                                                                         <div class="text-danger p-3 text-center">
                                                                                                             <h5>❌ خطا در بارگذاری تصویر</h5>
                                                                                                             <span>loadSeries Fun</span>
                                                                                                             <p class="small">${error.message || 'فایل DICOM خراب یا قابل دسترس نیست'}</p>
                                                                                                             <button onclick="location.reload()" class="btn btn-sm btn-primary mt-2">تلاش مجدد</button>
                                                                                                         </div>
                                                                                                     </div>
                                                                                             `;
 }

}

`

The code goes in this section.
فایل DICOM خراب یا قابل دسترس نیست

I took a log.
I placed markers before and after this line; it seems to run into a problem when it reaches this line.
" const image = await cornerstone.loadImage(imageIds[stack.currentImageIdIndex]);
"

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions