// Create a single PDF file void CreateOneBitmap(string fileName, CourseDesignator courseDesignator) { RectangleF mapRectangle = controller.GetCurrentPrintAreaRectangle(courseDesignator); // Get the course view for the course we are printing. CourseView courseView = CourseView.CreatePrintingCourseView(eventDB, courseDesignator); // Get the correct purple color to print the course in. short ocadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; FindPurple.GetPurpleColor(mapDisplay, appearance, out ocadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Create a course layout from the view. CourseLayout layout = new CourseLayout(); layout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); layout.SetLayerColor(CourseLayer.MainCourse, ocadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, CourseLayer.MainCourse); // Set the course layout into the map display mapDisplay.SetCourse(layout); mapDisplay.SetPrintArea(null); ExportBitmap exportBitmap = new ExportBitmap(mapDisplay); exportBitmap.CreateBitmap(fileName, mapRectangle, GetImageFormat(), bitmapCreationSettings.Dpi, bitmapCreationSettings.WorldFile ? mapDisplay.CoordinateMapper : null); }
private TopologyDropTargetCourseObj FindNearbyDropTarget(PointF location) { const float MAXDISTANCE = 9F; const float MINDRAGDIST = 5F; CourseLayout layout = selectionMgr.TopologyLayout; TopologyDropTargetCourseObj nearest = null; Id <CourseControl> courseControlDrag = courseObjectDrag.courseControlId; float nearestDistance = float.MaxValue; // Find nearest drop target that is within MAXDISTANCE of location, and not adjacent to the // course control we are dragging. foreach (CourseObj obj in layout) { TopologyDropTargetCourseObj dropTarget = obj as TopologyDropTargetCourseObj; if (dropTarget != null && ((dropTarget.courseControlId != courseControlDrag && dropTarget.courseControlId2 != courseControlDrag) || courseObjectStart.DistanceFromPoint(dropTarget.location) > MINDRAGDIST)) { float distance = Geometry.DistanceF(location, dropTarget.location); if (distance < nearestDistance && distance < MAXDISTANCE) { nearestDistance = distance; nearest = dropTarget; } } } return(nearest); }
// Format the given CourseView into a bunch of course objects, and add it to the given course Layout public RectangleF FormatCourseToLayout(SymbolDB symbolDB, CourseView courseViewAllVariations, CourseView specificVariation, CourseLayout courseLayout, Id <CourseControl> ccSelection1, Id <CourseControl> ccSelection2, CourseLayer layerAllVariations, CourseLayer layerSpecificVariation) { this.eventDB = courseViewAllVariations.EventDB; this.symbolDB = symbolDB; this.courseLayout = courseLayout; this.courseLayerAllVariationsAndParts = layerAllVariations; this.courseLayerSpecificVariation = layerSpecificVariation; this.controlViewsAllVariationsAndParts = courseViewAllVariations.ControlViews; this.controlViewsSpecificVariation = specificVariation.ControlViews; this.controlPositions = new ControlPosition[controlViewsAllVariationsAndParts.Count]; this.courseControlIdsSpecificVariation = QueryEvent.EnumCourseControlIds(eventDB, specificVariation.CourseDesignator).ToArray(); this.courseControlIdSelection1 = ccSelection1; this.courseControlIdSelection2 = ccSelection2; this.variationMap = QueryEvent.GetVariantCodeMapping(eventDB, courseViewAllVariations.CourseDesignator); SizeF totalAbstractSize = AssignControlPositions(0, controlViewsAllVariationsAndParts.Count, 0, 0); // Now create objects now that the positions have been created. courseObjRatio = 1.0F; appearance = new CourseAppearance(); for (int index = 0; index < controlViewsAllVariationsAndParts.Count; ++index) { CreateObjectsForControlView(controlViewsAllVariationsAndParts[index], controlPositions[index]); } PointF bottomCenter = LocationFromAbstractPosition(0, 0); SizeF size = SizeFromAbstractSize(totalAbstractSize); RectangleF rect = new RectangleF(bottomCenter.X - size.Width / 2, bottomCenter.Y - size.Height, size.Width, size.Height); rect.Inflate(widthUnit, heightUnit); return(rect); }
CourseLayout CreateCourseLayout(CourseView courseView) { // Create the CourseLayout. CourseLayout courseLayout = new CourseLayout(); courseLayout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); courseLayout.SetLayerColor(CourseLayer.MainCourse, NormalCourseAppearance.courseOcadId, NormalCourseAppearance.courseColorName, creationSettings.cyan, creationSettings.magenta, creationSettings.yellow, creationSettings.black, creationSettings.purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, courseAppearance, courseLayout, CourseLayer.MainCourse); return(courseLayout); }
// Update the topology void UpdateTopology() { if (topologyCourseView == null) { activeTopologyCourseLayout = null; } else { // Place the active course in the layout. activeTopologyCourseLayout = new CourseLayout(); activeTopologyCourseLayout.SetLayerColor(CourseLayer.AllVariations, 1, NormalCourseAppearance.blackColorName, 0, 0, 0, 0.55F, false); activeTopologyCourseLayout.SetLayerColor(CourseLayer.MainCourse, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); activeTopologyCourseLayout.SetLayerColor(CourseLayer.InvisibleObjects, 2, "DropTargets", 0, 0, 0, 0, false); TopologyFormatter formatter = new TopologyFormatter(); formatter.FormatCourseToLayout(symbolDB, topologyCourseView, activeCourseView, activeTopologyCourseLayout, selectedCourseControl, selectedCourseControl2, CourseLayer.AllVariations, CourseLayer.MainCourse); } }
// Left mouse button selects the object clicked on, or drag something already selected. public override MapViewer.DragAction LeftButtonDown(Pane pane, PointF location, float pixelSize, ref bool displayUpdateNeeded) { if (pane == Pane.Map) { CourseLayout activeCourse = controller.GetCourseLayout(); CourseObj clickedObject; PointF handleLocation; Cursor handleCursor; // Area we initiating a drag of a corner? clickedObject = HitTestHandle(location, pixelSize, out handleLocation, out handleCursor); if (clickedObject != null) { // being dragging the corner DragHandleMode commandMode = new DragHandleMode(controller, clickedObject, handleLocation, location); controller.SetCommandMode(commandMode); displayUpdateNeeded = true; return(MapViewer.DragAction.ImmediateDrag); } // Are we initiating a drag of an object? clickedObject = HitTestDraggable(location, pixelSize); if (clickedObject != null) { // Begin dragging the clicked object. DragObjectMode commandMode = new DragObjectMode(controller, eventDB, selectionMgr, clickedObject, location); controller.SetCommandMode(commandMode); displayUpdateNeeded = true; return(MapViewer.DragAction.ImmediateDrag); } return(MapViewer.DragAction.DelayedDrag); } else if (pane == Pane.Topology) { CourseObj clickedObject = HitTest(pane, location, pixelSize, (co => !(co is TopologyDropTargetCourseObj))); if (clickedObject is ControlNumberCourseObj || clickedObject is CrossingCourseObj || (clickedObject is StartCourseObj && (eventDB.GetControl(((StartCourseObj)clickedObject).controlId).kind == ControlPointKind.MapExchange))) { // Can drag control numbers, crossing points, or map exchanges. selectionMgr.SelectCourseObject(clickedObject); displayUpdateNeeded = true; return(MapViewer.DragAction.DelayedDrag); } } return(MapViewer.DragAction.None); }
// Hit test a location to see if it is over a selected, draggable objects. If so, // return that course object, otherwise, return null. CourseObj HitTestDraggable(PointF location, float pixelSize) { CourseObj[] selectedObjects = selectionMgr.SelectedCourseObjects; if (selectedObjects != null) { // If the cursor is above a selected control, start, finish that is a moveable object. CourseObj hitObject = CourseLayout.HitTestCollection(selectedObjects, location, pixelSize, CourseLayer.All, null); if (hitObject != null && DraggableObject(hitObject)) { return(hitObject); } } return(null); }
// Hit test a point to see if it is over an existing control, or will create a new control. Id <ControlPoint> HitTestPoint(PointF mouseLocation, float pixelSize, out PointF highlightLocation) { if (allControls) { // If all controls, always new control. highlightLocation = new PointF(mouseLocation.X + PIXELOFFSETX * pixelSize, mouseLocation.Y + PIXELOFFSETY * pixelSize); return(Id <ControlPoint> .None); } else { // Are we over a control we might add? CourseLayout layout = controller.GetCourseLayout(); PointCourseObj courseObj = layout.HitTest(mouseLocation, pixelSize, CourseLayer.AllControls, (co => co is PointCourseObj)) as PointCourseObj; if (courseObj != null) { highlightLocation = courseObj.location; return(courseObj.controlId); } else { courseObj = layout.HitTest(mouseLocation, pixelSize, CourseLayer.MainCourse, (co => co is PointCourseObj)) as PointCourseObj; if (courseObj != null && courseObj.controlId.IsNotNone) { // Allow selecting a control in the current course for a butterfly course. But -- it must be a normal control or crossing point, and not adjacent to the control being inserted. if (eventDB.GetControl(courseObj.controlId).kind == controlKind && (controlKind == ControlPointKind.Normal || controlKind == ControlPointKind.CrossingPoint)) { Id <CourseControl> courseControl1, courseControl2; CourseDesignator courseDesignator; LegInsertionLoc legInsertionLoc; GetControlInsertionPoint(courseObj.location, out courseDesignator, out courseControl1, out courseControl2, out legInsertionLoc); if (eventDB.GetCourse(courseDesignator.CourseId).kind != CourseKind.Score && (exchangeAtControl || (courseObj.courseControlId != courseControl1 && courseObj.courseControlId != courseControl2))) { highlightLocation = courseObj.location; return(courseObj.controlId); } } } highlightLocation = new PointF(mouseLocation.X + PIXELOFFSETX * pixelSize, mouseLocation.Y + PIXELOFFSETY * pixelSize); return(Id <ControlPoint> .None); } } }
private CourseObj HitTest(Pane pane, PointF location, float pixelSize, Predicate <CourseObj> filter) { CourseLayout activeCourse = (pane == Pane.Map) ? controller.GetCourseLayout() : controller.GetTopologyLayout(); CourseObj clickedObject; clickedObject = activeCourse.HitTest(location, pixelSize, CourseLayer.MainCourse, filter); if (clickedObject == null) { clickedObject = activeCourse.HitTest(location, pixelSize, CourseLayer.Descriptions, filter); } if (clickedObject == null && pane == Pane.Topology) { clickedObject = activeCourse.HitTest(location, pixelSize, CourseLayer.AllVariations, filter); } return(clickedObject); }
// Set the courses being displayed. public void SetCourse(CourseLayout newCourse) { if (!object.Equals(course, newCourse)) { course = newCourse; if (course == null) { courseMap = null; } else { courseMap = course.RenderToMap(new CourseLayout.MapRenderOptions()); } RaiseChanged(null); } }
// Determine if two course layouts are equal. Important because is can prevent expensive redraws of the course. public override bool Equals(object obj) { if (obj == null || !(obj is CourseLayout)) { return(false); } if ((object)this == obj) { return(true); // identical objects are equal. } CourseLayout other = (CourseLayout)obj; for (int i = 0; i < LAYERCOUNT; i++) { if (other.colorC[i] != colorC[i] || other.colorK[i] != colorK[i] || other.colorM[i] != colorM[i] || other.colorY[i] != colorY[i] || other.colorOverprint[i] != colorOverprint[i]) { return(false); } if (other.ocadColorId[i] != ocadColorId[i] || other.colorName[i] != colorName[i]) { return(false); } } List <CourseObj> otherList = other.objects; if (otherList.Count != objects.Count) { return(false); } for (int i = 0; i < objects.Count; ++i) { if (!(objects[i].Equals(otherList[i]))) { return(false); } } return(true); }
// The core printing routine. void DrawPage(IGraphicsTarget graphicsTarget, CoursePage page) { // Get the course view for the course we are printing. CourseView courseView = CourseView.CreatePrintingCourseView(eventDB, page.courseDesignator); // Get the correct purple color to print the course in. short ocadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; FindPurple.GetPurpleColor(mapDisplay, appearance, out ocadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Create a course layout from the view. CourseLayout layout = new CourseLayout(); layout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); layout.SetLayerColor(CourseLayer.MainCourse, ocadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, CourseLayer.MainCourse); // Set the course layout into the map display mapDisplay.SetCourse(layout); mapDisplay.SetPrintArea(null); // Set the transform, and the clip. Matrix transform = Geometry.CreateInvertedRectangleTransform(page.mapRectangle, page.printRectangle); PushRectangleClip(graphicsTarget, page.printRectangle); graphicsTarget.PushTransform(transform); // Determine the resolution in map coordinates. Matrix inverseTransform = transform.Clone(); inverseTransform.Invert(); float minResolutionPage = 100F / 2400F; // Assume 2400 DPI as the base resolution, to get very accurate print. float minResolutionMap = Geometry.TransformDistance(minResolutionPage, inverseTransform); // And draw. mapDisplay.Draw(graphicsTarget, page.mapRectangle, minResolutionMap); graphicsTarget.PopTransform(); graphicsTarget.PopClip(); }
// Update the course void UpdateCourse() { CourseAppearance appearance = controller.GetCourseAppearance(); // Get purple color. short purpleOcadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; controller.GetPurpleColor(out purpleOcadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Place the active course in the layout. activeCourse = new CourseLayout(); activeCourse.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); activeCourse.SetLayerColor(CourseLayer.MainCourse, NormalCourseAppearance.courseOcadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, (purpleOverprint && (extraCourses == null || extraCourses.Count == 0))); CourseFormatter.FormatCourseToLayout(symbolDB, activeCourseView, appearance, activeCourse, CourseLayer.MainCourse); if (showAllControls && !activeCourseDesignator.IsAllControls) { // Create the all controls view. CourseView allControlsView = CourseView.CreateFilteredAllControlsView(eventDB, new CourseDesignator[] { activeCourseDesignator }, allControlsFilter, new CourseViewOptions() { showNonDescriptionSpecials = false, showDescriptionSpecials = false }); // Add it to the CourseLayout. activeCourse.SetLayerColor(CourseLayer.AllControls, NormalCourseAppearance.allControlsOcadId, NormalCourseAppearance.allControlsColorName, NormalCourseAppearance.allControlsColorC, NormalCourseAppearance.allControlsColorM, NormalCourseAppearance.allControlsColorY, NormalCourseAppearance.allControlsColorK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, allControlsView, appearance, activeCourse, CourseLayer.AllControls); } if (extraCourses != null && extraCourses.Count > 0) { for (int i = 0; i < extraCourses.Count; ++i) { Id<Course> courseId = extraCourses[i]; if (eventDB.IsCoursePresent(courseId)) { AddExtraCourseToLayout(activeCourse, courseId, i % CourseLayout.EXTRACOURSECOUNT); } } } }
// extraCourseIndex indicates the color/layer. private void AddExtraCourseToLayout(CourseLayout courseLayout, Id<Course> courseId, int extraCourseIndex) { if (extraCourseIndex >= CourseLayout.EXTRACOURSECOUNT) return; CourseAppearance appearance = controller.GetCourseAppearance(); CourseLayer layer = CourseLayer.OtherCourse1 + extraCourseIndex; // Create the course view. CourseView courseView = CourseView.CreateCourseView(eventDB, new CourseDesignator(courseId), new CourseViewOptions() { showNonDescriptionSpecials = false, showDescriptionSpecials = false, showControlNumbers = false }); // Add it to the CourseLayout. courseLayout.SetLayerColor(layer, (short) (NormalCourseAppearance.extraCourseOcadId + extraCourseIndex), string.Format(NormalCourseAppearance.allControlsColorName, extraCourseIndex + 1), NormalCourseAppearance.extraCourseC[extraCourseIndex], NormalCourseAppearance.extraCourseM[extraCourseIndex], NormalCourseAppearance.extraCourseY[extraCourseIndex], NormalCourseAppearance.extraCourseK[extraCourseIndex], false); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, courseLayout, layer, new CourseFormatterOptions() { showControlNumbers = false }); }
// Get the area of the map we want to print, in map coordinates, and the print scale. // if the courseId is None, do all controls. // If asked for, crop to a single page size. RectangleF GetPrintAreaForCourse(CourseDesignator courseDesignator, out bool landscape, out PaperSize paperSize, out int margins, out float scaleRatio, out string description) { // Get the course view to get the scale ratio. CourseView courseView = CourseView.CreatePositioningCourseView(eventDB, courseDesignator); scaleRatio = courseView.ScaleRatio; description = courseView.CourseFullName; RectangleF printRectangle = controller.GetCurrentPrintAreaRectangle(courseDesignator); PrintArea printArea = controller.GetCurrentPrintArea(courseDesignator); landscape = printArea.pageLandscape; paperSize = new PaperSize("", printArea.pageWidth, printArea.pageHeight); margins = printArea.pageMargins; if (cropLargePrintArea) { // Crop the print area to a single page, portrait or landscape. // Try to keep CourseObjects in view as much as possible. CourseLayout layout = new CourseLayout(); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, 0); RectangleF courseObjectsArea = layout.BoundingRect(); courseObjectsArea.Intersect(printRectangle); // We may need to crop the print area to fit. float areaCovered; RectangleF printableArea = GetPrintablePageArea(landscape, paperSize, margins); RectangleF croppedRectangle = CropPrintArea(printRectangle, courseObjectsArea, GetScaledPrintableSizeInMapUnits(printableArea, scaleRatio), out areaCovered); return(croppedRectangle); } else { return(printRectangle); } }
// Write a map to the given file name. void ExportMap(CourseView courseView, string outputFilename) { // Create the CourseLayout. CourseLayout courseLayout = CreateCourseLayout(courseView); // OCAD 6-10 cannot handle images in the layout layer, and OOM doesn't have a layout layer. CourseLayout.MapRenderOptions mapRenderOptions = new CourseLayout.MapRenderOptions(); if ((creationSettings.fileFormat.kind == MapFileFormatKind.OCAD && creationSettings.fileFormat.version <= 10) || creationSettings.fileFormat.kind == MapFileFormatKind.OpenMapper) { mapRenderOptions.RenderImagesAsTemplates = true; } else { mapRenderOptions.RenderImagesAsTemplates = false; } // Create the map and write it out. Map map = courseLayout.RenderToMap(mapRenderOptions); using (map.Write()) { map.MapScale = courseView.MapScale; map.PrintScale = courseView.PrintScale; map.PrintArea = controller.GetCurrentPrintAreaRectangle(courseView.CourseDesignator); switch (controller.MapType) { case MapType.OCAD: // Set OCAD map as template. // OCAD 6 doesn't support another OCAD file as a template. if (!(creationSettings.fileFormat.kind == MapFileFormatKind.OCAD && creationSettings.fileFormat.version <= 6)) { AddTemplateToMap(map, new TemplateInfo(controller.MapFileName, new PointF(0, 0), 0, 0, true)); } // Use same real world coordinates as underlying map (nicer, but also works around bug in OCAD 11 // where background maps with real world coordinates aren't displayed if the map map doesn't have same real // world coordinates). map.RealWorldCoords = controller.MapRealWorldCoords; break; case MapType.Bitmap: case MapType.PDF: // Set bitmap as template. PointF centerPoint = Geometry.RectCenter(controller.MapDisplay.MapBounds); ImageFormat imageFormat; string mapFileName; float dpi; if (CreateBitmapFile()) { // Write a copy of the bitmap map. mapFileName = CreateBitmapFileName(out imageFormat); controller.MapDisplay.WriteBitmapMap(mapFileName, imageFormat, out dpi); } else { // Use existing map file. mapFileName = controller.MapFileName; dpi = controller.MapDpi; } AddTemplateToMap(map, new TemplateInfo(mapFileName, centerPoint, dpi, 0, true)); break; case MapType.None: break; default: Debug.Fail("Unexpected map type"); break; } } WriteImageBitmaps(map); InputOutput.WriteFile(outputFilename, map, creationSettings.fileFormat); }
// The core printing routine. The origin of the graphics is the upper-left of the margins, // and the printArea in the size to draw into (in hundreths of an inch). protected override void DrawPage(IGraphicsTarget graphicsTarget, int pageNumber, SizeF printArea, float dpi) { CoursePage page = pages[pageNumber]; // Get the course view for the course we are printing. CourseView courseView = CourseView.CreatePrintingCourseView(eventDB, page.courseDesignator); // Get the correct purple color to print the course in. short ocadId; float purpleC, purpleM, purpleY, purpleK; bool purpleOverprint; FindPurple.GetPurpleColor(mapDisplay, appearance, out ocadId, out purpleC, out purpleM, out purpleY, out purpleK, out purpleOverprint); // Create a course layout from the view. CourseLayout layout = new CourseLayout(); layout.SetLayerColor(CourseLayer.Descriptions, NormalCourseAppearance.blackColorOcadId, NormalCourseAppearance.blackColorName, NormalCourseAppearance.blackColorC, NormalCourseAppearance.blackColorM, NormalCourseAppearance.blackColorY, NormalCourseAppearance.blackColorK, false); layout.SetLayerColor(CourseLayer.MainCourse, ocadId, NormalCourseAppearance.courseColorName, purpleC, purpleM, purpleY, purpleK, purpleOverprint); CourseFormatter.FormatCourseToLayout(symbolDB, courseView, appearance, layout, CourseLayer.MainCourse); // Set the course layout into the map display mapDisplay.SetCourse(layout); this.mapDisplay.SetPrintArea(null); // Collecting garbage should make out of memory less common. GC.Collect(); if (graphicsTarget is GDIPlus_GraphicsTarget) { // We print to intermediate bands of bitmaps. This is the only way to get purple blending correct. // Other code ensure that if purple blending is on, we always take this code path. GDIPlus_GraphicsTarget gdiGraphicsTarget = ((GDIPlus_GraphicsTarget)graphicsTarget); Graphics g = gdiGraphicsTarget.Graphics; // Save and restore state so we can mess with stuff. GraphicsState graphicsState = g.Save(); // Printing via a bitmap. Works best with some print drivers. dpi = AdjustDpi(dpi); const long MAX_PIXELS_PER_BAND = 20000000; // 20M pixels = 60M bytes (3 bytes per pixel). List <CoursePage> bands = BandPageToLimitBitmapSize(page, dpi, MAX_PIXELS_PER_BAND); // Create the bitmap. Can do this once because each band is the same size. int bitmapWidth = (int)Math.Round(bands[0].printRectangle.Width * dpi / 100F); int bitmapHeight = (int)Math.Round(bands[0].printRectangle.Height * dpi / 100F); Bitmap bitmap = new Bitmap(bitmapWidth, bitmapHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); foreach (CoursePage band in bands) { // Set the transform Matrix transform = Geometry.CreateInvertedRectangleTransform(band.mapRectangle, new RectangleF(0, 0, bitmapWidth, bitmapHeight)); mapDisplay.Draw(bitmap, transform); try { // Draw the bitmap on the printer. g.DrawImage(bitmap, band.printRectangle); } catch (Exception) { } } // restore state. g.Restore(graphicsState); bitmap.Dispose(); } else { // Print directly. Used only when prerasterization is off. // Set the transform, and the clip. Matrix transform = Geometry.CreateInvertedRectangleTransform(page.mapRectangle, page.printRectangle); PushRectangleClip(graphicsTarget, page.printRectangle); graphicsTarget.PushTransform(transform); // Determine the resolution in map coordinates. Matrix inverseTransform = transform.Clone(); inverseTransform.Invert(); float minResolutionPage = 100F / dpi; float minResolutionMap = Geometry.TransformDistance(minResolutionPage, inverseTransform); // And draw. mapDisplay.Draw(graphicsTarget, page.mapRectangle, minResolutionMap); graphicsTarget.PopTransform(); graphicsTarget.PopClip(); } }