Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 1 | 2 |

 

  Вопрос: GetDIBits не работает Добавлено: 20.01.06 15:50  

Автор вопроса:  Victor | Web-сайт: vt-dbnz.narod.ru | ICQ: 345743490 
Есть такая очень полезная API-функция GetDIBits.
объявление ее выглядит так:
int GetDIBits(
  HDC hdc,           // handle to device context
  HBITMAP hbmp,      // handle to bitmap
  UINT uStartScan,   // first scan line to set in destination bitmap
  UINT cScanLines,   // number of scan lines to copy
  LPVOID lpvBits,    // address of array for bitmap bits
  LPBITMAPINFO lpbi, // address of structure with bitmap data
  UINT uUsage        // RGB or palette index
);

С API-viewer-а взято такое объявление (имя функции модифицировано, так сложилось):
Public Declare Function APIGetDiBits Lib "gdi32" Alias "GetDIBits" _
            (ByVal aHDC As Long, _
            ByVal hBitmap As Long, _
            ByVal nStartScan As Long, ByVal nNumScans As Long, _
            ByRef lpBits As Any, lpBI As BITMAPINFO, _
            ByVal wUsage As Long) As Long


Дальше есть ее упрощение:
Public Sub vtGetDIBitsFromImage(ByRef Data() As Long, _
                                ByVal hImage As Long, _
                                ByVal hDC As Long, _
                                Optional ByVal ClearReserved As Boolean = True)
Dim bmi As BITMAPINFO
Dim w As Long, h As Long
Dim Ret As Long

With bmi.bmiHeader
    .biSize = Len(bmi.bmiHeader)
End With
Ret = APIGetDiBits(hDC, hImage, 0, 0, ByVal 0, bmi, DIB_RGB_COLORS)
If Ret = 0 Then
    Err.Raise 1212, , "GetDIBIts for examining the dimensions failed!"
End If

With bmi.bmiHeader
    w = .biWidth
    h = Abs(.biHeight)
    .biBitCount = 32
    .biSizeImage = w * h * 4&
    .biPlanes = 1
    .biHeight = -h 'чтобы сам перевернул картинку
End With

ReDim Data(0 To w - 1, 0 To h - 1)

Ret = APIGetDiBits(hDC, hImage, 0, h, Data(0, 0), bmi, DIB_RGB_COLORS)
If Ret = 0 Then
    Err.Raise 1212, , "Getting bits failed!"
End If

If ClearReserved Then
    vtRepair Data 'не важно, что это, проверял с ClearReserved = False
End If

End Sub


И эта функция вызывается:
    vtGetDIBitsFromDevice BlackData, .hDC, ClearReserved:=False

Странное дело.
В отладке: дохожу до строчки vtGetDIBitsFromDevice BlackData,...
захожу внутрь, прохожу пошагово ВСЮ процедуру vtGetDIBitsFromImage и никаких ошибок не возникает. Но. При выходе возникает ошибка Bad dll calling convention (#=69).

Вопрос. Почему эта ошибка возникает вообще, и почему проблемы как бы с вызовом вбшной процедуры, а не с вызовом api?

Ответить

  Ответы Всего ответов: 30  

Номер ответа: 1
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #1
Добавлено: 20.01.06 16:03
49 Bad DLL calling convention Неправильное соглашение о вызове DLL
или Неверный вызов DLL

Ответить

Номер ответа: 2
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #2
Добавлено: 20.01.06 16:14
Private Const BI_RGB = 0&
Private Const DIB_RGB_COLORS = 0 '  color table in RGBs
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 RGBQUAD
        rgbBlue As Byte
        rgbGreen As Byte
        rgbRed As Byte
        rgbReserved As Byte
End Type
Private Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        bmiColors As RGBQUAD
End Type
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As BITMAPINFO, ByVal un As Long, ByVal lplpVoid As Long, ByVal handle As Long, ByVal dw As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Dim iBitmap As Long, iDC As Long
Private Sub Form_Paint()
    Dim bi24BitInfo As BITMAPINFO, bBytes() As Byte, Cnt As Long
    With bi24BitInfo.bmiHeader
        .biBitCount = 24
        .biCompression = BI_RGB
        .biPlanes = 1
        .biSize = Len(bi24BitInfo.bmiHeader)
        .biWidth = 100
        .biHeight = 100
    End With
    ReDim bBytes(1 To bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biHeight * 3) As Byte
    iDC = CreateCompatibleDC(0)
    iBitmap = CreateDIBSection(iDC, bi24BitInfo, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, ByVal 0&;)
    SelectObject iDC, iBitmap
    BitBlt iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, GetDC(0), 0, 0, vbSrcCopy
    GetDIBits iDC, iBitmap, 0, bi24BitInfo.bmiHeader.biHeight, bBytes(1), bi24BitInfo, DIB_RGB_COLORS
    For Cnt = LBound(bBytes) To UBound(bBytes)
        If bBytes(Cnt) < 50 Then
            bBytes(Cnt) = 0
        Else
            bBytes(Cnt) = bBytes(Cnt) - 50
        End If
    Next Cnt
    SetDIBitsToDevice Me.hdc, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, 0, 0, 0, bi24BitInfo.bmiHeader.biHeight, bBytes(1), bi24BitInfo, DIB_RGB_COLORS
    ;DeleteDC iDC
    ;DeleteObject iBitmap
End Sub


Ответить

Номер ответа: 3
Автор ответа:
 Victor



ICQ: 345743490 

Вопросов: 42
Ответов: 385
 Web-сайт: vt-dbnz.narod.ru
 Профиль | | #3
Добавлено: 20.01.06 16:42
По-моему, здесь написано то же самое, только 24-бита, и из конкретного места, к тому же с лишним копированием. Попробую. Если здесь такой ошибки не будет, для меня это будет просто мистика какая-то.

Ответить

Номер ответа: 4
Автор ответа:
 Victor



ICQ: 345743490 

Вопросов: 42
Ответов: 385
 Web-сайт: vt-dbnz.narod.ru
 Профиль | | #4
Добавлено: 20.01.06 16:45

1 To bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biHeight * 3
Это не будет работать при bi24BitInfo.bmiHeader.biWidth не делящегося на 4. Где padding на DWORD?

Ответить

Номер ответа: 5
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #5
Добавлено: 20.01.06 17:09
Пример я взял из API-Guide, проверял - делает фотку верха экрана и
помещает на форму!

Ответить

Номер ответа: 6
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #6 Добавлено: 20.01.06 18:33
то, что "работает" - случайное стечение обстоятельств.
Должно быть *4, а не *3, т.к. кроме трех байт цвета, ещё один байт отводится на альфу.

Ответить

Номер ответа: 7
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #7
Добавлено: 20.01.06 18:56
Ну так что работает?
То что нужно?

Ответить

Номер ответа: 8
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #8 Добавлено: 20.01.06 21:13
Ну так что работает?

С какого перепугу оно вдруг работать будет? Написал же - случайное стечение обстоятельств (ширина и высота рисунка кратны 4)

Попробуй сделать рисунок не 100х100, а например 98х98 и внимательно посмотри, что будет :)
Попробуй форму поресайзить, или свернуть - развернуть, или мышью ткнуть в рисуночек. Попробуй...

Ответить

Номер ответа: 9
Автор ответа:
 CyRax



Разработчик Offline Client

ICQ: 204447456 

Вопросов: 180
Ответов: 4229
 Web-сайт: basicproduction.nm.ru
 Профиль | | #9
Добавлено: 20.01.06 21:22
HOOLIGAN,
 но как то же он умещает 10000 RGBQUAD'ов в 30000 байт, хотя по идее буфер должен быть минимум 40000. Мистика какая то :)

Ответить

Номер ответа: 10
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #10 Добавлено: 20.01.06 22:08
Да в том то и фокус, что не умещает :)
Никаких попиксельных манипуляций с рисунком на уровне отдельно взятого цвета не происходит, поэтому и не видно, сколько процентов рисунка содержится в массиве bBytes.
А как только начнешь по всем правилам например устанавливать все пиксели рисунка в красный цвет - тут тебе сразу и выползет: в красный установится только 3/4 рисунка, последняя недостающая четверть будет черной, т.к. массив под нее не рассчитан, и SetDIBitsToDevice закрасит красным 3/4, а последняя четверть останется незаполненной (черной).
Вот такай капкан в api-guide :)

Ответить

Номер ответа: 11
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #11 Добавлено: 20.01.06 22:13
А то, что прога не сразу выпадает от неправильного размера - возможно до поры до времени спасает bound checking.
Но стоит только сделать некратным 4 размер рисунка, и checking не спасает - прога вылетает к чертям по эксепшен ACCESS_VIOLATION.

Ответить

Номер ответа: 12
Автор ответа:
 Victor



ICQ: 345743490 

Вопросов: 42
Ответов: 385
 Web-сайт: vt-dbnz.narod.ru
 Профиль | | #12
Добавлено: 21.01.06 00:58
Там написано.
.biBitCount = 24

Это значит, что на пиксель отводится ровно три байта, то есть 24 бита. Но в битмапах есть такое правило: каждая строчка должна занималь колво байтов, делящееся на четыре. А так никакой альфы там нет, и по этому надо именно *3, а не на 4.
Просто надо было посчитать длину строчки в байтах и выровнять ее на границу двойного слова. Типа
LineLengthInBytes = -int( -(width*3) / 4 ) * 4
И считать длину массива как LineLength*height.

Простите, что до сих пор не проверил код на действие.

Ответить

Номер ответа: 13
Автор ответа:
 HOOLIGAN



Вопросов: 0
Ответов: 1066
 Профиль | | #13 Добавлено: 21.01.06 09:12
Простите, что до сих пор не проверил код на действие

Ну тогда проверь сначала, потом будешь говорить, что на 3 умножать надо.

Это значит, что на пиксель отводится ровно три байта, то есть 24 бита. Но в битмапах есть такое правило: каждая строчка должна занималь колво байтов, делящееся на четыре


Это кто ж такое правило придумал? Ровным на 4 должно быть начало массива, все остальные пиксели автоматом становятся кратными 4.
Сначала посмотри, что представляет из себя этот массив, а потом будешь говорить, сколько байт на пиксель

typedef struct tagRGBQUAD {
  BYTE    rgbBlue;
  BYTE    rgbGreen;
  BYTE    rgbRed;
  BYTE    rgbReserved;
} RGBQUAD;


Remarks
The [B]bmiColors member of the BITMAPINFO structure consists of an array of RGBQUAD structures[/B]


Черным по белому написано: массив RGBQUAD-ов
Думаю, теперь тебе видно, сколько байт на пиксель отводится, и на сколько нужно умножать?

Ответить

Номер ответа: 14
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #14
Добавлено: 21.01.06 10:42
Ну вот все и хорошо, а то сразу не работает, не работает - все гуд,
все работает!

Ответить

Номер ответа: 15
Автор ответа:
 [root]



Вопросов: 45
Ответов: 1212
 Web-сайт: bit.pirit.info
 Профиль | | #15
Добавлено: 21.01.06 10:54
Ага простите та простите, а вот спасибо то даже не сказал! ;-)

Ответить

Страница: 1 | 2 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам