<style type="text/css">
<!--
button.toolbar {
border: 1px;
border-style: solid;
background-color: white;
border-color: white;
font-family: Verdana, Arial, Tahoma, "MS Sans Serif", sans-serif;
font-size: 9pt;
}
div.toolbar {
background-color: white;
border-color: #FF9900;
padding: 1px 2px 2px 2px;
}
-->
</style>
<script language=javascript>
<!--
function InsertText(strInsertText)
{
if (Submitted) return false;
if (strInsertText <= 0) return false;
var objTextArea = document.SubmitForm.ArticleText;
if (objTextArea)
{
if (document.selection && document.selection.createRange)
{
objTextArea.focus();
var objSelectedTextRange = document.selection.createRange();
var strSelectedText = objSelectedTextRange.text;
objSelectedTextRange.text = strInsertText + strSelectedText;
}
else
{
objTextArea.value += strInsertText;
objTextArea.focus();
}
}
return false;
}
function QuoteText(author)
{
var txt = "";
if (document.getSelection) txt = document.getSelection();
else if (document.selection && document.selection.createRange) txt = document.selection.createRange().text;
else return;
var bUseHTML = true; //(document.MessageForm.Format && !document.MessageForm.Format.checked);
if (txt != "")
{
var Quote = "";
var objTextArea = document.SubmitForm.ArticleText;
if (objTextArea && objTextArea.value != "") Quote += "\n";
if (bUseHTML) Quote += "<small><b>";
Quote += (author + " wrote:");
if (bUseHTML) Quote += "</b></small>\n<i>";
else Quote += "\n";
Quote += txt;
if (bUseHTML) Quote += "</i>";
Quote += "\n\n";
InsertText(Quote);
}
else
alert('You did not select any text to quote');
}
//-->
</script>
<script language="JavaScript1.2" type="text/javascript">
<!--
// Based on the work of Jason Jystad. Endless kudos and thanks Jason.
function ToggleWrapSelection(strTag)
{
if (Submitted) return false;
if (strTag.length <= 0) return false;
var StartTag = "<" + strTag + ">";
var EndTag = "</" + strTag + ">";
var objTextArea = document.SubmitForm.ArticleText;
if (objTextArea)
{
if (document.selection && document.selection.createRange)
{
objTextArea.focus();
var objSelectedTextRange = document.selection.createRange();
var strSelectedText = objSelectedTextRange.text;
var nStrtLen = StartTag.length;
var nEndLen = EndTag.length;
var nSelLen = strSelectedText.length;
if (strSelectedText.substr(0, nStrtLen) == StartTag &&
strSelectedText.substr(nSelLen-nEndLen) == EndTag)
{
objSelectedTextRange.text = strSelectedText.substr(nStrtLen, nSelLen-nStrtLen-nEndLen);
}
else
objSelectedTextRange.text = StartTag + strSelectedText + EndTag;
if (strSelectedText.length == 0)
{
objSelectedTextRange.move("character", -(strTag.length + 3));
objSelectedTextRange.select();
}
objTextArea.focus();
}
else
{
var strAppendText = StartTag + EndTag;
objTextArea.value += strAppendText;
objTextArea.focus();
}
}
return false;
}
function InLinkErAte(NewWindow)
{
if (Submitted) return false;
var objTextArea = document.SubmitForm.ArticleText;
if (objTextArea)
{
if (document.selection && document.selection.createRange)
{
objTextArea.focus();
var objSelectedTextRange = document.selection.createRange();
var strSelectedText = objSelectedTextRange.text;
var objRegEx = new RegExp("(ht|f)tps?:\/\/");
var strProtocol = "";
if (strSelectedText.length == 0)
{
if (NewWindow)
{
alert("Please select a URL within the message text to convert");
return false;
}
}
else
{
if (!objRegEx.test(strSelectedText)) strProtocol = "http://";
}
var URI = strProtocol + strSelectedText;
var offset = 0;
if (NewWindow)
{
objSelectedTextRange.text = "<a href=\"" + URI + "\">" + strSelectedText
+ "</a>[<a target=_blank title='New Window' href=\""
+ URI + "\">^</a>]";
offset = 8 + URI.length + 47;
}
else
{
objSelectedTextRange.text = "<a href=\"" + URI + "\">"
+ strSelectedText + "</a>";
offset = 4;
}
if (strSelectedText.length == 0)
{
objSelectedTextRange.move("character", -offset);
objSelectedTextRange.select();
}
}
else
{
var strAppendText = "<a href=\"\"" + strTarget + "></a>";
objTextArea.value += strAppendText;
objTextArea.focus();
}
}
return false;
}
function ToggleHTML()
{
if (Submitted) return false;
var objTextArea = document.SubmitForm.ArticleText;
if (objTextArea)
{
if (document.selection && document.selection.createRange)
{
objTextArea.focus();
var objSelectedTextRange = document.selection.createRange();
var strNewText = objSelectedTextRange.text;
strNewText = strNewText.replace(/&/g, "&");
strNewText = strNewText.replace(/>/g, ">");
strNewText = strNewText.replace(/</g, "<");
objSelectedTextRange.text = strNewText;
}
else
{
alert("This function is presently only compatible with IE4+ on Win32 platforms.");
}
}
return false;
}
function InitToolbar(objITToolbar)
{
if (!objITToolbar) { return false; }
var intITCounter = 0;
var nButtons = objITToolbar.childNodes.length;
var objITButton;
var intITTotalWidth = 0;
for (intITCounter = 0; intITCounter < nButtons; intITCounter++)
{
objITButton = objITToolbar.childNodes[intITCounter];
if (objITButton.type == "button" || objITButton.type == "submit")
{
intITTotalWidth += objITButton.offsetWidth;
objITButton.onmouseover = function(){
if (true || this.name != "pinable" || (this.name == "pinable" && this.style.borderStyle != "inset")) {
this.style.borderWidths = "1px, 1px, 1px, 1px";
this.style.borderColor = "#ff9900";
this.style.backgroundColor = "#ffcc99";
this.style.borderStyle = "outset";
}
}
objITButton.onmouseout = function(){
if (this.name != "pinable" || (this.name == "pinable" && this.style.borderStyle != "inset")) {
this.style.borderWidths = "1px, 1px, 1px, 1px";
this.style.borderColor = "white";
this.style.backgroundColor = "white";
this.style.borderStyle = "solid";
}
}
objITButton.onmousedown = function(){
this.style.borderWidths = "1px, 1px, 1px, 1px";
this.style.borderColor = "#ff9900";
if (this.name == "pinable" && this.style.borderStyle == "inset") {
this.style.borderStyle = "outset";
}
else {
this.style.borderStyle = "inset";
}
}
objITButton.onmouseup = function(){
if (this.name != "pinable" || (this.name == "pinable" && this.style.borderStyle != "inset")) {
this.style.borderWidths = "1px, 1px, 1px, 1px";
this.style.borderColor = "#ff9900";
this.style.borderStyle = "outset";
}
//window.focus();
}
}
}
//objITToolbar.style.width = intITTotalWidth + 20;
}
-->
</script>
<!-- HTML for article "Loading JPG & PNG resources using GDI+" by Joe Woodbury
URL: http://www.codeproject.com/cs/media/cgdiplusbitmap.asp
Article content copyright Joe Woodbury
All formatting, additions and alterations Copyright � CodeProject, 2003
-->
<!----------------------------- Ignore ----------------------------->
<link rel="stylesheet" type=text/css href="http://www.codeproject.com/styles/global.css">
<p><b>Please choose 'View Source' in your browser to view the HTML, or
File | Save to save this file to your hard drive for editing.</b></p>
<hr size=1 noshade>
<!----------------------------- Ignore ----------------------------->
<!----------------------------- Article Starts ----------------------------->
<ul class=download>
<li><a href="cgdiplusbitmap/cgdiplusbitmap_demo.zip">Download demo project - 122 Kb </a></li>
<li><a href="cgdiplusbitmap/cgdiplusbitmap_src.zip">Download source - 1 Kb</a></li>
</ul>
<h2>Introduction</h2>
<p>Recently, I needed to display some JPG and PNG files. I had an old
copy of LeadTools and the open source libraries for both formats, but wanted my executable
to be as small as possible. So I decided to give GDI+ a try. I quickly found that
I'm not a big fan of GDI+--I find it poorly designed and very quirky--but it worked
well for my purposes until I discovered, to my horror, that GDI+ cannot load JPG or
PNG files stored as resources!</p>
<p>Like, I'm sure, other developers facing this issue, I disbelieved the
documentation and tried <code>Bitmap::FromResource</code> to no avail. While perusing the
Bitmap methods available, I ran across <code>Bitmap::FromStream</code>.</p>
<p>After a bit of testing and several errors, due mostly to the horrible GDI+
documentation, I came up with working code. After a night of rest, I decided
to encapsulate the code in a simple class to ensure memory got freed. The result
were two classes: <code> CGdiPlusBitmap</code> and <code>CGdiPlusBitmapResource</code>.</p>
<h2>The Gotcha</h2>
<p>Before discussing the code itself, there is a caveat with GDI+ that must be addressed.
In GDI+, the original image information must be available at all times--it does not double
buffer the data. In other words, if you open a bitmap using <code>Bitmap::FromFile</code>,
you cannot delete or otherwise change that file while the image is open. This same
restriction applies to the <code>CGdiPlusBitmapResource</code>.</p>
<p>In my second iteration of the code, I was creating the Bitmap using <code>Bitmap::FromStream</code>
and then freeing the global memory. Everything appeared fine until I attempted to draw
the bitmap, whereupon I got an generic error. Remembering the caveat about <code>Bitmap::FromFile</code>
I realized I needed to retain the allocated global memory, thus the desire for a class
that automatically frees that memory.</p>
<h2>The Class</h2>
<p>For kicks, I created two classes, with the base class being a very simple encapsulation
of Bitmap. I suppose that if I ever had the patience and desire, I could extend that class.
(Some may be curious why I didn't simply subclass the ATL class <code>CImage</code>. It's because the
<code>CGdiPlusBitmapResource</code> has to be used in code that doesn't use MFC or ATL. However, the code
is so simple, it could easily be modified to use <code> CImage</code> as the base class.)</p>
<p>I'm not even going to bother going over the <code> CGdiPlusBitmap</code> class except to say that it
has a single, public, data member <code>Bitmap* m_pBitmap</code>. (In the class I prefaced
the GDI+ objects with the <code> Gdiplus</code> namespace in case the developer doesn't want to declare
<code>using namespace Gdiplus;</code>.)</p>
<p>The <code> CGdiPlusBitmapResource</code> class has several constructors and several overloaded
<code>Load</code> functions. The overloaded functions simply allow lazy programmers,
like myself, to not have to type <code>MAKEINTRESOURCE</code>. The main <code>Load</code>
function takes the resource name and type as strings and is the key to the class. This
code follows in its entirety:</p>
<pre>
inline
bool CGdiPlusBitmapResource::Load(LPCTSTR pName, LPCTSTR pType, HMODULE hInst)
{
Empty();
HRSRC hResource = ::FindResource(hInst, pName, pType);
if (!hResource)
return false;
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (!imageSize)
return false;
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (!pResourceData)
return false;
m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
if (!m_hBuffer)
return false;
void* pBuffer = ::GlobalLock(m_hBuffer);
if (!pBuffer)
{
::GlobalFree(m_hBuffer);
m_hBuffer = NULL;
return false;
}
CopyMemory(pBuffer, pResourceData, imageSize);
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(m_hBuffer, TRUE, &pStream) == S_OK)
{
m_pBitmap = Gdiplus::Bitmap::FromStream(pStream);
pStream->Release();
}
return m_pBitmap && m_pBitmap->GetLastStatus() == Gdiplus::Ok;
}</pre>
<p>I find the code very self explanatory, though those that know the return
value of <code>::LoadResource</code> is an <code> HGLOBAL</code> may find the apparent
double copy using <code>CopyMemory</code> confusing. In brief
<code>CreateStreamOnHGlobal</code> requires a <code> HGLOBAL</code> handle
allocated by <code> GlobalAlloc</code> using the <code> GMEM_MOVEABLE</code> flag.</p>
<h2>The Demo</h2>
<p>The demo was thrown together with Visual Studio .NET 2002 (VC++ 7.0) and
was tested under Windows XP. If you want to compile it with VC++ 6.0, you
can convert the project using a utility here on CodeProject.</p>
<p>The demo allows you to load resampled JPG or PNG files (For the curious I
took both photographs in Oahu, Hawaii for, and while filming content of, a
multimedia product. One is of Laie Bay, the other is a sunset viewed from Waikiki.)</p>
<h2>Disclaimer</h2>
<p>I am not a GDI+ expert, nor am I a big fan. Please don't ask me questions
about it, though if you have any suggestions or improvements, please let me know.</p>
<!----------------------------- Article Ends ----------------------------->