获取EMF文件内全部文字, 并按照左上到右下的顺序排序
因为工作要求, 需要对EMF文件文字内容做分析.....SO, 如下代码出现了
懒得加注释了, 反正对外接口属性就那么几个, 根据英文猜吧, 很容易的
说明一下:
这个东西结果会对所有文字内容按照左上到右下的顺序排序(EMF内数据顺序是根据画图顺序来的, 所以不一定是什么顺序, 但是数据分析就要得到行列关系)
但是图片没有行列概念, 所以我简单借鉴了一下纯粹横排版模式, 认为2个文字元素, 只要显示范围的中线在对方范围内, 就会被认为是同一行
2015-10-19:
1.修改了几个排序时的BUG, 增加了一个对显示区域的处理, 最大方式减少对排版的影响
2.修改了获取SmallTextOut的处理方式
- {
- EMF文件分析单元
- 读取EMF内文字元素并排版
- 最后修改时间 2015-10-19
- by: 刘志林
- E-Mail: lzl_17948876@hotmail.com
- }
- unit Comm.EMFInfo;
- interface
- uses
- System.Types, System.Generics.Collections,
- Vcl.Graphics;
- type
- TEMFStrInfo = record
- DisplayRect: TRect; {显示区域}
- Text: string; {显示内容}
- LineKey: string; {行标记}
- end;
- PEMFStrInfo = ^TEMFStrInfo;
- TEMFStrInfoList = Class
- private
- FList: TList<PEMFStrInfo>;
- FDic: TDictionary<string, UInt32>;
- FMaxHeight: Integer;
- FJSONStrs: string; {定位查找失败时,使用文本进行泛查找}
- function GetItem(Index: UInt32): TEMFStrInfo;
- function GetCount: UInt32;
- function GetJSONStrs: string;
- public
- constructor Create;
- destructor Destroy; override;
- procedure Append(AEMF: TMetafile; var AHeight: Integer);
- procedure Clear;
- property Count: UInt32 read GetCount;
- property Items[Index: UInt32]: TEMFStrInfo read GetItem;
- function TryGetInfo(AInfoName: string; var AInfo: TEMFStrInfo; var AIndex: UInt32): Boolean;
- function StrAnalyze(ALeavePattern: array of string; var AResult: string): Boolean;
- property JSONStr: string read GetJSONStrs;
- property MaxHeight: Integer read FMaxHeight;
- end;
- implementation
- uses
- System.SysUtils, System.Classes, System.Generics.Defaults,
- System.RegularExpressions,
- Winapi.Windows,
- Vcl.Printers,
- QJSON;
- const
- // if set use ANSI version else UNICODE
- SMALLTEXT_TYPE_ANSI = $;
- // if set use EMR_SMALLTEXTOUT else use EMR_SMALLTEXTOUTCLIP
- SMALLTEXT_TYPE_WITHOUT_CLIP = $;
- // Structures
- type
- EMR_SMALLTEXTOUT_HEAD = RECORD
- emr: emr;
- ptlReference: TPoint;
- nChars: DWORD;
- fuOptions: DWORD; // this record type
- // == SMALLTEXT_TYPE_WITHOUT_CLIP
- // == SMALLTEXT_TYPE_ANSI
- // also holds fuOptions like in the ExtTextOut function
- iGraphicsMode: DWORD; // See iMode parameter of SetGraphicsMode
- exScale: Single; { X and Y scales from Page units to .01mm units }
- eyScale: Single; { if graphics mode is GM_COMPATIBLE. }
- END;
- PEMRSmallTextOutHead = ^EMR_SMALLTEXTOUT_HEAD;
- EMR_SMALLTEXTOUTCLIPA = RECORD
- emr: emr;
- ptlReference: TPoint; // might be in negative numbers, so take abs
- nChars: DWORD;
- fuOptions: DWORD; // this record type
- // != SMALLTEXT_TYPE_WITHOUT_CLIP
- // == SMALLTEXT_TYPE_ANSI
- // also holds fuOptions like in the ExtTextOut function
- iGraphicsMode: DWORD; // See iMode parameter of SetGraphicsMode
- exScale: Single; { X and Y scales from Page units to .01mm units }
- eyScale: Single; { if graphics mode is GM_COMPATIBLE. }
- rclClip: TRect;
- cString: Array [ .. ] of AnsiChar;
- { This is followed by the string array }
- END;
- PEMRSmallTextOutClipA = ^EMR_SMALLTEXTOUTCLIPA;
- EMR_SMALLTEXTOUTCLIPW = RECORD
- emr: emr;
- ptlReference: TPoint;
- nChars: DWORD;
- fuOptions: DWORD; // this record type
- // != SMALLTEXT_TYPE_WITHOUT_CLIP
- // != SMALLTEXT_TYPE_ANSI
- // also holds fuOptions like in the ExtTextOut function
- iGraphicsMode: DWORD; // See iMode parameter of SetGraphicsMode
- exScale: Single; { X and Y scales from Page units to .01mm units }
- eyScale: Single; { if graphics mode is GM_COMPATIBLE. }
- rclClip: TRect;
- cString: Array [ .. ] of WideChar;
- { This is followed by the string array }
- END;
- PEMRSmallTextOutClipW = ^EMR_SMALLTEXTOUTCLIPW;
- EMR_SMALLTEXTOUTA = RECORD
- emr: emr;
- ptlReference: TPoint;
- nChars: DWORD;
- fuOptions: DWORD; // this record type
- // == SMALLTEXT_TYPE_WITHOUT_CLIP
- // == SMALLTEXT_TYPE_ANSI
- // also holds fuOptions like in the ExtTextOut function
- iGraphicsMode: DWORD; // See iMode parameter of SetGraphicsMode
- exScale: Single; { X and Y scales from Page units to .01mm units }
- eyScale: Single; { if graphics mode is GM_COMPATIBLE. }
- cString: Array [ .. ] of AnsiChar;
- { This is followed by the string array }
- END;
- PEMRSmallTextOutA = ^EMR_SMALLTEXTOUTA;
- EMR_SMALLTEXTOUTW = RECORD
- emr: emr;
- ptlReference: TPoint;
- nChars: DWORD;
- fuOptions: DWORD; // this record type
- // == SMALLTEXT_TYPE_WITHOUT_CLIP
- // != SMALLTEXT_TYPE_ANSI
- // also holds fuOptions like in the ExtTextOut function
- iGraphicsMode: DWORD; // See iMode parameter of SetGraphicsMode
- exScale: Single; { X and Y scales from Page units to .01mm units }
- eyScale: Single; { if graphics mode is GM_COMPATIBLE. }
- cString: Array [ .. ] of WideChar;
- { This is followed by the string array }
- END;
- PEMRSmallTextOutW = ^EMR_SMALLTEXTOUTW;
- var
- FReferenceDC: VCL.Graphics.TBitmap;
- function EnumTextProc(DC: HDC; lpHTable: PHANDLETABLE; EMFR: PENHMETARECORD;
- nObj, lpData: Integer): Integer; stdcall;
- function _IsEffeetiveRect(const ARect: TRect): Boolean;
- begin
- Result := (not ARect.IsEmpty) and (ARect.Right > ) and (ARect.Left > )
- and (ARect.Bottom - ARect.Top > ) and (ARect.Right - ARect.Left > );
- end;
- procedure _ShrinkRect(var ARect: TRect; ASize: TSize);
- var
- v: Integer;
- begin
- v := ARect.Left + ASize.cx;
- if ARect.Right > v then
- ARect.Right := v;
- v := ARect.Top + ASize.cy;
- if ARect.Bottom > v then
- ARect.Bottom := v;
- end;
- var
- nSize: TSize;
- nStrA: PAnsiChar;
- nStrW: PWideChar;
- nEMRTO: PEMRExtTextOut;
- nEMRSTOHead: PEMRSmallTextOutHead;
- nEMRSTO_A: PEMRSmallTextOutA;
- nEMRSTO_AC: PEMRSmallTextOutClipA;
- nEMRSTO_W: PEMRSmallTextOutW;
- nEMRSTO_WC: PEMRSmallTextOutClipW;
- nOTR: PEMFStrInfo;
- nEMFElementList: TList<PEMFStrInfo>;
- begin
- nEMFElementList := Pointer(lpData);
- nSize.cX := ;
- nSize.cY := ;
- if (EMFR.iType = EMR_EXTTEXTOUTA) then
- begin
- nEMRTO := PEMRExtTextOut(EMFR);
- nStrA := AnsiStrAlloc(nEMRTO.EMRText.nChars + );
- try
- FillChar(nStrA^, nEMRTO.EMRText.nChars + , );
- Move(pointer( + Cardinal(@nEMRTO.EMRText) + nEMRTO.EMRText.offString)^,
- nStrA^, nEMRTO.EMRText.nChars);
- New(nOTR);
- with nOTR^ do
- begin
- Text := Trim(nStrA);
- DisplayRect := nEMRTO.rclBounds;
- LineKey := '';
- end;
- finally
- StrDispose(nStrA);
- end;
- Winapi.Windows.GetTextExtentPoint32(FReferenceDC.Canvas.Handle,
- nOTR^.Text, Length(nOTR^.Text), nSize);
- nOTR^.DisplayRect.NormalizeRect;
- _ShrinkRect(nOTR^.DisplayRect, nSize);
- if (nOTR^.Text <> '') and _IsEffeetiveRect(nOTR^.DisplayRect) then
- nEMFElementList.Add(nOTR)
- else
- Dispose(nOTR);
- end
- else if (EMFR.iType = EMR_EXTTEXTOUTW) then
- begin
- nEMRTO := PEMRExtTextOut(EMFR);
- nStrW := WideStrAlloc(nEMRTO.EMRText.nChars + );
- try
- FillChar(nStrW^, (nEMRTO.EMRText.nChars + ) * , );
- Move(pointer( + Cardinal(@nEMRTO.EMRText) + nEMRTO.EMRText.offString div )^,
- nStrW^, nEMRTO.EMRText.nChars * );
- New(nOTR);
- with nOTR^ do
- begin
- Text := Trim(nStrW);
- DisplayRect := nEMRTO.rclBounds;
- LineKey := '';
- end;
- finally
- StrDispose(nStrW);
- end;
- Winapi.Windows.GetTextExtentPoint32(FReferenceDC.Canvas.Handle,
- nOTR^.Text, Length(nOTR^.Text), nSize);
- nOTR^.DisplayRect.NormalizeRect;
- _ShrinkRect(nOTR^.DisplayRect, nSize);
- if (nOTR^.Text <> '') and _IsEffeetiveRect(nOTR^.DisplayRect) then
- nEMFElementList.Add(nOTR)
- else
- Dispose(nOTR);
- end
- else if EMFR.iType = EMR_SMALLTEXTOUT then
- begin
- nEMRSTOHead := PEMRSmallTextOutHead(EMFR);
- New(nOTR);
- if nEMRSTOHead.fuOptions and SMALLTEXT_TYPE_ANSI = SMALLTEXT_TYPE_ANSI then
- begin
- if nEMRSTOHead.fuOptions and SMALLTEXT_TYPE_WITHOUT_CLIP = SMALLTEXT_TYPE_WITHOUT_CLIP then
- begin
- nEMRSTO_A := Pointer(nEMRSTOHead);
- nStrA := AnsiStrAlloc(nEMRSTO_A^.nChars + );
- try
- FillChar(nStrA^, nEMRSTO_A^.nChars + , );
- Move(nEMRSTO_A^.cString[], nStrA^, nEMRSTO_A^.nChars);
- with nOTR^ do
- begin
- Text := Trim(nStrA);
- DisplayRect := Rect(nEMRSTO_A^.ptlReference.X, nEMRSTO_A^.ptlReference.Y,
- MAXWORD, MAXWORD);
- LineKey := '';
- end;
- finally
- StrDispose(nStrA);
- end;
- end
- else
- begin
- nEMRSTO_AC := Pointer(nEMRSTOHead);
- nStrA := AnsiStrAlloc(nEMRSTO_AC^.nChars + );
- try
- FillChar(nStrA^, nEMRSTO_AC^.nChars + , );
- Move(nEMRSTO_AC^.cString[], nStrA^, nEMRSTO_AC^.nChars);
- with nOTR^ do
- begin
- Text := Trim(nStrA);
- DisplayRect := nEMRSTO_AC^.rclClip;
- DisplayRect.TopLeft := nEMRSTO_AC^.ptlReference;
- LineKey := '';
- end;
- finally
- StrDispose(nStrA);
- end;
- end;
- end
- else
- begin
- if nEMRSTOHead.fuOptions and SMALLTEXT_TYPE_WITHOUT_CLIP = SMALLTEXT_TYPE_WITHOUT_CLIP then
- begin
- nEMRSTO_W := Pointer(nEMRSTOHead);
- nStrW := WideStrAlloc(nEMRSTO_W^.nChars + );
- try
- FillChar(nStrW^, (nEMRSTO_W^.nChars + ) * , );
- Move(nEMRSTO_W^.cString[], nStrW^, nEMRSTO_W^.nChars * );
- with nOTR^ do
- begin
- Text := Trim(nStrW);
- DisplayRect := Rect(nEMRSTO_W^.ptlReference.X, nEMRSTO_W^.ptlReference.Y,
- MAXWORD, MAXWORD);
- LineKey := '';
- end;
- finally
- StrDispose(nStrA);
- end;
- end
- else
- begin
- nEMRSTO_WC := Pointer(nEMRSTOHead);
- nStrW := WideStrAlloc(nEMRSTO_WC^.nChars + );
- try
- FillChar(nStrW^, (nEMRSTO_WC^.nChars + ) * , );
- Move(nEMRSTO_WC^.cString[], nStrW^, nEMRSTO_WC^.nChars * );
- with nOTR^ do
- begin
- Text := Trim(nStrW);
- DisplayRect := nEMRSTO_AC^.rclClip;
- DisplayRect.TopLeft := nEMRSTO_AC^.ptlReference;
- LineKey := '';
- end;
- finally
- StrDispose(nStrA);
- end;
- end;
- end;
- Winapi.Windows.GetTextExtentPoint32(FReferenceDC.Canvas.Handle,
- nOTR^.Text, Length(nOTR^.Text), nSize);
- nOTR^.DisplayRect.NormalizeRect;
- _ShrinkRect(nOTR^.DisplayRect, nSize);
- if (nOTR^.Text <> '') and _IsEffeetiveRect(nOTR^.DisplayRect) then
- nEMFElementList.Add(nOTR)
- else
- Dispose(nOTR);
- end;
- Result := ;
- end;
- type
- TEMFStrInfoCompare = class(TComparer<PEMFStrInfo>)
- public
- function Compare(const Left, Right: PEMFStrInfo): Integer; override;
- end;
- { TEMFStrInfoCompare }
- function TEMFStrInfoCompare.Compare(const Left, Right: PEMFStrInfo): Integer;
- var
- nCPLeft, nCPRight: TPoint;
- nLIR, nRIL: Int8;
- nLineKey: string;
- begin
- nCPLeft := Left^.DisplayRect.CenterPoint;
- nCPRight := Right^.DisplayRect.CenterPoint;
- if nCPLeft.Y <= Right^.DisplayRect.Top then
- nLIR := -
- else if nCPLeft.Y >= Right^.DisplayRect.Bottom then
- nLIR :=
- else
- nLIR := ;
- if nCPRight.Y <= Left^.DisplayRect.Top then
- nRIL := -
- else if nCPRight.Y >= Left^.DisplayRect.Bottom then
- nRIL :=
- else
- nRIL := ;
- if (nLIR = ) or (nRIL = ) then
- begin
- if Left^.LineKey <> '' then
- Right^.LineKey := Left^.LineKey
- else if Right^.LineKey <> '' then
- Left^.LineKey := Right^.LineKey
- else
- begin
- Left^.LineKey := TGUID.NewGuid.ToString;
- Right^.LineKey := Left^.LineKey;
- end;
- {有任意left或right在另一方区域内的, 认为在同一行, 通过x位置判断排序}
- if nCPLeft.X < nCPRight.X then {根据左侧判断位置}
- Result := -
- else if nCPLeft.X > nCPRight.X then
- Result :=
- else if nCPLeft.Y < nCPRight.Y then
- Result := -
- else if nCPLeft.Y > nCPRight.Y then
- Result :=
- else
- Result := ;
- end
- else
- begin
- Result := nLIR;
- end;
- end;
- { TEMFStrInfoList }
- procedure TEMFStrInfoList.Append(AEMF: TMetafile; var AHeight: Integer);
- var
- nList: TList<PEMFStrInfo>;
- nInfoExists: Boolean;
- nCheckPoint: TPoint;
- i: Integer;
- nCompare: TEMFStrInfoCompare;
- nPI: PEMFStrInfo;
- nTmpLineKey, nTmpJSONStr: string;
- nJ, nJLine: TQJson;
- begin
- nList := TList<PEMFStrInfo>.Create;
- try
- {读取文件元素存入列表}
- EnumEnhMetafile(, AEMF.Handle, @EnumTextProc, Pointer(nList), Rect(, , , ));
- nCompare := TEMFStrInfoCompare.Create;
- try
- {排序}
- try
- nList.Sort(nCompare);
- finally
- nCompare.Free;
- end;
- except
- end;
- {计算最大高度, 元素名称存入字典}
- AHeight := ;
- nJ := TQJson.Create;
- try
- // nJ.TryParse(FJSONStrs);
- nJ.DataType := jdtArray;
- nJLine := nil;
- nTmpLineKey := '';
- for i := to nList.Count - do
- begin
- nPI := nList[i];
- if nPI^.LineKey = '' then
- nPI^.LineKey := TGUID.NewGuid.ToString; {没有相同行标记的给一个标记}
- {需要换行}
- if (nTmpLineKey = '') or (not SameText(nTmpLineKey, nPI^.LineKey)) then
- nJLine := nil;
- {当前行标记}
- nTmpLineKey := nPI^.LineKey;
- if nPI^.DisplayRect.Bottom > AHeight then
- AHeight := nPI^.DisplayRect.Bottom;
- OffsetRect(nPI^.DisplayRect, , FMaxHeight);
- FDic.AddOrSetValue(nPI^.Text, FList.Add(nPI));
- if (nJLine = nil) then
- nJLine := nJ.AddArray('');
- nJLine.Add.AsString := nPI^.Text;
- end;
- nTmpJSONStr := nJ.Encode(False);
- nTmpJSONStr := Copy(nTmpJSONStr, , Length(nTmpJSONStr) - );
- if FJSONStrs = '' then
- FJSONStrs := nTmpJSONStr
- else
- FJSONStrs := FJSONStrs + ',' + nTmpJSONStr;
- finally
- nJ.Free;
- end;
- FMaxHeight := FMaxHeight + AHeight;
- finally
- nList.Free;
- end;
- end;
- procedure TEMFStrInfoList.Clear;
- var
- i: Integer;
- begin
- FMaxHeight := ;
- FJsonStrs := '';
- for i := to FList.Count - do
- Dispose(FList[i]);
- FList.Clear;
- FDic.Clear;
- end;
- constructor TEMFStrInfoList.Create;
- begin
- FList := TList<PEMFStrInfo>.Create;
- FDic := TDictionary<string, UInt32>.Create;
- FMaxHeight := ;
- FJsonStrs := '';
- end;
- destructor TEMFStrInfoList.Destroy;
- var
- i: Integer;
- begin
- for i := to FList.Count - do
- Dispose(FList[i]);
- FList.Free;
- FDic.Free;
- inherited;
- end;
- function TEMFStrInfoList.GetCount: UInt32;
- begin
- Result := FList.Count;
- end;
- function TEMFStrInfoList.GetItem(Index: UInt32): TEMFStrInfo;
- begin
- Result := FList[Index]^;
- end;
- function TEMFStrInfoList.GetJSONStrs: string;
- begin
- Result := '[' + FJSONStrs + ']';
- end;
- function TEMFStrInfoList.StrAnalyze(ALeavePattern: array of string; var AResult: string): Boolean;
- function _RegExAnalyze(AData, APattern: string): string;
- var
- nMatches: TMatchCollection;
- begin
- nMatches := TRegEx.Matches(AData, APattern, [roMultiLine]);
- if nMatches.Count > then
- Result := nMatches.Item[].Value;
- end;
- var
- i: Integer;
- nTmpData: string;
- begin
- AResult := '';
- try
- nTmpData := FJSONStrs;
- for i := Low(ALeavePattern) to High(ALeavePattern) do
- begin
- nTmpData := _RegExAnalyze(nTmpData, ALeavePattern[i]);
- if nTmpData = '' then
- Break;
- end;
- AResult := nTmpData;
- except
- on E: Exception do
- raise Exception.CreateFmt('正则分析失败[%s]', [E.Message]);
- end;
- Result := AResult <> '';
- end;
- function TEMFStrInfoList.TryGetInfo(AInfoName: string; var AInfo: TEMFStrInfo; var AIndex: UInt32): Boolean;
- begin
- Result := FDic.TryGetValue(AInfoName, AIndex);
- if Result then
- AInfo := FList[AIndex]^;
- end;
- initialization
- FReferenceDC := VCL.Graphics.TBitmap.Create;
- with FReferenceDC do
- begin
- PixelFormat := pf24bit;
- Width := ;
- Height := ;
- end;
- finalization
- FreeAndNil(FReferenceDC);
- end.
获取EMF文件内全部文字, 并按照左上到右下的顺序排序的更多相关文章
- 从运行时的工作空间获取EMF文件(IFILE)
//EMFFILE_URI为EMF文件的URI String uriString = EMFFILE_URI.trimFragment().toPlatformString(true); if (ur ...
- python 获取excel文件内sheet名称列表
xl = pd.ExcelFile('foo.xls') xl.sheet_names # see all sheet names xl.parse(sheet_name) # read a spec ...
- 使用GridView来获取xml文件数据
在任何一个系统中,数据的读取和编辑都是至关重要的.无论你是CS还是BS,都需要对数据进行操作.其实 我们可以发现,很多软件和系统最终都是对于数据库中数据的处理.之前在CS的学习过程中我们接触到了很多 ...
- 编写Java程序,在硬盘中选取一个 txt 文件,读取该文档的内容后,追加一段文字“[ 来自新华社 ]”,保存到一个新的 txt 文件内
查看本章节 查看作业目录 需求说明: 在硬盘中选取一个 txt 文件,读取该文档的内容后,追加一段文字"[ 来自新华社 ]",保存到一个新的 txt 文件内 实现思路: 创建 Sa ...
- XML序列化 判断是否是手机 字符操作普通帮助类 验证数据帮助类 IO帮助类 c# Lambda操作类封装 C# -- 使用反射(Reflect)获取dll文件中的类型并调用方法 C# -- 文件的压缩与解压(GZipStream)
XML序列化 #region 序列化 /// <summary> /// XML序列化 /// </summary> /// <param name="ob ...
- 在Autodesk Vault 2014中使用VDF(Vault Development Framework) API获取所有文件的属性信息
这几天在玩儿Vault API, 从Autodesk Vault 2014开始提供了Vault Development Framework(VDF) API,让开发工作更简单了.在Vault 20 ...
- 关于 MAXScript 获取全部文件
MAXScript 官方文档里关于获取文件夹下所有文件的方法 fn getFilesRecursive root pattern = ( dir_array = GetDirectories (roo ...
- SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...
- vue 双语言切换中,data内翻译文字不正常切换的解决方案
背景 有这么一个登录页面,相关功能如下: 支持双语言,点击切换语言 表单内部有一个自定义的select,里面option的label.value都是的名字由外部提供:其中预设的option的label ...
随机推荐
- XSS攻击及防御
XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性.其原理是攻击者向有XSS漏洞的网站中输入 ...
- Nginx与Apache的比较
Nginx与Apache的比较 Nginx相对于Apache的优点 轻量级.同样起web服务,比apache占用更少的资源和内存 抗并发.nginx处理请求是异步非阻塞,而apache则是阻塞型.在高 ...
- Caffe初试(三)使用caffe的cifar10网络模型训练自己的图片数据
由于我涉及一个车牌识别系统的项目,计划使用深度学习库caffe对车牌字符进行识别.刚开始接触caffe,打算先将示例中的每个网络模型都拿出来用用,当然这样暴力的使用是不会有好结果的- -||| ,所以 ...
- TFS二次开发系列:三、TFS二次开发的第一个实例
首先我们需要认识TFS二次开发的两大获取服务对象的类. 他们分别为TfsConfigurationServer和TfsTeamProjectCollection,他们的不同点在于可以获取不同的TFS ...
- NIO初识
Java编程中的NIO,俗称new I/O,是在JDK1.4版本之后开始引入的,在JDK1.4之前,Java服务端大多使用同步阻塞式来处理网络请求,在低流量.低并发情况还能抗住,在如今互联网时代,信息 ...
- Pyqt+QRcode 生成 识别 二维码
1.生成二维码 python生成二维码是件很简单的事,使用第三方库Python QRCode就可生成二维码,我用Pyqt给QRcode打个壳 一.python-qrcode介绍 python-qrco ...
- [转载]使用PyQt来编写第一个Python GUI程序
转载自:http://python.jobbole.com/81276/ 英文版出处:http://pythonforengineers.com/your-first-gui-app-with-pyt ...
- ajax下载文件
得到所有Post数据: var postData=Request.Form.ToString() 构建JS代码 // Ajax 文件下载jQuery.download = function(url, ...
- 彻底解决m2eclipse之Unable to update index for central
原文链接:https://my.oschina.net/itblog/blog/208581 maven是个好东西,eclipse上的maven插件m2eclipse也非常方便,但是最近这个东西经常无 ...
- PV 与 并发数 之间的故事
PV: Page View UV: Unique Visitor 在一些已经上线的项目中,运营会统计每日的PV,UV,IP 等数据 而根据PV量,可以推算出一个相对较科学的并发数,来作为负载测试的一个 ...