Type TSImage = Class
	Function Create(stream); overload;
	Begin
		content_ := stream;
		width_ := 0;
		height_ := 0;
		imagetypeDef := array(
			('name': 'bmp', 'position': 0, 'value': array(0x42, 0x4d)),
			('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)),
			('name': 'gif', 'position': 0, 'value': array(0x47, 0x49, 0x46, 0x38, 0x39, 0x61)),
			('name': 'gif', 'position': 0, 'value': array(0x47, 0x49, 0x46, 0x38, 0x37, 0x61)),
			('name': 'jpeg', 'position': 0, 'value': array(0xFF, 0xD8, 0xFF, 0xE1)),
			('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)),
			('name': 'tiff', 'position': 0, 'value': array(0x49, 0x49), 'order': 'littleEndian'),
			('name': 'tiff', 'position': 0, 'value': array(0x4D, 0x4D), 'order': 'bigEndian'),
		);
		stringObj_ := new TMemoryStream();
		size := length(stream);
		stringObj_.Write(stream[0:size-1], size);
		index := getImageType(imagetypeDef);
		ExtFileName := imagetypeDef[index]['name'];
		case ExtFileName of
			'bmp':
				[width_, height_] := bmp_dimensions();
			'png':
				[width_, height_] := png_dimensions();
			'gif':
				[width_, height_] := gif_dimensions();
			'tiff':
				[width_, height_] := tiff_dimensions(imagetypeDef[i]['order']);
			'jpeg', 'jpg':
				[width_, height_] := jpeg_dimensions();
		end
		//println("width_ = {}, height_ = {}", width_, height_);
	End;

	Function getImageType(def);
	Begin
		for i:=0 to length(def)-1 do
		begin
			value := def[i]['value'];
			stringObj_.Seek(def[i]['position']);
			for j:=0 to length(value)-1 do
			begin
				r := 0;
				stringObj_.Read(r, 1);
				if r <> value[j] then break;
				if j = length(value)-1 then return i;
			end
		end
		return -1;
	End

	Function Width();
	Begin
		return width_;
	End;

	Function Height();
	Begin
		return height_;
	End;

	Property Content read readContent;
	Function readContent();
	Begin
		return content_;
	End;

	Function jpeg_dimensions();
	Begin
		des1 := 0xff;
		des2 := 0xc0;
		des3 := 0xc2;
		flag := 1;
		while flag do
		begin
			r1 := stringObj_.Read(byte1, 1);
			r2 := stringObj_.Read(byte2, 1);
			if r1 = 0 or r2 = 0 then break;
			if byte1 = des1 and (byte2 = des2 or byte2 = des3) then flag := 0;
		end
		if flag then return array(0, 0);
		stringObj_.Read(tmp, 3);
		height := readBigEndianByte(2);
		width := readBigEndianByte(2);
		return array(width, height);
	End;

	Function tiff_dimensions(byteOrder);
	Begin
		stringObj_.seek(4);
		if byteOrder = 'bigEndian' then
			IFD := readBigEndianByte(4);
		else stringObj_.Read(IFD, 4);
		return array(0, 0);
	End;

	Function bmp_dimensions();
	Begin
		stringObj_.Seek(0x12);
		width := 0;
		stringObj_.Read(width, 4);
		height := 0;
		stringObj_.Read(height, 4);

		//stringObj_.Seek(0x26);
		//horz_px_per_meter := 0;
		//stringObj_.Read(horz_px_per_meter, 4);
		//vert_px_per_meter := 0;
		//stringObj_.Read(vert_px_per_meter, 4);
		//horz_dpi_ := _bmp_dpi(horz_px_per_meter);
		//vert_dpi_ := _bmp_dpi(vert_px_per_meter);
		return array(width, height);
	End;

	Function png_dimensions();
	Begin
		stringObj_.Seek(0x10);
		width := readBigEndianByte(4);
		height := readBigEndianByte(4);
		return array(width, height);
	End;

	Function gif_dimensions();
	Begin
		stringObj_.Seek(0x6);
		width := 0;
		stringObj_.Read(width, 2);
		height := 0;
		stringObj_.Read(height, 2);
		return array(width, height);
	End;

	Function readBigEndianByte(num);
	Begin
		ret := 0;
		while num do
		begin
			stringObj_.Read(b, 1);
			ret := _Shl(ret, 8);
			ret += b;
			num --;
		end
		return ret;
	End;

	ExtFileName:string;
	Name:string;
	content_;
	stringObj_;
	width_:integer;
	height_:integer;
End;
