;# ==================================================================== ;# ;# gifcat.pl: GIFファイル連結ライブラリ Ver1.50 ;# ;# Copyright (c) 1997,1998 s-hasei@mtg.biglobe.ne.jp ;# ;# 著作権は放棄しませんが、自由に使用・改造・再配布可能です。 ;# 改造版を再配布する際は、必ずファイル名を変更して、オリジナルを添付して ;# 配布してください。 ;# ;# 基本的な使い方 ;# require "gifcat.pl"; ;# open(OUT, "> out.gif"); ;# binmode(OUT); # MS-DOS や Windows の場合に必要です。 ;# print OUT &gifcat'gifcat("xx.gif", "yy.gif", "zz.gif"); ;# close(OUT); ;# ;# デバッグ用(GIFの解析出力) ;# require "gifcat.pl"; ;# &gifcat'gifprint("xx.gif", "yy.gif", "zz.gif"); ;# ;# 制限事項 ;# アニメGIFは連結できません。 ;# 大きさの異なるGIFファイルは連結できません。 ;# ;# 最新版入手先 ;# http://www2e.biglobe.ne.jp/~s-hasei/cgi-bin/gifcat.pl ;# ;# 更新履歴: ;# 1997.05.03 初版。 ;# 1997.05.10 スペルミス修正。 ;# 1997.05.29 サイズの異なるカラーテーブルに対応。 ;# 1997.07.07 エラー発生時にexit()しないように修正。 ;# 1998.05.05 Trailerを持たないGIFファイルを連結できないバグを修正。 ;# 1998.05.05 横幅が256を超えるGIFの出力ができないバグを修正。 ;# 1998.05.05 gifprint()で連結結果を出力しないように修正。 ;# 1998.05.10 連結できないGIF画像があるというバグを修正。 ;# 1998.08.20 Ver1.50 変数の初期化を行うように修正。 ;# 1998.08.20 Ver1.50 透過GIFに対応。 ;# ;# ==================================================================== package gifcat; ;# ===================================================== ;# gifcat'gifprint() - print out GIF diagnostics. ;# ===================================================== sub gifprint { $pflag = 1; &gifcat(@_); } ;# ===================================================== ;# gifcat'gifcat() - get a concatenated GIF image. ;# ===================================================== sub gifcat { $Gif = 0; $useLocalColorTable = 0; @files = @_; for $file (@files) { ($dev,$ino,$mode,$nlink,$uid,$gif,$rdev, $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($file); open(IN, "$file"); binmode(IN); sysread(IN, $buf, $size); close(IN); $cnt = 0; &GifHeader(); while (1) { $x1 = ord(substr($buf, $cnt, 1)); if ($x1 == 0x2c) { &ImageBlock(); } elsif ($x1 == 0x21) { $x2 = ord(substr($buf, $cnt + 1, 1)); if ($x2 == 0xf9) { &GraphicControlExtension(); } elsif ($x2 == 0xfe) { &CommentExtension(); } elsif ($x2 == 0x01) { &PlainTextExtension(); } elsif ($x2 == 0xff) { &ApplicationExtension(); } else { return("ERROR"); } } elsif ($x1 == 0x3b) { &Trailer(); last; } elsif ($cnt == $size) { last; } else { return("ERROR"); } } undef($buf); $Gif++; } if ($pflag == 1) { return; } $GifImage .= "GIF89a"; $GifImage .= pack("C", $logicalScreenWidth & 0x00ff); $GifImage .= pack("C", ($logicalScreenWidth & 0xff00) >> 8); $GifImage .= pack("C", $logicalScreenHeight & 0x00ff); $GifImage .= pack("C", ($logicalScreenHeight & 0xff00) >> 8); if ($useLocalColorTable) { $PackedFields18[0] &= ~0x80; } $GifImage .= pack("C", $PackedFields18[0]); $GifImage .= pack("C", $BackgroundColorIndex); $GifImage .= pack("C", $PixelAspectRatio); if ($useLocalColorTable == 0) { $GifImage .= $globalColorTable[0]; } for ($i = 0; $i < $Gif; $i++) { $GifImage .= pack("CCC", 0x21, 0xf9, 0x04); $GifImage .= pack("C", $PackedFields23 | $TransparentColorFlag[$i]); $GifImage .= pack("CC", 0x00, 0x00); $GifImage .= pack("C", $TransparentColorIndex[$i]); $GifImage .= pack("C", 0x00); $GifImage .= pack("C", 0x2c); $n = $ImageWidth * $i; $GifImage .= pack("C", $n & 0x00ff); $GifImage .= pack("C", ($n & 0xff00) >> 8); $GifImage .= pack("CC", 0x00, 0x00); $GifImage .= pack("C", $ImageWidth & 0x00ff); $GifImage .= pack("C", ($ImageWidth & 0xff00) >> 8); $GifImage .= pack("C", $ImageHeight & 0x00ff); $GifImage .= pack("C", ($ImageHeight & 0xff00) >> 8); if ($useLocalColorTable) { $PackedFields20[$i] |= 0x80; $PackedFields20[$i] &= ~0x07; $PackedFields20[$i] |= ($PackedFields18[$i] & 0x07); $GifImage .= pack("C", $PackedFields20[$i]); $GifImage .= $globalColorTable[$i]; } else { $GifImage .= pack("C", $PackedFields20[$i]); } $GifImage .= pack("C", $LzwMinimumCodeSize[$i]); $GifImage .= $ImageData[$i]; } $GifImage .= pack("C", 0x3b); } ;# ===================================== ;# GifHeader ;# ===================================== sub GifHeader { $Signature = substr($buf, $cnt, 3); $cnt += 3; $Version = substr($buf, $cnt, 3); $cnt += 3; $LogicalScreenWidth = ord(substr($buf, $cnt + 0, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $LogicalScreenHeight = ord(substr($buf, $cnt + 0, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $PackedFields18[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++; $GlobalColorTableFlag = ($PackedFields18[$Gif] & 0x80) >> 7; $ColorResolution = (($PackedFields18[$Gif] & 0x70) >> 4) + 1; $SortFlag = ($PackedFields18[$Gif] & 0x08) >> 3; $SizeOfGlobalColorTable = 2 ** (($PackedFields18[$Gif] & 0x07) + 1); $BackgroundColorIndex = ord(substr($buf, $cnt, 1)); $cnt++; $PixelAspectRatio = ord(substr($buf, $cnt, 1)); $cnt++; if ($GlobalColorTableFlag) { $GlobalColorTable = substr($buf, $cnt, $SizeOfGlobalColorTable * 3); $cnt += $SizeOfGlobalColorTable * 3; } $logicalScreenWidth += $LogicalScreenWidth; if ($logicalScreenHeight < $LogicalScreenHeight) { $logicalScreenHeight = $LogicalScreenHeight; } if ($GlobalColorTableFlag) { $globalColorTable[$Gif] = $GlobalColorTable; if ($Gif > 0) { if ($GlobalColorTable ne $globalColorTable[$Gif - 1]) { $useLocalColorTable = 1; } } } if ($pflag) { printf("=====================================\n"); printf("GifHeader\n"); printf("=====================================\n"); printf("Signature: %s\n", $Signature); printf("Version: %s\n", $Version); printf("Logical Screen Width: %d\n", $LogicalScreenWidth); printf("Logical Screen Height: %d\n", $LogicalScreenHeight); printf("Global Color Table Flag: %d\n", $GlobalColorTableFlag); printf("Color Resolution: %d\n", $ColorResolution); printf("Sort Flag: %d\n", $SortFlag); printf("Size of Global Color Table: %d\n", $SizeOfGlobalColorTable); printf("Background Color Index: %d\n", $BackgroundColorIndex); printf("Pixel Aspect Ratio: %d\n", $PixelAspectRatio); printf("Global Color Table: ...\n"); } } ;# ===================================== ;# Image Block ;# ===================================== sub ImageBlock { $ImageSeparator = ord(substr($buf, $cnt, 1)); $cnt++; $ImageLeftPosition = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $ImageTopPosition = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $ImageWidth = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $ImageHeight = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $PackedFields20[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++; $LocalColorTableFlag = ($PackedFields20[$Gif] & 0x80) >> 7; $InterlaceFlag = ($packedFields20[$Gif] & 0x40) >> 6; $SortFlag = ($PackedFields20[$Gif] & 0x20) >> 5; $Reserved = ($PackedFields20[$Gif] & 0x18) >> 3; $SizeOfLocalColorTable = 2 ** (($PackedFields20[$Gif] & 0x07) + 1); if ($LocalColorTableFlag) { $cnt += $SizeOfLocalColorTable * 3; } $LzwMinimumCodeSize[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++; $ImageData[$Gif] = &DataSubBlock(); if ($pflag) { printf("=====================================\n"); printf("Image Block\n"); printf("=====================================\n"); printf("Image Separator: 0x%02x\n", $ImageSeparator); printf("Image Left Position: %d\n", $ImageLeftPosition); printf("Image Top Position: %d\n", $ImageTopPosition); printf("Image Width: %d\n", $ImageWidth); printf("Image Height: %d\n", $ImageHeight); printf("Local Color Table Flag: %d\n", $LocalColorTableFlag); printf("Interlace Flag: %d\n", $InterlaceFlag); printf("Sort Flag: %d\n", $SortFlag); printf("Reserved: --\n"); printf("Size of Local Color Table: %d\n", $SizeOfLocalColorTable); printf("Local Color Table: ...\n"); printf("LZW Minimum Code Size: %d\n", $LzwMinimumCodeSize[$Gif]); printf("Image Data: ...\n"); printf("Block Terminator: 0x00\n"); } } ;# ===================================== ;# Graphic Control Extension ;# ===================================== sub GraphicControlExtension { $ExtensionIntroducer = ord(substr($buf, $cnt, 1)); $cnt++; $GraphicControlLabel = ord(substr($buf, $cnt, 1)); $cnt++; $BlockSize = ord(substr($buf, $cnt, 1)); $cnt++; $PackedFields23 = ord(substr($buf, $cnt, 1)); $cnt++; $Reserved = ($PackedFields23 & 0xe0) >> 5; $DisposalMethod = ($PackedFields23 & 0x1c) >> 5; $UserInputFlag = ($PackedFields23 & 0x02) >> 1; $TransparentColorFlag[$Gif] = $PackedFields23 & 0x01; $DelayTime = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt+1, 1)) * 256; $cnt += 2; $TransparentColorIndex[$Gif] = ord(substr($buf, $cnt, 1)); $cnt++; $BlockTerminator = ord(substr($buf, $cnt, 1)); $cnt++; if ($pflag) { printf("=====================================\n"); printf("Graphic Control Extension\n"); printf("=====================================\n"); printf("Extension Introducer: 0x%02x\n", $ExtensionIntroducer); printf("Graphic Control Label: 0x%02x\n", $GraphicControlLabel); printf("Block Size: %d\n", $BlockSize); printf("Reserved: --\n"); printf("Disposal Method: %d\n", $DisposalMethod); printf("User Input Flag: %d\n", $UserInputFlag); printf("Transparent Color Flag: %d\n", $TransparentColorFlag[$Gif]); printf("Delay Time: %d\n", $DelayTime); printf("Transparent Color Index: %d\n", $TransparentColorIndex[$Gif]); printf("Block Terminator: 0x00\n"); } } ;# ===================================== ;# Comment Extension ;# ===================================== sub CommentExtension { $ExtensionIntroducer = ord(substr($buf, $cnt, 1)); $cnt++; $CommentLabel = ord(substr($buf, $cnt, 1)); $cnt++; &DataSubBlock(); if ($pflag) { printf("=====================================\n"); printf("Comment Extension\n"); printf("=====================================\n"); printf("Extension Introducer: 0x%02x\n", $ExtensionIntroducer); printf("Comment Label: 0x%02x\n", $CommentLabel); printf("Comment Data: ...\n"); printf("Block Terminator: 0x%02x\n", $BlockTerminator); } } ;# ===================================== ;# Plain Text Extension ;# ===================================== sub PlainTextExtension { $ExtensionIntroducer = ord(substr($buf, $cnt, 1)); $cnt++; $PlainTextLabel = ord(substr($buf, $cnt, 1)); $cnt++; $BlockSize = ord(substr($buf, $cnt, 1)); $cnt++; $TextGridLeftPosition = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $TextGridTopPosition = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $TextGridWidth = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $TextGridHeight = ord(substr($buf, $cnt, 1)) + ord(substr($buf, $cnt + 1, 1)) * 256; $cnt += 2; $CharacterCellWidth = ord(substr($buf, $cnt, 1)); $cnt++; $CharacterCellHeight = ord(substr($buf, $cnt, 1)); $cnt++; $TextForegroundColorIndex = ord(substr($buf, $cnt, 1)); $cnt++; $TextBackgroundColorIndex = ord(substr($buf, $cnt, 1)); $cnt++; &DataSubBlock(); if ($pflag) { printf("=====================================\n"); printf("Plain Text Extension\n"); printf("=====================================\n"); printf("Extension Introducer: 0x%02x\n", $ExtensionIntroducer); printf("Plain Text Label: 0x%02x\n", $PlainTextLabel); printf("Block Size: 0x%02x\n", $BlockSize); printf("Text Grid Left Position: %d\n", $TextGridLeftPosition); printf("Text Grid Top Position: %d\n", $TextGridTopPosition); printf("Text Grid Width: %d\n", $TextGridWidth); printf("Text Grid Height: %d\n", $TextGridHeight); printf("Text Foreground Color Index: %d\n", $TextForegroundColorIndex); printf("Text Background Color Index: %d\n", $TextBackgroundColorIndex); printf("Plain Text Data: ...\n"); printf("Block Terminator: 0x00\n"); } } ;# ===================================== ;# Application Extension ;# ===================================== sub ApplicationExtension { $ExtensionIntroducer = ord(substr($buf, $cnt, 1)); $cnt++; $ExtentionLabel = ord(substr($buf, $cnt, 1)); $cnt++; $BlockSize = ord(substr($buf, $cnt, 1)); $cnt++; $ApplicationIdentifire = substr($buf, $cnt, 8); $cnt += 8; $ApplicationAuthenticationCode = substr($buf, $cnt, 3); $cnt += 3; &DataSubBlock(); if ($pflag) { printf("=====================================\n"); printf("Application Extension\n"); printf("=====================================\n"); printf("Extension Introducer: 0x%02x\n", $ExtensionIntroducer); printf("Extension Label: 0x%02x\n", $PlainTextLabel); printf("Block Size: 0x%02x\n", $BlockSize); printf("Application Identifire: ...\n"); printf("ApplicationAuthenticationCode: ...\n"); printf("Block Terminator: 0x00\n"); } } ;# ===================================== ;# Trailer ;# ===================================== sub Trailer { $cnt++; if ($pflag) { printf("=====================================\n"); printf("Trailer\n"); printf("=====================================\n"); printf("Trailer: 0x3b\n"); printf("\n"); } } ;# ===================================== ;# Data Sub Block ;# ===================================== sub DataSubBlock { local($n, $from); $from = $cnt; while ($n = ord(substr($buf, $cnt, 1))) { $cnt++; $cnt += $n; } $cnt++; return(substr($buf, $from, $cnt - $from)); } 1;