gps/GPSResources/tcpmpVerOld/camera/tiff.c

656 lines
13 KiB
C
Executable File

/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: tiff.c 313 2005-10-29 15:15:47Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "../common/common.h"
#include "../common/zlib/zlib.h"
#include "tiff.h"
DECLARE_BITINIT
DECLARE_BITLOAD
typedef struct tiff
{
codec Codec;
buffer Buffer;
bool_t ErrorShowed;
bool_t BigEndian;
const uint8_t* Ptr;
int BitCount;
int BytesPerRow;
int BytesPerRow2;
int Planar;
int Channels;
int Left;
bool_t Reverse;
} tiff;
static int UpdateInput(tiff* p)
{
p->ErrorShowed = 0;
BufferClear(&p->Buffer);
if (p->Codec.In.Format.Type == PACKET_VIDEO)
{
PacketFormatCopy(&p->Codec.Out.Format,&p->Codec.In.Format);
p->Codec.Out.Format.Format.Video.Pixel.Flags = PF_RGB;
p->Codec.Out.Format.Format.Video.Pixel.BitCount = 24;
p->Codec.Out.Format.Format.Video.Pixel.BitMask[0] = 0xFF;
p->Codec.Out.Format.Format.Video.Pixel.BitMask[1] = 0xFF00;
p->Codec.Out.Format.Format.Video.Pixel.BitMask[2] = 0xFF0000;
DefaultPitch(&p->Codec.Out.Format.Format.Video);
}
return ERR_NONE;
}
static NOINLINE int Read32(tiff* p)
{
int v;
if (p->BigEndian)
v = LOAD32BE(p->Ptr);
else
v = LOAD32LE(p->Ptr);
p->Ptr += 4;
return v;
}
static NOINLINE int Read16(tiff* p)
{
int v;
if (p->BigEndian)
v = LOAD16BE(p->Ptr);
else
v = LOAD16LE(p->Ptr);
p->Ptr += 2;
return v;
}
static NOINLINE int ReadVal(tiff* p,int Type)
{
switch (Type)
{
case 1: return *(p->Ptr++);
case 3: return Read16(p);
case 4: return Read32(p);
}
return 0;
}
static NOINLINE int NotSupported(tiff* p)
{
if (!p->ErrorShowed)
{
p->ErrorShowed = 1;
ShowError(p->Codec.Node.Class,TIFF_ID,TIFF_NOT_SUPPORTED);
}
return ERR_NOT_SUPPORTED;
}
static NOINLINE void Write(tiff* p,const uint8_t* Data,int Size)
{
int n,i,j;
if (p->Planar == 1)
{
while (Size>0)
{
if (!p->Left)
p->Left = p->BytesPerRow;
n = min(p->Left,Size);
Size -= n;
p->Left -= n;
switch (p->BitCount)
{
case 1:
j = n*8;
if (!p->Left)
j -= 8*p->BytesPerRow - p->BytesPerRow2;
for (i=0;i<j;++i)
p->Buffer.Data[p->Buffer.WritePos++] = (uint8_t)((Data[i>>3] >> (7-(i&7))) & 1);
break;
case 2:
j = n*4;
if (!p->Left)
j -= 4*p->BytesPerRow - p->BytesPerRow2;
for (i=0;i<j;++i)
p->Buffer.Data[p->Buffer.WritePos++] = (uint8_t)((Data[i>>2] >> (6-2*(i&3))) & 3);
break;
case 4:
j = n*2;
if (!p->Left)
j -= 2*p->BytesPerRow - p->BytesPerRow2;
for (i=0;i<j;++i)
p->Buffer.Data[p->Buffer.WritePos++] = (uint8_t)((Data[i>>1] >> (4-4*(i&1))) & 15);
break;
default:
memcpy(p->Buffer.Data + p->Buffer.WritePos,Data,n);
p->Buffer.WritePos += n;
break;
}
Data += n;
if (!p->Left)
p->Buffer.WritePos += p->Codec.Out.Format.Format.Video.Pitch - p->BytesPerRow2;
}
}
else
{
while (Size>0)
{
if (!p->Left)
p->Left = p->BytesPerRow;
n = min(p->Left,Size);
Size -= n;
p->Left -= n;
while (--n>=0)
{
p->Buffer.Data[p->Buffer.WritePos] = *(++Data);
p->Buffer.WritePos += p->Channels;
}
if (!p->Left)
p->Buffer.WritePos += p->Codec.Out.Format.Format.Video.Pitch - p->BytesPerRow*p->Channels;
}
}
}
static void Inflate(tiff *p,const uint8_t* Data,int Size,int Total)
{
int i,n;
z_stream Inflate;
uint8_t Buffer[4096];
memset(&Inflate,0,sizeof(Inflate));
if (inflateInit2(&Inflate, MAX_WBITS) == Z_OK)
{
Inflate.next_in = (Bytef*)Data;
Inflate.avail_in = Size;
do
{
Inflate.next_out = Buffer;
Inflate.avail_out = sizeof(Buffer);
i = inflate(&Inflate, Z_SYNC_FLUSH);
n = sizeof(Buffer) - Inflate.avail_out;
if (n>Total)
n=Total;
Write(p,Buffer,n);
Total -= n;
} while (i>=0 && i!=Z_STREAM_END && Total>0);
inflateEnd(&Inflate);
}
}
/*
static void Fax3(tiff *p,const uint8_t* Data,int Size,int Total)
{
//todo
}
*/
static void LZW(tiff *p,const uint8_t* Data,int Size)
{
bitstream bs;
uint16_t Prefix[4096];
uint8_t Suffix[4096];
uint8_t Stack[4096];
uint8_t FirstChar;
int ClearCode = 256;
int EOICode = ClearCode+1;
int FreeCode = ClearCode+2;
int OldCode = -1;
int CodeSize = 9;
int i;
for (i=0;i<ClearCode;++i)
Suffix[i] = (uint8_t)i;
FirstChar = 0;
bitinit(&bs,Data,Size);
while (!biteof(&bs))
{
uint8_t* StackPtr;
int Code;
bitload(&bs);
Code = bitget(&bs,CodeSize);
if (Code == EOICode)
break;
if (Code == ClearCode)
{
CodeSize = 9;
FreeCode = ClearCode + 2;
OldCode = -1;
continue;
}
if (Code > FreeCode)
break;
if (OldCode<0)
{
FirstChar = Suffix[Code];
Write(p,&FirstChar,1);
OldCode = Code;
continue;
}
StackPtr = Stack+sizeof(Stack);
i = Code;
if (i == FreeCode)
{
*(--StackPtr) = FirstChar;
i = OldCode;
}
while (i>ClearCode)
{
*(--StackPtr) = Suffix[i];
i = Prefix[i];
}
FirstChar = Suffix[i];
*(--StackPtr) = FirstChar;
Prefix[FreeCode] = (uint16_t)OldCode;
Suffix[FreeCode] = FirstChar;
if (FreeCode < 4096) ++FreeCode;
if (CodeSize<12 && FreeCode == (1<<CodeSize)-1)
++CodeSize;
OldCode = Code;
Write(p,StackPtr,Stack+sizeof(Stack)-StackPtr);
}
}
static int Process(tiff* p, const packet* Packet, const flowstate* State)
{
int n,Compress;
size_t IFD;
int RowPerStrip;
video Video;
const uint8_t *Strips;
rgb Pal[256];
int StripsType,StripsLen;
int Bits[3];
int BitCount;
int h,ch;
int i,j,k;
if (!Packet)
return ERR_NEED_MORE_DATA;
p->Ptr = Packet->Data[0];
if (Packet->Length<8)
return ERR_INVALID_DATA;
if (p->Ptr[0]=='M' && p->Ptr[1]=='M')
p->BigEndian = 1;
else
if (p->Ptr[0]=='I' && p->Ptr[1]=='I')
p->BigEndian = 0;
else
return ERR_INVALID_DATA;
p->Ptr += 2;
if (Read16(p) != 42)
return ERR_INVALID_DATA;
IFD = Read32(p);
if (IFD<8 || IFD+2+4 >= Packet->Length)
return ERR_INVALID_DATA;
p->Reverse = 0;
RowPerStrip = MAX_INT;
memset(&Video,0,sizeof(Video));
p->Planar = 1;
p->Channels = 0;
Compress = 1;
Strips = NULL;
StripsType = 0;
StripsLen = 0;
BitCount = 0;
Video.Pixel.Flags = PF_RGB;
Video.Aspect = ASPECT_ONE; //todo
for (i=0;i<256;++i)
Pal[i].v = CRGB(i,i,i);
p->Ptr = (const uint8_t*)Packet->Data[0]+IFD;
n = Read16(p);
while (--n>=0)
{
const uint8_t* Save = p->Ptr+12;
int Tag = Read16(p);
int Type = Read16(p);
int Len = Read32(p);
size_t Pos = Read32(p);
switch (Type)
{
case 1:
case 2: i=1; break;
case 3: i=2; break;
case 4: i=4; break;
case 5: i=8; break;
default: i=0; break;
}
i *= Len;
if (i<=4)
p->Ptr -= 4;
else
{
if (Pos > Packet->Length-i)
continue;
p->Ptr = (const uint8_t*)Packet->Data[0]+Pos;
}
// read integer
i = 0;
if (Len==1)
switch (Type)
{
case 1: i=p->Ptr[0]; break;
case 3: i=Read16(p); p->Ptr-=2; break;
case 4: i=Read32(p); p->Ptr-=4; break;
}
switch (Tag)
{
case 0x100:
Video.Width = i;
break;
case 0x101:
Video.Height = i;
break;
case 0x102:
if (Len>3)
return NotSupported(p);
p->Channels = Len;
BitCount = 0;
for (i=0;i<Len;++i)
{
Bits[i] = ReadVal(p,Type);
Video.Pixel.BitMask[i] = ((1 << Bits[i])-1) << BitCount;
BitCount += Bits[i];
}
p->BitCount = BitCount;
Video.Pixel.BitCount = BitCount;
if (Video.Pixel.BitCount==1 ||
Video.Pixel.BitCount==2 ||
Video.Pixel.BitCount==4)
{
int n = 1<<BitCount;
for (i=0;i<n;++i)
{
int j = (255*i)/(n-1);
Pal[i].v = CRGB(j,j,j);
}
Video.Pixel.BitCount=8;
}
if (Video.Pixel.BitCount & 7) // only 1,2,4,8,16,24,32 bitdepth supported
return NotSupported(p);
break;
case 0x103:
Compress = i;
break;
case 0x106:
switch (i)
{
case 0: // invert grayscale
Video.Pixel.Flags = PF_GRAYSCALE|PF_PALETTE;
for (i=0;i<256;++i)
Pal[i].v ^= CRGB(255,255,255);
break;
case 1: // grayscale
Video.Pixel.Flags = PF_GRAYSCALE|PF_PALETTE;
break;
case 2: // rgb
Video.Pixel.Flags = PF_RGB;
break;
case 3: // palette
Video.Pixel.Flags = PF_PALETTE;
break;
}
break;
case 0x10A: // fill order
p->Reverse = i==2;
break;
case 0x111: // strip offsets
Strips = p->Ptr;
StripsType = Type;
StripsLen = Len;
break;
case 0x116:
RowPerStrip = i;
break;
case 0x11C:
p->Planar = i;
if (i != 1 && BitCount != p->Channels*8) // only 24,32 supported
return NotSupported(p);
break;
case 0x15B:
// jpeg tables
break;
case 0x140:
Video.Pixel.Flags = PF_PALETTE;
k = 1<<BitCount;
if (Len >= 3*k)
for (j=0;j<3;++j)
for (i=0;i<k;++i)
Pal[i].ch[j] = (uint8_t)(ReadVal(p,Type)>>8);
break;
}
p->Ptr = Save;
}
if (!Strips || !Video.Width || !Video.Height || !p->Channels)
return ERR_INVALID_DATA;
if ((Video.Pixel.Flags & PF_PALETTE) && (p->Channels!=1 || Video.Pixel.BitCount!=8))
return NotSupported(p);
DefaultPitch(&Video);
if (!EqVideo(&Video,&p->Codec.Out.Format.Format.Video))
{
if ((Video.Pixel.Flags & PF_PALETTE) && PacketFormatExtra(&p->Codec.Out.Format,sizeof(Pal)))
{
memcpy(p->Codec.Out.Format.Extra,Pal,sizeof(Pal));
Video.Pixel.Palette = p->Codec.Out.Format.Extra;
}
p->Codec.In.Format.Format.Video.Width = Video.Width;
p->Codec.In.Format.Format.Video.Height = Video.Height;
p->Codec.Out.Format.Format.Video = Video;
ConnectionUpdate(&p->Codec.Node,CODEC_OUTPUT,p->Codec.Out.Pin.Node,p->Codec.Out.Pin.No);
}
BufferDrop(&p->Buffer);
if (!BufferAlloc(&p->Buffer,Video.Pitch*Video.Height,4096))
return ERR_OUT_OF_MEMORY;
p->Ptr = Strips;
p->Left = 0;
ch = 0;
h = Video.Height;
for (n=0;n<StripsLen && h>0;++n)
{
int Len,Pos,y;
const uint8_t* Src;
Pos = ReadVal(p,StripsType);
Len = Packet->Length - Pos;
if (Len <= 0)
break;
Src = (const uint8_t*)Packet->Data[0]+Pos;
y = min(RowPerStrip,h);
h -= y;
if (p->Planar == 1)
{
p->BytesPerRow = ((BitCount*Video.Width + 7) >> 3);
p->BytesPerRow2 = ((Video.Pixel.BitCount*Video.Width + 7) >> 3);
}
else
p->BytesPerRow2 = p->BytesPerRow = ((Bits[ch] * Video.Width + 7) >> 3);
switch (Compress)
{
case 1:
Write(p,Src,p->BytesPerRow*y);
break;
// case 2: //rle
// break;
// case 3: //fax3
// Fax3(p,Src,Len,p->BytesPerRow*y);
// break;
// case 4: //fax4
// break;
case 5:
LZW(p,Src,Len);
break;
case 8:
case 32946: //zlib
Inflate(p,Src,Len,p->BytesPerRow*y);
break;
default:
return NotSupported(p);
}
if (p->Planar != 1 && h==0)
{
// next plane
if (ch == p->Channels) break;
h = Video.Height;
p->Left = 0;
p->Buffer.WritePos = ++ch;
}
}
p->Codec.Packet.RefTime = Packet->RefTime;
p->Codec.Packet.Length = p->Buffer.WritePos;
p->Codec.Packet.Data[0] = p->Buffer.Data;
return ERR_NONE;
}
static int Resend(tiff* p)
{
int Result = ERR_INVALID_DATA;
if (p->Buffer.WritePos)
{
packet Packet;
flowstate State;
State.CurrTime = TIME_RESEND;
State.DropLevel = 0;
memset(&Packet,0,sizeof(Packet));
Packet.RefTime = TIME_UNKNOWN;
Packet.Length = p->Buffer.WritePos;
Packet.Data[0] = p->Buffer.Data;
Result = p->Codec.Out.Process(p->Codec.Out.Pin.Node,&Packet,&State);
}
return Result;
}
static int Flush(tiff* p)
{
BufferDrop(&p->Buffer);
return ERR_NONE;
}
static int Create(tiff* p)
{
p->Codec.Process = (packetprocess)Process;
p->Codec.UpdateInput = (nodefunc)UpdateInput;
p->Codec.ReSend = (nodefunc)Resend;
p->Codec.Flush = (nodefunc)Flush;
return ERR_NONE;
}
static const nodedef TIFF =
{
sizeof(tiff),
TIFF_ID,
CODEC_CLASS,
PRI_DEFAULT,
(nodecreate)Create,
NULL,
};
//-------------------------------------------------------------------------------------------
static const nodedef TIFFFile =
{
0, // parent size
TIFF_FILE_ID,
RAWIMAGE_CLASS,
PRI_DEFAULT,
};
//---------------------------------------------------------------------------------------------
void TIFF_Init()
{
NodeRegisterClass(&TIFF);
NodeRegisterClass(&TIFFFile);
}
void TIFF_Done()
{
NodeUnRegisterClass(TIFF_ID);
NodeUnRegisterClass(TIFF_FILE_ID);
}