Я уже писал о разборе порций формата WebP, и сейчас продолжил исследование. После компиляции libwebp я нашел пару утилит - webpinfo показывает информацию на экране
webpmux - управление метаданными. Я извлек поля EXIF и начал изучать. Файлы начинаются одинаково - байты 4D, 4D, 00, 2A, ?? ?? ?? ?? ExifMeta. Стал искать описание и нашел одну статью.
Получается, что данные EXIF хранятся в формате TIFF. Дальнейшие поиски вывели на описание формата. Я написал код разбора данных и получил короткую часть без комментария.
TIFF состоит из данных: два байта, обозначающих порядок байтов 4D 4D для Motorola, 49 49 для Intel.Следующее слово обозначает версию 2A или 2B. За ними хранится 32-битное слово смещение данных - 8 или 16 для моих файлов.
Следующие данные IFD(Image File Directories) - слово число тегов, массив тегов размером 12*число и смещение для следующего IFD. Если смещение равно 0, то это означает, что список закончен. В моем примере смещение равнялось 0, но был тег $8769, который указывал на следующее IFD.
Массив тегов состоит из слово TagID(идентификатор тега), слово DataType(тип данных), слово 32бит Data Count(длина), 32бит DataOffset(смещение данных). Список тегов отдельно.
Теперь код готов, но как его проверить? Я уже перепробовал разные варианты запросов к Google, но нашел один вариант - tiffdump.Скомпилировать не удалось, нашел гнутый вариант. Программа выплюнула только первую часть и остановилась. В командной строке указал смещение в файле и получил остатки. Вчера вечером нашел еще один вариант - tiffinfo(TIFF Tag Information Reader), который показывает подробную информацию, но не показывает текстовую информацию. Жаль, что исходник не опубликован. Сегодня я решил продолжить обработку тегов, меня интересовал тег $9286(UserComment):
Использовал описание, и получил текст.
;27.03.2025 7:38 fix finale version
Global byteswap
Procedure mesg(m$)
Debug m$
EndProcedure
; Procedure.l xchEndianL(e.l)
; ProcedureReturn (e & $ff) << 24 + (e & $ff00) << 8 + (e >> 8) & $ff00 + (e >> 24) & $ff
; EndProcedure
; Procedure.u swap16(v.u)
; ProcedureReturn ((v&255)<<8)|(((v&$FF00)>>8)&255)
; EndProcedure
Procedure.u fetchw(v.u)
If byteswap
v=((v&255)<<8)|(((v&$FF00)>>8)&255)
EndIf
ProcedureReturn v
EndProcedure
Procedure.l fetchl(e.l)
If byteswap
e=(e & $ff) << 24 + (e & $ff00) << 8 + (e >> 8) & $ff00 + (e >> 24) & $ff
EndIf
ProcedureReturn e
EndProcedure
Procedure.s gettype(td)
; 1 byte 8bit
; 2 ascii 8bit,null-terminated string
; 3 short 16bit unsigned
; 4 long 32bit unsigned
; 5 rational two 32bit unsigned integers
Select td
Case 1:t$="BYTE unsigned"
Case 2:t$="ASCII 8bit, null terminate"
Case 3:t$="SHORT 16bit unsigned"
Case 4:t$="LONG 32bit unsigned"
Case 5:t$="RATIONAL two 2bit unsigned"
Case 6:t$="TIFF 6.0 SBYTE 8bit signed"
Case 7:t$="TIFF 6.0 UNDEFINE 8bit byte"
Case 8:t$="TIFF 6.0 SSHORT 16bit signed"
Case 9:t$="TIFF 6.0 SLONG 32bit signed"
Case 10:t$="TIFF 6.0 SRATIONAL two 32bit signed"
Case 11:t$="TIFF 6.0 FLOAT 4-byte single-precision IEEE �oating-point value"
Case 12:t$="TIFF 6.0 DOUBLE 8-byte double-precision IEEE �oating-point value"
Default:
t$="Unknown:"+Hex(td,#PB_Word)
EndSelect
ProcedureReturn t$
EndProcedure
f$="exif2.exif"
fs=FileSize(f$)
If fs>0
*m=AllocateMemory(fs)
If *m
If ReadFile(0,f$)
ReadData(0,*m,fs)
CloseFile(0)
;https://www.media.mit.edu/pia/Research/deepview/exif.html
byteswap=-1
If PeekA(*m)=$49 And PeekA(*m+1)=$49 And PeekA(*m+2)=$2a And PeekA(*m+3)=$00;identifier
byteswap=0
ElseIf PeekA(*m)=$4D And PeekA(*m+1)=$4D And PeekA(*m+2)=$00 And PeekA(*m+3)=$2a
byteswap=1
EndIf
If byteswap<>-1
ofs=fetchl( PeekL(*m+4) );IFDOffset
exitfd=0
While ofs<fs
NumDirEntries.u=fetchw(PeekU(*M+ofs));NumDirEntries
ofs+2
For i=1 To NumDirEntries
TagId.u=fetchw( PeekU(*m+ofs) )
DataType.u=fetchw( PeekU(*m+ofs+2) )
DataCount=fetchl( PeekL(*m+ofs+4) )
DataOffset=fetchl( PeekL(*m+ofs+8) )
If DataOffset<fs-4 And DataOffset>0
v$="v$="+Hex( fetchl( PeekL(*m+DataOffset) ),#PB_Long )
Else
v$="???"
EndIf
If tagid=$9286;UserComment
; ShowMemoryViewer(*m+DataOffset,DataCount+1)
; http://www.fifi.org/doc/jhead/exif-e.html
; 0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
If PeekA(*m+DataOffset)=$41 And PeekA(*m+DataOffset+1)=$53 And PeekA(*m+DataOffset+2)=$43 And PeekA(*m+DataOffset+3)=$49 And PeekA(*m+DataOffset+4)=$49
v$="text="+PeekS(*m+DataOffset+8,DataCount-7,#PB_Ascii)
EndIf
; 0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
; 0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
; 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
EndIf
Debug "Tag:"+Hex(TagId)+",Type:("+Hex(DataType)+")"+gettype(DataType)+" ofs:"+Hex(DataOffset,#PB_Long)+",Len:"+Hex(DataCount,#PB_Long)+","+v$
If tagid=$8769 Or tagid=$8825 Or tagid=$a005
exitfd=DataOffset
Break
EndIf
ofs+12
Next i
Debug "---IFD end---"
If exitfd
ofs=exitfd
exitfd=0
Else
oo=fetchl( PeekL(*m+ofs) )
ofs+4
; If byteswap
; oo=xchEndianL(oo)
; EndIf
If oo
ofs=oo
Else
Break
EndIf
EndIf
;taglist-Array of Tags 12 bytes each
; word TagId
; word DataType
;NextIFDOffset-Offset to next IFD
Wend
Debug "*** Done ****"
Else
mesg("Bad format!")
EndIf
Else
mesg("Read error!")
EndIf;If ReadFile(0,f$)
FreeMemory(*m)
Else
mesg("Memory error!")
EndIf;If *m
Else
mesg("Bad size:"+Str(fs))
EndIf;If fs>0
Полный разбор тегов я делать не буду. JPEG View умеет читать данные из WebP, да и нет особой необходимости. Разве что попробую сформировать поле с комментарием.
Файлы тут
Комментарии
Отправить комментарий