/***************************************************************************** * * 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;iBuffer.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;iBuffer.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;iBuffer.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 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<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;iBitCount = BitCount; Video.Pixel.BitCount = BitCount; if (Video.Pixel.BitCount==1 || Video.Pixel.BitCount==2 || Video.Pixel.BitCount==4) { int n = 1<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<= 3*k) for (j=0;j<3;++j) for (i=0;i>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;n0;++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); }