⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 invert_bitmap_inplace.shtml.htm

📁 mfc资料集合5
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="Zafir Anjum">
   <TITLE>Bitmap & Palette - Invert (mirror) a bitmap in-place</TITLE>
</HEAD>
<body background="../fancyhome/back.gif" tppabs="http://www.codeguru.com/fancyhome/back.gif" bgcolor="#FFFFFF" link="#B50029" vlink="#8E2323" alink="#FF0000">
<table WIDTH="100%">
<tr WIDTH="100%">
<td><td>
</tr>
</table>


<CENTER>
<H3>
<FONT COLOR="#AOAO99">Invert (mirror) a bitmap in-place</FONT></H3></CENTER>

<CENTER>
<H3>

<HR></H3></CENTER>

This code was contributed by <A HREF="mailto:Roger_Onslow@compsys.com.au">Roger Onslow</A>.


<p>It is possible to invert a bitmap (laterally or vertically) IN-PLACE - ie.
without creating any intermediate or temporary bitmaps. You can modify the 
original bitmap directly. This can be very
useful if you are wanting to reflect a LARGE bitmap, and don't want to
allocate the extra storage.  The operation requires 50% more StretchBlt
operations, but does not have the overhead of creating the extra bitmaps
and device contexts.  Compare this to GetInvertedBitmap presented elsewhere
which needs to make a copy of the original bitmap. 



<p>The Windows SDK appears to provide very few functions for manipulating the
contents of a bitmap.  Sure, you can draw on a bitmap using GDI functions.
And you can copy a rectangular part of a bitmap onto another bitmap with
BitBlt or StretchBlt, but that's about it.

<p>However, the BitBlt and StretchBlt routines are quite powerful little
beasts,
and you can do all sorts of manipulations using them.

<p>For example, you can use StretchBlt to copy a bitmap onto another bitmap,
but
reflect it in the x or y axis along the way.  And if you do both at once,
you
can copy the image flipped upside down.  To do this, you specify a negative
value for the destination width (for a y-axis reflection) or destination
height (or a x-axis reflection).

<p>You can also use the various raster operations (or ROPs) to achieve various
interesting effects by specifying how the source and destination bits
interact
with each other.

<p>All these operations are good for copying from one bitmap to another (
including copy from a bitmap to the screen - which is just another bitmap
anyway).  But what about actually CHANGING a bitmap itself?

<p>Well, you could make a second bitmap, do your magic with it, and then copy
the
result back.  However, that means you need an extra BitBlt to copy back,
AND
you need extra storage for the temporary bitmap.

<p>A better solution is to do all the changes in place on the original bitmap.
This is not always possible, but when it is, you get savings in both memory
and processing.

<p>In this article we will look at using StretchBlt to do x and y axis
reflections in-place, WITHOUT needing another bitmap.

<p>Before leaping straight into some code, lets go back to one of the simplest
functions a beginning program learns how to write - the function to swap
the
values of two variables.

<PRE><TT><FONT COLOR="#990000">
void Swap (int& a, int &b) {
     int temp = a;
     a = b;
     b = temp;
}
</FONT></TT></PRE>

<p>This function swaps two integer variables.  Note that this requires the use
of a temporary variable, which I have given the unoriginal name 'temp'.  We
make a copy of 'a' in 'temp', overwrite 'a' with 'b' (but we still have a
copy
in 'temp') and then finally clobber 'b' with the saved value in 'temp'.
All
very simple - and a temporary int is not a problem.

<p>But what if a and b are large structures or blocks of memory instead?  Then
a temporary could be an expensive thing indeed?  But how can we swap the
values without it?

<p>Elementary, my dear Watson, we use logic!

<p>One of the basic primitive operations that you can do to a lump of bits is
called an exclusive-or ('XOR') operation.  It is a cousin of the more
familiar
'AND' and 'OR' operations that we all know and love.  When you combine two
values with an 'XOR', you get a 1-bit for each bit that is different and a
'0' bit for each that is the same.  That is, it sets a bit if and only if
one
or the other (but not both) of the input bits are set.

<p>Here are some 'truth tables' that might clear it up.  Compare the table for
XOR with those for AND and OR.

<PRE><TT><FONT COLOR="#990000">
XOR     0       1         AND   0       1         OR    0       1
0       0       1           0   0       0           0   0       1
1       1       0           1   0       1           1   1       1
</FONT></TT></PRE>

<p>By looking at the truth table for XOR, you can see that it effectively
toggles
(or swaps) the state of a bit of one input when the corresponding bit of
the
other input is 1.

<p>Also not that '(A XOR B) XOR B)' returns A, regardless of B.  The first XOR
with B swaps the state of some of the bits, and then the second XOR swaps
the
same states back again.

<p>In C (and C++) the XOR operator is '^', so 'a ^ b' will do a bit-wise XOR
operation between a and b and return the result.  There is also a
XOR-assignment operator '^=', so 'a ^= b' will do a bit-wise XOR of b ont
a,
replacing the original value of a.

<p>Now comes some magic, we can use XOR's bit state swapping abilities to do
our entire integer swapping WITHOUT a temporary.

<PRE><TT><FONT COLOR="#990000">
void InPlaceSwap (int& a, int &b) {
     a ^= b;
     b ^= a;
     a ^= b;
}
</FONT></TT></PRE>

<p>Let's look at some bits to see this in action. We'll start off with a=12
and
b = 10 (in binary a=1100, b=1010).  Watch what happens to the bits as each
statement of InPlaceSwap executes:

<PRE><TT><FONT COLOR="#990000">
                  a     b      Algebra
               1100  1010
    a ^= b;    0110  1010      a' = a^b
    b ^= a;    0110  1100      b' = b^a' = b^a^b = a
    a ^= b;    1010  1100      a" = a'^b' = a^b^a = b
</FONT></TT></PRE>

<p>The end result is that a and b are swapped.

<p>You can use the same technique to swap to large blocks of memory by XOR-ing
their bits using the same algorithm.  In fact, you can swap chunks of bits
in
a BITMAP using this algorithm - by using BitBlt with the SRCINVERT raster
op,
which does an XOR operation.

<PRE><TT><FONT COLOR="#990000">
void SwapBlt (CDC* pDC1, int x1, int y1,
                 int nWidth, int nHeight,
                 CDC* pDC2, int x2, int y2
                 ) {
     if (! nWidth || ! nHeight) return;
     pDC1->BitBlt(x1,y1, nWidth,nHeight, pDC2, x2,y2, SRCINVERT);
     pDC2->BitBlt(x2,y2, nWidth,nHeight, pDC1, x1,y1, SRCINVERT);
     pDC1->BitBlt(x1,y1, nWidth,nHeight, pDC2, x2,y2, SRCINVERT);
}
</FONT></TT></PRE>

<p>The SwapBlt function above uses exactly the same algorithm as the
SwapInPlace
function previously to swap the rectangle of size nWidth x nHeight at [x1,
y1]
with the one at [x2,y2].  Each BitBlt simply does an XOR of two chunks of
bitmap memory.

<p>By creating a compatible device context and selecting a bitmap into it, you
can use SwapBlt to swap the left hand side and right hand side of the
bitmap
image as shown below.

<p>First we need a helper function to give us the actual width and height of
the
bitmap.

<PRE><TT><FONT COLOR="#990000">
void GetWidthAndHeight(CBitmap* pBitmap, int* pw, int* ph) const {
     if (! pBitmap && ! pBitmap->GetSafeHandle()) {     // no bitmap yet
          if (pw) *pw = 0;
          if (ph) *ph = 0;
     } else {
          BITMAP bm;
          pBitmap->GetObject(sizeof(bm), &bm);
          if (pw) *pw = bm.bmWidth;
          if (ph) *ph = bm.bmHeight;
     }
}
</FONT></TT></PRE>

<p>Here's the swapper:

<PRE><TT><FONT COLOR="#990000">
void SwapLeftAndRightHalves (CBitmap* pBitmap) {
     if (!pBitmap || ! pBitmap->GetSafeHandle()) return;
     // create DC and select bitmap into it
     CDC dc;
     CDC* pDC = &dc;
     pDC->CreateCompatibleDC( NULL );
     CBitmap* pBmpOldImage = pDC->SelectObject(pBitmap);
     // get bitmap size
     int nWidth,nHeight;
     ::GetWidthAndHeight(pBitmap,&nWidth,&nHeight);
     // do the swap
     int nHalfWidth = nWidth/2;
     if (nHalfWidth < 1) return;
     ::SwapBlt(pDC,0,0,nHalfWidth,nHeight,pDC,nWidth-nHalfWidth,0);
     // reselect old bitmap into DC
     pDC->SelectObject(pBmpOldImage);
}
</FONT></TT></PRE>

<p>This function simply works out the width of the two halves, by halving the
bitmap width.  Then it swaps the left and right sides by passing the same

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -