How create a DICOM image from byte (DCMTK) - c++

I want to use the DCMTK 3.6.1 library in an existing project that can create DICOM image. I want to use this library because I want to make the compression of the DICOM images. In a new solution (Visual Studio 2013/C++) Following the example in the DCMTK official documentation, I have this code, that works properly.
using namespace std;
int main()
{
DJEncoderRegistration::registerCodecs();
DcmFileFormat fileformat;
/**** MONO FILE ******/
if (fileformat.loadFile("Files/test.dcm").good())
{
DcmDataset *dataset = fileformat.getDataset();
DcmItem *metaInfo = fileformat.getMetaInfo();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the dataset
//to be created EXS_JPEGProcess14SV1
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
// check if everything went well
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
// force the meta-header UIDs to be re-generated when storing the file
// since the UIDs in the data set may have changed
delete metaInfo->remove(DCM_MediaStorageSOPClassUID);
delete metaInfo->remove(DCM_MediaStorageSOPInstanceUID);
metaInfo->putAndInsertString(DCM_ImplementationVersionName, "New Implementation Version Name");
//delete metaInfo->remove(DCM_ImplementationVersionName);
//dataset->remove(DCM_ImplementationVersionName);
// store in lossless JPEG format
fileformat.saveFile("Files/carrellata_esami_compresso.dcm", EXS_JPEGProcess14SV1);
}
}
DJEncoderRegistration::cleanup();
return 0;
}
Now I want to use the same code in an existing C++ application where
if (infoDicom.arrayImgDicom.GetSize() != 0) //Things of existing previous code
{
//I have added here the registration
DJEncoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();
DJ_RPLossless params;
dataset->putAndInsertUint16(DCM_Rows, infoDicom.rows);
dataset->putAndInsertUint16(DCM_Columns, infoDicom.columns,);
dataset->putAndInsertUint16(DCM_BitsStored, infoDicom.m_bitstor);
dataset->putAndInsertUint16(DCM_HighBit, infoDicom.highbit);
dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
dataset->putAndInsertUint16(DCM_RescaleIntercept, infoDicom.rescaleintercept);
dataset->putAndInsertString(DCM_PhotometricInterpretation,"MONOCHROME2");
dataset->putAndInsertString(DCM_PixelSpacing, "0.086\\0.086");
dataset->putAndInsertString(DCM_ImagerPixelSpacing, "0.096\\0.096");
BYTE* pData = new BYTE[sizeBuffer];
LPBYTE pSorg;
for (int nf=0; nf<iNumberFrames; nf++)
{
//this contains all the PixelData and I put it into the dataset
pSorg = (BYTE*)infoDicom.arrayImgDicom.GetAt(nf);
dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
//and I put it in my data set
//but this IF return false so che canWriteXfer fails...
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
dataset->remove(DCM_MediaStorageSOPClassUID);
dataset->remove(DCM_MediaStorageSOPInstanceUID);
}
//the saveFile fails too, and the error is "Pixel
//rappresentation non found" but I have set the Pixel rep with
//dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
OFCondition status = fileformat.saveFile("test1.dcm", EXS_JPEGProcess14SV1);
DJEncoderRegistration::cleanup();
if (status.bad())
{
int error = 0; //only for test
}
thefile.Write(pSorg, sizeBuffer); //previous code
}
Actually I made test with image that have on one frame, so the for cycle is done only one time. I don't understand why if I choose dataset->chooseRepresentation(EXS_LittleEndianImplicit, &params); or dataset->chooseRepresentation(EXS_LittleEndianEXplicit, &params); works perfectly but not when I choose dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
If I use the same image in the first application, I can compress the image without problems...
EDIT: I think the main problem to solve is the status = dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &rp_lossless) that return "Tag not found". How can I know wich tag is missed?
EDIT2: As suggest in the DCMTK forum I have added the tag about the Bits Allocated and now works for few images, but non for all. For some images I have again "Tag not found": how can I know wich one of tags is missing? As a rule it's better insert all the tags?

I solve the problem adding the tags DCM_BitsAllocated and DCM_PlanarConfiguration. This are the tags that are missed. I hope that is useful for someone.

At least you should call the function chooseRepresentation, after you have applied the data.
**dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);**
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);

Related

How to read the length of audio files using Juce "C++." Without playing the file

I'm trying to display the length of audio files in a Playlist component for an application.
I've not used Juce or C++ before, and I can't understand how to do that from Juce documentation.
I want to make a function that takes an audio file's URL and returns the length in seconds of that audio without playing that file or doing anything else with that file.
I've tried a lot of things, and all of them didn't work, and this is the last thing I've tried:
void PlaylistComponent::trackStats(URL audioURL)
{
AudioFormatManager formatManager;
std::unique_ptr<AudioFormatReaderSource> readerSource;
AudioTransportSource transportSource;
auto* reader = formatManager.createReaderFor(audioURL.createInputStream(false));
if (reader != nullptr)
{
std::unique_ptr<AudioFormatReaderSource> newSource(new AudioFormatReaderSource(reader, true));
transportSource.setSource(newSource.get(), 0, nullptr, reader->sampleRate);
readerSource.reset(newSource.release());
DBG("PlaylistComponent::trackStats(URL audioURL): " << transportSource.getLengthInSeconds());
}
else
{
DBG("Something went wrong loading the file");
}
}
And this is the PlaylistComponent header file:
class PlaylistComponent : public juce::Component,
public juce::TableListBoxModel,
public Button::Listener,
public FileDragAndDropTarget
{
...
}
juce::AudioFormatReaderSource has a method called getTotalLength() which returns the total amount of samples.
Divide that by the sample rate of the file and you have the total length in seconds. Something like this:
if (auto* reader = audioFormatReaderSource->getAudioFormatReader())
double lengthInSeconds = static_cast<double> (audioFormatReaderSource->getTotalLength()) / reader->sampleRate;
You can do this very early on in the audio file opening procedure. You only need an AudioFormatReader instance (no need to create an AudioFormatReaderSource):
// create juce::File from a path juce::String (from a drag & drop event etc).
File file{filePath};
// make sure it is a file and not a directory, etc.
if (!file.existsAsFile()) return;
// create the AudioFormatReader that contains the data
AudioFormatReader *reader = formatManagerInstance.createReaderFor(file);
// make sure a valid reader can be created (not an unsupported file)
if (reader == nullptr) return;
// log the length in seconds
std::cout << reader->lengthInSamples / reader->sampleRate << "\n";
Note: for this to work you will need to
have access to your AudioFormatManager instance and
have already registered the format(s) of the file type (usually through a .registerBasicFormats() call on your AudioFormatManager instance.
IMPORTANT: if successful the createReaderFor() method uses new to create a new AudioFormatReaderInstance, so make sure to use delete on it when you are finished using it to avoid memory leaks

Convert from CanvasBitmap to ID3D11Texture2D

I have a program that prepares a movie frame using Win2d. The frame is in CanvasBitmap format.
I would like to save such frames as a movie. For this, I'm switching from CanvasBitmap to ID3D11Texture2D. I do it as below, but after saving dozens of samples, I have errors of the type 'Device lost'. Probably the reason is the release of the sample.
Is there another way to switch from CanvasBitmap to ID3D11Texture2D - so that saving the movie frames efficiently?
int AddWin2DFrame (CanvasBitmap^ frame)
{
ComPtr<ID2D1Device> nativeDevice = GetWrappedResource<ID2D1Device>(frame->Device);
ComPtr<ID2D1Bitmap1> nativeBitmap = GetWrappedResource<ID2D1Bitmap1>(frame);
ComPtr<IDXGISurface> dxgiSurface;
CHK(nativeBitmap->GetSurface(&dxgiSurface));
ComPtr<ID3D11Resource> d3dResource;
CHK(dxgiSurface.As(&d3dResource));
Microsoft::WRL::ComPtr<IMFMediaBuffer> writeBuffer;
CHK(MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), d3dResource.Get(), 0, false, &writeBuffer));
ComPtr<IMF2DBuffer> p2DBuffer;
DWORD length;
writeBuffer->QueryInterface(__uuidof(IMF2DBuffer), &p2DBuffer);
CHK(p2DBuffer->GetContiguousLength(&length));
CHK(writeBuffer->SetCurrentLength(length));
Microsoft::WRL::ComPtr<IMFSample> writeSample;
CHK(MFCreateSample(&writeSample));
CHK(writeSample->AddBuffer(writeBuffer.Get()));
CHK(writeSample->SetSampleDuration(sampleDuration));
CHK(writeSample->SetSampleTime(_hnsSampleTime));
CHK(_spSinkWriter->WriteSample(_streamIndex, writeSample.Get()));
}
The problem has already been solved. It is fixed by setting MF_SINK_WRITER_D3D_MANAGER as below:
ComPtr<IMFAttributes> spAttr;
CHK(MFCreateAttributes(&spAttr, 4));
CHK(spAttr->SetUnknown(MF_SINK_WRITER_D3D_MANAGER, deviceManager.Get()));
.........
CHK(MFCreateSinkWriterFromURL(ws1.c_str(), spByteStream.Get(), spAttr.Get(), &_spSinkWriter));

Convert Image to base64 in GDK

I am currently working on passing image as Base64 to a rest service. But I am not able to read the file. Here is my code:
if (requestCode == iPictureCode && resultCode == RESULT_OK) {
String picturePath = data.getStringExtra(Intents.EXTRA_PICTURE_FILE_PATH);
String image = processPictureWhenReady(picturePath);
}
`private String processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it.
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath());
bitmap = CameraUtils.resizeImageToHalf(bitmap);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, stream);
String base64Image = Base64.encodeToString(stream.toByteArray(), Base64.DEFAULT);
return base64Image;
}
}`
it never enters the if block for 'pictureFile.exists()'
What could be the problem?
It looks like you adapted your code from the example in the developer docs, but you removed the else clause where a FileObserver is used to detect when the image is actually available. You need that part as well because the full-sized image may not be ready immediately when the activity returns.

How to check whether inserted SD Card is write protected or not in Qt?

Hi friends I am working on an application where I should check the file system of the SD card and also I need to check whether the SD card inserted is write protected or not. I was successful in getting the file system details as follows:
TCHAR volumeName[MAX_PATH + 1] = { 0 };
TCHAR fileSystemName[MAX_PATH + 1] = { 0 };
DWORD serialNumber = 0;
DWORD maxComponentLen = 0;
DWORD fileSystemFlags = 0;
LPCWSTR path = deviceData->m_strPath.utf16(); // deviceData gives me the path of the SD Card
// Get the file system details
if (GetVolumeInformation(
path,
volumeName,
ARRAYSIZE(volumeName),
&serialNumber,
&maxComponentLen,
&fileSystemFlags,
fileSystemName,
ARRAYSIZE(fileSystemName)))
{
newData.strFileSystem = QString::fromUtf16(fileSystemName);
}
m_SDInfoList.append(newData); // m_SDInfoList is QList
With this approach I get to know whether the file system is FAT32 or NTFS. Now I want to achieve the write protected details. Is their a Qt API that can gimme whether the inserted SD Card is write protected or not??? Please help :)
Update:
This is what I did using QFileInfo:
QFileInfo fileInfo(deviceData->m_strPath);
if(!fileInfo.isWritable())
{
newData.strStatus = "WriteProtect Enabled";
}
else
{
newData.strStatus = "WriteProtect Disabled";
}
It always ends up giving me WriteProtect Disable even though I have set the write protected permission.
I suspect you can't do that with Qt. You'll need to add custom code for each target platform.
However, you can simply try to create an empty file and then immediately delete it. If creating the file fails then the volume is likely read only (or it has ran out of free space, you'll need to check the error codes to be sure).
Not sure about how to do it in QT, but WinAPI provides you with GetVolumeInformation (http://pinvoke.net/default.aspx/kernel32/GetVolumeInformation.html) method (allows you to check weather drive is write protected or not), that returns the following flag:
/// <summary>
/// The specified volume is read-only.
/// </summary>
ReadOnlyVolume = 0x80000,

MediaEngine audio playback on WinRT

I'm trying to add music to my game that runs on WinRT. The music should be in an encoded format (mp3, ogg, etc.) and should be streamable and be decoded by the hardware (for performance reasons).
I've looked through the samples, and found out that MediaEngine can do something like this (I hope).
However, I'm having problems making it work. I keep getting ComExceptions everytime I try to create IMFByteStream from IRandomAccessStream via MFCreateMFByteStreamOnStreamEx().
It might be that I'm not handling tasks correctly, since they are a new paradigm for me.
Here's some code (pretty similar to the sample I mentioned before):
void MyMedia::PlayMusic ()
{
try
{
StorageFolder^ installedLocation = Windows::ApplicationModel::Package::Current->InstalledLocation;
Concurrency::task<StorageFile^> m_pickFileTask = Concurrency::task<StorageFile^>(installedLocation->GetFileAsync("music.mp3"), m_tcs.get_token());
SetURL(StringHelper::toString("music.mp3"));
auto player = this;
m_pickFileTask.then([&player](StorageFile^ fileHandle)
{
Concurrency::task<IRandomAccessStream^> fOpenStreamTask = Concurrency::task<IRandomAccessStream^> (fileHandle->OpenAsync(Windows::Storage::FileAccessMode::Read));
fOpenStreamTask.then([&player](IRandomAccessStream^ streamHandle)
{
try
{
player->SetBytestream(streamHandle);
if (player->m_spMediaEngine)
{
MEDIA::ThrowIfFailed(
player->m_spMediaEngine->Play()
);
}
} catch(Platform::Exception^)
{
MEDIA::ThrowIfFailed(E_UNEXPECTED);
}
}
);
}
);
} catch(Platform::Exception^ ex)
{
Printf("error: %s", ex->Message);
}
}
void MyMedia::SetBytestream(IRandomAccessStream^ streamHandle)
{
HRESULT hr = S_OK;
ComPtr<IMFByteStream> spMFByteStream = nullptr;
//The following line always throws a ComException
MEDIA::ThrowIfFailed(
MFCreateMFByteStreamOnStreamEx((IUnknown*)streamHandle, &spMFByteStream)
);
MEDIA::ThrowIfFailed(
m_spEngineEx->SetSourceFromByteStream(spMFByteStream.Get(), m_bstrURL)
);
return;
}
Bonus: If you know a better solution to my audio needs, please leave a comment.
I managed to fix this. There was two problems I found.
Media Foundation was not initialized
MFStartup(MF_VERSION); needs to be called before Media Foundation can be used. I added this code just before creating the media engine.
Referencing a pointer.
Line m_pickFileTask.then([&player](StorageFile^ fileHandle) should be m_pickFileTask.then([player](StorageFile^ fileHandle). This is already a pointer to the current class, and & provides the address of variable, so I was actually passing the pointer's pointer.