SR2D: как в спрайт загрузить картинку из массива?

Работа с 2D и 3D графикой, видео, звуком.

Модератор: Mikle

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 20.06.2019 (Чт) 19:01

Пытаюсь пользоваться этой фантастической библиотекой :D Жаль, справки нет...

Я так понимаю, что в спрайте не предусмотрена загрузка картинок из массива. Как бы её прикрутить?

Пока что просто сохраняю из спрайтов в один файл массивы cBuf и публичные свойства, а потом назад загружаю. Это работает, но шибко уж большие файлы получаются :)

Способ загружаться из IPicture не подходит, поскольку так нельзя загрузить картинку с альфа-каналом :cry:
Артур
 
   

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение Mikle » 20.06.2019 (Чт) 21:35

arthur2 писал(а):Я так понимаю, что в спрайте не предусмотрена загрузка картинок из массива. Как бы её прикрутить?

Можно подробнее? Из какого массива? Массив чего, каких элементов? И загрузить куда, в SR2D_Sprite?

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 21.06.2019 (Пт) 3:59

Я имею ввиду, как загрузить в спрайт картинку из файла, уже прочитанного в массив байтов.
Артур
 
   

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение Mikle » 21.06.2019 (Пт) 8:31

А он прочитан как целый файл (с заголовком, кодированием и т. п.), или как готовые данные ARGB?
Если первое - требуется что-то типа LoadFromFileInMemory, могу подумать над этим.
Если второе - Init спрайту под нужный размер и CopyMemory с адреса данных в памяти на адрес Spr.DataPtr(0, 0).

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 21.06.2019 (Пт) 19:39

Mikle писал(а):А он прочитан как целый файл (с заголовком, кодированием и т. п.), или как готовые данные ARGB?
Изначально была задача - ну хоть как-нибудь :) Хотя, конечно, лучше первое

Давно замечал такую штуку - пока сам пытаюсь ковыряться, решение вопроса обычно продвигается медленно и какими-то извилинами. А как сформулируешь да выложишь на форум - очень часто вопрос быстро решается словно сам собой.

В общем, я нашел вот этот пример: viewtopic.php?f=28&t=31865
Там есть загрузка из байтов, но в iPicture, что меня отпугнуло, когда натыкался на него раньше. А оказалось, что очень просто можно вживить загрузку из байтов оттуда в твою LoadFromFile. Практически весь код твой, только две строки поменялись.

Код: Выделить всё
Public Sub LoadFromBytes(Bytes() As Byte, Optional ByVal Trans As SR2D_Transform = TrNone, Optional ByVal W As Long = 0, Optional ByVal H As Long = 0, Optional ByVal cKey As Long = -1)
  Dim Res As Long
  Dim Stream  As IUnknown

  Dim tSI As GdiplusStartupInput
  Dim GDIP As Long
  Dim Bmp As Long
  Dim lData As BitmapData
  Dim R As RECTL
  Dim x As Long, y As Long
  Dim Sp As SR2D_Sprite

  If Trans <> TrNone Or W > 0 Or H > 0 Then
    Set Sp = New SR2D_Sprite
    Sp.LoadFromBytes Bytes
    LoadFromSprite Sp, Trans, W, H, cKey
  Else
    tSI.GdiplusVersion = 1
    Res = GdiplusStartup(GDIP, tSI)
    If Res = 0 Then
   
        CreateStreamOnHGlobal Bytes(0), False, Stream
     
      Res = GdipLoadImageFromStream(Stream, Bmp)
      If Res = 0 Then
        GdipGetImageWidth Bmp, x
        GdipGetImageHeight Bmp, y
        R.Left = 0
        R.Right = x
        R.Top = 0
        R.Bottom = y
        Res = GdipBitmapLockBits(Bmp, R, ImageLockModeRead, PixelFormat32bppARGB, lData)
        If Res = 0 Then
          Init x, y, OpPaint
          CopyMemory ByVal lData.Scan0, cBuf(0), x * y * 4
          GdipBitmapUnlockBits Bmp, lData
          If cKey >= 0 Then AddColorKey cKey: Op = OpAlphaTest
        End If
        GdipDisposeImage Bmp
      End If
      Set Stream = Nothing
      GdiplusShutdown GDIP
    End If
  End If
End Sub

В общем, работает :) Осталось понять, всё ли правильно - в частности, не нужно ли как-то по-особому уничтожать или освобождать стрим?
Артур
 
   

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение Mikle » 21.06.2019 (Пт) 21:16

С виду всё правильно, только это я бы и назвал LoadFromFileInMemory, а название LoadFromBytes у меня больше ассоциируется с сырыми данными.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 21.06.2019 (Пт) 21:23

всё ли правильно

Нет конечно. CreateStreamOnHGlobal первым параметром принимает hGlobal а не указатель на данные в SafeArray. Если нужно передать указатель то проще вызвать SHCreateMemStream.
GdipBitmapLockBits позволяет передать буфер, так что можно обойтись без CopyMemory (кстати в котором тоже ошибка - перепутаны dst/src).
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 21.06.2019 (Пт) 22:03

Mikle писал(а):только это я бы и назвал LoadFromFileInMemory
Собственно, я тут и не писал ничего - функция твоя, вставка вместе с названием - из кирпича от Andrey Fedorov.

The trick писал(а): Если нужно передать указатель то проще вызвать SHCreateMemStream.
Но ведь код работает. Почему, если передано не то? А чем проще SHCreateMemStream?
The trick писал(а):GdipBitmapLockBits позволяет передать буфер, так что можно обойтись без CopyMemory (кстати в котором тоже ошибка - перепутаны dst/src).
В эту часть я не вникал - код из оригинала. КопиМемери тоже оригинальная - из SR2D.dll
Артур
 
   

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение Mikle » 21.06.2019 (Пт) 22:17

The trick писал(а):CopyMemory (кстати в котором тоже ошибка - перепутаны dst/src)

Тут CopyMemory из SR2D.dll. Я когда-то сделал и оставил потому, что, вроде бы, было быстрее, чем RtlMoveMemory.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 21.06.2019 (Пт) 23:32

arthur2 писал(а):Но ведь код работает. Почему, если передано не то? А чем проще SHCreateMemStream?

Нет никакой гарантии что SA память под массив будет корректно работать в качестве HGLOBAL. Проще тем что сразу задает возможность задать правильную инициализацию.

arthur2 писал(а):В эту часть я не вникал - код из оригинала. КопиМемери тоже оригинальная - из SR2D.dll

Ну там можно так сделать чтобы GdipBitmapLockBits непосредственно копировала данные с помощью флагов (ImageLockModeUserInputBuf ):
Код: Выделить всё
' //
' // Load picture from memory
' //
Public Function LoadPictureFromMemory( _
                ByVal pData As Long, _
                ByVal lSize As Long) As StdPicture
    Dim hMem            As Long
    Dim pLocData        As Long
    Dim pIStream        As IUnknown
    Dim hGdipImg        As Long
    Dim hDib            As Long
    Dim tRC             As RECT
    Dim tBI             As BITMAPINFO
    Dim hdc             As Long
    Dim pBitsData       As Long
    Dim tBmpData        As BitmapData
    Dim IID_IPicture    As UUID
    Dim tPicDesc        As PICTDESC
    Dim cIPicture       As IPicture

    If Not InitializeGDIPlus() Then Exit Function
   
    hMem = GlobalAlloc(GMEM_MOVEABLE, lSize)
    If hMem = 0 Then GoTo CleanUp
   
    pLocData = GlobalLock(hMem)
    If pLocData = 0 Then GoTo CleanUp
   
    CopyMemory ByVal pLocData, ByVal pData, lSize
   
    GlobalUnlock hMem
   
    If CreateStreamOnHGlobal(hMem, True, pIStream) Then GoTo CleanUp
    If GdipLoadImageFromStream(pIStream, hGdipImg) Then GoTo CleanUp
    If GdipGetImageWidth(hGdipImg, tRC.iRight) Then GoTo CleanUp
    If GdipGetImageHeight(hGdipImg, tRC.iBottom) Then GoTo CleanUp
   
    With tBI.bmiHeader
   
        .biBitCount = 32
        .biHeight = -tRC.iBottom
        .biWidth = tRC.iRight
        .biPlanes = 1
        .biSize = Len(tBI.bmiHeader)
       
    End With
   
    hdc = GetDC(0)
    If hdc = 0 Then GoTo CleanUp
   
    hDib = CreateDIBSection(hdc, tBI, 0, tBmpData.scan0, 0, 0)
    If hDib = 0 Then GoTo CleanUp
   
    With tBmpData
   
        .height = tRC.iBottom
        .width = tRC.iRight
        .PixelFormat = PixelFormat32bppPARGB
        .stride = .width * 4
   
    End With
   
    If GdipBitmapLockBits(hGdipImg, tRC, ImageLockModeUserInputBuf Or _
                          ImageLockModeRead, PixelFormat32bppPARGB, tBmpData) Then GoTo CleanUp
    If GdipBitmapUnlockBits(hGdipImg, tBmpData) Then GoTo CleanUp
   
    IIDFromString StrPtr("{7BF80980-BF32-101A-8BBB-00AA00300CAB}"), IID_IPicture
   
    tPicDesc.cbSizeofstruct = Len(tPicDesc)
    tPicDesc.hbitmap = hDib
    tPicDesc.picType = vbPicTypeBitmap
   
    If OleCreatePictureIndirect(tPicDesc, IID_IPicture, True, cIPicture) Then GoTo CleanUp

    Set LoadPictureFromMemory = cIPicture
   
CleanUp:
   
    If hdc Then ReleaseDC 0, hdc
    If hGdipImg Then GdipDisposeImage hGdipImg
   
    If Not pIStream Is Nothing Then
        Set pIStream = Nothing
    Else
        GlobalFree hMem
    End If
   
    If LoadPictureFromMemory Is Nothing Then
   
        If hDib Then DeleteObject hDib
       
    End If
   
    UninitializeGDIPlus

End Function
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 22.06.2019 (Сб) 6:53

The trick писал(а):Нет никакой гарантии что SA память под массив будет корректно работать в качестве HGLOBAL
Но я ведь передаю не SA, а просто указатель на первый байт? Причем, нигде даже не передаю длину массива? Почему это работает?

The trick писал(а):Проще тем что сразу задает возможность задать правильную инициализацию.
У тебя в коде ты выделяешь память, копируешь туда массив и передаёшь-таки в CreateStreamOnHGlobal именно HGLOBAL. Почему же не сделать проще с SHCreateMemStream? А можно как-то получить HGLOBAL на уже существующий блок памяти?
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 22.06.2019 (Сб) 7:13

Mikle писал(а):Тут CopyMemory из SR2D.dll. Я когда-то сделал и оставил потому, что, вроде бы, было быстрее, чем RtlMoveMemory.
Кстати, аналогичная функция есть и в MSVBVM60:
Код: Выделить всё
Declare Sub CopyBytes Lib "MSVBVM60.DLL" Alias "__vbaCopyBytes" _
     (ByVal Size As Long, Dest As Any, Source As Any) 'Аналогично RtlMoveMemory, но только для неперекрывающихся блоков
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 22.06.2019 (Сб) 8:11

Заменил на:
Код: Выделить всё
        CreateStreamOnHGlobal ByVal LocalHandle(Bytes(0)), False, Stream
Теперь правильно?
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 23.06.2019 (Вс) 21:51

arthur2 писал(а):Но я ведь передаю не SA, а просто указатель на первый байт? Причем, нигде даже не передаю длину массива? Почему это работает?

Просто тебе повезло что память для массива выделяется в Heap-куче и ты передаешь первый элемент.

The trick писал(а):У тебя в коде ты выделяешь память, копируешь туда массив и передаёшь-таки в CreateStreamOnHGlobal именно HGLOBAL. Почему же не сделать проще с SHCreateMemStream? А можно как-то получить HGLOBAL на уже существующий блок памяти?

Это старый код, который показывает работу ImageLockModeUserInputBuf, а не создание стрима. Проще было бы конечно с SHCreateMemStream. В общем случае нельзя, т.к. Global/Local функции транслируются в соответствующие Heap функции. Произвольный блок может не принадлежать какой-либо куче.
UA6527P

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 23.06.2019 (Вс) 21:52

arthur2 писал(а):Заменил на:
Код: Выделить всё
        CreateStreamOnHGlobal ByVal LocalHandle(Bytes(0)), False, Stream
Теперь правильно?

Нет.
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 24.06.2019 (Пн) 6:40

The trick писал(а):Произвольный блок может не принадлежать какой-либо куче.
Но мы ведь говорим не о произвольном блоке, а о массиве, выделенном бейсиком. Разве это не значит, что бейсик при создании массива уже все как нужно выделил а залочил?

The trick писал(а):Теперь правильно?

Нет.
Почему?
Разве то, что LocalHandle/GlobalHandle вернула ненулевое значение, не означает, что блок, о котором речь, уже как нужно выделен и залочен? Ведь если передать не первый, а второй байт, они вернут-таки ноль. И если GlobalHandle почему-то возвращает недействительный хендл, то откуда тогда система при создании стрима знает длину блока?
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 25.06.2019 (Вт) 6:10

Нарыл некоторые ответы: https://www.transl-gunsmoker.ru/2009/10 ... ock-4.html

В связи с чем ещё несколько вопросов:
Почему ты выделяешь именно перемещаемую память, а не фиксированную? И почему разлочиваешь блок до того, как перестал его использовать?

Чтобы не возникало недопонимания: я не говорю, что это неправильно, я просто интересуюсь, почему так.
Артур
 
   

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение Mikle » 25.06.2019 (Вт) 9:19

arthur2 писал(а):Почему ты выделяешь именно перемещаемую память, а не фиксированную?

Я так понял, вопрос про cBuf()?
Размер спрайта заранее неизвестен, кроме того, он может меняться.
Я не передаю указатель на него ни в какие внешние функции, которые могут его запомнить для дальнейшего использования. Сами функции внутри себя тоже не вызывают перемещение.
На сколько знаю, VB6 до выполнения ReDim данному массиву тоже не переместит память спонтанно, это не дотнет.
После ваших с Хакером и The Trick обсуждений я уже начинаю сомневаться, впрочем, я эти обсуждения только просмотрел "по диагонали", пока не вникал.
arthur2 писал(а):почему разлочиваешь блок до того, как перестал его использовать?

Это про какой момент в коде?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 25.06.2019 (Вт) 13:00

Позже отвечу на две темы, сейчас нет возможности.
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение arthur2 » 25.06.2019 (Вт) 18:35

Mikle
Извини, это я Анатолию :) Про GMEM_MOVEABLE. Так увлёкся, что уже и забыл, с чего началось. А по загрузке картинки из памяти, вроде, более-менее всё понятно - просто стрим получаем, как и предложил The trick, через SHCreateMemStream, раз с хендлами такие непонятки :)

Но по SR2D у меня реально ещё куча вопросов! :) Наверное, правильней начать новую тему, а то мы в оффтоп убежали.

The trickПочему разлочиваешь раньше, дошло :) Дальше обращение к блоку через хендл
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: SR2D: как в спрайт загрузить картинку из массива?

Сообщение The trick » 28.06.2019 (Пт) 8:35

arthur2 писал(а):Но мы ведь говорим не о произвольном блоке, а о массиве, выделенном бейсиком. Разве это не значит, что бейсик при создании массива уже все как нужно выделил а залочил?

Бейсик выделяет массивы не через Global/Local функции. Ты спрашиваешь как получить хендл для существующего блока, блок может не принадлежать какой-либо куче вообще.

arthur2 писал(а):Почему?
Разве то, что LocalHandle/GlobalHandle вернула ненулевое значение, не означает, что блок, о котором речь, уже как нужно выделен и залочен? Ведь если передать не первый, а второй байт, они вернут-таки ноль. И если GlobalHandle почему-то возвращает недействительный хендл, то откуда тогда система при создании стрима знает длину блока?

Она возвращает действительный хендл только потому что тебе повезло, но полагаться на это не нужно. Просто в твоем примере память для массива выделяется в куче и Global/Local функции с ней работают, поэтому все гладко, но не исключено что память будет выделятся где-то в другом месте. Также SA дескриптор может ссылаться на данные в стеке, в File-Mapping'е и т.п.
UA6527P


Вернуться в Мультимедиа

Кто сейчас на конференции

Сейчас этот форум просматривают: SemrushBot и гости: 30

    TopList