Использование формата WebP на PureBasic

 


Этот формат картинок мне встречается очень давно, поэтому я решил разобраться с ним. Нашел примеры и долго искал libwebp.dll, на сайте попадаются только x64. Начал читать о формате и написал программу, которая выводит список порций(chunks):

f$="comment_temp5.webp"
;f$="meme-simpsons-google.webp"
;f$="tumblr_dfa085bb1a513f4508d05430d2e06d8a_2b18d8d2_540.webp"
If ReadFile(0,f$)
  s1.a=ReadAsciiCharacter(0)
  s2.a=ReadAsciiCharacter(0)
  s3.a=ReadAsciiCharacter(0)
  s4.a=ReadAsciiCharacter(0)
  If s1=$52 And s2=$49 And s3=$46 And s4=$46
    fs.l=ReadLong(0)
    Debug "size="+Str(fs+8)
  s1.a=ReadAsciiCharacter(0)
  s2.a=ReadAsciiCharacter(0)
  s3.a=ReadAsciiCharacter(0)
  s4.a=ReadAsciiCharacter(0)
  If s1=$57 And s2=$45 And s3=$42 And s4=$50
    While Not Eof(0)
      c$=""
      For i=1 To 4
        c$=c$+Chr(ReadAsciiCharacter(0))
      Next i
      cs.l=ReadLong(0)
      Debug c$+"("+Str(cs)+")"
      FileSeek(0,cs,#PB_Relative)
    Wend
  Else
    MessageRequester("WebP","Not WebP")
  EndIf
  Else
    MessageRequester("WebP","Not RIFF")
  EndIf
  CloseFile(0)
Else
  MessageRequester("WebP","Error read "+f$)
EndIf

Выходит, что это всего лишь RIFF со специальными порциями. Для файла omment_temp5.webp вышло:

size=80040
VP8X(10)
VP8 (76838)
EXIF(86)
XMP (3062)

EXIF я еще не осилил, поэтому и не стал разбирать по частям.
На форуме MASM32 нашлись еще два примерчика:

UsePNGImageEncoder()
Prototype.i WebPGetInfo(*webp_data, data_size.i, *width, *height)
Prototype.i WebPDecodeRGBAInto(*webp_data, data_size.i, *output_buffer, output_buffer_size.i, output_stride.i)
Prototype.i WebPDecodeBGRAInto(*webp_data, data_size.i, *output_buffer, output_buffer_size.i, output_stride.i)

Global WebPGetInfo.WebPGetInfo
Global WebPDecodeRGBAInto.WebPDecodeRGBAInto
Global WebPDecodeBGRAInto.WebPDecodeBGRAInto
If OpenLibrary(0, "libwebp.dll")
  WebPGetInfo.WebPGetInfo = GetFunction(0, "WebPGetInfo")
  WebPDecodeRGBAInto.WebPDecodeRGBAInto= GetFunction(0, "WebPDecodeRGBAInto")
  WebPDecodeBGRAInto.WebPDecodeBGRAInto = GetFunction(0, "WebPDecodeBGRAInto")
  
  f$="comment_temp5.webp"
  fs=FileSize(f$)
  *m=AllocateMemory(fs)
  If *m
    If ReadFile(0,f$)
      ReadData(0,*m,fs)
      CloseFile(0)
      WebPGetInfo(*m, fs, @dWidth, @dHeight)
      CreateImage(0, dWidth, dHeight, 32)
      StartDrawing(ImageOutput(0))
      Pitch = DrawingBufferPitch()
      Format = DrawingBufferPixelFormat()
      Buffer = DrawingBuffer()
      rr=WebPDecodeBGRAInto(*m, fs, Buffer, Pitch * dHeight, Pitch)
;flip orisontal
      For y=0 To dHeight>>1
        For x=0 To dWidth-1
          p1=PeekL( Buffer+4*(x+y*dWidth) );Point(x,y)
          p2=PeekL( Buffer+4*(x+(dHeight-1-y)*dWidth) );Point(x,dHeight-1-y)
          PokeL(Buffer+4*(x+(dHeight-1-y)*dWidth),p1);Box(x,y,1,1,p2)
          PokeL( Buffer+4*(x+y*dWidth),p2 );Box(x,dHeight-1-y,1,1,p1)
        Next x
      Next y
      StopDrawing()
      SaveImage(0,"hh.png",#PB_ImagePlugin_PNG)
    Else
      Debug "Read error:"+f$
    EndIf
    FreeMemory(*m)
  Else
    Debug "memory error:"+Str(fs)
  EndIf
Else  
  MessageRequester("load DLL","Error")
EndIf

С декодированием файла вышел один косяк - картинка вышла вверх ногами, поэтому был написан индусский код, и позже исправлен. С созданием картинки вышла заморочка, поэтому я немного исправил найденный пример:
Prototype.i WebPGetEncoderVersion()
Prototype.i WebPFree(*p)
Prototype.i WebPEncodeRGBA(*gba, width, height, stride, quality_factor.f, *output);stride corresponds to the number of bytes needed to jump from one row to the next

  If OpenLibrary(0, "libwebp.dll")
    WebPGetEncoderVersion.WebPGetEncoderVersion = GetFunction(0, "WebPGetEncoderVersion")
    WebPFree.WebPFree = GetFunction(0, "WebPFree")
    WebPEncodeRGBA.WebPEncodeRGBA = GetFunction(0, "WebPEncodeRGBA")
    
    ;Debug Hex(WebPGetEncoderVersion())
    *c=AllocateMemory(80004)
    
    For y=0 To 99
      For x=0 To 99
        cc.a=x!y
        PokeA(*c+y*400+x*4+3,255);alpha
        PokeA(*c+y*400+x*4+1,x-y);green
        PokeA(*c+y*400+x*4+2,y);blue
        PokeA(*c+y*400+x*4,x);red
    Next x
  Next y
  ;ShowMemoryViewer(*c,1024)
    ;stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3)
    fl=WebPEncodeRGBA(*c, 100, 100, 400, 80.0, @webp_data)
;?var stride = (width * colorImageFrame.Format.BitsPerPixel + 7) / 8;
    ;ShowMemoryViewer(webp_data,fl)
    If CreateFile(0,"huemae.webp")
      WriteData(0,webp_data,fl)
    Else
      MessageRequester("Write file","Error")
    EndIf
    FreeMemory(*c)
    WebPFree(webp_data)
    
    CloseLibrary(0)
  Else  
    MessageRequester("load DLL","Error")
  EndIf

Косяк заключался в параметре stride для функции - это число байт, необходимых для перехода по линиям данных. В примере был 80, но правильнее будет 400.

Мне, как всегда, показалось мало, и я решил скомпилировать новую версию 1.5.0. На сайте есть описание, поэтому я скачал и установил VS 2013. Самое гнусное занятие - это компиляция.
Ярлык командной строки нашел тут: c:\Program Files\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\

Потом набрал
d:
cd libwebp-1.5.0
nmake /f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output UNICODE=1

Часть предложенных опций не скомпилировалась, нужно разбираться с конфигурацией. Статичные библиотеки скомпилировались. но PureBasic заистерил при компиляции- Unresolved external.
В архиве есть картинки, исходники и пара версий библиотек. Хорошо бы разобраться с анимацией и прозрачностью.

Комментарии