in src/dcmFileDraft.cpp [131:273]
void DcmFileDraft::write(DcmOutputStream* outStream) {
std::unique_ptr<DcmPixelData> pixelData =
std::make_unique<DcmPixelData>(DCM_PixelData);
DcmOffsetList offsetList;
std::unique_ptr<DcmPixelSequence> compressedPixelSequence =
std::make_unique<DcmPixelSequence>(DCM_PixelSequenceTag);
std::unique_ptr<DcmPixelItem> offsetTable =
std::make_unique<DcmPixelItem>(DcmTag(DCM_Item, EVR_OB));
compressedPixelSequence->insert(offsetTable.release());
DcmtkImgDataInfo imgInfo;
std::vector<uint8_t> frames;
// What channel components in represent.
// Values = RGB or YBR_FULL_422.
// value determined by compression JPEG2000 & RAW = RGB
// Jpeg compressed = YBR_FULL_422
// TiffFrame jpeg compressed = RGB or YBR_FULL_422 value
// dependent on encoding of jpeg.
std::string framePhotoMetrIntrp = "";
// Text description of rough image processing which generated frames.
std::string derivationDescription = "";
// Actual size of imaging for frames writen in dicom file.
// Summed across frames. Used to calculate imaging compression ratio.
int64_t imagingSizeBytes = 0;
const int64_t frameDataSize = framesData_.size();
// get general state from first frame.
if (frameDataSize > 0) {
const int firstFrameNumber = 0;
while (!framesData_[firstFrameNumber]->isDone()) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
Frame *frame = framesData_[firstFrameNumber].get();
framePhotoMetrIntrp =
std::move(static_cast<std::string>(frame->photoMetrInt()));
derivationDescription = sourceImageDescription_ +
frame->derivationDescription();
// maximum length of derivationDescription vr type is 1024 chars
// subtracting 1 to allow for null.
derivationDescription = std::move(derivationDescription.substr(0, 1023));
}
// if image is encoded as raw compute total size of all frames and reserve
// memory to speed addition of data to raw write buffer.
uint64_t totalFrameByteSize = 0;
for (size_t frameNumber = 0; frameNumber < frameDataSize; ++frameNumber) {
while (!framesData_[frameNumber]->isDone()) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
Frame *frame = framesData_[frameNumber].get();
if (frame->hasDcmPixelItem()) {
break; // Jpeg or JPeg2000 encoded data.
} else {
totalFrameByteSize += frame->dicomFrameBytesSize();
}
}
if (totalFrameByteSize > 0) {
frames.reserve(totalFrameByteSize);
}
for (size_t frameNumber = 0; frameNumber < frameDataSize; ++frameNumber) {
while (!framesData_[frameNumber]->isDone()) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
Frame *frame = framesData_[frameNumber].get();
if (frame->hasDcmPixelItem()) { // Jpeg or JPeg2000 encoded data.
// if currentSize is odd this will be fixed by dcmtk during
// DcmOtherByteOtherWord::write()
// passing ownership of frame pointer to dcmtk.
compressedPixelSequence->insert(frame->dcmPixelItem());
// 8 bytes extra for header
Uint32 currentSize = frame->dicomFrameBytesSize() + 8;
// odd frame size requires padding, i.e. last fragment uses odd
// length pixel item
if (currentSize & 1) {
currentSize++;
}
offsetList.push_back(currentSize);
} else {
frames.insert(frames.end(), frame->dicomFrameBytes(),
frame->dicomFrameBytes() + frame->dicomFrameBytesSize());
frame->clearDicomMem(); // memory copied clear.
}
imagingSizeBytes += frame->dicomFrameBytesSize();
}
if (imagingSizeBytes > 0) {
// compute uncompressed size realtive to frames written in file. Possible
// to split frames across multiple files.
const double uncompressed = static_cast<double>(3 * frameWidth_ *
frameHeight_ * frameDataSize);
const double storedImageSize = static_cast<double>(imagingSizeBytes);
const double compression_ratio = uncompressed / storedImageSize;
imgInfo.compressionRatio = std::to_string(compression_ratio);
imgInfo.derivationDescription = derivationDescription;
} else {
imgInfo.compressionRatio = "";
imgInfo.derivationDescription = "";
}
switch (compression_) {
case JPEG:
imgInfo.transSyn = EXS_JPEGProcess1;
imgInfo.photoMetrInt = (framePhotoMetrIntrp.empty()) ?
"YBR_FULL_422" : framePhotoMetrIntrp.c_str();
pixelData->putOriginalRepresentation(imgInfo.transSyn, nullptr,
compressedPixelSequence.release());
break;
case JPEG2000:
imgInfo.transSyn = EXS_JPEG2000LosslessOnly;
imgInfo.photoMetrInt = (framePhotoMetrIntrp.empty()) ?
"RGB" : framePhotoMetrIntrp.c_str();
pixelData->putOriginalRepresentation(imgInfo.transSyn, nullptr,
compressedPixelSequence.release());
break;
default:
imgInfo.transSyn = EXS_LittleEndianExplicit;
imgInfo.photoMetrInt = (framePhotoMetrIntrp.empty()) ?
"RGB" : framePhotoMetrIntrp.c_str();
pixelData->putUint8Array(&frames[0], frames.size());
}
imgInfo.samplesPerPixel = 3;
imgInfo.planConf = 0;
imgInfo.rows = frameHeight_;
imgInfo.cols = frameWidth_;
imgInfo.bitsAlloc = 8;
imgInfo.bitsStored = 8;
imgInfo.highBit = 7;
imgInfo.pixelRepr = 0;
const int64_t batchSize = fileFrameCount();
const int64_t numberOfFrames = batchSize + prior_batch_frames_;
uint32_t rowSize = 1 + ((imageWidth_ - 1) / frameWidth_);
uint32_t totalNumberOfFrames =
rowSize * (1 + ((imageHeight_ - 1) / frameHeight_));
DcmtkUtils::startConversion(
imageHeight_, imageWidth_, rowSize, studyId_, seriesId_, imageName_,
std::move(pixelData), imgInfo, batchSize, row_, column_, instanceNumber_,
downsample_, batchNumber_, numberOfFrames - batchSize,
totalNumberOfFrames, tiled_, additionalTags_, firstLevelWidthMm_,
firstLevelHeightMm_, outStream);
}