import { DIBitmap , PatternBitmap16 } from "./Bitmap" ; import { Blob } from "./Blob" ; import { GDIContext } from "./GDIContext" ; import { Helper , WMFJSError } from "./Helper" ; import { PointS , Rect } from "./Primitives" ; import { Region } from "./Region" ; import { Brush , ColorRef , Font , Palette , Pen } from "./Style" ; export class WMFRecords { private _records : ( ( gdi : GDIContext ) => void ) [ ] ; constructor ( reader , first ) { this . _records = [ ] ; let all = false ; let curpos = first ; main_loop : while ( ! all ) { reader . seek ( curpos ) ; const size = reader . readUint32 ( ) ; if ( size < 3 ) { throw new WMFJSError ( "Invalid record size" ) ; } const type = reader . readUint16 ( ) ; switch ( type ) { case Helper . GDI . RecordType . META_EOF : all = true ; break main_loop ; case Helper . GDI . RecordType . META_SETMAPMODE : { const mapMode = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setMapMode ( mapMode ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETWINDOWORG : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setWindowOrg ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETWINDOWEXT : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setWindowExt ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_OFFSETWINDOWORG : { const offY = reader . readInt16 ( ) ; const offX = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . offsetWindowOrg ( offX , offY ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETVIEWPORTORG : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setViewportOrg ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETVIEWPORTEXT : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setViewportExt ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_OFFSETVIEWPORTORG : { const offY = reader . readInt16 ( ) ; const offX = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . offsetViewportOrg ( offX , offY ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SAVEDC : { this . _records . push ( ( gdi ) => { gdi . saveDC ( ) ; } ) ; break ; } case Helper . GDI . RecordType . META_RESTOREDC : { const saved = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . restoreDC ( saved ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETSTRETCHBLTMODE : { const stretchMode = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setStretchBltMode ( stretchMode ) ; } ) ; break ; } case Helper . GDI . RecordType . META_DIBSTRETCHBLT : { const haveSrcDib = ( ( type >> 8 ) + 3 !== size ) ; const rasterOp = reader . readUint16 ( ) | ( reader . readUint16 ( ) << 16 ) ; const srcH = reader . readInt16 ( ) ; const srcW = reader . readInt16 ( ) ; const srcY = reader . readInt16 ( ) ; const srcX = reader . readInt16 ( ) ; const destH = reader . readInt16 ( ) ; const destW = reader . readInt16 ( ) ; const destY = reader . readInt16 ( ) ; const destX = reader . readInt16 ( ) ; const datalength = size * 2 - ( reader . pos - curpos ) ; const dib = new DIBitmap ( reader , datalength ) ; this . _records . push ( ( gdi ) => { gdi . stretchDibBits ( srcX , srcY , srcW , srcH , destX , destY , destW , destH , rasterOp , dib ) ; } ) ; break ; } case Helper . GDI . RecordType . META_STRETCHDIB : { const rasterOp = reader . readUint16 ( ) | ( reader . readUint16 ( ) << 16 ) ; const colorUsage = reader . readInt16 ( ) ; const srcH = reader . readInt16 ( ) ; const srcW = reader . readInt16 ( ) ; const srcY = reader . readInt16 ( ) ; const srcX = reader . readInt16 ( ) ; const destH = reader . readInt16 ( ) ; const destW = reader . readInt16 ( ) ; const destY = reader . readInt16 ( ) ; const destX = reader . readInt16 ( ) ; const datalength = size * 2 - ( reader . pos - curpos ) ; const dib = new DIBitmap ( reader , datalength ) ; this . _records . push ( ( gdi ) => { gdi . stretchDib ( srcX , srcY , srcW , srcH , destX , destY , destW , destH , rasterOp , colorUsage , dib ) ; } ) ; break ; } case Helper . GDI . RecordType . META_ESCAPE : { const func = reader . readUint16 ( ) ; const count = reader . readUint16 ( ) ; const offset = reader . pos ; const blob = new Blob ( reader , offset ) ; this . _records . push ( ( gdi ) => { gdi . escape ( func , blob , offset , count ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETTEXTALIGN : { const textAlign = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setTextAlign ( textAlign ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETBKMODE : { const bkMode = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setBkMode ( bkMode ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETTEXTCOLOR : { const textColor = new ColorRef ( reader ) ; this . _records . push ( ( gdi ) => { gdi . setTextColor ( textColor ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETBKCOLOR : { const bkColor = new ColorRef ( reader ) ; this . _records . push ( ( gdi ) => { gdi . setBkColor ( bkColor ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEBRUSHINDIRECT : { const datalength = size * 2 - ( reader . pos - curpos ) ; const brush = new Brush ( reader , datalength , false ) ; this . _records . push ( ( gdi ) => { gdi . createBrush ( brush ) ; } ) ; break ; } case Helper . GDI . RecordType . META_DIBCREATEPATTERNBRUSH : { const datalength = size * 2 - ( reader . pos - curpos ) ; const brush = new Brush ( reader , datalength , true ) ; this . _records . push ( ( gdi ) => { gdi . createBrush ( brush ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEPENINDIRECT : { const pen = new Pen ( reader ) ; this . _records . push ( ( gdi ) => { gdi . createPen ( pen ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEFONTINDIRECT : { const datalength = size * 2 - ( reader . pos - curpos ) ; const font = new Font ( reader , datalength ) ; this . _records . push ( ( gdi ) => { gdi . createFont ( font ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SELECTOBJECT : { const idx = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . selectObject ( idx , null ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SELECTPALETTE : { const idx = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . selectObject ( idx , "palette" ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SELECTCLIPREGION : { const idx = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . selectObject ( idx , "region" ) ; } ) ; break ; } case Helper . GDI . RecordType . META_DELETEOBJECT : { const idx = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . deleteObject ( idx ) ; } ) ; break ; } case Helper . GDI . RecordType . META_RECTANGLE : { const rect = new Rect ( reader ) ; this . _records . push ( ( gdi ) => { gdi . rectangle ( rect , 0 , 0 ) ; } ) ; break ; } case Helper . GDI . RecordType . META_ROUNDRECT : { const rh = reader . readInt16 ( ) ; const rw = reader . readInt16 ( ) ; const rect = new Rect ( reader ) ; this . _records . push ( ( gdi ) => { gdi . rectangle ( rect , rw , rh ) ; } ) ; break ; } case Helper . GDI . RecordType . META_LINETO : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . lineTo ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_MOVETO : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . moveTo ( x , y ) ; } ) ; break ; } case Helper . GDI . RecordType . META_TEXTOUT : { const len = reader . readInt16 ( ) ; if ( len > 0 ) { const text = reader . readString ( len ) ; reader . skip ( len % 2 ) ; const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . textOut ( x , y , text ) ; } ) ; } break ; } case Helper . GDI . RecordType . META_EXTTEXTOUT : { const y = reader . readInt16 ( ) ; const x = reader . readInt16 ( ) ; const len = reader . readInt16 ( ) ; const fwOpts = reader . readUint16 ( ) ; let hasRect = null ; let hasDx = null ; if ( size * 2 === 14 + len + len % 2 ) { hasRect = false ; hasDx = false ; } if ( size * 2 === 14 + 8 + len + len % 2 ) { hasRect = true ; hasDx = false ; } if ( size * 2 === 14 + len + len % 2 + len * 2 ) { hasRect = false ; hasDx = true ; } if ( size * 2 === 14 + 8 + len + len % 2 + len * 2 ) { hasRect = true ; hasDx = true ; } const rect = hasRect ? new Rect ( reader ) : null ; if ( len > 0 ) { const text = reader . readString ( len ) ; reader . skip ( len % 2 ) ; const dx = [ ] ; if ( hasDx ) { for ( let i = 0 ; i < text . length ; i ++ ) { dx . push ( reader . readInt16 ( ) ) ; } } this . _records . push ( ( gdi ) => { gdi . extTextOut ( x , y , text , fwOpts , rect , dx ) ; } ) ; } break ; } case Helper . GDI . RecordType . META_EXCLUDECLIPRECT : { const rect = new Rect ( reader ) ; this . _records . push ( ( gdi ) => { gdi . excludeClipRect ( rect ) ; } ) ; break ; } case Helper . GDI . RecordType . META_INTERSECTCLIPRECT : { const rect = new Rect ( reader ) ; this . _records . push ( ( gdi ) => { gdi . intersectClipRect ( rect ) ; } ) ; break ; } case Helper . GDI . RecordType . META_POLYGON : { let cnt = reader . readInt16 ( ) ; const points = [ ] ; while ( cnt > 0 ) { points . push ( new PointS ( reader ) ) ; cnt -- ; } this . _records . push ( ( gdi ) => { gdi . polygon ( points , true ) ; } ) ; break ; } case Helper . GDI . RecordType . META_SETPOLYFILLMODE : { const polyfillmode = reader . readUint16 ( ) ; this . _records . push ( ( gdi ) => { gdi . setPolyFillMode ( polyfillmode ) ; } ) ; break ; } case Helper . GDI . RecordType . META_POLYPOLYGON : { const cnt = reader . readUint16 ( ) ; const polygonsPtCnts = [ ] ; for ( let i = 0 ; i < cnt ; i ++ ) { polygonsPtCnts . push ( reader . readUint16 ( ) ) ; } const polygons = [ ] ; for ( let i = 0 ; i < cnt ; i ++ ) { const ptCnt = polygonsPtCnts [ i ] ; const p = [ ] ; for ( let ip = 0 ; ip < ptCnt ; ip ++ ) { p . push ( new PointS ( reader ) ) ; } polygons . push ( p ) ; } this . _records . push ( ( gdi ) => { gdi . polyPolygon ( polygons ) ; } ) ; break ; } case Helper . GDI . RecordType . META_POLYLINE : { let cnt = reader . readInt16 ( ) ; const points = [ ] ; while ( cnt > 0 ) { points . push ( new PointS ( reader ) ) ; cnt -- ; } this . _records . push ( ( gdi ) => { gdi . polyline ( points ) ; } ) ; break ; } case Helper . GDI . RecordType . META_ELLIPSE : { const rect = new Rect ( reader ) ; this . _records . push ( ( gdi ) => { gdi . ellipse ( rect ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEPALETTE : { const palette = new Palette ( reader ) ; this . _records . push ( ( gdi ) => { gdi . createPalette ( palette ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEREGION : { const region = new Region ( reader ) ; this . _records . push ( ( gdi ) => { gdi . createRegion ( region ) ; } ) ; break ; } case Helper . GDI . RecordType . META_CREATEPATTERNBRUSH : { const datalength = size * 2 - ( reader . pos - curpos ) ; const patternBitmap = new PatternBitmap16 ( reader , datalength ) ; const brush = new Brush ( reader , datalength , patternBitmap ) ; this . _records . push ( ( gdi ) => { gdi . createPatternBrush ( brush ) ; } ) ; break ; } case Helper . GDI . RecordType . META_OFFSETCLIPRGN : { const offY = reader . readInt16 ( ) ; const offX = reader . readInt16 ( ) ; this . _records . push ( ( gdi ) => { gdi . offsetClipRgn ( offX , offY ) ; } ) ; break ; } case Helper . GDI . RecordType . META_REALIZEPALETTE : case Helper . GDI . RecordType . META_SETPALENTRIES : case Helper . GDI . RecordType . META_SETROP2 : case Helper . GDI . RecordType . META_SETRELABS : case Helper . GDI . RecordType . META_SETTEXTCHAREXTRA : case Helper . GDI . RecordType . META_RESIZEPALETTE : case Helper . GDI . RecordType . META_SETLAYOUT : case Helper . GDI . RecordType . META_FILLREGION : case Helper . GDI . RecordType . META_SETMAPPERFLAGS : case Helper . GDI . RecordType . META_SETTEXTJUSTIFICATION : case Helper . GDI . RecordType . META_SCALEWINDOWEXT : case Helper . GDI . RecordType . META_SCALEVIEWPORTEXT : case Helper . GDI . RecordType . META_FLOODFILL : case Helper . GDI . RecordType . META_FRAMEREGION : case Helper . GDI . RecordType . META_ANIMATEPALETTE : case Helper . GDI . RecordType . META_EXTFLOODFILL : case Helper . GDI . RecordType . META_SETPIXEL : case Helper . GDI . RecordType . META_PATBLT : case Helper . GDI . RecordType . META_PIE : case Helper . GDI . RecordType . META_STRETCHBLT : case Helper . GDI . RecordType . META_INVERTREGION : case Helper . GDI . RecordType . META_PAINTREGION : case Helper . GDI . RecordType . META_ARC : case Helper . GDI . RecordType . META_CHORD : case Helper . GDI . RecordType . META_BITBLT : case Helper . GDI . RecordType . META_SETDIBTODEV : case Helper . GDI . RecordType . META_DIBBITBLT : default : { let recordName = "UNKNOWN" ; for ( const name in Helper . GDI . RecordType ) { const recordTypes = Helper . GDI . RecordType ; if ( recordTypes [ name ] === type ) { recordName = name ; break ; } } Helper . log ( "[WMF] " + recordName + " record (0x" + type . toString ( 16 ) + ") at offset 0x" + curpos . toString ( 16 ) + " with " + ( size * 2 ) + " bytes" ) ; break ; } } curpos += size * 2 ; } if ( ! all ) { throw new WMFJSError ( "Could not read all records" ) ; } } public play ( gdi ) { const len = this . _records . length ; for ( let i = 0 ; i < len ; i ++ ) { this . _records [ i ] ( gdi ) ; } } }