Skip to content

Commit

Permalink
fix(apply-presentation-state-to-image): pstate itkImage copy crash
Browse files Browse the repository at this point in the history
Fix the crash related to copying of outputImage when
processing presentation states.

Enforce consistent construction of Value object,
SetString, and AddMember for rapidjson document
in apply-presentation-state-to-image operation.
  • Loading branch information
thewtex authored and jadh4v committed Jun 13, 2023
1 parent eef53d5 commit 3a9d2f5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 33 deletions.
65 changes: 33 additions & 32 deletions packages/dicom/apply-presentation-state-to-image.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "itkOutputImage.h"
#include "itkOutputTextStream.h"
#include "itkPipeline.h"
#include "itkImageAlgorithm.h"

#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */

Expand Down Expand Up @@ -126,15 +127,15 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
Document::AllocatorType& alloc = doc.GetAllocator();

Value presentationLabel;
presentationLabel.SetString(ps.getPresentationLabel(), std::strlen(ps.getPresentationLabel()));
presentationLabel.SetString(ps.getPresentationLabel(), std::strlen(ps.getPresentationLabel()), alloc);
doc.AddMember("PresentationLabel",
presentationLabel, alloc);
Value presentationDescription;
presentationDescription.SetString(ps.getPresentationDescription(), std::strlen(ps.getPresentationDescription()));
presentationDescription.SetString(ps.getPresentationDescription(), std::strlen(ps.getPresentationDescription()), alloc);
doc.AddMember("PresentationDescription",
presentationDescription, alloc);
Value presentationCreatorsName;
presentationCreatorsName.SetString(ps.getPresentationCreatorsName(), std::strlen(ps.getPresentationCreatorsName()));
presentationCreatorsName.SetString(ps.getPresentationCreatorsName(), std::strlen(ps.getPresentationCreatorsName()), alloc);
doc.AddMember("PresentationCreatorsName",
presentationCreatorsName, alloc);
if (ps.haveActiveVOIWindow())
Expand All @@ -145,13 +146,13 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
doc.AddMember("CurrentWindowCenter", Value(center), alloc);
doc.AddMember("CurrentWindowWidth", Value(width), alloc);
Value currentVoiDescription;
currentVoiDescription.SetString(ps.getCurrentVOIDescription(), strlen(ps.getCurrentVOIDescription()));
currentVoiDescription.SetString(ps.getCurrentVOIDescription(), strlen(ps.getCurrentVOIDescription()), alloc);
doc.AddMember("CurrentVOIDescription", currentVoiDescription, alloc);
}
else if (ps.haveActiveVOILUT())
{
Value currentVoiDescription;
currentVoiDescription.SetString(ps.getCurrentVOIDescription(), strlen(ps.getCurrentVOIDescription()));
currentVoiDescription.SetString(ps.getCurrentVOIDescription(), strlen(ps.getCurrentVOIDescription()), alloc);
doc.AddMember("CurrentVOIDescription", currentVoiDescription, alloc);
}

Expand Down Expand Up @@ -275,10 +276,10 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
{
Value layerJson(kObjectType);
Value graphicLayerName;
graphicLayerName.SetString(ps.getGraphicLayerName(layer), std::strlen(ps.getGraphicLayerName(layer)));
graphicLayerName.SetString(ps.getGraphicLayerName(layer), std::strlen(ps.getGraphicLayerName(layer)), alloc);
layerJson.AddMember("Name", graphicLayerName, alloc);
Value graphicLayerDescription;
graphicLayerDescription.SetString(ps.getGraphicLayerDescription(layer), std::strlen(ps.getGraphicLayerDescription(layer)));
graphicLayerDescription.SetString(ps.getGraphicLayerDescription(layer), std::strlen(ps.getGraphicLayerDescription(layer)), alloc);
layerJson.AddMember("Description", graphicLayerDescription, alloc);
if (ps.haveGraphicLayerRecommendedDisplayValue(layer))
{
Expand Down Expand Up @@ -310,7 +311,7 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
Value textObjectJson(kObjectType);
// display contents of text object
Value textObjectText;
textObjectText.SetString(ptext->getText(), std::strlen(ptext->getText()));
textObjectText.SetString(ptext->getText(), std::strlen(ptext->getText()), alloc);
textObjectJson.AddMember("Text", textObjectText, alloc);
if (ptext->haveAnchorPoint())
{
Expand All @@ -319,7 +320,7 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
textObjectJson.AddMember("AnchorPoint", apv, alloc);
Value anchorPointUnits;
std::string anchorPointUnitsString(ptext->getAnchorPointAnnotationUnits()==DVPSA_display? "display" : "pixel");
anchorPointUnits.SetString(anchorPointUnitsString.c_str(), anchorPointUnitsString.length());
anchorPointUnits.SetString(anchorPointUnitsString.c_str(), anchorPointUnitsString.length(), alloc);
textObjectJson.AddMember("AnchorPointUnits", anchorPointUnits, alloc);
textObjectJson.AddMember("AnchorPointVisible", Value(ptext->anchorPointIsVisible()), alloc);
}
Expand All @@ -331,7 +332,7 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
textObjectJson.AddMember("BoundingBox", itk::wasm::getArrayJson(box, alloc), alloc);
Value boundingBoxUnits;
std::string boundingBoxUnitsString(ptext->getBoundingBoxAnnotationUnits()==DVPSA_display ? "display" : "pixel");
boundingBoxUnits.SetString(boundingBoxUnitsString.c_str(), boundingBoxUnitsString.length());
boundingBoxUnits.SetString(boundingBoxUnitsString.c_str(), boundingBoxUnitsString.length(), alloc);
textObjectJson.AddMember("BoundingBoxUnits", boundingBoxUnits, alloc);

DVPSTextJustification justification = ptext->getBoundingBoxHorizontalJustification();
Expand Down Expand Up @@ -369,20 +370,23 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
if (pgraphic)
{
Value graphicJson(kObjectType);
std::string graphicType = "none";
std::string graphicTypeString = "none";
switch (pgraphic->getGraphicType())
{
case DVPST_polyline: graphicType = "polyline"; break;
case DVPST_interpolated: graphicType = "interpolated"; break;
case DVPST_circle: graphicType = "circle"; break;
case DVPST_ellipse: graphicType = "ellipse"; break;
case DVPST_point: graphicType = "point"; break;
case DVPST_polyline: graphicTypeString = "polyline"; break;
case DVPST_interpolated: graphicTypeString = "interpolated"; break;
case DVPST_circle: graphicTypeString = "circle"; break;
case DVPST_ellipse: graphicTypeString = "ellipse"; break;
case DVPST_point: graphicTypeString = "point"; break;
}
graphicJson.AddMember("GraphicType", Value(graphicType.c_str(), alloc), alloc);

Value graphicType;
graphicType.SetString(graphicTypeString.c_str(), graphicTypeString.length(), alloc);
graphicJson.AddMember("GraphicType", graphicType, alloc);
graphicJson.AddMember("IsFilled", Value(pgraphic->isFilled()), alloc);
Value units;
std::string unitsString(pgraphic->getAnnotationUnits()==DVPSA_display? "display" : "pixel");
units.SetString(unitsString.c_str(), unitsString.length());
units.SetString(unitsString.c_str(), unitsString.length(), alloc);
graphicJson.AddMember("Units", units, alloc);

j = pgraphic->getNumberOfPoints();
Expand Down Expand Up @@ -425,10 +429,10 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
curveJson.AddMember("AxisUnitsX", Value(pcurve->getCurveAxisUnitsX(), alloc), alloc);
curveJson.AddMember("AxisUnitsY", Value(pcurve->getCurveAxisUnitsY(), alloc), alloc);
Value label;
label.SetString(pcurve->getCurveLabel(), std::strlen(pcurve->getCurveLabel()));
label.SetString(pcurve->getCurveLabel(), std::strlen(pcurve->getCurveLabel()), alloc);
curveJson.AddMember("Label", label, alloc);
Value description;
description.SetString(pcurve->getCurveDescription(), std::strlen(pcurve->getCurveDescription()));
description.SetString(pcurve->getCurveDescription(), std::strlen(pcurve->getCurveDescription()), alloc);
curveJson.AddMember("Description", description, alloc);

j = pcurve->getNumberOfPoints();
Expand Down Expand Up @@ -471,14 +475,14 @@ static void dumpPresentationState(STD_NAMESPACE ostream &out, DVPresentationStat
value << "0x" << STD_NAMESPACE hex << ps.getActiveOverlayGroup(layer, ovlidx) << STD_NAMESPACE dec;
overlayJson.AddMember("Group", Value(value.str().c_str(), alloc), alloc);
Value label;
label.SetString(ps.getActiveOverlayLabel(layer, ovlidx), std::strlen(ps.getActiveOverlayLabel(layer, ovlidx)));
label.SetString(ps.getActiveOverlayLabel(layer, ovlidx), std::strlen(ps.getActiveOverlayLabel(layer, ovlidx)), alloc);
overlayJson.AddMember("Label", label, alloc);
Value description;
description.SetString(ps.getActiveOverlayDescription(layer, ovlidx), std::strlen(ps.getActiveOverlayDescription(layer, ovlidx)));
description.SetString(ps.getActiveOverlayDescription(layer, ovlidx), std::strlen(ps.getActiveOverlayDescription(layer, ovlidx)), alloc);
overlayJson.AddMember("Description", description, alloc);
Value type;
std::string typeString(ps.activeOverlayIsROI(layer, ovlidx) ? "ROI" : "graphic");
type.SetString(typeString.c_str(), typeString.length());
type.SetString(typeString.c_str(), typeString.length(), alloc);
overlayJson.AddMember("Type", type, alloc);

/* get overlay data */
Expand Down Expand Up @@ -523,7 +527,7 @@ using ColorImageType = itk::Image<ColorPixelType, Dimension>;
using OutputColorImageType = itk::wasm::OutputImage<ColorImageType>;

template<typename OutputImageType, typename PixelType, unsigned int Dim>
int GenerateOutputImage(OutputImageType& outputImage, const unsigned long width, const unsigned long height, const std::array<double, 2>& pixelSpacing, const void* pixelData)
int GenerateOutputImage(typename OutputImageType::Pointer & outputImage, const unsigned long width, const unsigned long height, const std::array<double, 2>& pixelSpacing, const void* pixelData)
{
using ImportFilterType = itk::ImportImageFilter<PixelType, Dim>;
auto importFilter = itk::ImportImageFilter<PixelType, Dim>::New();
Expand All @@ -547,14 +551,12 @@ int GenerateOutputImage(OutputImageType& outputImage, const unsigned long width,
// ColorImageType::Internal
importFilter->SetImportPointer((PixelType*)pixelData, numberOfPixels, false);
importFilter->Update();

// set as output image
outputImage = importFilter->GetOutput();
return EXIT_SUCCESS;
}

template int GenerateOutputImage<GrayImageType, GrayPixelType, 2U>(OutputGrayImageType&, const unsigned long, const unsigned long, const std::array<double, 2>&, const void*);
template int GenerateOutputImage<ColorImageType, ColorPixelType, 2U>(OutputColorImageType&, const unsigned long, const unsigned long, const std::array<double, 2>&, const void*);
template int GenerateOutputImage<GrayImageType, GrayPixelType, 2U>(typename GrayImageType::Pointer &, const unsigned long, const unsigned long, const std::array<double, 2>&, const void*);
template int GenerateOutputImage<ColorImageType, ColorPixelType, 2U>(typename ColorImageType::Pointer &, const unsigned long, const unsigned long, const std::array<double, 2>&, const void*);

int main(int argc, char *argv[])
{
Expand Down Expand Up @@ -648,6 +650,9 @@ int main(int argc, char *argv[])
}
DVInterface dvi(opt_cfgName);
OFCondition status = EC_Normal;
const void *pixelData = NULL;
GrayImageType::Pointer grayImage;
ColorImageType::Pointer colorImage;

if (opt_pstName == NULL)
{
Expand All @@ -661,11 +666,9 @@ int main(int argc, char *argv[])

if (status == EC_Normal)
{
// std::cout << "dvi getCurrentPState " << dvi.getCurrentPState() << std::endl;
if (!noPstateOutput) dumpPresentationState(pstateOutStream.Get(), dvi.getCurrentPState());
if (!noBitmapOutput)
{
const void *pixelData = NULL;
unsigned long width = 0;
unsigned long height = 0;
OFLOG_DEBUG(appLogger, "creating pixel data");
Expand All @@ -686,14 +689,12 @@ int main(int argc, char *argv[])
{
if (colorOutput)
{
ColorImageType::Pointer colorImage;
auto result = GenerateOutputImage<ColorImageType, ColorPixelType, 2U>(colorImage, width, height, pixelSpacing, pixelData);
outputColorImage.Set(colorImage);
return result;
}
else
{
GrayImageType::Pointer grayImage;
auto result = GenerateOutputImage<GrayImageType, GrayPixelType, 2U>(grayImage, width, height, pixelSpacing, pixelData);
outputGrayImage.Set(grayImage);
return result;
Expand Down
2 changes: 1 addition & 1 deletion packages/dicom/typescript/test/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ test('Apply presentation state to dicom image.', async t => {

t.assert(baselineJsonObject.PresentationLabel === pstateJsonOut.PresentationLabel)
t.assert(baselineJsonObject.PresentationSizeMode === pstateJsonOut.PresentationSizeMode)
t.assert(JSON.stringify(baselineJsonObject) === JSON.stringify(pstateJsonOut))
t.deepEqual(JSON.stringify(baselineJsonObject), JSON.stringify(pstateJsonOut), 'JSON not equal')

const baselineImage = 'gsps-pstate-image-baseline.pgm'
const baselineImageFilePath = baselinePathPrefix + baselineImage
Expand Down

0 comments on commit 3a9d2f5

Please sign in to comment.