public static void Run( string source, PngLevel pngLevel, int checkId, bool tolerant ) { PSD.File psd = QueryImage.Run( source ); if ( !ImportImage.CheckPSD( psd ) ) return; MapInfo info = MapInfo.FromBitmap( psd.Layers[Boot.MapInfoLayerName].Image ); // Extract the 3 buffers from the PSD int[] colorbuffer, idbuffer, borderbuffer; ImportImage.GetBuffers( psd, out colorbuffer, out idbuffer, out borderbuffer ); // Get the convertor IIDConvertor convertor = ImportImage.GetConvertor( info ); if ( convertor == null ) return; IIDConvertor tconvertor = null; if ( convertor is Inferis2IDConvertor && tolerant ) tconvertor = new InferisProxIDConvertor(); if ( tconvertor != null ) Console.WriteLine( "Using tolerant ID conversion." ); // If needed, write out test PNGs of the extracted layers if ( pngLevel != PngLevel.None ) ImportImage.WriteTestPNGs( colorbuffer, idbuffer, borderbuffer, pngLevel, info ); if ( info.LightmapZoom == 0 ) { Console.Write( "Checking ID map... " ); // Use another buffer, since we need to remember the original for the image import later on. int[] cidbuffer = new int[idbuffer.Length]; if ( checkId >= 0 && checkId <= Province.Count ) { Point[] tagged = new Point[idbuffer.Length]; int t = 0; for ( int i=0; i<idbuffer.Length; ++i ) { cidbuffer[i] = convertor.ConvertRGB( idbuffer[i] ); if ( cidbuffer[i] == checkId ) { tagged[t++] = new Point( i%info.Width, i/info.Width ); } } Console.WriteLine( "Done." ); Console.WriteLine(); Console.WriteLine( "ID {0} was found at the following locations in the file:", checkId ); for ( int i=0; i<t; ++i ) { Console.WriteLine( "* {0},{1}", tagged[i].X, tagged[i].Y ); } } else { ushort[] tagged = new ushort[Province.InternalCount]; int invalid = 0; for ( int i=0; i<idbuffer.Length; ++i ) { cidbuffer[i] = convertor.ConvertRGB( idbuffer[i] ); if ( cidbuffer[i] < 0 || cidbuffer[i] > Province.Count ) { if ( tconvertor != null ) cidbuffer[i] = tconvertor.ConvertRGB( idbuffer[i] ); if ( cidbuffer[i] < 0 || cidbuffer[i] > Province.Count ) { if ( invalid++ == 0 ) Console.WriteLine(); Console.WriteLine( "Error: Found invalid ID {2} at ({0},{1}). RGB value = {3:X6}", i % info.Width, (int)(i/info.Width), cidbuffer[i], (idbuffer[i] & 0xFFFFFF) ); } else { tagged[cidbuffer[i]]++; } } else { tagged[cidbuffer[i]]++; } } if ( invalid > 0 ) { Console.WriteLine( "Error: Invalid IDs encountered. Cannot import. Please fix." ); return; } Console.WriteLine( "Done." ); Console.WriteLine(); Console.WriteLine( "The IDs found in this file are:" ); bool first = true; int avgtot = 0, avgcnt = 0; for ( int i=0; i<tagged.Length; ++i ) { if ( tagged[i] > 0 ) { if ( !first ) Console.Write( ", " ); Console.Write( "{0} ({1})", i, tagged[i] ); first = false; avgtot += tagged[i]; avgcnt++; } } Console.WriteLine(); Console.WriteLine(); avgtot = (avgtot/avgcnt)/10; Console.WriteLine( "Possible stray IDs (average = {0}):", avgtot*10 ); for ( int i=0; i<tagged.Length; ++i ) { if ( tagged[i] > 0 && tagged[i] < avgtot ) { Console.WriteLine( "* {0} ({1}x)", i, tagged[i] ); } } Console.WriteLine(); } } else { Console.WriteLine( "This is not a lightmap1 exported file: no id check is necessary." ); } Console.WriteLine( "The source file checked out okay. You should probably do a /SI run now before importing." ); }
private void MapImageParsedArguments_ProcessOption(ParsedArguments sender, ProcessArgumentEventArgs e) { switch ( e.Value.ToLower() ) { case "i": case "import": action = Action.ImportImage; simulate = false; break; case "e": case "export": action = Action.ExportImage; break; case "q": case "query": action = Action.QueryImage; break; case "si": case "simulateimport": action = Action.ImportImage; simulate = true; break; case "c": case "check": action = Action.CheckImage; break; case "o": overwrite = true; break; case "1": case "2": case "3": useLightmap = int.Parse( e.Value ); break; case "p": case "png": if (e.Data.Length > 0) { foreach(string s in e.Data.Split(new char[] { ',' })) { switch (s.ToLower()) { case "shading": case "s": case "shades": case "shade": pngLevel |= PngLevel.Shading; break; case "ids": case "i": case "id": case "idmap": pngLevel |= PngLevel.IDs; break; case "borders": case "b": case "border": pngLevel |= PngLevel.Borders; break; } } } else { pngLevel = PngLevel.All; } break; case "d": case "direct": direct = true; break; case "g": if ( e.Data.Length > 0 ) { try { regen = int.Parse( e.Data ); } catch ( FormatException ) { // Do nothing } } else { regen = 1; } break; case "r": if ( e.Data.Length > 0 ) { if ( e.Data.ToLower() == "full" ) { region = new Rectangle( -1, -1, -1, -1 ); mode = RegionMode.Full; } else { int size = -1; try { size = int.Parse( e.Data ); } catch ( FormatException ) { size = -1; } if ( size <= 0 ) { string[] spec= e.Data.Split( new char[] {','}, 4 ); if ( spec.Length >= 4 ) { Rectangle newRegion = region; try { newRegion = new Rectangle( int.Parse( spec[0] ), int.Parse( spec[1] ), int.Parse( spec[2] ), int.Parse( spec[3] ) ); } catch ( FormatException ) { // Do nothing } region = newRegion; } mode = RegionMode.Normal; } else { region = new Rectangle( 0, 0, size, size ); mode = RegionMode.All; } } } break; case "relocate": if ( e.Data.Length > 0 ) { string[] spec= e.Data.Split( new char[] {','}, 2 ); if ( spec.Length >= 2 ) { Point newReloc = reloc; try { newReloc = new Point( int.Parse( spec[0] ), int.Parse( spec[1] ) ); } catch ( FormatException ) { // Do nothing } reloc = newReloc; } } break; case "id": try { id = int.Parse( e.Data ); } catch ( FormatException ) { id = -1; } break; case "pedantic": tolerant = false; break; case "checkidgrid": checkidgrid = true; break; } }
public static void Run( string source, string target, int regen, Point relocate, bool nowrite, PngLevel pngLevel, bool tolerant, bool checkIdgrid ) { if (pngLevel != PngLevel.All && pngLevel != PngLevel.None) { Console.WriteLine("Can't use PNG specifier with import. Use /p instead of /p:<spec>."); return; } if ( nowrite ) Console.WriteLine( "*** Simulation ***\n" ); // Open the PSD, and check if it's valid. PSD.File psd = QueryImage.Run( source ); if ( !CheckPSD( psd ) ) return; Console.WriteLine( ); // Get the mapinfo from the PSD MapInfo info = MapInfo.FromBitmap( psd.Layers[Boot.MapInfoLayerName].Image ); if ( !relocate.IsEmpty ) { relocate = new Point( Lightmap.FitToGrid( relocate.X ), Lightmap.FitToGrid( relocate.Y ) ); Console.WriteLine( "Image will be relocated from {0},{1} to {2},{3}...", info.X, info.Y, relocate.X, relocate.Y ); info.Location = relocate; } // Extract the 3 buffers from the PSD int[] colorbuffer, idbuffer, borderbuffer; ImportImage.GetBuffers( psd, out colorbuffer, out idbuffer, out borderbuffer ); // Remove ref to PSD so it can get garbagecollected psd = null; // Get the convertor IIDConvertor convertor = GetConvertor( info ); if ( convertor == null ) return; IIDConvertor tconvertor = null; if ( convertor is Inferis2IDConvertor && tolerant ) tconvertor = new InferisProxIDConvertor(); if ( tconvertor != null ) Console.WriteLine( "Using tolerant ID conversion." ); // Now, open the map file Console.WriteLine( "Opening target file \"{0}\"...", Path.GetFileName( target ) ); EU2.Edit.File file = new EU2.Edit.File(); file.ReadFrom( target ); int[] cidbuffer = null; if ( info.LightmapZoom == 0 ) { Console.Write( "Checking ID map... " ); // Use another buffer, since we need to remember the original for the image import later on. cidbuffer = new int[idbuffer.Length]; int invalid = 0; for ( int i=0; i<idbuffer.Length; ++i ) { cidbuffer[i] = convertor.ConvertRGB( idbuffer[i] ); if ( cidbuffer[i] < 0 || cidbuffer[i] > Province.Count ) { if ( tconvertor != null ) cidbuffer[i] = tconvertor.ConvertRGB( idbuffer[i] ); if ( cidbuffer[i] < 0 || cidbuffer[i] > Province.Count ) { Console.WriteLine( "Error: Found invalid ID {2} at ({0},{1}). RGB value = {3:X6}", i % info.Width, (int)(i/info.Width), cidbuffer[i], (idbuffer[i] & 0xFFFFFF) ); if ( invalid++ > 10 ) { Console.WriteLine( "Error: Too many invalid IDs found... Stopping." ); break; } } } if ( cidbuffer[i] == Province.TerraIncognitaID ) cidbuffer[i] = Province.MaxValue; } if ( invalid > 0 ) { Console.WriteLine( "Error: Invalid IDs encountered. Cannot import. Please fix." ); return; } } // If needed, write out test PNGs of the extracted layers if (pngLevel != PngLevel.None) WriteTestPNGs(colorbuffer, idbuffer, borderbuffer, pngLevel, info); // and get the correct Lightmap Lightmap map = null; switch ( info.LightmapZoom ) { case 0: map = file.Lightmap1; break; case 1: map = file.Lightmap2; break; case 2: map = file.Lightmap3; break; } if ( map == null ) { Console.WriteLine( "Error: The source image was exported from lightmap{0}, but it no longer exists in the target file." ); return; } if ( map.Zoom == 0 ) { // Then check if the bitmap differs... ushort[] checkbuffer = file.IDMap.ExportBitmapBuffer( info.Bounds ); bool mismatch = false; System.Diagnostics.Debug.Assert( checkbuffer.Length == cidbuffer.Length, "ID buffers have non-matching size" ); for ( int i=0; !mismatch && i<cidbuffer.Length; ++i ) { if ( cidbuffer[i] != checkbuffer[i] ) mismatch = true; } if ( mismatch ) { if ( map.Zoom > 0 ) { Console.WriteLine( "Changes to ID map only supported for lightmap 1." ); return; } Console.WriteLine( "Mismatch found, updating the ID map." ); file.IDMap.ImportBitmapBuffer( info.Bounds, cidbuffer ); } else Console.WriteLine( " No update needed to the ID map." ); ushort[] affectedIDs = null; bool doBoundboxes = false; if ( regen > 0 ) { // regenerate certain files first... if ( regen > 2 ) { Console.WriteLine( "Regenerating adjacenties (complete)..." ); file.AdjacencyTable = file.IDMap.BuildAdjacencyTable( file.Provinces ); // This marks all ids as affected. affectedIDs = new ushort[Province.Count]; for ( ushort i=0; i<Province.Count; ++i ) affectedIDs[i] = i; // Force regen of boundboxes doBoundboxes = true; } else if ( mismatch || regen > 1 ) { Console.Write( "Regenerating adjacenties (quick) " ); if ( regen > 1 ) Console.Write( "(forced)" ); Console.WriteLine( "... " ); // Rebuild part and note the affected Ids. affectedIDs = file.IDMap.BuildAdjacencyTable( file.AdjacencyTable, info.Bounds, file.Provinces ); // Force regen of boundboxes doBoundboxes = true; } } // reattach map.Attach( file.Provinces, file.AdjacencyTable, file.IDMap ); if ( doBoundboxes ) { Console.WriteLine( "Regenerating boundboxes..." ); file.BoundBoxes = new BoundBoxes( file.IDMap.CalculateBoundBoxes() ); } if ( affectedIDs != null && affectedIDs.Length > 0 ) { Rectangle[] boxes = file.BoundBoxes.GetBoxes( affectedIDs ); int[] indexes = map.GetBlockIndexes( boxes ); int[] indexes2 = map.GetBlockIndexes( info.Bounds ); int total = indexes.Length; for ( int i=0; i<indexes.Length; ++i ) { for ( int e=0; e<indexes2.Length; ++e ) { if ( indexes[i] == indexes2[e] ) { indexes[i] = -1; total--; break; } } } Console.WriteLine( "Decompressing blocks of affected provinces outside of modified area." ); Console.Write( "{0} provinces affected, {1} blocks to recompress... ", affectedIDs.Length, total ); if ( total > 0 ) { indexes2 = new int[total]; total = 0; for ( int i=0; i<indexes.Length; ++i ) { if ( indexes[i] > 0 ) indexes2[total++] = indexes[i]; } map.Recompress( indexes2 ); } if ( nowrite && checkIdgrid ) { Console.Write( "Checking for IDGrid complexity..." ); Rectangle errorArea; if ( IDGrid.CheckAreaForOverflow( file.IDMap, info.Bounds, out errorArea ) ) { Console.WriteLine(" ok!" ); } else { Console.WriteLine( " too complex (error in region {0},{1}-{2},{3}).", errorArea.Left, errorArea.Top, errorArea.Right, errorArea.Bottom); } } Console.WriteLine( "Done." ); } } else { Console.Write( "Scaling down ID map (file changes will not be applied at this zoom level)..." ); ushort[] tmpbuffer = MapToolsLib.Utils.ScaleIDBuffer( file.IDMap.ExportBitmapGrid( map.CoordMap.ZoomedToActual( info.Bounds ) ), map.Zoom ); idbuffer = new int[tmpbuffer.Length]; for ( int i=0; i<idbuffer.Length; ++i ) { if ( tmpbuffer[i] >= Province.Count ) tmpbuffer[i] = Province.TerraIncognitaID; idbuffer[i] = (tconvertor == null ? convertor : tconvertor).ConvertID( tmpbuffer[i] ); } Console.WriteLine( " Done." ); } Console.WriteLine( "Importing image..." ); RawImage rawimg = new IOShader( tconvertor == null ? convertor : tconvertor ).Unshade32( map.Zoom, info.Bounds, colorbuffer, idbuffer, borderbuffer ); map.EncodeImage( rawimg ); if ( !nowrite ) { file.WriteTo( target ); Console.Write( "Import successful." ); } else { try { file.WriteTo( System.IO.FileStream.Null ); } catch ( Exception e ) { Console.Write( "There's an error when saving the target file." ); throw e; } Console.Write( "The import process was tested successfully. You can safely do a real import with the same source and target." ); } }
public static void WriteTestPNGs( int[] colorbuffer, int[] idbuffer, int[] borderbuffer, PngLevel pngLevel, MapInfo info ) { Console.Write( "Writing buffer check PNGs..."); if ((pngLevel & PngLevel.Shading)>0) { Console.Write("Colorbuffer... "); Visualiser.CreateImage32(colorbuffer, info.Size).Save("test-Shading.png", ImageFormat.Png); } if ((pngLevel & PngLevel.IDs)>0) { Console.Write("IDbuffer... "); Visualiser.CreateImage32(idbuffer, info.Size).Save("test-IDs.png", ImageFormat.Png); } if ((pngLevel & PngLevel.Borders)>0) { Console.Write("Borderbuffer... "); Visualiser.CreateImage32(borderbuffer, info.Size).Save("test-Borders.png", ImageFormat.Png); } Console.WriteLine( "Done!" ); }
private static void DoExport( Lightmap map, Rectangle region, PngLevel pngLevel, IDMap idmap, string sourcefile, string target ) { Console.WriteLine( "Decoding image..." ); RawImage rawimg = map.DecodeImage( region ); int[] shadebuffer, idbuffer, borderbuffer; new IOShader( Boot.DefaultConvertor ).MultiShade32( rawimg, out shadebuffer, out idbuffer, out borderbuffer ); // We don't use the lightmap version as a source: this can lead to errors. // Use the idmap as source. For lightmap2 and lightmap3, this needs to be scaled down. // -- NOTE: if this is changed, don't forget to turn on the id converting in the IOShader.Multishade above! ushort[] tmpbuffer = null; if ( map.Zoom == 0 ) { tmpbuffer = idmap.ExportBitmapBuffer( rawimg.Bounds ); } else { Console.WriteLine( "Scaling idmap..." ); tmpbuffer = MapToolsLib.Utils.ScaleIDBuffer( idmap.ExportBitmapGrid( map.CoordMap.ZoomedToActual( rawimg.Bounds ) ), map.Zoom ); } // Convert it to the map format for ( int i=0; i<idbuffer.Length; ++i ) { if ( tmpbuffer[i] >= Province.Count ) tmpbuffer[i] = Province.TerraIncognitaID; idbuffer[i] = Boot.DefaultConvertor.ConvertID( tmpbuffer[i] ); } if ( pngLevel != PngLevel.None ) { string basetarget = Path.ChangeExtension( Path.GetFileNameWithoutExtension( target ) + "-###", Path.GetExtension( target ) ); if ((pngLevel & PngLevel.Shading) > 0) { target = basetarget.Replace("###", Boot.ShadingLayerName); Console.WriteLine("Exporting to \"{0}\"...", Path.GetFileName(target)); Visualiser.CreateImage32(shadebuffer, rawimg.Size).Save(target, ImageFormat.Png); } if ((pngLevel & PngLevel.IDs) > 0) { target = basetarget.Replace("###", Boot.IDLayerName); Console.WriteLine("Exporting to \"{0}\"...", Path.GetFileName(target)); Visualiser.CreateImage32(idbuffer, rawimg.Size).Save(target, ImageFormat.Png); } if ((pngLevel & PngLevel.Borders) > 0) { target = basetarget.Replace("###", Boot.BorderLayerName); Console.WriteLine("Exporting to \"{0}\"...", Path.GetFileName(target)); Visualiser.CreateImage32(borderbuffer, rawimg.Size).Save(target, ImageFormat.Png); } } else { Console.WriteLine( "Exporting to \"{0}\"...", Path.GetFileName( target ) ); PSD.File psd = new PSD.File( rawimg.Size ); Bitmap img = new MapInfo( map.Zoom, rawimg.Location, rawimg.Size, sourcefile, Path.GetFileName( target ), Boot.DefaultConvertor ).AsBitmap(); PSD.Layer l = psd.Layers.Add( new PSD.Layer( Boot.MapInfoLayerName, 0, 0, img ) ); l.Opacity = 255; l.Visible = false; l.ProtectTransparancy = true; img = Visualiser.CreateImage32( shadebuffer, rawimg.Size ); l = psd.Layers.Add( new PSD.Layer( Boot.ShadingLayerName, 0, 0, img ) ); l.Opacity = 254; l.Visible = true; l.ProtectTransparancy = false; img = Visualiser.CreateImage32( idbuffer, rawimg.Size ); l = psd.Layers.Add( new PSD.Layer( Boot.IDLayerName, 0, 0, img ) ); l.Opacity = 254; l.Mode = PSD.LayerMode.Overlay; l.Visible = true; l.ProtectTransparancy = false; img = Visualiser.CreateImage32( borderbuffer, rawimg.Size, true ); l = psd.Layers.Add( new PSD.Layer( Boot.BorderLayerName, 0, 0, img ) ); l.Opacity = 254; l.Visible = true; l.ProtectTransparancy = false; // -- Write the psd FileStream stream = null; try { stream = new FileStream( target, FileMode.Create, FileAccess.Write, FileShare.None ); psd.WriteTo( new BinaryWriter( stream ) ); } finally { if ( stream != null ) stream.Close(); } } }
public static void Run( string source, string target, Rectangle region, RegionMode mode, int zoom, PngLevel pngLevel, bool direct ) { if ( (mode == RegionMode.Normal && region.IsEmpty) || (mode == RegionMode.All && region.Width <= 0 ) ) { Console.WriteLine( "No region was specified. Use \"/r:<x,y,width,height>\", \"/r:full\" or \"/r:<size>\" to specify the region to export." ); return; } Console.WriteLine( "Opening source file \"{0}\"...", Path.GetFileName( source ) ); region.Width -= 1; region.Height -= 1; IFile file; if ( direct ) { file = new EU2.Edit.EU2Proxy(); file.ReadFrom( source ); // source is EU2 dir } else { file = new EU2.Edit.File(); file.ReadFrom( source ); } Lightmap map = null; switch ( zoom ) { case 1: map = file.Lightmap1; break; case 2: map = file.Lightmap2; break; case 3: map = file.Lightmap3; break; } if ( map == null ) { Console.WriteLine( "The source file does not contain lightmap{0}.", zoom ); return; } map.VolatileDecompression = true; if ( mode == RegionMode.All ) { int size = ((region.Width+Lightmap.BlockSize-1) >> Lightmap.BlockFactor) << Lightmap.BlockFactor; Console.WriteLine( "Exporting full map as separate files of size {0}x{0}.", size ); for ( int y=0; y<map.Size.Height; y+=size ) { for ( int x=0; x<map.Size.Width; x+=size ) { region = new Rectangle( x, y, size, size ); string parttarget = Path.Combine( Path.GetDirectoryName( target ), Path.GetFileNameWithoutExtension( target ) + String.Format( "-[{0},{1}-{2},{3}]", region.Left, region.Top, region.Right, region.Bottom ) + Path.GetExtension( target ) ); DoExport( map, region, pngLevel, file.IDMap, Path.GetFileName( source ), parttarget ); } } } else if ( mode == RegionMode.Full ) { Console.WriteLine( "Exporting full map as one file." ); region = new Rectangle( new Point( 0, 0 ), map.Size ); DoExport( map, region, pngLevel, file.IDMap, Path.GetFileName( source ), target ); } else { Console.WriteLine( "Exporting map region: ({0},{1})-({2},{3}) (width={4}, height={5}).", region.Left, region.Top, region.Right, region.Bottom, region.Width, region.Height ); DoExport(map, region, pngLevel, file.IDMap, Path.GetFileName(source), target); } Console.Write( "Export successful." ); }