Scope
ScopeMultiImageEncoder.cpp
1 #include "StdAfx.h"
2 #include "ScopeMultiImageEncoder.h"
3 #include "ScopeImage.h"
4 #include "helpers/helpers.h"
5 #include "parameters/Scope.h"
6 
7 namespace scope {
8 
9 ScopeMultiImageEncoder::ScopeMultiImageEncoder(const bool& _dosave, const uint32_t& _channels, const bool& _compresstiff)
10  : dosave(_dosave)
11  , channels(_channels)
12  , compresstiff(_compresstiff)
13  , framecount(0)
14  , factory(nullptr)
15  , streams(_channels, nullptr)
16  , encoders(_channels, nullptr)
17  , frameencoders(_channels, nullptr) {
18  if ( dosave ) {
19  hr(__FUNCTION__) = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); // Need to do this here to be in the correct thread (?!)
20  hr(__FUNCTION__) = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*)&factory);
21  }
22 }
23 
25  if ( dosave ) {
26  for ( size_t c = 0 ; c < channels ; c++ ) {
27  // if nothing was saved , encoders were not used and the safe release would throw an exception!!
28  if ( framecount != 0 ) {
29  // Commit all images and close stream to disk. This finalizes the image.
30  hr(encoders[c]->Commit());
31  }
32  SafeRelease(&encoders[c]);
33  SafeRelease(&streams[c]);
34  }
36  CoUninitialize();
37  }
38 }
39 
40 void ScopeMultiImageEncoder::Initialize(const std::vector<std::wstring>& _filenames) {
41  if ( dosave ) {
42  assert(_filenames.size() == channels);
43  for ( size_t c = 0 ; c < channels ; c++ ) {
44  // Make the TIFF encoders
45  hr(factory->CreateEncoder(GUID_ContainerFormatTiff, NULL, &encoders[c]), __FUNCTION__);
46  // Make the streams for disk writing
47  hr(factory->CreateStream(&streams[c]), __FUNCTION__);
48  hr(streams[c]->InitializeFromFilename(_filenames[c].c_str(), GENERIC_WRITE), __FUNCTION__);
49  // Connect encoder to stream
50  hr(encoders[c]->Initialize(streams[c], WICBitmapEncoderNoCache), __FUNCTION__);
51  }
52  }
53 }
54 
56  if ( dosave ) {
57  for ( size_t c = 0 ; c < channels ; c++ ) {
58  // For detail of TIFF encoder configuration see: WIC Encoding Overview at http://msdn.microsoft.com/en-us/library/windows/desktop/ee719871%28v=vs.85%29.aspx#tiffencoding
59  IPropertyBag2 *pPropertybag = NULL;
60 
61  // Make a new frameencoder from the encoder
62  hr(encoders[c]->CreateNewFrame(&frameencoders[c], &pPropertybag), __FUNCTION__);
63 
64  // This is how you customize the TIFF output.
65  PROPBAG2 option = { 0 };
66  option.pstrName = L"TiffCompressionMethod";
67  VARIANT varValue;
68  VariantInit(&varValue);
69  varValue.vt = VT_UI1;
70  if ( compresstiff )
71  varValue.bVal = WICTiffCompressionZIP;
72  else
73  varValue.bVal = WICTiffCompressionNone;
74  hr(pPropertybag->Write(1, &option, &varValue));
75  hr(frameencoders[c]->Initialize(pPropertybag));
76  }
77  if ( framecount == 0 )
78  WriteMetadata();
79  }
80  framecount++;
81 }
82 
84  // We do all this in StorageControllerImpl::FixTIFFTags !
85 
86  /*for ( size_t c = 0 ; c < channels ; c++ ) {
87  IWICMetadataQueryWriter* metadatawriter = nullptr;
88  hr(frameencoders[c]->GetMetadataQueryWriter(&metadatawriter));
89  PROPVARIANT value;
90  PropVariantInit(&value);
91  value.vt = VT_LPWSTR;
92  value.pwszVal = L"A Scope image";
93  hr(metadatawriter->SetMetadataByName(L"/ifd/{ushort=270}", &value));
94 
95  // WIC does not let you overwrite tags it sets itself (i.e. resolution unit and resolution) ! -> FixTIFFFTags
96  PROPVARIANT value2;
97  PropVariantInit(&value2);
98  value2.vt = VT_I2;
99  value2.iVal = 1;
100  hr(metadatawriter->SetMetadataByName(L"/ifd/{ushort=296}", &value2)); // Unit for resolution (datatype short)
101 
102  PROPVARIANT value3;
103  PropVariantInit(&value3);
104  value3.vt = VT_R4;
105  value3.fltVal = 3.3;
106  hr(metadatawriter->SetMetadataByName(L"/ifd/{ushort=282}", &value3));
107 
108  SafeRelease(&metadatawriter);
109  }*/
110 }
111 
112 void ScopeMultiImageEncoder::WriteFrame(ScopeMultiImagePtr const _multiimage) {
113  if ( dosave ) {
114  assert(channels == _multiimage->Channels());
115  for ( size_t c = 0 ; c < channels ; c++ ) {
116  // Set pixel format and check if supported by encoder
117  WICPixelFormatGUID formatGUID = GUID_WICPixelFormat16bppGray;
118  hr(frameencoders[c]->SetPixelFormat(&formatGUID), __FUNCTION__);
119  hr((IsEqualGUID(formatGUID, GUID_WICPixelFormat16bppGray) ? S_OK : E_FAIL), __FUNCTION__);
120 
121  /* Some advice about the WIC buffer stuff
122  Taken from Windows Imaging Component Basics by Kenny Kerr http://msdn.microsoft.com/en-us/magazine/cc500647.aspx)
123  "The stride can be one of the more confusing aspects of bitmaps.
124  Stride is the count of bytes between scanlines. Generally speaking, the bits that make up the pixels of a bitmap are packed into rows.
125  A single row should be long enough to store one row of the bitmap's pixels.
126  The stride is the length of a row measured in bytes, rounded up to the nearest DWORD (4 bytes).
127  This allows bitmaps with fewer than 32 bits per pixel (bpp) to consume less memory while still providing good performance.
128  You can use the following function to calculate the stride for a given bitmap:
129  const UINT byteCount = bitCount / 8;
130  const UINT stride = (width * byteCount + 3) & ~3; "
131  */
132 
133  // RESONANCE CODE
134  // if in resonance scanner mode, the forward and backward lines are stored in one row, i.e. the image has other dimensions
135 
136  // I do not see why this is necessary, if the image is anyway postprocessed the lines can be stored the usual way..., RKr 7/1/15
137 
138  /*if ( _resonance ) {
139  hr(frameencoders[c]->SetSize(_multiimage->Linewidth() * 2, _multiimage->Lines() / 2), __FUNCTION__);
140 
141  const UINT cbStride = (_multiimage->Linewidth() * 2 * 2 + 3) & ~3;
142  const UINT cbBufferSize = _multiimage->Lines() / 2 * cbStride;
143 
144  ScopeImageAccessU16 imagedata(*_multiimage->GetChannel(c));
145 
146  // Have to reinterpret since WritePixels wants a byte pointer to the data (which in our case is acutally 16bit uint16_t
147  //const std::vector<uint16_t>* dataptr(imagedata.GetConstData());
148  //uint16_t* dataptr = imagedata.GetConstData()->data();
149  hr(frameencoders[c]->WritePixels(_multiimage->Lines() / 2, cbStride, cbBufferSize, reinterpret_cast<BYTE*>(imagedata.GetPointer())), __FUNCTION__);
150  }
151  else {*/
152  hr(frameencoders[c]->SetSize(_multiimage->Linewidth(), _multiimage->Lines()), __FUNCTION__);
153 
154  const UINT cbStride = (_multiimage->Linewidth() * 2 + 3) & ~3;
155  const UINT cbBufferSize = _multiimage->Lines() * cbStride;
156 
157  ScopeImageAccessU16 imagedata(*_multiimage->GetChannel(c));
158 
159  // Have to reinterpret since WritePixels wants a byte pointer to the data (which in our case is acutally 16bit uint16_t
160  hr(frameencoders[c]->WritePixels(_multiimage->Lines(), cbStride, cbBufferSize, reinterpret_cast<BYTE*>(imagedata.GetPointer())), __FUNCTION__);
161  //}
162 
163  // Commit frame to image
164  hr(frameencoders[c]->Commit(), __FUNCTION__);
166  }
167  }
168 }
169 
170 void ScopeMultiImageEncoder::WriteFrameNewPart(ScopeMultiImagePtr const _multiimage) {
171  if ( dosave ) {
172  assert(channels < _multiimage->Channels());
173  for ( size_t c = 0 ; c < channels ; c++ ) {
174  hr(frameencoders[c]->SetSize(_multiimage->Linewidth(), _multiimage->Lines()), __FUNCTION__);
175 
176  WICPixelFormatGUID formatGUID = GUID_WICPixelFormat16bppGray;
177  hr(frameencoders[c]->SetPixelFormat(&formatGUID), __FUNCTION__);
178  hr((IsEqualGUID(formatGUID, GUID_WICPixelFormat16bppGray) ? S_OK : E_FAIL), __FUNCTION__);
179 
180  UINT cbStride = (_multiimage->Linewidth() * 2 + 3) & ~3;
181  ScopeImage<uint16_t>::datapart_t part = _multiimage->GetChannel(c)->Newpart();
182  UINT cbBufferSize = static_cast<UINT>((part.second - part.first)/_multiimage->Linewidth() * cbStride);
183 
184  ScopeImageAccessU16 imagedata(*_multiimage->GetChannel(c));
185  hr(frameencoders[c]->WritePixels(_multiimage->Lines(), cbStride, cbBufferSize, reinterpret_cast<BYTE*>(imagedata.GetPointer())), __FUNCTION__);
186 
187  hr(frameencoders[c]->Commit(), __FUNCTION__);
189  }
190  }
191 }
192 
193 }
void NewFrame()
Creates a new frame, initializes its frameencoder, and writes metadata.
IWICImagingFactory * factory
our Windows Imaging Component factory
void Initialize(const std::vector< std::wstring > &_filenames)
Creates and initializes encoders and streams for disk writing.
std::vector< IWICBitmapFrameEncode * > frameencoders
a frameencoder for each channel (remade for each frame)
void SafeRelease(Interface **ppInterfaceToRelease)
A safe release for COM objects.
Definition: helpers.h:25
std::vector< IWICStream * > streams
a stream for each channel
const bool compresstiff
do TIFF compressiong?
Gives RAII safe access (read&write) to the pixeldata of a ScopeImage.
Definition: ScopeImage.h:11
This is the include file for standard system include files, or project specific include files that ar...
ScopeMultiImageEncoder(const ScopeMultiImageEncoder &)
disable copy and assignment
const bool dosave
do we actually save (true) or only count the frames (false)
~ScopeMultiImageEncoder()
Releases resources and uninitializes COM.
void WriteFrameNewPart(ScopeMultiImagePtr const _multiimage)
Writes the new part of a multiimage into the current frames.
void WriteMetadata()
Writes metadata via the current frameencoder into a frame Is not functional, due to limitations in WI...
uint32_t framecount
keeping track of how many frames we encoded
Various helper functions and classes for Scope.
void WriteFrame(ScopeMultiImagePtr const _multiimage)
Writes a complete multi image into the current frames.
std::vector< IWICBitmapEncoder * > encoders
an encoder for each channel
std::pair< typename std::vector< T >::iterator, typename std::vector< T >::iterator > datapart_t
pair of two iterators over the data vector
Definition: ScopeImage.h:33
const uint32_t channels
how many channels to encode