{"id":711,"date":"2011-10-17T18:04:41","date_gmt":"2011-10-17T17:04:41","guid":{"rendered":"http:\/\/www.nuonsoft.com\/blog\/?p=711"},"modified":"2011-10-17T18:04:41","modified_gmt":"2011-10-17T17:04:41","slug":"introduction-to-wic-how-to-use-wic-to-load-an-image-and-draw-it-with-gdi","status":"publish","type":"post","link":"https:\/\/www.nuonsoft.com\/blog\/2011\/10\/17\/introduction-to-wic-how-to-use-wic-to-load-an-image-and-draw-it-with-gdi\/","title":{"rendered":"Introduction to WIC: How to use WIC to load an image, and draw it with GDI?"},"content":{"rendered":"<p>The Windows Imaging Component (WIC) is a flexible and robust API for working with images on Windows. The API is extensible. Third-party vendors can create new image codecs (readers and writers) to make new image formats available to all applications that use the WIC API. Here is a brief <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee719654.aspx\" target=\"_blank\">description from the MSDN<\/a>:<\/p>\n<blockquote><p>The Windows Imaging Component (WIC) provides an extensible framework for working with images and image metadata. WIC makes it possible for independent software vendors (ISVs) and independent hardware vendors (IHVs) to develop their own image codecs and get the same platform support as standard image formats (for example, TIFF, JPEG, PNG, GIF, BMP, and HDPhoto). A single, consistent set of interfaces is used for all image processing, regardless of image format, so any application using the WIC gets automatic support for new image formats as soon as the codec is installed. The extensible metadata framework makes it possible for applications to read and write their own proprietary metadata directly to image files, so the metadata never gets lost or separated from the image.<\/p><\/blockquote>\n<p>The MSDN states the primary features of WIC as follows:<\/p>\n<ul>\n<li>Enables application developers to perform image processing operations on any image format through a single, consistent set of common interfaces, without requiring prior knowledge of specific image formats.<\/li>\n<li>Provides an extensible &#8220;plug and play&#8221; architecture for image codecs, pixel formats, and metadata, with automatic run-time discovery of new formats.<\/li>\n<li>Supports reading and writing of arbitrary metadata in image files, with the ability to preserve unrecognized metadata during editing.<\/li>\n<li>Preserves high bit depth image data, up to 32 bits per channel, throughout the image processing pipeline.<\/li>\n<li>Provides built-in support for most popular image formats, pixel formats, and metadata schemas.<\/li>\n<\/ul>\n<p>WIC comes with the following standard built-in codecs:<\/p>\n<ul>\n<li>BMP (Windows Bitmap Format), BMP Specification v5.<\/li>\n<li>GIF (Graphics Interchange Format 89a), GIF Specification 89a\/89m<\/li>\n<li>ICO (Icon Format)<\/li>\n<li>JPEG (Joint Photographic Experts Group), JFIF Specification 1.02<\/li>\n<li>PNG (Portable Network Graphics), PNG Specification 1.2<\/li>\n<li>TIFF (Tagged Image File Format), TIFF Specification 6.0<\/li>\n<li>Windows Media Photo, HD Photo Specification 1.0<\/li>\n<\/ul>\n<p>All codecs can both load and save the specific image format, except the ICO codec which can only load icon files and not save them.<\/p>\n<p>Reading all this, it looks like WIC is pretty powerful, and the best part is that it&#8217;s easy to use as I will demonstrate in this article.<!--more--> So, let&#8217;s get started with some code.<br \/>\nThe first thing you need to do is include the following headers and link with Windowscodecs.lib:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#include &lt;wincodec.h&gt;\r\n#include &lt;wincodecsdk.h&gt;<\/pre>\n<p>WIC uses COM, however, this should not scare you away. The main thing to remember is to use a COM smart pointer which makes it much easier and prevents memory leaks. The COM smart pointer I&#8217;ll be using is <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ezzw7k98(v=VS.100).aspx\" target=\"_blank\">CComPtr<\/a>. This smart pointer is defined in atlbase.h.<br \/>\nTo start working with WIC, you need an instance of the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690281(v=VS.85).aspx\" target=\"_blank\">IWICImagingFactory<\/a>. You only have to create one such instance and can use it for the entire lifetime of the application. Below is the header file of a class that wraps an IWICImagingFactory instance into a singleton class to give easy access to it from anywhere in your application.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#pragma once\r\n\r\n#include &lt;atlbase.h&gt;\r\n#include &lt;wincodec.h&gt;\r\n#include &lt;memory&gt;\r\n\r\nclass CWICImagingFactory\r\n{\r\npublic:\r\n\tinline static CWICImagingFactory&amp; GetInstance()\r\n\t{\r\n\t\tif (nullptr == m_pInstance.get())\r\n\t\t\tm_pInstance.reset(new CWICImagingFactory());\r\n\t\treturn *m_pInstance;\r\n\t}\r\n\r\n\tvirtual IWICImagingFactory* GetFactory() const;\r\n\r\nprotected:\r\n\tCComPtr&lt;IWICImagingFactory&gt; m_pWICImagingFactory;\r\n\r\nprivate:\r\n\tCWICImagingFactory();\t\/\/ Private because singleton\r\n\tstatic std::shared_ptr&lt;CWICImagingFactory&gt; m_pInstance;\r\n};<\/pre>\n<p>This code is using the C++11 <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb982026.aspx\" target=\"_blank\">std::shared_ptr<\/a> smart pointer. If your compiler does not yet support this smart pointer, you can replace it with any other smart pointer, for example boost::shared_ptr. Note that this singleton class is not threadsafe. The GetInstance() method contains a race-condition. So, if you need this singleton to be threadsafe, you&#8217;ll have to add some synchronization to the GetInstance() method.<\/p>\n<p>The implementation file of the CWICImagingFactory is rather straightforward:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#include &quot;stdafx.h&quot;\r\n#include &quot;WICImagingFactory.h&quot;\r\n#include &lt;assert.h&gt;\r\n\r\nstd::shared_ptr&lt;CWICImagingFactory&gt; CWICImagingFactory::m_pInstance;\r\n\r\nCWICImagingFactory::CWICImagingFactory()\r\n\t: m_pWICImagingFactory(nullptr)\r\n{\r\n\tHRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,\r\n\t\tIID_IWICImagingFactory, (LPVOID*)&amp;m_pWICImagingFactory);\r\n\tassert(SUCCEEDED(hr));\r\n}\r\n\r\nIWICImagingFactory* CWICImagingFactory::GetFactory()  const\r\n{\r\n\tassert(m_pWICImagingFactory);\r\n\treturn m_pWICImagingFactory;\r\n}<\/pre>\n<p>Now that we have access to an IWICImagingFactory instance, let&#8217;s start with writing the definition of a class called CNuonImg that uses WIC to load and render images.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#pragma once\r\n\r\n#include &lt;atlbase.h&gt;\r\n#include &lt;wincodec.h&gt;\r\n#include &lt;wincodecsdk.h&gt;\r\n\r\nclass CNuonImg\r\n{\r\npublic:\r\n\tCNuonImg();\r\n\tvirtual ~CNuonImg();\r\n\r\n\t\/\/ Opens the nFrame-th frame of the given image file.\r\n\t\/\/ Throws HRESULT in case of failure.\r\n\tvirtual void Open(const wchar_t* pszFile, UINT nFrame = 0);\r\n\r\n\t\/\/ Returns true if an image is loaded successfully, false otherwise\r\n\tvirtual bool IsLoaded() const;\r\n\r\n\t\/\/ Renders the loaded image to the given device context hDC,\r\n\t\/\/ at position x,y and size cx, cy.\r\n\t\/\/ Throws HRESULT in case of failure.\r\n\tvirtual void Render(HDC hDC, UINT x, UINT y, UINT cx, UINT cy);\r\n\r\n\t\/\/ Returns the width of the loaded image.\r\n\tvirtual UINT GetWidth() const;\r\n\r\n\t\/\/ Returns the height of the loaded image.\r\n\tvirtual UINT GetHeight() const;\r\n\r\nprotected:\r\n\tvirtual void Cleanup();\r\n\r\n\tCComPtr&lt;IWICBitmapDecoder&gt; m_pDecoder;\r\n\tCComPtr&lt;IWICBitmapFrameDecode&gt; m_pFrame;\r\n\tCComPtr&lt;IWICFormatConverter&gt; m_pConvertedFrame;\r\n\tUINT m_nWidth;\r\n\tUINT m_nHeight;\r\n};<\/pre>\n<p>The constructor of this class initializes the data members, and initializes COM.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">CNuonImg::CNuonImg()\r\n\t: m_pDecoder(nullptr)\r\n\t, m_pFrame(nullptr)\r\n\t, m_pConvertedFrame(nullptr)\r\n\t, m_nWidth(0)\r\n\t, m_nHeight(0)\r\n{\r\n\t\/\/ Initialize COM\r\n\tCoInitialize(nullptr);\r\n}<\/pre>\n<p>The destructor performs some cleanup and uninitializes COM.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">CNuonImg::~CNuonImg()\r\n{\r\n\tCleanup();\r\n\r\n\t\/\/ Uninitialize COM\r\n\tCoUninitialize();\r\n}<\/pre>\n<p>The Cleanup() method cleans up the previously loaded image and prepares the class to load another image.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">void CNuonImg::Cleanup()\r\n{\r\n\tm_nWidth = m_nHeight = 0;\r\n\r\n\tif (m_pConvertedFrame)\r\n\t{\r\n\t\tm_pConvertedFrame.Release();\r\n\t\tm_pConvertedFrame = nullptr;\r\n\t}\r\n\tif (m_pFrame)\r\n\t{\r\n\t\tm_pFrame.Release();\r\n\t\tm_pFrame = nullptr;\r\n\t}\r\n\tif (m_pDecoder)\r\n\t{\r\n\t\tm_pDecoder.Release();\r\n\t\tm_pDecoder = nullptr;\r\n\t}\r\n}<\/pre>\n<p>It&#8217;s not strictly required to call Cleanup() from the destructor. The class is using CComPtr to wrap all COM pointers, and the CComPtr class will automatically release the COM pointers when the destructor of the CComPtr instances is executed. However, the class needs a Cleanup() method anyway, to allow loading a second image with the same CNuonImg instance, so, we might as well call the Cleanup() method in the destructor also.<\/p>\n<p>The remaining of the code will call a lot of methods on COM interfaces. It&#8217;s good coding practice to check the return value of each COM method call. To make this easier, the code uses the following little helper macro:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#define IfFailedThrowHR(expr) {HRESULT hr = (expr); if (FAILED(hr)) throw hr;}<\/pre>\n<p>This executes an expression expr, which returns an HRESULT. The HRESULT is checked and if it&#8217;s a failure, the HRESULT value is thrown as an exception. You should change this error handling mechanism to suit your requirements.<\/p>\n<p>The Open() method is of course the most interesting method. It loads the given image. The parameter nFrame is the index of the frame that you want to load. Certain image formats, for example TIFF and GIF, support multiple frames inside a single image file. The first frame in the file has index 0.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">void CNuonImg::Open(const wchar_t* pszFile, UINT nFrame\/* = 0*\/)\r\n{\r\n\ttry\r\n\t{\r\n\t\t\/\/ Cleanup a previously loaded image\r\n\t\tCleanup();\r\n\r\n\t\t\/\/ Get the WIC factory from the singleton wrapper class\r\n\t\tIWICImagingFactory* pFactory = CWICImagingFactory::GetInstance().GetFactory();\r\n\t\tassert(pFactory);\r\n\t\tif (!pFactory)\r\n\t\t\tthrow WINCODEC_ERR_NOTINITIALIZED;\r\n\r\n\t\t\/\/ Create a decoder for the given image file\r\n\t\tIfFailedThrowHR(pFactory-&gt;CreateDecoderFromFilename(\r\n\t\t\tpszFile, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &amp;m_pDecoder));\r\n\r\n\t\t\/\/ Validate the given frame index nFrame\r\n\t\tUINT nCount = 0;\r\n\t\t\/\/ Get the number of frames in this image\r\n\t\tif (SUCCEEDED(m_pDecoder-&gt;GetFrameCount(&amp;nCount)))\r\n\t\t{\r\n\t\t\tif (nFrame &gt;= nCount)\r\n\t\t\t\tnFrame = nCount - 1; \/\/ If the requested frame number is too big, default to the last frame\r\n\t\t}\r\n\t\t\/\/ Retrieve the requested frame of the image from the decoder\r\n\t\tIfFailedThrowHR(m_pDecoder-&gt;GetFrame(nFrame, &amp;m_pFrame));\r\n\r\n\t\t\/\/ Retrieve the image dimensions\r\n\t\tIfFailedThrowHR(m_pFrame-&gt;GetSize(&amp;m_nWidth, &amp;m_nHeight));\r\n\r\n\t\t\/\/ Convert the format of the image frame to 32bppBGR\r\n\t\tIfFailedThrowHR(pFactory-&gt;CreateFormatConverter(&amp;m_pConvertedFrame));\r\n\t\tIfFailedThrowHR(m_pConvertedFrame-&gt;Initialize(\r\n\t\t\t\tm_pFrame,                        \/\/ Source frame to convert\r\n\t\t\t\tGUID_WICPixelFormat32bppBGR,     \/\/ The desired pixel format\r\n\t\t\t\tWICBitmapDitherTypeNone,         \/\/ The desired dither pattern\r\n\t\t\t\tNULL,                            \/\/ The desired palette \r\n\t\t\t\t0.f,                             \/\/ The desired alpha threshold\r\n\t\t\t\tWICBitmapPaletteTypeCustom       \/\/ Palette translation type\r\n\t\t\t\t));\r\n\t}\r\n\tcatch (...)\r\n\t{\r\n\t\t\/\/ Cleanup after something went wrong\r\n\t\tCleanup();\r\n\t\t\/\/ Rethrow the exception, so the client code can handle it\r\n\t\tthrow;\r\n\t}\r\n}<\/pre>\n<p>The above code shows the basics of loading an image. To learn more about the different parameters to the different COM calls, consult the MSDN. Here are a couple of MSDN links to make it easy to find the right pages:<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690281(v=VS.85).aspx\" target=\"_blank\">IWICImagingFactory<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690307(v=vs.85).aspx\" target=\"_blank\">IWICImagingFactory::CreateDecoderFromFilename()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690086(v=VS.85).aspx\" target=\"_blank\">IWICBitmapDecoder<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690099(v=VS.85).aspx\" target=\"_blank\">IWICBitmapDecoder::GetFrameCount()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690098(v=VS.85).aspx\" target=\"_blank\">IWICBitmapDecoder::GetFrame()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690134(v=VS.85).aspx\" target=\"_blank\">IWICBitmapFrameDecode<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690185(v=VS.85).aspx\" target=\"_blank\">IWICBitmapSource::GetSize()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690317(v=vs.85).aspx\" target=\"_blank\">IWICImagingFactory::CreateFormatConverter()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690274(v=vs.85).aspx\" target=\"_blank\">IWICFormatConverter<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690279(v=VS.85).aspx\" target=\"_blank\">IWICFormatConverter::Initialize()<\/a><\/li>\n<\/ul>\n<p>The CNuonImg::IsLoaded(), CNuonImg::GetWidth(), and CNuonImg::GetHeigh() methods are simple one-liners.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">bool CNuonImg::IsLoaded() const\r\n{\r\n\treturn m_pConvertedFrame != nullptr;\r\n}\r\n\r\nUINT CNuonImg::GetWidth() const\r\n{\r\n\treturn m_nWidth;\r\n}\r\n\r\nUINT CNuonImg::GetHeight() const\r\n{\r\n\treturn m_nHeight;\r\n}<\/pre>\n<p>The CNuonImg::Render() method is responsible for rendering the image to the given HDC.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#define DIB_WIDTHBYTES(bits) ((((bits) + 31)&gt;&gt;5)&lt;&lt;2)\r\n\r\nvoid CNuonImg::Render(HDC hDC, UINT x, UINT y, UINT cx, UINT cy)\r\n{\r\n\t\/\/ Make sure an image has been loaded\r\n\tif (!IsLoaded())\r\n\t\tthrow WINCODEC_ERR_WRONGSTATE;\r\n\r\n\t\/\/ Get the WIC factory from the singleton wrapper class\r\n\tIWICImagingFactory* pFactory = CWICImagingFactory::GetInstance().GetFactory();\r\n\tif (!pFactory)\r\n\t\tthrow WINCODEC_ERR_NOTINITIALIZED;\r\n\r\n\t\/\/ Create a WIC image scaler to scale the image to the requested size\r\n\tCComPtr&lt;IWICBitmapScaler&gt; pScaler = nullptr;\r\n\tIfFailedThrowHR(pFactory-&gt;CreateBitmapScaler(&amp;pScaler));\r\n\tIfFailedThrowHR(pScaler-&gt;Initialize(m_pConvertedFrame, cx, cy, WICBitmapInterpolationModeFant));\r\n\r\n\t\/\/ Render the image to a GDI device context\r\n\tHBITMAP hDIBBitmap = NULL;\r\n\ttry\r\n\t{\r\n\t\t\/\/ Get a DC for the full screen\r\n\t\tHDC hdcScreen = GetDC(NULL);\r\n\t\tif (!hdcScreen)\r\n\t\t\tthrow 1;\r\n\r\n\t\tBITMAPINFO bminfo;\r\n\t\tZeroMemory(&amp;bminfo, sizeof(bminfo));\r\n\t\tbminfo.bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);\r\n\t\tbminfo.bmiHeader.biWidth        = cx;\r\n\t\tbminfo.bmiHeader.biHeight       = -(LONG)cy;\r\n\t\tbminfo.bmiHeader.biPlanes       = 1;\r\n\t\tbminfo.bmiHeader.biBitCount     = 32;\r\n\t\tbminfo.bmiHeader.biCompression  = BI_RGB;\t\t\r\n\r\n\t\tvoid* pvImageBits = nullptr;\t\/\/ Freed with DeleteObject(hDIBBitmap)\r\n\t\thDIBBitmap = CreateDIBSection(hdcScreen, &amp;bminfo, DIB_RGB_COLORS, &amp;pvImageBits, NULL, 0);\r\n\t\tif (!hDIBBitmap)\r\n\t\t\tthrow 2;\r\n\r\n\t\tReleaseDC(NULL, hdcScreen);\r\n\r\n\t\t\/\/ Calculate the number of bytes in 1 scanline\r\n\t\tUINT nStride = DIB_WIDTHBYTES(cx * 32);\r\n\t\t\/\/ Calculate the total size of the image\r\n\t\tUINT nImage = nStride * cy;\r\n\t\t\/\/ Copy the pixels to the DIB section\r\n\t\tIfFailedThrowHR(pScaler-&gt;CopyPixels(nullptr, nStride, nImage, reinterpret_cast&lt;BYTE*&gt;(pvImageBits)));\r\n\r\n\t\t\/\/ Copy the bitmap to the target device context\r\n\t\t::SetDIBitsToDevice(hDC, x, y, cx, cy, 0, 0, 0, cy, pvImageBits, &amp;bminfo, DIB_RGB_COLORS);\r\n\r\n\t\tDeleteObject(hDIBBitmap);\r\n\t}\r\n\tcatch (...)\r\n\t{\r\n\t\tif (hDIBBitmap)\r\n\t\t\tDeleteObject(hDIBBitmap);\r\n\t\t\/\/ Rethrow the exception, so the client code can handle it\r\n\t\tthrow;\r\n\t}\r\n}<\/pre>\n<p>Here are some links to the MSDN documentation to learn more about the different parameters to the functions used in the above piece of code.<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee690168(VS.85).aspx\" target=\"_blank\">IWICBitmapScaler<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ee690296(v=vs.85).aspx\" target=\"_blank\">IWICImagingFactory::CreateBitmapScaler()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee690169(v=VS.85).aspx\" target=\"_blank\">IWICBitmapScaler::Initialize()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd183494(VS.85).aspx\" target=\"_blank\">CreateDIBSection()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee690179(v=VS.85).aspx\" target=\"_blank\">IWICBitmapSource::CopyPixels()<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd162974(VS.85).aspx\" target=\"_blank\">SetDIBitsToDevice()<\/a><\/li>\n<\/ul>\n<p>Now you can start using the class to load and render images. The basic flow for rendering an image to a device context (hDC) at position (0,0) with given width and height is as follows:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">try\r\n{\r\n\tCNuonImg img;\r\n\twchar_t* filename = L&quot;C:\\\\Users\\\\Public\\\\Pictures\\\\Sample Pictures\\\\Tulips.jpg&quot;;\r\n\timg.Open(filename);\r\n\timg.Render(hDC, 0, 0, width, height);\r\n}\r\ncatch (HRESULT hr)\r\n{\r\n\t\/\/ Handle error\r\n}<\/pre>\n<p><a href=\"http:\/\/www.nuonsoft.com\/downlds\/WICDemo1.zip\">Click here<\/a> to download a small MFC demo application that uses the above class to load an image.<\/p>\n<p>That&#8217;s it for this first introduction to WIC. If you have suggestions for topics for future posts about WIC, let me know in the comments below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Windows Imaging Component (WIC) is a flexible and robust API for working with images on Windows. The API is extensible. Third-party vendors can create new image codecs (readers and writers) to make new image formats available to all applications that use the WIC API. Here is a brief description from the MSDN: The Windows [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,17],"tags":[130,131],"class_list":["post-711","post","type-post","status-publish","format-standard","hentry","category-c","category-software-development","tag-wic","tag-windows-imaging-component"],"_links":{"self":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/711","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=711"}],"version-history":[{"count":27,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/711\/revisions"}],"predecessor-version":[{"id":738,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/711\/revisions\/738"}],"wp:attachment":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=711"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/categories?post=711"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/tags?post=711"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}