Skip to content

Commit 8c7ea6e

Browse files
authored
Merge pull request #910 from cpinter/set-dicom-thumbnail-size
ENH: Allow setting DICOM thumbnail dimensions and resize function
2 parents 8ec9136 + f76775c commit 8c7ea6e

File tree

2 files changed

+139
-60
lines changed

2 files changed

+139
-60
lines changed

Libs/DICOM/Widgets/ctkDICOMThumbnailGenerator.cpp

Lines changed: 118 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
#include "ctkLogger.h"
2525

2626
// Qt includes
27+
#include <QDebug>
28+
#include <QDir>
2729
#include <QImage>
2830

2931
// DCMTK includes
3032
#include "dcmtk/dcmimgle/dcmimage.h"
3133

3234
static ctkLogger logger ( "org.commontk.dicom.DICOMThumbnailGenerator" );
33-
struct Node;
3435

3536
//------------------------------------------------------------------------------
3637
class ctkDICOMThumbnailGeneratorPrivate
@@ -44,20 +45,26 @@ class ctkDICOMThumbnailGeneratorPrivate
4445
protected:
4546
ctkDICOMThumbnailGenerator* const q_ptr;
4647

48+
int Width;
49+
int Height;
50+
bool SmoothResize;
51+
4752
private:
4853
Q_DISABLE_COPY( ctkDICOMThumbnailGeneratorPrivate );
4954
};
5055

5156
//------------------------------------------------------------------------------
52-
ctkDICOMThumbnailGeneratorPrivate::ctkDICOMThumbnailGeneratorPrivate(ctkDICOMThumbnailGenerator& o):q_ptr(&o)
57+
ctkDICOMThumbnailGeneratorPrivate::ctkDICOMThumbnailGeneratorPrivate(ctkDICOMThumbnailGenerator& o)
58+
: q_ptr(&o)
59+
, Width(256)
60+
, Height(256)
61+
, SmoothResize(false)
5362
{
54-
5563
}
5664

5765
//------------------------------------------------------------------------------
5866
ctkDICOMThumbnailGeneratorPrivate::~ctkDICOMThumbnailGeneratorPrivate()
5967
{
60-
6168
}
6269

6370

@@ -74,64 +81,117 @@ ctkDICOMThumbnailGenerator::~ctkDICOMThumbnailGenerator()
7481
}
7582

7683
//------------------------------------------------------------------------------
77-
bool ctkDICOMThumbnailGenerator::generateThumbnail(DicomImage *dcmImage, const QString &path){
78-
QImage image;
79-
// Check whether we have a valid image
80-
EI_Status result = dcmImage->getStatus();
81-
if (result != EIS_Normal)
82-
{
83-
logger.error(QString("Rendering of DICOM image failed for thumbnail failed: ") + DicomImage::getString(result));
84-
return false;
85-
}
86-
// Select first window defined in image. If none, compute min/max window as best guess.
87-
// Only relevant for monochrome.
88-
if (dcmImage->isMonochrome())
89-
{
90-
if (dcmImage->getWindowCount() > 0)
91-
{
92-
dcmImage->setWindow(0);
93-
}
94-
else
95-
{
96-
dcmImage->setMinMaxWindow(OFTrue /* ignore extreme values */);
97-
}
98-
}
99-
/* get image extension and prepare image header */
100-
const unsigned long width = dcmImage->getWidth();
101-
const unsigned long height = dcmImage->getHeight();
102-
unsigned long offset = 0;
103-
unsigned long length = 0;
104-
QString header;
105-
106-
if (dcmImage->isMonochrome())
84+
int ctkDICOMThumbnailGenerator::width()const
85+
{
86+
Q_D(const ctkDICOMThumbnailGenerator);
87+
return d->Width;
88+
}
89+
90+
//------------------------------------------------------------------------------
91+
void ctkDICOMThumbnailGenerator::setWidth(int width)
92+
{
93+
Q_D(ctkDICOMThumbnailGenerator);
94+
d->Width = width;
95+
}
96+
97+
//------------------------------------------------------------------------------
98+
int ctkDICOMThumbnailGenerator::height()const
99+
{
100+
Q_D(const ctkDICOMThumbnailGenerator);
101+
return d->Height;
102+
}
103+
104+
//------------------------------------------------------------------------------
105+
void ctkDICOMThumbnailGenerator::setHeight(int height)
106+
{
107+
Q_D(ctkDICOMThumbnailGenerator);
108+
d->Height = height;
109+
}
110+
111+
//------------------------------------------------------------------------------
112+
bool ctkDICOMThumbnailGenerator::smoothResize()const
113+
{
114+
Q_D(const ctkDICOMThumbnailGenerator);
115+
return d->SmoothResize;
116+
}
117+
118+
//------------------------------------------------------------------------------
119+
void ctkDICOMThumbnailGenerator::setSmoothResize(bool on)
120+
{
121+
Q_D(ctkDICOMThumbnailGenerator);
122+
d->SmoothResize = on;
123+
}
124+
125+
//------------------------------------------------------------------------------
126+
bool ctkDICOMThumbnailGenerator::generateThumbnail(DicomImage *dcmImage, const QString &path)
127+
{
128+
Q_D(ctkDICOMThumbnailGenerator);
129+
130+
QImage image;
131+
// Check whether we have a valid image
132+
EI_Status result = dcmImage->getStatus();
133+
if (result != EIS_Normal)
134+
{
135+
qCritical() << Q_FUNC_INFO << QString("Rendering of DICOM image failed for thumbnail failed: ") + DicomImage::getString(result);
136+
return false;
137+
}
138+
// Select first window defined in image. If none, compute min/max window as best guess.
139+
// Only relevant for monochrome.
140+
if (dcmImage->isMonochrome())
141+
{
142+
if (dcmImage->getWindowCount() > 0)
107143
{
108-
// write PGM header (binary monochrome image format)
109-
header = QString("P5 %1 %2 255\n").arg(width).arg(height);
110-
offset = header.length();
111-
length = width * height + offset;
144+
dcmImage->setWindow(0);
112145
}
113146
else
114147
{
115-
// write PPM header (binary color image format)
116-
header = QString("P6 %1 %2 255\n").arg(width).arg(height);
117-
offset = header.length();
118-
length = width * height * 3 /* RGB */ + offset;
148+
dcmImage->setMinMaxWindow(OFTrue /* ignore extreme values */);
119149
}
120-
/* create output buffer for DicomImage class */
121-
QByteArray buffer;
122-
/* copy header to output buffer and resize it for pixel data */
123-
buffer.append(header);
124-
buffer.resize(length);
125-
126-
/* render pixel data to buffer */
127-
if (dcmImage->getOutputData(static_cast<void *>(buffer.data() + offset), length - offset, 8, 0))
128-
{
129-
if (!image.loadFromData( buffer ))
130-
{
131-
logger.error("QImage couldn't created");
132-
return false;
133-
}
150+
}
151+
/* get image extension and prepare image header */
152+
const unsigned long width = dcmImage->getWidth();
153+
const unsigned long height = dcmImage->getHeight();
154+
unsigned long offset = 0;
155+
unsigned long length = 0;
156+
QString header;
157+
158+
if (dcmImage->isMonochrome())
159+
{
160+
// write PGM header (binary monochrome image format)
161+
header = QString("P5 %1 %2 255\n").arg(width).arg(height);
162+
offset = header.length();
163+
length = width * height + offset;
164+
}
165+
else
166+
{
167+
// write PPM header (binary color image format)
168+
header = QString("P6 %1 %2 255\n").arg(width).arg(height);
169+
offset = header.length();
170+
length = width * height * 3 /* RGB */ + offset;
171+
}
172+
/* create output buffer for DicomImage class */
173+
QByteArray buffer;
174+
/* copy header to output buffer and resize it for pixel data */
175+
buffer.append(header);
176+
buffer.resize(length);
177+
178+
/* render pixel data to buffer */
179+
if (dcmImage->getOutputData(static_cast<void *>(buffer.data() + offset), length - offset, 8, 0))
180+
{
181+
if (!image.loadFromData( buffer ))
182+
{
183+
qCritical() << Q_FUNC_INFO << "QImage couldn't created";
184+
return false;
134185
}
135-
image.scaled(128,128,Qt::KeepAspectRatio).save(path,"PNG");
136-
return true;
186+
}
187+
image.scaled( d->Width, d->Height, Qt::KeepAspectRatio,
188+
(d->SmoothResize ? Qt::SmoothTransformation : Qt::FastTransformation) ).save(path,"PNG");
189+
return true;
190+
}
191+
192+
//------------------------------------------------------------------------------
193+
bool ctkDICOMThumbnailGenerator::generateThumbnail(const QString dcmImagePath, const QString& thumbnailPath)
194+
{
195+
DicomImage dcmImage(QDir::toNativeSeparators(dcmImagePath).toUtf8());
196+
return this->generateThumbnail(&dcmImage, thumbnailPath);
137197
}

Libs/DICOM/Widgets/ctkDICOMThumbnailGenerator.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,32 @@ class DicomImage;
3636
class CTK_DICOM_WIDGETS_EXPORT ctkDICOMThumbnailGenerator : public ctkDICOMAbstractThumbnailGenerator
3737
{
3838
Q_OBJECT
39+
Q_PROPERTY(int width READ width WRITE setWidth)
40+
Q_PROPERTY(int height READ height WRITE setHeight)
41+
Q_PROPERTY(bool smoothResize READ smoothResize WRITE setSmoothResize)
42+
3943
public:
4044
/// \brief Construct a ctkDICOMThumbnailGenerator object
41-
///
4245
explicit ctkDICOMThumbnailGenerator(QObject* parent = 0);
4346
virtual ~ctkDICOMThumbnailGenerator();
4447

45-
virtual bool generateThumbnail(DicomImage* dcmImage, const QString& path );
48+
virtual bool generateThumbnail(DicomImage* dcmImage, const QString& path);
49+
50+
Q_INVOKABLE bool generateThumbnail(const QString dcmImagePath, const QString& thumbnailPath);
51+
52+
/// Set thumbnail width
53+
void setWidth(int width);
54+
/// Get thumbnail width
55+
int width() const;
56+
/// Set thumbnail height
57+
void setHeight(int height);
58+
/// Get thumbnail height
59+
int height() const;
60+
/// Set thumbnail resize method
61+
/// \param on Smooth resize if true, fast if false. False by default
62+
void setSmoothResize(bool on);
63+
/// Get thumbnail height
64+
bool smoothResize() const;
4665

4766
protected:
4867
QScopedPointer<ctkDICOMThumbnailGeneratorPrivate> d_ptr;

0 commit comments

Comments
 (0)