biSizeImage与width,height的关系??

Cacar 2007-11-03 12:55:54
BITMAPINFOHEADER中biSizeImage这一项是图像数据的大小吧?为什么不等于宽*高呢?比如309*63的位图,读到的biSizeImage是58466,63*309的位图(旋转90度),biSizeImage却是59330~是不是跟“宽度需是4的整数倍"什么的有关系,迷糊了~希望知道的给解释一下:)
...全文
234 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
Cacar 2007-11-07
  • 打赏
  • 举报
回复
明白了,24位深度,应该是 ((24*width)+31)、32*4*height,就是biSizeImage的值了。。共同学习!
Cacar 2007-11-07
  • 打赏
  • 举报
回复
急~谁来给看看~~~*_*!
Cacar 2007-11-06
  • 打赏
  • 举报
回复
309*63的情况,宽度309最近的4的整数倍是312,312*63*3=58968(位深24),跟踪看到biSizeImage却是58466,为什么啊?怎么算的?
wrcluomo 2007-11-06
  • 打赏
  • 举报
回复
WIDTH '是指大于或等于WIDTH的离4最近的整倍数.
wrcluomo 2007-11-06
  • 打赏
  • 举报
回复
biSizeImage指定位图数据实际占用的字节数,即WIDTH'*HEIGHT,WIDTH'是指大于或等于WIDTH的离4最近的整数.
如果BICOMPRESSION为BI_RGB时,该项可能为0
Cacar 2007-11-04
  • 打赏
  • 举报
回复
有空的来给指点下撒~
Cacar 2007-11-03
  • 打赏
  • 举报
回复
比如309*63的位图,读到的biSizeImage是58466,63*309的位图(旋转90度),biSizeImage却是59330,这个怎么算的,309对齐是312,63对齐是64~也算不出来biSizeImage(这里对应的58466和59330)啊?
凤矶 2007-11-03
  • 打赏
  • 举报
回复
有关系,内存对齐,大部分是4字节对齐。
Bmp To Mif 转换器 // (karimov 2005) // This program was originnaly written by one of the ECE241 students to convert an image // supplied in a BMP file into an MIF file format for use with Quartus II. // // This program has recently been modified to work with the new VGA controller used with the DE2 // board. // // What to do: // 1. Create an image in Microsoft paint (or other program). The image must be 160 pixels wide, 120 pixels high and // use 24-bits to represent colour information. // 2. Once you create the image you need, flip it up-side down. Then save the BMP file. (example: foo.bmp) // 3. Run this converter in command prompt using the name of the BMP file you created as a command-line parameter. // For example: // bmp2mif foo.bmp // 4. The program generates two files: // image.colour.mif - an MIF file with 3 bits colour information obtained from the BMP file you supplied // image.mono.mif - an MIF file containing 1 bit of colour for every pixel on the screen. The dot will either be // black or white. // You can change the file names once they are created, but they should still have the .mif extension. // // 5. Copy the proper MIF file to the directory where your design is located and include it in your project. // 6. Change the BACKGROUND_IMAGE parameter of the VgaAdapter to indicate your MIF file. // 7. The COLOR_CHANNEL_DEPTH parameter must be set to 1 to work with the image.colour.mif file. #include #include #define FLIP_INT(c) ((c >> 24) & 0x000000FF) | ((c & 0x00FF0000) >> 8) | ((c & 0x0000FF00) << 8) | ((c & 0x000000FF) <> 8) | ((c & 0x00FF) << 8) typedef struct s_header { unsigned short bfType; unsigned int bfSize; unsigned short reserved1; unsigned short reserved2; unsigned int offset; } t_bmp_header; typedef struct s_bmp_info { unsigned int biSize; unsigned int biWidth; unsigned int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; unsigned int biXPelsPerMeter; unsigned int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } t_bmp_info; int faprint(FILE *fcol, FILE *fm, const char *pattern) { fprintf(fcol, pattern); return fprintf(fm, pattern); } int main(int argc, char* argv[]) { FILE *f, *fcol, *fm; int y; unsigned int x, c, r, g, b; unsigned int width, height; if (argc != 2) { printf("Usage: bmp2mif \n"); return 0; } else { printf("Input file is: %s\n", argv[1]); } printf("This program converts n x m 24-bit .BMP image to MIF file\n"); printf("There are 2 files produced:\n"); printf("\timage.colour.mif - 8-colour channel, n x m x 3\n"); printf("\timage.mono.mif - black and white image, n x m x 1\n\n"); f = fopen(argv[1], "rb"); fcol = fopen("image.colour.mif", "wb"); fm = fopen("image.mono.mif", "wb"); if (f) { t_bmp_header header; t_bmp_info info; fread(&header, 14, 1, f); /* sizeof(t_bmp_header) returns 16 instead of 14. Should be 14. */ fread(&info, sizeof(t_bmp_info), 1, f); #if !defined (WIN32) header.bfSize = FLIP_INT(header.bfSize); header.bfType = FLIP_SHORT(header.bfType); header.offset = FLIP_INT(header.offset); header.reserved1 = FLIP_SHORT(header.reserved1); header.reserved2 = FLIP_SHORT(header.reserved2); info.biSize = FLIP_INT(info.biSize); info.biWidth = FLIP_INT(info.biWidth); info.biHeight = FLIP_INT(info.biHeight); info.biPlanes = FLIP_SHORT(info.biPlanes); info.biBitCount = FLIP_SHORT(info.biBitCount); info.biCompression = FLIP_INT(info.biCompression); info.biSizeImage = FLIP_INT(info.biSizeImage); info.biXPelsPerMeter = FLIP_INT(info.biXPelsPerMeter); info.biYPelsPerMeter = FLIP_INT(info.biYPelsPerMeter); info.biClrUsed = FLIP_INT(info.biClrUsed); info.biClrImportant = FLIP_INT(info.biClrImportant); #endif printf("Input file is %ix%i %i-bit depth\n", info.biWidth, info.biHeight, info.biBitCount); if (info.biBitCount == 24) { char temp[100]; width = info.biWidth; height = info.biHeight; printf("Converting...\n"); sprintf(temp, "Depth = %i;\r\n",width*height); faprint(fcol, fm, temp); fprintf(fcol, "Width = 3;\r\n"); fprintf(fm, "Width = 1;\r\n"); faprint(fcol, fm, "Address_radix=dec;\r\n"); faprint(fcol, fm, "Data_radix=bin;\r\n"); faprint(fcol, fm, "Content\r\n"); faprint(fcol, fm, "BEGIN\r\n"); sprintf(temp, "\t[0..%i] : 000;\r\n", width*height - 1); fprintf(fcol, temp); sprintf(temp, "\t[0..%i] : 0;\r\n", width*height - 1); fprintf(fm, temp); fseek(f, 54, SEEK_SET); for(y=height-1; y >=0; y--) { x = 0; fprintf(fcol, "\t%i :", y*width+x); fprintf(fm, "\t%i :", y*width+x); for(x=0; x 0) && ((x % 40) == 0)) { fprintf(fcol, ";\r\n\t%i :", y*width + x); fprintf(fm, ";\r\n\t%i :", y*width + x); } #if defined (WIN32) c = ((c >> 24) & 0x000000FF) | ((c & 0x00FF0000) >> 8) | ((c & 0x0000FF00) << 8) | ((c & 0x000000FF) <>= 8; b = (c & 0xFF0000) >> 16; g = (c & 0x00FF00) >> 8; r = (c & 0x0000FF); c = r + g + b; c /= 3; r = (r >= 128 ? 1 : 0); g = (g >= 128 ? 1 : 0); b = (b >= 128 ? 1 : 0); c = (c >= 128 ? 1 : 0); fprintf(fcol, " %i%i%i", r, g, b); fprintf(fm, " %i", c); } faprint(fcol, fm, ";\r\n"); if ((x*3) % 4 != 0) { fread(&c, 4-((x*3) % 4), 1, f); } } faprint(fcol, fm, "End;\r\n"); } else printf("Input file image.bmp is not in a 24-bit colour format!\n"); fclose(fm); fclose(fcol); fclose(f); printf("All done.\n"); } else printf("Cannot open input file. Check for input.bmp\n"); }
What is a DIB Section?
A DIB (Device Independent Bitmap) Section is a GDI object like a standard DIB but which additionally provides a pointer to the memory used to store the bitmap bits to which the creating application has direct access. This allows ultimate flexibility if you want to modify the bits of a bitmap.

Using DIB Sections
A DIB section is created using the GDI CreateDIBSection call. You need to modify the declare provided for this in the VB API guide because this declare assumes you cannot use the pointer to the bitmap returned by the function and simply discards it. Here are the declares you need:


Private Type BITMAPINFOHEADER '40 bytes
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBQUAD
End Type

' Note - this is not the declare in the API viewer - modify lplpVoid to be
' Byref so we get the pointer back:
Private Declare Function CreateDIBSection Lib "gdi32" _
(ByVal hdc As Long, _
pBitmapInfo As BITMAPINFO, _
ByVal un As Long, _
lplpVoid As Long, _
ByVal handle As Long, _
ByVal dw As Long) As Long


To create the DIB Section, you initialise a BITMAPINFO structure with the required fields, which are all in the bmiHeader sub-structure:

Member Required Value
biSize Size of the BITMAPINFO structure
biWidth Width of the DIBSection in pixels

biHeight Height of the DIBSection in pixels

biPlanes Number of colour planes. Set to 1

biBitCount Bits per pixel. Set to 24 for true colour

biCompression Whether to use compression. If you want to work on the bits, set this to BI_RGB so the image is uncompressed
biSizeImage The size of the image in bytes. This is worked out from the width, height, number of bits per pixel. In a 24 bit image there are three bytes per pixel. Additionally, GDI requires that every horizontal line in the image aligns on a four byte boundary. So for a 24 bit image the ImageSize is biWidth*biHeight*3 rounded up to the nearest four bytes. You can round up to the width to the nearest four bytes as follows:
(.biWidth * 3 + 3) And &HFFFFFFFC



This allows you to create a DIB Section. You call CreateDIBSection like this:

hDib = CreateDIBSection( _
lHDC, _
m_tBI, _
DIB_RGB_COLORS, _
m_lPtr, _
0, 0)


Where:

hDib is a variable to receive the GDI handle to the DIB Section
lHDC is a valid DC, for example a Form's DC or the desktop DC

m_tBI is a the BITMAPINFO structure
m_lPtr is a variable to receive the pointer to the memory containing the bitmap bits.

To actually display a DIB Section, you must select it into a DC.

m_hDC = CreateCompatibleDC(0)
If (m_hDC <> 0) Then
If (CreateDIB(m_hDC, lWidth, lHeight, m_hDIb)) Then
m_hBmpOld = SelectObject(m_hDC, m_hDIb)
Create = True
Else
DeleteObject m_hDC
m_hDC = 0
End If
End If



Once it is in a DC you can then use BitBlt to paint it to another device context or to transfer the contents of another device context into it. Remember you must keep track of all the handles created in GDI so you can clear them up again when the DIBSection is no longer needed. To clear up, you need to:

Select the old bitmap (m_hBmpOld) back into the DC.
Delete the DIB section.
Delete the DC.
So far this has created a DIB which you can load with a graphic and display on the screen, but this achieves no more than you can do with a standard bitmap. The good stuff starts when you start modifying the bitmap bits.

Modifying the Bitmap Bits Directly
CreateDIBSection returns an address to the memory containing the bitmap. You can manipulate this directly through VB using a cool technique to make the memory look like a VB Byte array. This technique was originally presented in VBPJ article (Note the original article is no longer easily available). It uses a hidden VB call exposed by MSVBVM50.DLL (which is also available in VB6 - thanks to Paul Wilde for pointing this out) and the ubiquitous CopyMemory call. In my opinion, “CopyMemory” is the best language feature in VB (except that it isn't VB at all!)

Here are the declares you need:

Private Type SAFEARRAY2D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
Bounds(0 To 1) As SAFEARRAYBOUND
End Type
Private Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Ptr() As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)



To make the byte array point to the memory, you have to fill in the SAFEARRAY2D structure and then use CopyMemory as follows:

Dim tSA As SAFEARRAY2D
Dim bDib() As Byte

' Get the bits in the from DIB section:
With tSA
.cbElements = 1
.cDims = 2
.Bounds(0).lLbound = 0
' Height of the bitmap
.Bounds(0).cElements = m_tBI.bmiHeader.biHeight
.Bounds(1).lLbound = 0
' Width of the bitmap in bits (see earlier):
.Bounds(1).cElements = BytesPerScanLine()
.pvData = m_lPtr
End With
' Make the bDib() array point to the memory addresses:
CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4



Now the bDib() array is a two dimensional array with the first dimension being the x values and the second being the y values. A 24 bit DIB section is arranged so the bytes run Blue, Green, Red and remember that since the array is padded to a DWORD boundary there may be up to three unused bytes at the end of each row. So, for example, to set the top left pixel to purple you would write this:

bDib(0,0) = 255 ' Blue
bDib(1, 0) = 0 ' Green
bDib(2, y) = 255 ' Red



Once you have finished with the bDib array, you need to be sure to clear up the SAFEARRAY pointer you have created. If you fail to do this, your code will work under Win9x but will crash NT4.0:

CopyMemory ByVal VarPtrArray(bDib), 0&, 4


Enough of That, I Want to Use It
That covers the theory of using DIB Sections. To make it easy, I include a self-contained class (cDibSection) which you can include. The implementation is as follows:

Method Description
BytesPerScanLine Returns the number of bytes horizontally, taking into account the bits per pixel and 4 byte boundary padding.
ClearUp Frees up any GDI objects held by the class. Called automatically when the class terminates.
CopyToClipboard Does as it says!
Create Creates a DIB section of the specified width and height in pixels.
CreateFromPicture Creates a DIB section the same size as a VB picture object and copies the bitmap in it into the DIB section.
DIBSectionBitsPtr Returns the address of the DIBSection's bits in memory.
hdc Returns the memory device context used by the class to hold the DIB Section. You can use this in GDI operations, but do not call DeleteObject on it.
hDib Returns a handle to the DIBSection held by the class. You can use this in GDI operations, but do not call DeleteObject on it.
Height Returns the Height of the DIBSection in pixels.
LoadPictureBlt Copies all or a part of a picture from another Device Context into the DIB section.
PaintPicture Similar to the VB paint picture method, this copies all or part of the DIB section to another device context using the specified Raster Operation.
RandomiseBits Randomises the pixels in the DIB Section, either to random colours or gray scaled.
Resample Resizes the DIB using linear interpolation to create a smoother resized version than you would get if you used StretchBlt.
Width Returns the width of the DIB in pixels.


A Simple Fade Example
This demonstrates how to fade out a bitmap. It should run as a real-time animation, provided the image size isn't too big. I've found that images which are too large don't show as a smooth animation even when the fade code runs quickly enough because BitBlt tends to "tear". This occurs because BitBlt doesn't completely display the bitmap during a single screen refresh and therefore the image is partially displayed before the refresh occurs. To get round this problem you need to use DirectX.

This sample is simplified version of the static and fade example available for download on the Image Processing using DIB Sections page.

To try this sample, create a new project and add the cDIBSection class to it. Copy the declares for CopyMemory, VarPtrArray and SAFEARRAY2D into the project's form.

Then add this sub:

Private Sub Fade( _
ByRef cTo As cDIBSection, _
ByVal lAmount As Long _
)
Dim bDib() As Byte
Dim x As Long, y As Long
Dim xMax As Long, yMax As Long
Dim lB As Long, lG As Long, lR As Long
Dim lA As Long, lA2 As Long
Dim lTIme As Long
Dim tSA As SAFEARRAY2D

' have the local matrix point to bitmap pixels
With tSA
.cbElements = 1
.cDims = 2
.Bounds(0).lLbound = 0
.Bounds(0).cElements = cTo.Height
.Bounds(1).lLbound = 0
.Bounds(1).cElements = cTo.BytesPerScanLine
.pvData = cTo.DIBSectionBitsPtr
End With
CopyMemory ByVal VarPtrArray(bDib), VarPtr(tSA), 4

yMax = cTo.Height - 1
xMax = cTo.Width - 1

For x = 0 To (xMax * 3) Step 3
For y = 0 To yMax
lB = lAmount * bDib(x, y) \ 255
lG = lAmount * bDib(x + 1, y) \ 255
lR = lAmount * bDib(x + 2, y) \ 255
bDib(x, y) = lB
bDib(x + 1, y) = lG
bDib(x + 2, y) = lR
Next y
Next x

CopyMemory ByVal VarPtrArray(bDib), 0&, 4

End Sub


Add a Command Button to the Form, and put this code behind it:

Private Sub Command1_Click()

Dim cDib As New cDibSection
Dim cDibBuffer as New cDibSection
Dim i As Long

' Load the picture to fade:
Set sPic = LoadPicture("Put Your File Here!")
cDib.CreateFromPicture sPic

' Create a copy of it:
cDibBuffer.Create cDib.Width, cDib.Height
cDib.PaintPicture cDibBuffer.HDC

' Fade Loop:
For i = 0 To 255 Step 4
' Fade the dib by amount i:
Fade cDib, i
' Draw it:
cDib.PaintPicture Form1.hDC
' Breathe a little. You may have to put a slowdown here:
DoEvents
' Reset for next fade:
cDibBuffer.PaintPicture cDib.HDC
Next i

End Sub



Now run the code. When you click the button, the image will be faded as fast as your system allows. The code will run slowly in the IDE but will go much much quicker if you compile it to native code. Also, checking all the Advanced Optimisation settings will make it run about 60% faster again! On my machine (PII 266 with 8Mb Xpert@Work card) it does 40fps when working on a 256x256 pixel image.



Using DIB Sections in VB An Easy to Use Class for manipulating DIBSections plus a blindingly quick technique for updating the bits Updated! 17 February 1999 The previous version of this code crashed when run under NT4.0. This was because the code was not always clearing up the SAFEARRAY pointer after it had finished using it. Under Win9x, this did not cause a problem but NT is stricter. All the samples and the code are now updated to fix this problem. This is a supporting article describing in more detail the DIB Section techniques used in the vbAccelerator Image Processor. It describes what DIB Sections are, how to use them and provides a class I wrote to wrap up the DIB Section. What is a DIB Section?A DIB (Device Independent Bitmap) Section is a GDI object like a standard DIB but which additionally provides a pointer to the memory used to store the bitmap bits to which the creating application has direct access. This allows ultimate flexibility if you want to modify the bits of a bitmap. Using DIB SectionsA DIB section is created using the GDI CreateDIBSection call. You need to modify the declare provided for this in the VB API guide because this declare assumes you cannot use the pointer to the bitmap returned by the function and simply discards it. Here are the declares you need:Private Type BITMAPINFOHEADER '40 bytes biSize As Long biWidth As Long biHeight As Long biPlanes As Integer biBitCount As Integer biCompression As Long biSizeImage As Long biXPelsPerMeter As Long biYPelsPerMeter As Long biClrUsed As Long biClrImportant As Long End Type Private Type BITMAPINFO bmiHeader As BITMAPINFOHEADER bmiColors As RGBQUAD End Type ' Note - this is not the declare in the API viewer - modify lplpVoid to be ' Byref so we get the pointer back:

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧