/** Reads pixel data and corresponding attributes like rows etc. from image * file and inserts them into dataset. * @param dset - [out] The dataset to export the pixel data attributes to * @param outputTS - [out] The proposed transfex syntax of the dataset * @return EC_Normal, if successful, error otherwise */ OFCondition I2DImgSource::readAndInsertSpecificTags( DcmDataset* dset, E_TransferSyntax& outputTS) { Uint16 samplesPerPixel, rows, cols, bitsAlloc, bitsStored, highBit, pixelRepr, planConf; Uint16 pixAspectH = 1; Uint16 pixAspectV = 1; OFString photoMetrInt; outputTS = EXS_Unknown; char* pixData = NULL; Uint32 length; OFCondition cond = readPixelData(rows, cols, samplesPerPixel, photoMetrInt, bitsAlloc, bitsStored, highBit, pixelRepr, planConf, pixAspectH, pixAspectV, pixData, length, outputTS); if (cond.bad()) return cond; if (m_debug) printMessage(m_logStream, "Document2Dcm: Store imported pixel data to DICOM file"); cond = dset->putAndInsertUint16(DCM_SamplesPerPixel, samplesPerPixel); if (cond.bad()) return cond; cond = dset->putAndInsertOFStringArray(DCM_PhotometricInterpretation, photoMetrInt); if (cond.bad()) return cond; cond = dset->putAndInsertOFStringArray(DCM_ConversionType, "WSD"); if (cond.bad()) return cond; /* cond = dset->putAndInsertOFStringArray(DCM_ImagerPixelSpacing, "1.000000\\1.000000"); if (cond.bad()) return cond; cond = dset->putAndInsertOFStringArray(DCM_PixelSpacing, "1.000000\\1.000000"); if (cond.bad()) return cond; */ cond = dset->putAndInsertOFStringArray(DCM_ImagePositionPatient, "0.000000\\0.000000\\0.000000"); if (cond.bad()) return cond; cond = dset->putAndInsertOFStringArray(DCM_ImageOrientationPatient, "1.000000\\0.000000\\0.000000\\0.000000\\1.000000\\0.000000"); if (cond.bad()) return cond; // Should only be written if Samples per Pixel > 1 if (samplesPerPixel > 1) { cond = dset->putAndInsertUint16(DCM_PlanarConfiguration, planConf); if (cond.bad()) return cond; } cond = dset->putAndInsertUint16(DCM_Rows, rows); if (cond.bad()) return cond; cond = dset->putAndInsertUint16(DCM_Columns, cols); if (cond.bad()) return cond; cond = dset->putAndInsertUint16(DCM_BitsAllocated, bitsAlloc); if (cond.bad()) return cond; cond = dset->putAndInsertUint16(DCM_BitsStored, bitsStored); if (cond.bad()) return cond; cond = dset->putAndInsertUint16(DCM_HighBit, highBit); if (cond.bad()) return cond; cond = dset->putAndInsertUint16(DCM_PixelRepresentation, pixelRepr); if (cond.bad()) return cond; if (Recompress()) { // create initial pixel sequence DcmElement* element = newDicomElement(DcmTag(DCM_PixelData, EVR_OW)); element->putUint8Array((const Uint8*)pixData, length); cond = dset->insert(element); if (cond.bad()) { delete element; return cond; } //lo pasamos a jpeg lossless // create representation parameters for lossy and lossless OFCmdUnsignedInt opt_selection_value = 6; //este numero implica cierta perdida... si fuera 0 seria lossless real OFCmdUnsignedInt opt_point_transform = 3; E_TransferSyntax opt_oxfer; GNC::GCS::Permisos::EstadoPermiso codificacion = GNC::GCS::IControladorPermisos::Instance()->Get("core.importacion", "codec"); switch (codificacion.ObtenerValor<int>()) { case 0: { //baseline opt_oxfer = EXS_JPEGProcess1; DJ_RPLossy rp_lossy((int)90); const DcmRepresentationParameter *rp = &rp_lossy; dset->chooseRepresentation(opt_oxfer, rp); } break; case 1: { //progresivo opt_oxfer = EXS_JPEGProcess10_12; DJ_RPLossy rp_lossy((int)90); const DcmRepresentationParameter *rp = &rp_lossy; dset->chooseRepresentation(opt_oxfer, rp); } break; case 2: default: { //lossless GNC::GCS::Permisos::EstadoPermiso estado = GNC::GCS::IControladorPermisos::Instance()->Get("core.importacion", "quality"); if (estado) { opt_point_transform = std::min<int>(estado.ObtenerValor<int>(), 14); opt_point_transform = std::max<int>(estado.ObtenerValor<int>(), 0); } opt_oxfer = EXS_JPEGProcess14SV1; DJ_RPLossless rp_lossless((int)opt_selection_value, (int)opt_point_transform); const DcmRepresentationParameter *rp = &rp_lossless; dset->chooseRepresentation(opt_oxfer, rp); } break; } if(!dset->canWriteXfer(opt_oxfer)) return OFCondition(EC_UnsupportedEncoding); // force meta-header to refresh SOP Class/Instance UIDs. delete dset->remove(DCM_MediaStorageSOPClassUID); delete dset->remove(DCM_MediaStorageSOPInstanceUID); outputTS = opt_oxfer; return cond; } else { if (IsCompressed()) { DcmPixelSequence *pixelSequence = NULL; if (m_debug) printMessage(m_logStream, "Document2Dcm: Store imported pixel data to DICOM file"); // create initial pixel sequence pixelSequence = new DcmPixelSequence(DcmTag(DCM_PixelData, EVR_OB)); if (pixelSequence == NULL) return EC_MemoryExhausted; // insert empty offset table into sequence DcmPixelItem *offsetTable = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB)); if (offsetTable == NULL) { delete pixelSequence; pixelSequence = NULL; return EC_MemoryExhausted; } cond = pixelSequence->insert(offsetTable); if (cond.bad()) { delete offsetTable; offsetTable = NULL; delete pixelSequence; pixelSequence = NULL; return cond; } // insert frame into pixel sequence DcmOffsetList dummyList; cond = pixelSequence->storeCompressedFrame(dummyList, (Uint8*) pixData, length, 0); // storeCompressedFrame(..) does a deep copy, so the pixdata memory can be freed now delete[] pixData; if (cond.bad()) { delete pixelSequence; return cond; } cond = dset->insert(pixelSequence); if (cond.bad()) delete pixelSequence; if (m_debug) printMessage(m_logStream, "Document2Dcm: Inserting Image Pixel module information"); return dset->putAndInsertUint16(DCM_PixelRepresentation, pixelRepr); } else { //little endian to little endian... // create initial pixel sequence DcmElement* element = newDicomElement(DcmTag(DCM_PixelData, EVR_OW)); element->putUint8Array((const Uint8*)pixData, length); cond = dset->insert(element); if (cond.bad()) { delete element; return cond; } outputTS = EXS_LittleEndianExplicit; return cond; } } }
OFCondition Association::SendObject(DcmDataset *dataset) { OFCondition cond; DcmDataset *statusDetail = NULL; T_DIMSE_C_StoreRQ req; T_DIMSE_C_StoreRSP rsp; // check if we SOPClass and SOPInstance in dataset if (!DU_findSOPClassAndInstanceInDataSet(dataset, sopClass, sopInstance)) { return DIMSE_BADDATA; } /* which presentation context should be used */ presId = ASC_findAcceptedPresentationContextID(assoc, sopClass); if (presId == 0) { const char *modalityName = dcmSOPClassUIDToModality(sopClass); if (!modalityName) modalityName = dcmFindNameOfUID(sopClass); if (!modalityName) modalityName = "unknown SOP class"; return DIMSE_BADDATA; } // init store bzero((char*)&req, sizeof(req)); req.MessageID = msgId; strncpy(req.AffectedSOPClassUID, sopClass, sizeof(req.AffectedSOPClassUID)); strncpy(req.AffectedSOPInstanceUID, sopInstance, sizeof(req.AffectedSOPInstanceUID)); req.DataSetType = DIMSE_DATASET_PRESENT; req.Priority = DIMSE_PRIORITY_LOW; // convert to accepted transfer syntax T_ASC_PresentationContext pc; cond = ASC_findAcceptedPresentationContext(assoc->params, presId, &pc); ASC_dumpPresentationContext(&pc, COUT); DJEncoderRegistration::registerCodecs( ECC_lossyYCbCr, EUC_never, // UID generation (never create new UID's) OFFalse, // verbose OFTrue); // optimize huffman table DJDecoderRegistration::registerCodecs(); DcmXfer opt_oxferSyn(pc.acceptedTransferSyntax); E_TransferSyntax ori_oxferSyn = dataset->getOriginalXfer(); DcmXfer original_xfer(dataset->getOriginalXfer()); if(opt_oxferSyn.getXfer() != ori_oxferSyn) { std::cout << "Converting object to accepted transfer-syntax " << opt_oxferSyn.getXferName() << std::endl; OFCondition cond; // create RepresentationParameter DJ_RPLossless rp_lossless(6, 0); DJ_RPLossy rp_lossy(m_CompressionQuality); // NEW const DcmRepresentationParameter *rp = NULL; if(opt_oxferSyn.getXfer() == EXS_JPEGProcess14SV1 || opt_oxferSyn.getXfer() == EXS_JPEGProcess14) { rp = &rp_lossless; } else if(opt_oxferSyn.getXfer() == EXS_JPEGProcess1 || opt_oxferSyn.getXfer() == EXS_JPEGProcess2_4) { rp = &rp_lossy; } // recompress ? if(rp != NULL) { if(original_xfer.isEncapsulated()) { std::cout << "DICOM file is already compressed, convert to uncompressed xfer syntax first\n"; if(EC_Normal != dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL)) { std::cout << "No conversion from compressed original to uncompressed xfer syntax possible!\n"; } } } cond = dataset->chooseRepresentation(opt_oxferSyn.getXfer(), rp); if(cond.bad()) { DimseCondition::dump(cond); } if (dataset->canWriteXfer(opt_oxferSyn.getXfer())) { std::cout << "Output transfer syntax " << opt_oxferSyn.getXferName() << " can be written" << std::endl; } else { std::cout << "No conversion to transfer syntax " << opt_oxferSyn.getXferName() << " possible!" << std::endl; } } // store it cond = DIMSE_storeUser( assoc, presId, &req, NULL, dataset, NULL, NULL, (m_timeout == 0) ? DIMSE_BLOCKING : DIMSE_NONBLOCKING, m_timeout, &rsp, &statusDetail); // increase message id msgId++; // what happened if(rsp.DataSetType == DIMSE_DATASET_PRESENT) { printf("Response with dataset:\n"); } if (statusDetail != NULL) { printf("Status detail:\n"); statusDetail->print(COUT, false); delete statusDetail; } if (cond != EC_Normal) { return cond; } return (rsp.DimseStatus == STATUS_Success) ? EC_Normal : DIMSE_BADDATA; }
OFCondition Association::SendObject(DcmDataset *dataset) { OFCondition cond = EC_Normal; DcmDataset *statusDetail = NULL; if (Stopped()) { return DUL_NETWORKCLOSED; } T_DIMSE_C_StoreRQ req; T_DIMSE_C_StoreRSP rsp; // check if we SOPClass and SOPInstance in dataset if (!DU_findSOPClassAndInstanceInDataSet(dataset, sopClass, sopInstance)) { return makeOFCondition(OFM_dcmnet, DIMSEC_BADDATA, OF_error, "No SOPClass or SOPInstanceUID found on dataset"); } /* which presentation context should be used */ presId = ASC_findAcceptedPresentationContextID(assoc, sopClass); if (presId == 0) { const char *modalityName = dcmSOPClassUIDToModality(sopClass); if (!modalityName) modalityName = dcmFindNameOfUID(sopClass); if (!modalityName) modalityName = "unknown SOP class"; std::ostringstream os; os << "No valid presentation context found. SOPClass = " << sopClass << " Modality = " << modalityName; return makeOFCondition(OFM_dcmnet, DIMSEC_BADDATA, OF_error, os.str().c_str()); } bzero((char*) & req, sizeof (req)); req.MessageID = msgId; strncpy(req.AffectedSOPClassUID, sopClass, sizeof (req.AffectedSOPClassUID)-1); req.AffectedSOPClassUID[sizeof (req.AffectedSOPClassUID)-1] = 0; strncpy(req.AffectedSOPInstanceUID, sopInstance, sizeof (req.AffectedSOPInstanceUID)-1); req.AffectedSOPInstanceUID[sizeof(req.AffectedSOPInstanceUID)-1] = 0; req.DataSetType = DIMSE_DATASET_PRESENT; req.Priority = DIMSE_PRIORITY_LOW; // convert to accepted transfer syntax T_ASC_PresentationContext pc; cond = ASC_findAcceptedPresentationContext(assoc->params, presId, &pc); ASC_dumpPresentationContext(&pc, COUT); DcmXfer opt_oxferSyn(pc.acceptedTransferSyntax); E_TransferSyntax ori_oxferSyn = dataset->getOriginalXfer(); DcmXfer original_xfer(dataset->getOriginalXfer()); if (opt_oxferSyn.getXfer() != ori_oxferSyn) { LOG_DEBUG(ambitolog, "Converting object into accepted Transfer-Syntax: " << opt_oxferSyn.getXferName()); OFCondition cond; // create RepresentationParameter DJ_RPLossless rp_lossless(6, 0); DJ_RPLossy rp_lossy(70); // NEW const DcmRepresentationParameter *rp = NULL; if (opt_oxferSyn.getXfer() == EXS_JPEGProcess14SV1 || opt_oxferSyn.getXfer() == EXS_JPEGProcess14) { rp = &rp_lossless; } else if (opt_oxferSyn.getXfer() == EXS_JPEGProcess1 || opt_oxferSyn.getXfer() == EXS_JPEGProcess2_4) { rp = &rp_lossy; } // recompress ? if (rp != NULL) { if (original_xfer.isEncapsulated()) { LOG_DEBUG(ambitolog, "The DICOM file is already compressed. It will previously converted to uncompressed Transfer Syntax"); if (EC_Normal != dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL)) { return makeOFCondition(OFM_dcmnet, DIMSEC_BADDATA, OF_error, "Unable to convert the original format to uncompressed Transfer Syntax"); } } } cond = dataset->chooseRepresentation(opt_oxferSyn.getXfer(), rp); if (cond.bad()) { LOG_ERROR(ambitolog, "Error choosing representation: " << cond.text()); } if (dataset->canWriteXfer(opt_oxferSyn.getXfer())) { LOG_DEBUG(ambitolog, "The output transfer syntax (" << opt_oxferSyn.getXferName() << " can be writen"); } else { std::ostringstream os; os << "Unable to find any possible converson to output Transfer Syntax " << opt_oxferSyn.getXferName(); return makeOFCondition(OFM_dcmnet, DIMSEC_BADDATA, OF_error, os.str().c_str()); } } // store it cond = DIMSE_storeUser( assoc, presId, &req, NULL, dataset, NULL, NULL, (m_timeout == 0) ? DIMSE_BLOCKING : DIMSE_NONBLOCKING, m_timeout, &rsp, &statusDetail); // increase message id msgId++; // what happened if (rsp.DataSetType == DIMSE_DATASET_PRESENT) { LOG_DEBUG(ambitolog, "Response with dataset"); } if (statusDetail != NULL) { LOG_TRACE(ambitolog, "Status: " << DumpDataset(statusDetail)); delete statusDetail; } if (cond != EC_Normal) { return cond; } if (rsp.DimseStatus == STATUS_Success) { return EC_Normal; } else { LOG_ERROR(ambitolog, "DIMSE Status failed: " << rsp.DimseStatus); return DIMSE_BADDATA; } }