From 2141e1d01651e284c1857e28d0a984838d2235e2 Mon Sep 17 00:00:00 2001 From: Raymond Date: Mon, 5 Apr 2010 01:36:21 +0200 Subject: [PATCH] Minor changes + added todo list. --- Units/MMLCore/fontloader.pas | 19 +- Units/MMLCore/ocr.pas | 6 +- Units/MMLCore/ocrutil.pas | 552 ++++++++++++++++------------------- todo.txt | 10 + 4 files changed, 268 insertions(+), 319 deletions(-) create mode 100644 todo.txt diff --git a/Units/MMLCore/fontloader.pas b/Units/MMLCore/fontloader.pas index b1db0a4..f5970ba 100644 --- a/Units/MMLCore/fontloader.pas +++ b/Units/MMLCore/fontloader.pas @@ -49,10 +49,12 @@ type TMFonts = class(TObject) private Fonts: TList; - Path: String; + FPath: String; Client : TObject; function GetFontIndex(const Name: String): Integer; function GetFontByIndex(Index : integer): TMfont; + procedure SetPath(const aPath: String); + function GetPath: String; public constructor Create(Owner : TObject); destructor Destroy; override; @@ -60,10 +62,9 @@ type function FreeFont(const Name: String): Boolean; function LoadFont(const Name: String; Shadow: Boolean): boolean; function LoadSystemFont(const SysFont : TFont; const FontName : string) : boolean; - procedure SetPath(const aPath: String); - function GetPath: String; function Copy(Owner : TObject): TMFonts; function Count : integer; + property Path : string read GetPath write SetPath; property Font[Index : integer]: TMfont read GetFontByIndex; default; end; @@ -155,12 +156,12 @@ end; procedure TMFonts.SetPath(const aPath: String); begin - Path := aPath; + FPath := aPath; end; function TMFonts.GetPath: String; begin - Exit(Path); + Exit(FPath); end; function TMFonts.GetFontIndex(const Name: String): Integer; @@ -201,9 +202,9 @@ function TMFonts.LoadFont(const Name: String; Shadow: Boolean): boolean; var f: TMFont; begin - if not DirectoryExists(Path + Name) then + if not DirectoryExists(FPath + Name) then begin - raise Exception.Create('LoadFont: Directory ' + Path + Name + ' does not exists.'); + raise Exception.Create('LoadFont: Directory ' + FPath + Name + ' does not exists.'); Exit(False); end; @@ -211,7 +212,7 @@ begin f.Name := Name; if Shadow then F.Name := F.Name + '_s'; - f.Data := InitOCR( LoadGlyphMasks(Path + Name + DS, Shadow)); + f.Data := InitOCR( LoadGlyphMasks(FPath + Name + DS, Shadow)); Fonts.Add(f); {$IFDEF FONTDEBUG} TClient(Client).Writeln('Loaded Font ' + f.Name); @@ -270,7 +271,7 @@ var i:integer; begin Result := TMFonts.Create(Owner); - Result.Path := Self.GetPath(); + Result.Path := FPath; for i := 0 to Self.Fonts.Count -1 do Result.Fonts.Add(TMFont(Self.Fonts.Items[i]).Copy()); end; diff --git a/Units/MMLCore/ocr.pas b/Units/MMLCore/ocr.pas index fec2ef9..91e7475 100644 --- a/Units/MMLCore/ocr.pas +++ b/Units/MMLCore/ocr.pas @@ -45,7 +45,7 @@ type debugbmp: TMufasaBitmap; {$ENDIF} function GetFonts:TMFonts; - procedure SetFonts(NewFonts: TMFonts); + procedure SetFonts(const NewFonts: TMFonts); public constructor Create(Owner: TObject); destructor Destroy; override; @@ -139,7 +139,7 @@ var i: longint; begin // We're going to load all fonts now - FFonts.SetPath(path); + FFonts.Path := path; dirs := GetDirectories(path); Result := false; for i := 0 to high(dirs) do @@ -158,7 +158,7 @@ begin end; { Set new Fonts. We set it to a Copy of NewFonts } -procedure TMOCR.SetFonts(NewFonts: TMFonts); +procedure TMOCR.SetFonts(const NewFonts: TMFonts); begin Self.FFonts := NewFonts.Copy(Self.Client); end; diff --git a/Units/MMLCore/ocrutil.pas b/Units/MMLCore/ocrutil.pas index 2b72c02..3c702cd 100644 --- a/Units/MMLCore/ocrutil.pas +++ b/Units/MMLCore/ocrutil.pas @@ -8,54 +8,45 @@ uses Classes, SysUtils, MufasaTypes,bitmaps; type - TNormArray = array of integer; - TocrGlyphMask = record - ascii: char; - width,height: integer; - l,r,t,b: integer; - mask: TNormArray; - end; - TocrGlyphMaskArray = array of TocrGlyphMask; - TocrGlyphMetric = record - xoff,yoff: integer; - width,height: integer; - index: integer; //stores the internal TocrData index for this char - end; - TocrData = record - ascii: array[0..255] of TocrGlyphMetric; - pos: array of array of integer; - pos_adj: array of real; - neg: array of array of integer; - neg_adj: array of real; - map: array of char; - width,height, max_width, max_height: integer; - inputs,outputs: integer; - end; + TNormArray = array of integer; + TocrGlyphMask = record + ascii: char; + width,height: integer; + l,r,t,b: integer; + mask: TNormArray; + end; + TocrGlyphMaskArray = array of TocrGlyphMask; + TocrGlyphMetric = record + xoff,yoff: integer; + width,height: integer; + index: integer; //stores the internal TocrData index for this char + end; + TocrData = record + ascii: array[0..255] of TocrGlyphMetric; + pos: array of array of integer; + pos_adj: array of real; + neg: array of array of integer; + neg_adj: array of real; + map: array of char; + width,height, max_width, max_height: integer; + inputs,outputs: integer; + end; - TocrDataArray = array of TocrData; + TocrDataArray = array of TocrData; - {Begin To be removed} - Tbmp = record - data: array of TRGB32; - width,height: integer; - end; - {End To be removed} + tLab = record + L,a,b: real; + end; - - tLab = record - L,a,b: real; - end; - - procedure findBounds(glyphs: TocrGlyphMaskArray; out width,height: integer); - function LoadGlyphMask(const bmp : TMufasaBitmap; shadow: boolean; const ascii : char): TocrGlyphMask; - function LoadGlyphMasks(const path: string; shadow: boolean): TocrGlyphMaskArray; - function InitOCR(const Masks : TocrGlyphMaskArray): TocrData; - function GuessGlyph(glyph: TNormArray; ocrdata: TocrData): char; - function PointsToNorm(points: TpointArray; out w,h: integer): TNormArray; - function ImageToNorm(src: TRGB32Array; w,h: integer): TNormArray; - function ocrDetect(txt: TNormArray; w,h: integer; var ocrdata: TocrData): string; - function ExtractText(colors: PRGB32;{colors: tRGBArray;} w,h: integer): TNormArray; - function MakeTPAString(str: string): TpointArray; + procedure findBounds(glyphs: TocrGlyphMaskArray; out width,height: integer); + function LoadGlyphMask(const bmp : TMufasaBitmap; shadow: boolean; const ascii : char): TocrGlyphMask; + function LoadGlyphMasks(const path: string; shadow: boolean): TocrGlyphMaskArray; + function InitOCR(const Masks : TocrGlyphMaskArray): TocrData; + function GuessGlyph(glyph: TNormArray; ocrdata: TocrData): char; + function PointsToNorm(points: TpointArray; out w,h: integer): TNormArray; + function ImageToNorm(src: TRGB32Array; w,h: integer): TNormArray; + function ocrDetect(txt: TNormArray; w,h: integer; var ocrdata: TocrData): string; + function ExtractText(colors: PRGB32;{colors: tRGBArray;} w,h: integer): TNormArray; implementation uses @@ -64,86 +55,63 @@ uses graphtype, intfgraphics,graphics; {End To-Remove unit} - -function ReadBMP(path: string): Tbmp; -var - LazIntf : TLazIntfImage; - RawImageDesc : TRawImageDescription; -begin - if FileExists(path) then - begin; - LazIntf := TLazIntfImage.Create(0,0); - RawImageDesc.Init_BPP32_B8G8R8_BIO_TTB(LazIntf.Width,LazIntf.Height); - LazIntf.DataDescription := RawImageDesc; - LazIntf.LoadFromFile(path); - Result.width := LazIntf.Width; - Result.height := LazIntf.Height; - SetLength(result.data,LazIntf.Width*LazIntf.Height); - Move(LazIntf.PixelData[0],result.data[0],LazIntf.Width*LazIntf.Height*sizeOf(TRGB32)); - LazIntf.Free; - end; -end; - - - - {initalizes the remaining fields from a TocrGlyphMask and finds the global bounds} procedure findBounds(glyphs: TocrGlyphMaskArray; out width,height: integer); var - i,x,y,c,w,h: integer; - l,r,t,b: integer; - dat: TNormArray; + i,x,y,c,w,h: integer; + l,r,t,b: integer; + dat: TNormArray; begin - width:= 0; - height:= 0; - for c:= 0 to length(glyphs) - 1 do + width:= 0; + height:= 0; + for c:= 0 to length(glyphs) - 1 do + begin + dat:= glyphs[c].mask; + w:= glyphs[c].width; + h:= glyphs[c].height; + l:= w; + r:= 0; + t:= h; + b:= 0; + for i:= 0 to w*h-1 do begin - dat:= glyphs[c].mask; - w:= glyphs[c].width; - h:= glyphs[c].height; - l:= w; - r:= 0; - t:= h; - b:= 0; - for i:= 0 to w*h-1 do - begin - if dat[i] = 1 then - begin - x:= i mod w; - y:= i div w; - if x > r then r:= x; - if x < l then l:= x; - if y > b then b:= y; - if y < t then t:= y; - end; - end; - if l = w then l:= 0; - if t = h then t:= 0; - glyphs[c].r:= r; - glyphs[c].l:= l; - glyphs[c].b:= b; - glyphs[c].t:= t; - if (r - l + 1) > width then width:= r - l + 1; - if (b - t + 1) > height then height:= b - t + 1; + if dat[i] = 1 then + begin + x:= i mod w; + y:= i div w; + if x > r then r:= x; + if x < l then l:= x; + if y > b then b:= y; + if y < t then t:= y; + end; end; + if l = w then l:= 0; + if t = h then t:= 0; + glyphs[c].r:= r; + glyphs[c].l:= l; + glyphs[c].b:= b; + glyphs[c].t:= t; + if (r - l + 1) > width then width:= r - l + 1; + if (b - t + 1) > height then height:= b - t + 1; + end; end; {Use whatever you want if you don't like this} function GetFiles(Path, Ext: string): TstringArray; var - SearchRec : TSearchRec; - c : integer; + SearchRec : TSearchRec; + c : integer; begin - c := 0; - if FindFirst(Path + '*.' + ext, faAnyFile, SearchRec) = 0 then - begin - repeat - inc(c); - SetLength(Result,c); - Result[c-1] := SearchRec.Name; - until FindNext(SearchRec) <> 0; - SysUtils.FindClose(SearchRec); - end; + c := 0; + if FindFirst(Path + '*.' + ext, faAnyFile, SearchRec) = 0 then + begin + repeat + inc(c); + SetLength(Result,c); + Result[c-1] := SearchRec.Name; + until FindNext(SearchRec) <> 0; + SysUtils.FindClose(SearchRec); + end; end; function LoadGlyphMask(const bmp: TMufasaBitmap; shadow: boolean; const ascii : char): TocrGlyphMask; @@ -258,218 +226,215 @@ end; {guesses a glyph stored in glyph (which is an 1-0 image of the size specified by width and height in ocrdata} function GuessGlyph(glyph: TNormArray; ocrdata: TocrData): char; var - i,c,inputs,outputs,val: integer; - pos_weights: array of real; - neg_weights: array of real; - max, weight: real; + i,c,inputs,outputs,val: integer; + pos_weights: array of real; + neg_weights: array of real; + max, weight: real; begin - SetLength(pos_weights,ocrdata.outputs); - SetLength(neg_weights,ocrdata.outputs); - inputs:= ocrdata.inputs - 1; - outputs:= ocrdata.outputs - 1; - for i:= 0 to inputs do + SetLength(pos_weights,ocrdata.outputs); + SetLength(neg_weights,ocrdata.outputs); + inputs:= ocrdata.inputs - 1; + outputs:= ocrdata.outputs - 1; + for i:= 0 to inputs do + begin + val:= glyph[i]; + for c:= 0 to outputs do begin - val:= glyph[i]; - for c:= 0 to outputs do - begin - pos_weights[c]:= pos_weights[c] + ocrdata.pos[c][i] * val; - neg_weights[c]:= neg_weights[c] + ocrdata.neg[c][i] * val; - end - end; - max:= 0; - for i:= 0 to outputs do + pos_weights[c]:= pos_weights[c] + ocrdata.pos[c][i] * val; + neg_weights[c]:= neg_weights[c] + ocrdata.neg[c][i] * val; + end + end; + max:= 0; + for i:= 0 to outputs do + begin + weight:= pos_weights[i] * ocrdata.pos_adj[i] - neg_weights[i] * ocrdata.neg_adj[i]; + if (weight > max) then begin - weight:= pos_weights[i] * ocrdata.pos_adj[i] - neg_weights[i] * ocrdata.neg_adj[i]; - if (weight > max) then - begin - max:= weight; - result:= ocrdata.map[i]; - end; + max:= weight; + result:= ocrdata.map[i]; end; + end; end; {converts a TPA into a 1-0 image of the smallest possible size} function PointsToNorm(points: TpointArray; out w,h: integer): TNormArray; var - l,r,t,b: integer; - i,len,size: integer; - norm: TNormArray; + l,r,t,b: integer; + i,len,size: integer; + norm: TNormArray; begin - len:= length(points); - l:= points[0].x; - r:= points[0].x; - t:= points[0].y; - b:= points[0].y; - for i:= 1 to len-1 do - begin - if points[i].x < l then l:= points[i].x; - if points[i].x > r then r:= points[i].x; - if points[i].y < t then t:= points[i].y; - if points[i].y > b then b:= points[i].y; - end; - w:= r - l + 1; - h:= b - t + 1; - size:= w * h; - SetLength(norm,size); - for i:= 0 to len-1 do - norm[(points[i].x - l) + (points[i].y - t) * w]:= 1; - result:= norm; + len:= length(points); + l:= points[0].x; + r:= points[0].x; + t:= points[0].y; + b:= points[0].y; + for i:= 1 to len-1 do + begin + if points[i].x < l then l:= points[i].x; + if points[i].x > r then r:= points[i].x; + if points[i].y < t then t:= points[i].y; + if points[i].y > b then b:= points[i].y; + end; + w:= r - l + 1; + h:= b - t + 1; + size:= w * h; + SetLength(norm,size); + for i:= 0 to len-1 do + norm[(points[i].x - l) + (points[i].y - t) * w]:= 1; + result:= norm; end; function ImageToNorm(src: TRGB32Array; w,h: integer): TNormArray; var - norm: TNormArray; - i: integer; + norm: TNormArray; + i: integer; begin - SetLength(norm,w*h); - for i:= 0 to w*h-1 do - if (src[i].r = 255) and (src[i].g = 255) and (src[i].b = 255) then - norm[i]:= 1 else norm[i]:= 0; - result:= norm; + SetLength(norm,w*h); + for i:= 0 to w*h-1 do + if (src[i].r = 255) and (src[i].g = 255) and (src[i].b = 255) then + norm[i]:= 1 else norm[i]:= 0; + result:= norm; end; {takes a mask of only one line of text, a TocrData, and returns the string in it} function ocrDetect(txt: TNormArray; w,h: integer; var ocrdata: TocrData): string; var - l,r,t,b,x,y,xx,yy: integer; - upper,left,last,spaces: integer; - glyph: TNormArray; - empty: boolean; - ascii: char; + l,r,t,b,x,y,xx,yy: integer; + upper,left,last,spaces: integer; + glyph: TNormArray; + empty: boolean; + ascii: char; begin - result:= ''; - l:= -1; - r:= -1; - upper:= -9001; //large negative - left:= -9001; //large negative - x:= 0; - while x < w do + result:= ''; + l:= -1; + r:= -1; + upper:= -9001; //large negative + left:= -9001; //large negative + x:= 0; + while x < w do + begin + empty:= true; + for y:= 0 to h-1 do begin - empty:= true; - for y:= 0 to h-1 do - begin - if txt[x+y*w] = 1 then - begin - empty:= false; - break; - end; - end; - if (l = -1) and (not empty) then - begin - l:= x - end else if (l <> -1) then - begin - if empty then - r:= x - 1 - else if x = w-1 then - r:= x; - end; - if (r <> -1) and (l <> -1) then - begin - t:= -1; - b:= -1; - SetLength(glyph,0); - SetLength(glyph,ocrdata.width*ocrdata.height); - for yy:= 0 to h-1 do - begin - for xx:= l to r do - if txt[xx+yy*w] = 1 then begin t:= yy; break; end; - if t <> -1 then break; - end; - for yy:= h-1 downto 0 do - begin - for xx:= l to r do - if txt[xx+yy*w] = 1 then begin b:= yy; break; end; - if b <> -1 then break; - end; - if b - t + 1 > ocrdata.height then b:= b - (b-t+1-ocrdata.height); - if r - l + 1 > ocrdata.width then r:= r - (r-l+1-ocrdata.width); - for yy:= t to b do - for xx:= l to r do - glyph[(xx-l) + (yy-t)*ocrdata.width]:= txt[xx+yy*w]; - - ascii:= GuessGlyph(glyph,ocrdata); - if (upper = -9001) or (left = -9001) then - begin - upper:= t - ocrdata.ascii[ord(ascii)].yoff; - left:= l - ocrdata.ascii[ord(ascii)].xoff + ocrdata.ascii[ord(ascii)].width; - x:= left; - end else - begin - last:= left; - left:= l - ocrdata.ascii[ord(ascii)].xoff; - if last <> left then - begin - for spaces:= 1 to (left - last) div ocrdata.ascii[32].width do - result:= result + ' '; - end; - left:= left + ocrdata.ascii[ord(ascii)].width; - x:= left; - end; - - result:= result + ascii; - - l:= -1; - r:= -1; - - end; - inc(x); + if txt[x+y*w] = 1 then + begin + empty:= false; + break; + end; end; + if (l = -1) and (not empty) then + begin + l:= x + end else if (l <> -1) then + begin + if empty then + r:= x - 1 + else if x = w-1 then + r:= x; + end; + if (r <> -1) and (l <> -1) then + begin + t:= -1; + b:= -1; + SetLength(glyph,0); + SetLength(glyph,ocrdata.width*ocrdata.height); + for yy:= 0 to h-1 do + begin + for xx:= l to r do + if txt[xx+yy*w] = 1 then begin t:= yy; break; end; + if t <> -1 then break; + end; + for yy:= h-1 downto 0 do + begin + for xx:= l to r do + if txt[xx+yy*w] = 1 then begin b:= yy; break; end; + if b <> -1 then break; + end; + if b - t + 1 > ocrdata.height then b:= b - (b-t+1-ocrdata.height); + if r - l + 1 > ocrdata.width then r:= r - (r-l+1-ocrdata.width); + for yy:= t to b do + for xx:= l to r do + glyph[(xx-l) + (yy-t)*ocrdata.width]:= txt[xx+yy*w]; + + ascii:= GuessGlyph(glyph,ocrdata); + if (upper = -9001) or (left = -9001) then + begin + upper:= t - ocrdata.ascii[ord(ascii)].yoff; + left:= l - ocrdata.ascii[ord(ascii)].xoff + ocrdata.ascii[ord(ascii)].width; + x:= left; + end else + begin + last:= left; + left:= l - ocrdata.ascii[ord(ascii)].xoff; + if last <> left then + begin + for spaces:= 1 to (left - last) div ocrdata.ascii[32].width do + result:= result + ' '; + end; + left:= left + ocrdata.ascii[ord(ascii)].width; + x:= left; + end; + result:= result + ascii; + l:= -1; + r:= -1; + end; + inc(x); + end; end; function AvgColors(color1:TRGB32; weight1: integer; color2: TRGB32; weight2: integer): TRGB32; begin - result.r:= (color1.r * weight1 + color2.r * weight2) div (weight1 + weight2); - result.g:= (color1.g * weight1 + color2.g * weight2) div (weight1 + weight2); - result.b:= (color1.b * weight1 + color2.b * weight2) div (weight1 + weight2); + result.r:= (color1.r * weight1 + color2.r * weight2) div (weight1 + weight2); + result.g:= (color1.g * weight1 + color2.g * weight2) div (weight1 + weight2); + result.b:= (color1.b * weight1 + color2.b * weight2) div (weight1 + weight2); end; procedure RGBtoXYZ(color: TRGB32; out X, Y, Z: real); inline; var - nr,ng,nb: real; + nr,ng,nb: real; begin - nr:= color.r / 255.0; - ng:= color.g / 255.0; - nb:= color.b / 255.0; - if nr <= 0.04045 then nr:= nr / 12.92 else nr:= power((nr + 0.055)/1.055,2.4); - if ng <= 0.04045 then ng:= ng / 12.92 else ng:= power((ng + 0.055)/1.055,2.4); - if nb <= 0.04045 then nr:= nb / 12.92 else nb:= power((nb + 0.055)/1.055,2.4); - X:= 0.4124*nr + 0.3576*ng + 0.1805*nb; - Y:= 0.2126*nr + 0.7152*ng + 0.0722*nb; - Z:= 0.0193*nr + 0.1192*ng + 0.9505*nb; + nr:= color.r / 255.0; + ng:= color.g / 255.0; + nb:= color.b / 255.0; + if nr <= 0.04045 then nr:= nr / 12.92 else nr:= power((nr + 0.055)/1.055,2.4); + if ng <= 0.04045 then ng:= ng / 12.92 else ng:= power((ng + 0.055)/1.055,2.4); + if nb <= 0.04045 then nr:= nb / 12.92 else nb:= power((nb + 0.055)/1.055,2.4); + X:= 0.4124*nr + 0.3576*ng + 0.1805*nb; + Y:= 0.2126*nr + 0.7152*ng + 0.0722*nb; + Z:= 0.0193*nr + 0.1192*ng + 0.9505*nb; end; function labmod(i: real): real; inline; begin - if i > power(0.206896552,3) then - result:= power(i,0.333333333) - else - result:= 7.787037037*i + 0.137931034; + if i > power(0.206896552,3) then + result:= power(i,0.333333333) + else + result:= 7.787037037*i + 0.137931034; end; function ColortoLab(c: TRGB32): tLab; inline; var - X,Y,Z,sum,Xn,Yn,Zn: real; + X,Y,Z,sum,Xn,Yn,Zn: real; begin - RGBtoXYZ(c,X,Y,Z); - sum:= X + Y + Z; - if(sum = 0) then - begin - result.l := 0.0; - result.a := 0.0; - result.b := 0.0; - end; - Xn:= X / sum; - Yn:= Y / sum; - Zn:= Z / sum; - result.L:= 116.0*labmod(y/yn) - 16.0; - result.a:= 500.0*(labmod(x/xn)-labmod(y/yn)); - result.b:= 500.0*(labmod(y/yn)-labmod(z/zn)); + RGBtoXYZ(c,X,Y,Z); + sum:= X + Y + Z; + if(sum = 0) then + begin + result.l := 0.0; + result.a := 0.0; + result.b := 0.0; + end; + Xn:= X / sum; + Yn:= Y / sum; + Zn:= Z / sum; + result.L:= 116.0*labmod(y/yn) - 16.0; + result.a:= 500.0*(labmod(x/xn)-labmod(y/yn)); + result.b:= 500.0*(labmod(y/yn)-labmod(z/zn)); end; function colorDistSqr(a,b:TRGB32): integer; inline; begin - result:= (a.r-b.r)*(a.r-b.r)+(a.b-b.b)*(a.b-b.b)+(a.g-b.g)*(a.g-b.g); + result:= (a.r-b.r)*(a.r-b.r)+(a.b-b.b)*(a.b-b.b)+(a.g-b.g)*(a.g-b.g); end; function ExtractText(colors: PRGB32;{colors: tRGBArray;} w,h: integer): TNormArray; @@ -595,32 +560,5 @@ begin result:= norm; end; -function MakeTPAString(str: string): TpointArray; -var - i,j,c,off: integer; - bmp: array of Tbmp; -begin - raise Exception.Create('MakeTPAString sucks ass, don''t use it.'); - c:= 0; - off:= 0; - SetLength(bmp,length(str)); - for i:= 0 to length(str)-1 do - begin - bmp[i]:= ReadBmp('/home/merlijn/Programs/mufasa/Fonts/StatChars/' + inttostr(ord(str[i+1])) + '.bmp'); - SetLength(result,c+bmp[i].width*bmp[i].height); - for j:= 0 to bmp[i].width*bmp[i].height - 1 do - begin - if bmp[i].data[j].g = 255 then - begin - result[c].x:= j mod bmp[i].width + off; - result[c].y:= j div bmp[i].width; - inc(c); - end; - end; - off:= off + bmp[i].width; - SetLength(result,c); - end; -end; - end. diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..3347b27 --- /dev/null +++ b/todo.txt @@ -0,0 +1,10 @@ +- DTM Editor +- BMP Editor +- DTM Features +- SRL Installer +- Extra GUI icons +- Installer +- Test scripts +- DWS +- OCR exceptions + proper implementation of len +- Documentation + wiki \ No newline at end of file