Что нового

Анимации png

saraconor

Новичок
Сообщения
416
Репутация
3
Хочу сделать некий "помощник" в программе, при активации определенной кнопки будет возникать анимационная фигурка с прозрачностью, которая при наведении на элементы интерфейса будет подлетать к ним и окошками сообщений и жестами объяснять что это и как пользоваться (нечто вроде желтой собачки в Windows XP). Так вот, сперва нужно написать скрипт, который файлы для удобства использования скомпоновывает из отдельных кадров .png в единый файл ленту, это одна часть работы.
В дальнейшем понадобится удобный для использования UDF, с возможностью воспроизводить анимацию пользуясь этими лентами (разрезание ленты на кадры и цикличное воспроизведение), менять файлы анимации (как в виде ресурсов в скомпилированном виде, так и просто с путями на конкретные файлы) чтобы фигурка плавно меняла позы, зацикливать анимации, переходить от одного цикла анимаций в другой. И само окошко с GUI чтобы можно было перемещать из скрипта (не мышкой) чтобы при этом анимация не прекращалась, и не терялась прозрачность за картинкой. Нужно сделать обе части (компоновщик файлов и UDF анимации), по отдельности мне это не нужно.
Само собой все за денежку.
p.s. предлагать переделать все под gif не надо, нужно именно с png работать.
 

InnI

AutoIT Гуру
Сообщения
4,932
Репутация
1,435
За всю работу не возьмусь. Но могу подарить (совершенно бесплатно), вот эти заготовки. Тренировался на ваших же файлах: https://yadi.sk/d/RlYU45wNVl9AhQ

Скрипт объединения файлов в "ленту". Размеры рассчитываются по первому файлу, т.к. подразумевается, что все файлы одинакового размера. Чтобы не заморачиваться с сортировкой файлов нужно дать им числовые имена с учётом нулей, т.е. не 1.png, 2.png, а 01.png, 02.png и т.д.
Код:
#include <File.au3>
#include <GDIPlus.au3>

; поиск файлов
$aFiles = _FileListToArray(@ScriptDir, "*.png", 1)
If @error Then Exit

_GDIPlus_Startup()

; загрузка файлов
Global $aImg[$aFiles[0] + 1] = [$aFiles[0]]
For $i = 1 To $aImg[0]
  $aImg[$i] = _GDIPlus_ImageLoadFromFile($aFiles[$i])
Next

; размер первой картинки
$W = _GDIPlus_ImageGetWidth($aImg[1])
$H = _GDIPlus_ImageGetHeight($aImg[1])

; создание общей картинки
$Image = _GDIPlus_BitmapCreateFromScan0($W * $aImg[0], $H)
$Graph = _GDIPlus_ImageGetGraphicsContext($Image)

; рисование файлов на общую картинку
For $i = 1 To $aImg[0]
  _GDIPlus_GraphicsDrawImage($Graph, $aImg[$i], ($i - 1) * $W, 0)
Next

; сохранение ленты
_GDIPlus_ImageSaveToFile($Image, "ribbon.png")

; освобождение ресурсов
For $i = 1 To $aImg[0]
  _GDIPlus_ImageDispose($aImg[$i])
Next
_GDIPlus_ImageDispose($Image)
_GDIPlus_GraphicsDispose($Graph)
_GDIPlus_Shutdown()

Анимация "ленты" с перемещением окна за курсором мыши. В начале скрипта обязательно нужно задать ширину "кадра"
Код:
#include <GDIPlus.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

; выход по Shift+ESC
HotKeySet("+{esc}", "Quit")

; ширина кадра
$Width = 150

; загрузка ленты
_GDIPlus_Startup()
$Image = _GDIPlus_ImageLoadFromFile("ribbon.png")
If @error Then Exit _GDIPlus_Shutdown()

; расчёты
$Count = _GDIPlus_ImageGetWidth($Image) / $Width
$Height = _GDIPlus_ImageGetHeight($Image)

; разбиение на кадры
Global $aImg[$Count]
For $i = 0 To $Count - 1
  $Img = _GDIPlus_BitmapCloneArea($Image, $i * $Width, 0, $Width, $Height, $GDIP_PXF32ARGB)
  $aImg[$i] = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Img)
  _GDIPlus_ImageDispose($Img)
Next
_GDIPlus_ImageDispose($Image)
_GDIPlus_Shutdown()

; создание окна и анимация
$GUI = GUICreate("", $Width, $Height, -1, -1, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
GUISetState()
While 1
  For $i = 0 To $Count - 1
    Sleep(111)
    _WinAPI_UpdateLayeredWindowEx($GUI, -1, -1, $aImg[$i])
    WinMove($GUI, "", MouseGetPos(0) + 30, MouseGetPos(1) + 30)
  Next
WEnd

; удаление ресурсов
For $i = 0 To $Count - 1
  _WinAPI_DeleteObject($aImg[$i])
Next

; выход
Func Quit()
  Exit
EndFunc

по отдельности мне это не нужно
Ну, может кому-то пригодится...
Сообщение автоматически объединено:

Кстати, функция _WinAPI_UpdateLayeredWindowEx() поддерживает прозрачность. Поэтому можно не рисовать несколько одинаковых кадров с разной прозрачностью, а выводить один непрозрачный кадр, программно меняя ему прозрачность
Код:
; создание окна и анимация
$GUI = GUICreate("", $Width, $Height, -1, -1, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
GUISetState()
While 1
  ; выводится один кадр $aImg[6] с разной прозрачностью
  For $i = 0 To 5
    Sleep(111)
    _WinAPI_UpdateLayeredWindowEx($GUI, -1, -1, $aImg[6], $i * 40)
    WinMove($GUI, "", MouseGetPos(0) + 30, MouseGetPos(1) + 30)
  Next
  ; выводятся остальные кадры
  For $i = 6 To $Count - 1
    Sleep(111)
    _WinAPI_UpdateLayeredWindowEx($GUI, -1, -1, $aImg[$i])
    WinMove($GUI, "", MouseGetPos(0) + 30, MouseGetPos(1) + 30)
  Next
WEnd
 
Последнее редактирование:
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Спасибо большое за скрипты и комментарии там, буду думать как использовать.
Сообщение автоматически объединено:

К сожалению в новой версии Autoit скрипт воспроизведения из ленты больше не работает. Выдает ошибки в "WinAPIInternals.au3"
 
Последнее редактирование:

Prog

Продвинутый
Сообщения
567
Репутация
66
К сожалению в новой версии Autoit скрипт воспроизведения из ленты больше не работает.
я боюсь, у меня слетят все скрипты, которые до этого работали
Тогда зачем обновляли AutoIt?
Пользуйтесь той версией с которой нормально работало.
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Вроде что-то получается. Забавно, после компиляции касперыч накинулся на получившегося кадавра аки мопс на грелку.
 
Последнее редактирование:

Prog

Продвинутый
Сообщения
567
Репутация
66
Находится в файле WinAPIRes.au3
Подключите файл WinAPI.au3
Код:
; #FUNCTION# ====================================================================================================================
; Author.........: Yashied
; Modified.......: Jpm
; ===============================================================================================================================
Func _WinAPI_FindResourceEx($hInstance, $sType, $sName, $iLanguage)
    Local $sTypeOfType = 'int', $sTypeOfName = 'int'
    If IsString($sType) Then
        $sTypeOfType = 'wstr'
    EndIf
    If IsString($sName) Then
        $sTypeOfName = 'wstr'
    EndIf

    Local $aRet = DllCall('kernel32.dll', 'handle', 'FindResourceExW', 'handle', $hInstance, $sTypeOfType, $sType, _
            $sTypeOfName, $sName, 'ushort', $iLanguage)
    If @error Then Return SetError(@error, @extended, 0)
    ; If Not $aRet[0] Then Return SetError(1000, 0, 0)

    Return $aRet[0]
EndFunc   ;==>_WinAPI_FindResourceEx
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Все заработало. Но к сожалению касперский теперь уничтожает получившиеся файлы после компиляции. Можете подсказать как быть?
Код:
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Res_File_Add=ribbon.png, png, IMG1
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#include <GDIPlus.au3>
#include <WinAPISysWin.au3>

; выход по Shift+ESC
HotKeySet("+{esc}", "Quit")

; ширина кадра
$Width = 150

; загрузка ленты
_GDIPlus_Startup()
if @Compiled then
$hInstance = _WinAPI_GetModuleHandle(0)
$Image = _LoadResourceImage($hInstance, 'png', "IMG1")
Else
$Image = _GDIPlus_ImageLoadFromFile("ribbon.png")
endif
If @error Then Exit _GDIPlus_Shutdown()

; расчёты
$Count = _GDIPlus_ImageGetWidth($Image) / $Width
$Height = _GDIPlus_ImageGetHeight($Image)

; разбиение на кадры
Global $aImg[$Count]
For $i = 0 To $Count - 1
  $Img = _GDIPlus_BitmapCloneArea($Image, $i * $Width, 0, $Width, $Height, $GDIP_PXF32ARGB)
  $aImg[$i] = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Img)
  _GDIPlus_ImageDispose($Img)
Next
_GDIPlus_ImageDispose($Image)
_GDIPlus_Shutdown()

; создание окна и анимация
$GUI = GUICreate("", $Width, $Height, -1, -1, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
GUISetState()

  For $i = 0 To $Count - 1
    Sleep(25)
    _WinAPI_UpdateLayeredWindowEx($GUI, -1, -1, $aImg[$i])
;~     WinMove($GUI, "", MouseGetPos(0) + 30, MouseGetPos(1) + 30)  ;двинуть окно к курсору
  Next

; удаление ресурсов
For $i = 0 To $Count - 1
  _WinAPI_DeleteObject($aImg[$i])
Next

; выход
Func Quit()
  Exit
EndFunc


Func _LoadResourceImage($hInstance, $sResType, $sResName, $iResLanguage = 0)    ;подгрузка ресурса
    Local $hInfo, $hData, $pData, $iSize, $hMem, $pMem, $hStream, $hImage
    If $iResLanguage Then
        $hInfo = _WinAPI_FindResourceEx($hInstance, $sResType, $sResName, $iResLanguage)
    Else
        $hInfo = _WinAPI_FindResource($hInstance, $sResType, $sResName)
    EndIf
    $hData = _WinAPI_LoadResource($hInstance, $hInfo)
    $iSize = _WinAPI_SizeOfResource($hInstance, $hInfo)
    $pData = _WinAPI_LockResource($hData)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $hMem = DllCall("kernel32.dll", "ptr", "GlobalAlloc", "uint", 2, "ulong_ptr", $iSize)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $pMem = DllCall("kernel32.dll", "ptr", "GlobalLock", "ptr", $hMem[0])
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    DllCall("kernel32.dll", "none", "RtlMoveMemory", "ptr", $pMem[0], "ptr", $pData, "ulong_ptr", $iSize)
    DllCall("kernel32.dll", "int", "GlobalUnlock", "ptr", $hMem[0])
    $hStream = _WinAPI_CreateStreamOnHGlobal($hMem[0])
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $hImage = DllCall("gdiplus.dll", "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "ptr*", 0)
    If (@error) Or ($hImage[0]) Or (Not $hImage[2]) Then
        $hImage = 0
    EndIf
    DllCall("kernel32.dll", "ptr", "GlobalFree", "ptr", $hMem[0])
    If Not IsArray($hImage) Then
        Return SetError(1, 0, 0)
    EndIf
    Return $hImage[2]
EndFunc   ;==>_LoadResourceImage
 

Вложения

  • ribbon.png
    ribbon.png
    1.1 МБ · Просмотры: 1

Prog

Продвинутый
Сообщения
567
Репутация
66
Смените версию AutoIt или антивирус.
Если не вариант, добавьте скомпилированный скрипт в исключения антивируса или отправьте его в лабораторию Касперского указав на ложно-положительное срабатывание.
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
А можно как-то вылечить #AutoIt3Wrapper? Я то ладно, но ведь такой скрипт на любом компьютере с касперским будет удаляться.
У меня Internet Security, там нет возможности из карантина отправить на проверку файл.
 
Последнее редактирование:

Prog

Продвинутый
Сообщения
567
Репутация
66
Для этого нужно знать на что именно сработал антивирус. Экспериментируйте со скриптом и выясняйте в чем дело.
А можно как-то вылечить #AutoIt3Wrapper?
Замените #AutoIt3Wrapper_UseX64=n на #AutoIt3Wrapper_UseX64=yПриложение будет 64 битным и возможно Касперский не сработает.
Но на x86 системах работать не будет.
 
Последнее редактирование:
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Для этого нужно знать на что именно сработал антивирус. Экспериментируйте со скриптом и выясняйте в чем дело.

Замените #AutoIt3Wrapper_UseX64=n на #AutoIt3Wrapper_UseX64=yПриложение будет 64 битным и возможно Касперский не сработает.
Но на x86 системах работать не будет.
Так все нормально, работает. Спасибо вам
Сообщение автоматически объединено:

Почему-то на 133 кадре скрипт начинает выдавать файлы в 0 бит. Какие-то пределы по картинке?
 
Последнее редактирование:

Prog

Продвинутый
Сообщения
567
Репутация
66
Судя по всему превышает предел 65536 пикселей.

Вместо большой картинки-ленты поместите все картинки в архив и загружайте их оттуда по мере необходимости.
Таким архивом может быть файл в котором картинки находятся друг за другом.
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Судя по всему превышает предел 65536 пикселей.

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

Prog

Продвинутый
Сообщения
567
Репутация
66
Тогда разделите картинку-ленту на несколько чтобы длина каждой не превышала 65536 пикселей.
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Тогда разделите картинку-ленту на несколько чтобы длина каждой не превышала 65536 пикселей.
Да вот думаю теперь, как это сделать, а главное, как потом так скомпоновать, чтобы эти ленты проигрывались одна за другой плавно.
 

Prog

Продвинутый
Сообщения
567
Репутация
66
Дело в том что картинки должны быть внутри исполняемого файла в виде ресурса.
Любой файл можно поместить в ресурс исполняемого файла.
Нужно будет немного изменить функцию _LoadResourceImage() чтобы она загружала картинки из бинарного файла-архива, а не из длинной картинки-ленты.
 
Автор
S

saraconor

Новичок
Сообщения
416
Репутация
3
Просто файлы png по кадрам из архива? Вы можете привести пример? В прикрепленном часть файлов
 

Вложения

  • архив.rar
    1.5 МБ · Просмотры: 2
Верх