QQ、MSN聊天时的表情符号是怎么发送的?欢迎讨论。 (尚未解决) ( 积分: 100 )

  • 主题发起人 主题发起人 Corn2
  • 开始时间 开始时间
C

Corn2

Unregistered / Unconfirmed
GUEST, unregistred user!
表情符号应该是通过OLE方式嵌入的,但它们是怎么发送的?总不可能是转换成RTF格式,再以字符串的形式发送?我试过了,那样效率太低,压缩后效率也不佳。(一个16*16的图标转换成RTF串,占用将近3K字节,用delphi自带的压缩流压缩后也将近2K)
(请看完我的全部回复后再回复,OK?谢谢。)
 
表情符号应该是通过OLE方式嵌入的,但它们是怎么发送的?总不可能是转换成RTF格式,再以字符串的形式发送?我试过了,那样效率太低,压缩后效率也不佳。(一个16*16的图标转换成RTF串,占用将近3K字节,用delphi自带的压缩流压缩后也将近2K)
(请看完我的全部回复后再回复,OK?谢谢。)
 
我也想知道,帮你顶
 
你的思路是错误的。

聊天软件并不是直接传送表情图案,这样就太浪费网络资源了。
它的实现方法是通过传输一些特殊的值,来表示某一种表情。

如:$0001 表示高兴;
  $0002 表示生气等等;
$0003 ……………;
  ………………………
依此类推

再在客户端解释这些值,用说对应的图案显示出来。
 
那发送的时候怎么把表情符号转换成这些特定的字符串呢?
 
通过一些按钮,比如点“大笑”就在字符串中加入#0001。
这是字符串就会变成这样:聊天内容聊天内容聊天内容#0001聊天内容聊天内容。

重点不是怎么把符号图案转换成“值”,而是相反的把“值”解释成图案。
用图案来替换#0001:聊天内容聊天内容聊天内容[:D]聊天内容聊天内容。
 
程胜 说的并不全对,
对于标准表情只要发送#15之类的意义字符,
但对于非标准表情图片,也就是用户自定义的,就要发送图片了,而且图片接收后放在接收方用户的某一特定目录内,以便下次发同样表情时,不用重复发送。
 
我也曾想过用这种方法,但问题是当用户输入完成以后,编辑了输入内容怎么办?比如说,变动了表情符号的位置,或者,交换了两个表情的位置,或者,删除了某几个字或表情。那么,相应的,该怎么变换那串字符串呢?我怎么知道变动的那几个表情符号在字符串中对应的位置?我怎么知道某一个表情符号对应的是#0001?我怎么知道用户删除了某一个表情符号?
还有,假设用户编辑时,不是一个字符一个字符地删除,而是选定一段文字然后直接删除,或者直接覆盖,那么相应地,我那个字符串该怎么改?
 
我现在用的方法是:在OLE对象中嵌入流(流的内容就是#0001之类的字符串)。但当读取这些流的时候出现了一个莫名其妙的错误:在存储最后读取流的那个表情符号所对应的字符串的变量中加上了一段#0#0#40#0...之类的东西。不知道是怎么加上去的。
比如说,我用一个字符串数组存储#0001,#0002...,每嵌入一个表情符号,就嵌入相应的#0001,#0002,但读最后一个表情完后,就在#0003的后面添上了那串东西(假设最后读取的表情中嵌入的流是“#0003”),那个字符串数组变成了#0001,#0002,#0003#0#0#40#0...,#0004,...
不知道怎么回事
 
我做了一个DEMO:
procedure TForm1.btnInsertClick(Sender: TObject);
var
Bmp: TBitmap;
FStream: IStream;
FRTF: IRichEditOle;
FStorage: IStorage;
FLockBytes: ILockBytes;
ReObject: TReObject;
Written: Longint;
Content: string;
begin
Bmp := TBitmap.Create;
Bmp.LoadFromResourceName(hInstance, 'angry');

try
//创建并写入流:
SendMessage(ExRichEdit1.Handle, em_GetOleInterFace, 0, LongInt(@FRTF));
if not Assigned(FRTF) then Exit;
if not Succeeded(CreateILockBytesOnHGlobal(0,true,FLockBytes)) then Exit;
if not Succeeded(StgCreateDocfileOnILockBytes(FLockBytes,STGM_SHARE_EXCLUSIVE or
STGM_CREATE or STGM_READWRITE,0,FStorage)) then Exit;
if not Succeeded(FStorage.CreateStream('face', STGM_CREATE or STGM_READWRITE or STGM_SHARE_EXCLUSIVE, 0, 0, FStream)) then exit;
Content := Str[Count];
Inc(Count);
if not Succeeded(FStream.Write(@Content, Length(Content), @Written)) then exit;

ExRichEdit1.InsertBitmap(Bmp); //ExRichEdit控件可以直接通过这种方式插入BMP

//往已插入的图片中插入前面创建的流:
ExRichEdit1.SelLength := -1;
SendMessage(ExRichEdit1.Handle, em_GetOleInterFace, 0, LongInt(@FRTF));
Reobject.cbStruct := Sizeof(TReobject);
if (FRTF.GetObject(Integer(REO_IOB_SELECTION), ReObject, REO_GETOBJ_ALL_INTERFACES) = S_OK)
and (Assigned(ReObject.oleobj)) then
FRTF.SaveCompleted(Integer(REO_IOB_SELECTION), FStorage);
ExRichEdit1.SelStart := Start + 1;
ExRichEdit1.SelLength := 0;
ExRichEdit1.SetFocus;
finally
FRTF := nil;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Count := 0;
Str[0] := '0123';
Str[1] := '1234';
Str[2] := '2345';
Str[3] := '3456';
Str[4] := '4567';
Str[5] := '5678';
Str[6] := '6789';
end;

procedure TForm1.btnReadClick(Sender: TObject);
var
Content, s, ch, Res: string;
i, j, p: Integer;
FRTF: IRichEditOle;
FStorage: IStorage;
FStream: IStream;
Realsize: Longint;
Reobject: TReObject;
begin
Memo2.Clear;
Res := '';
p := 0; //ExRichEdit的指针
s := ExRichEdit1.WideText;
i := 1; //S的指针
repeat //一位位往下读s,如果是'?',有可能是OLE对象,尝试读取流。
Ch := s;
if Ord(Ch[1]) >= 127 then //汉字的第一字节
begin
Ch := Copy(s, i, 2);
Res := Res + Ch;
Inc(i, 2);
end
else if (Ch <> '?') then //OLE对象对应位置显示的是'?'
begin
Res := Res + Ch;
Inc(i);
end else
begin
ExRichEdit1.SelStart := p;
ExRichEdit1.SelLength := 1;
try
SendMessage(ExRichEdit1.Handle, em_GetOleInterFace, 0, LongInt(@FRTF));
Reobject.cbStruct := Sizeof(TReobject);
if Succeeded(FRTF.GetObject(Integer(REO_IOB_SELECTION), ReObject, REO_GETOBJ_ALL_INTERFACES))
and (Assigned(ReObject.oleobj)) then
begin
FStorage := Reobject.stg;
if Succeeded(FStorage.OpenStream('face', nil, STGM_READ or STGM_SHARE_EXCLUSIVE, 0, FStream)) then
begin
if Succeeded(FStream.Read(@Content, Sizeof(string), @Realsize)) then
Res := Res + Content;
end
else Res := Res + '?';
end
else Res := Res + '?';
finally
FRTF := nil;
end;
ExRichEdit1.SelLength := 0;
Inc(i);
end;
Inc(p);
until i > Length(s);
memo2.Text := Res;
ExRichEdit1.Clear;
Count := 0;
end; //执行到这句的时候出现了我上面说的错误,在Str字符串中插入了一段“乱码”

请各位大侠帮忙看看哪里出错了,调也调不出来。
 
如果怕被删除标准表情文件的话,干脆把标准表情做成一个res.dll资源文件,
你考虑的东西太多了,表情文件删除已经属于软件不完整的问题了。。。如果一直这样想下去的话,那你无论如何都得直接发送图片了。
 
我不是说删除这个BMP文件,我是说用户输入的时候,在输入框里删除了刚输入的某一个表情符号。我是把所有的表情符号都写在一个RES文件里。
 
小时候,有贼胆,没贼心;读书时,有贼心,没贼胆;现在贼胆贼心都有了,贼却没了.
 
传输的是编码啊,类似于Html中的InnerHtml
表情符号一般都是特定字符开头的字符串,比如//f代表Flower等等
读到这些字符串时再从本地load对应的图片
比如在某些WYSIWYG的web编辑器里,将一个字设为蓝色,在编辑窗体中看到的也是字变成了蓝色,但实际上传回web服务器的却是<font color="0000FF">字</font>
 
好贴收藏[:D]
 
你没必要将图片存为流啊.直接用特殊符号代替图片就行.对方收到后再把特殊符号替换成图片就OK了! 删除图片时就删除图片对应的特殊符号就行了.
 
同志们,我现在是用特殊符号代替图片,但问题我已经说了,当用户编辑输入内容后,相信得我该怎么改那串发送的字符串?如:用户删除了之前输入的某个表情,或者插入了某个表情,或者移动,我该怎么改那串东西?
关键问题是:怎么响应那个编辑框的OnChange事件(还有其他更合适的事件吗?不知道),响应用户键入的文字、表情、退格(删除)、移动表情等信息?
所以,我能想到的办法就是用流,然后当用户点“发送”的时候再顺序地读取每个字符,遇到OLE对象则读取流。这样就不用考虑我之前所想的问题了。
 
SendMessage(ExRichEdit1.Handle, em_GetOleInterFace, 0, LongInt(@FRTF));
if not Assigned(FRTF) then Exit;
if not Succeeded(CreateILockBytesOnHGlobal(0,true,FLockBytes)) then Exit;
if not Succeeded(StgCreateDocfileOnILockBytes(FLockBytes,STGM_SHARE_EXCLUSIVE or
STGM_CREATE or STGM_READWRITE,0,FStorage)) then Exit;
if not Succeeded(FStorage.CreateStream('face', STGM_CREATE or STGM_READWRITE or STGM_SHARE_EXCLUSIVE, 0, 0, FStream)) then exit;
Content := Str[Count];
Inc(Count);
if not Succeeded(FStream.Write(@Content, Length(Content), @Written)) then exit;

ExRichEdit1.InsertBitmap(Bmp); //ExRichEdit控件可以直接通过这种方式插入BMP

//往已插入的图片中插入前面创建的流:
ExRichEdit1.SelLength := -1;
SendMessage(ExRichEdit1.Handle, em_GetOleInterFace, 0, LongInt(@FRTF));
Reobject.cbStruct := Sizeof(TReobject);
if (FRTF.GetObject(Integer(REO_IOB_SELECTION), ReObject, REO_GETOBJ_ALL_INTERFACES) = S_OK)
and (Assigned(ReObject.oleobj)) then
FRTF.SaveCompleted(Integer(REO_IOB_SELECTION), FStorage);
ExRichEdit1.SelStart := Start + 1;
ExRichEdit1.SelLength := 0;
ExRichEdit1.SetFocus;
finally
FRTF := nil;
end;
end;
 
楼上的这位同志什么意思?
 
脚本嘛,还用说?
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
916
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部