Dave's Brain

Browse - programming tips - read a gdi plus bitmap from memory

Date: 2009jan12
Platform: Windows
Language: C++
Keywords: gdiplus, GDI+, Bitmap

Q.  How can I load a GDI+ bitmap from memory?

A.  The GDI+ Bitmap class can read from an IStream so if you make
your own class based on IStream it'll work.  Here's such a class:

// An IStream based class for in-memory files

class ByteStream : public IStream
{
	LONG				_refcount;
	std::vector<BYTE>		m_a;
	long				m_read_position;

public:

	void Reserve(const size_t n)
	{
		m_a.reserve(n);
	}

	void Init()
	{
		m_a.clear();
		m_read_position = 0;
	}

	ByteStream()
	{
		_refcount = 1;
		Init();
	}

	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject)
	{
		if (iid == __uuidof(IUnknown)
		|| iid == __uuidof(IStream)
		|| iid == __uuidof(ISequentialStream))
		{
			*ppvObject = static_cast<IStream*>(this);
			AddRef();
			return S_OK;
		}
		else
		{
			return E_NOINTERFACE;
		}
	}

	virtual ULONG STDMETHODCALLTYPE AddRef(void)
	{
		return (ULONG)InterlockedIncrement(&_refcount);
	}

	virtual ULONG STDMETHODCALLTYPE Release(void)
	{
        	ULONG res = (ULONG) InterlockedDecrement(&_refcount);
		if (res == 0) delete this;
		return res;
	}

	// ISequentialStream Interface
public:
	virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead)
	{
		size_t		bytes_left;
		size_t		bytes_out;

		if (pcbRead != NULL) *pcbRead = 0;
		if (m_read_position == m_a.size()) // EOF
		{
			return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA);
		}

		bytes_left = m_a.size() - m_read_position;
		bytes_out = min(cb, bytes_left);
		memcpy(pv, &m_a[m_read_position], bytes_out);
		m_read_position += bytes_out;
		if (pcbRead != NULL) *pcbRead = bytes_out;

		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten)
	{
		size_t	prev_size;

		if (cb <= 0)
		{
			if (pcbWritten != NULL) *pcbWritten = 0;
			return S_OK;
		}

		prev_size = m_a.size();
		m_a.resize(prev_size + cb);
		memcpy(&m_a[prev_size], pv, cb);
		if (pcbWritten != NULL) *pcbWritten = cb;

		return S_OK;
	}

	// IStream Interface
public:
	virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE Commit(DWORD)
	{
        	return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE Revert(void)
	{
        	return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
	{
        	return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE Clone(IStream **)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, DWORD dwOrigin, ULARGE_INTEGER* lpNewFilePointer)
	{
		long	start = 0;
		long	new_read_position;

		switch(dwOrigin)
		{
		case STREAM_SEEK_SET:
			start = 0;
			break;
		case STREAM_SEEK_CUR:
			start = m_read_position;
			break;
		case STREAM_SEEK_END:
			start = m_a.size();
			break;
		default:
			return STG_E_INVALIDFUNCTION;
			break;
		}

		new_read_position = start + (long)liDistanceToMove.QuadPart;
		// Allowed to move to m_a.size() which is EOF
		if (new_read_position < 0 || new_read_position > m_a.size())
		{
			return STG_E_SEEKERROR;
		}

		m_read_position = new_read_position;

		if (lpNewFilePointer != NULL)
		{
			lpNewFilePointer->QuadPart = m_read_position;
		}

		return S_OK;
	}

	virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD grfStatFlag)
	{
		if (pStatstg == NULL)
		{
			return STG_E_INVALIDFUNCTION;
		}

		ZeroMemory(pStatstg, sizeof(STATSTG));
		pStatstg->cbSize.QuadPart = m_a.size();
		return S_OK;
	}
};

void ExampleUse()
{
	ByteStream	bs;

	// Fill up the bs

	// Turn it into a bitmap
	Bitmap	bitmap(&bs);
}
What this info useful to you? You can donate to say thanks

Add a comment

Sign in to add a comment
Copyright © 2008-2012, dave - Code samples on Dave's Brain is licensed under the Creative Commons Attribution 2.5 License. However other material, including English text has all rights reserved.
Advertisements: