private unsafe void RenderOneToOne(Cairo.ImageSurface src, Cairo.ImageSurface dst, Gdk.Point offset, bool checker) { Gdk.Rectangle srcRect = new Gdk.Rectangle(offset, dst.GetBounds().Size); srcRect.Intersect(src.GetBounds()); ColorBgra *src_ptr = (ColorBgra *)src.DataPtr; ColorBgra *dst_ptr = (ColorBgra *)dst.DataPtr; int src_width = src.Width; int dst_width = dst.Width; int dst_height = dst.Height; for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow) { ColorBgra *dstRowPtr = dst.GetRowAddressUnchecked(dst_ptr, dst_width, dstRow); ColorBgra *srcRowPtr = src.GetPointAddressUnchecked(src_ptr, src_width, offset.X, dstRow + offset.Y); int dstCol = offset.X; int dstColEnd = offset.X + srcRect.Width; int checkerY = dstRow + offset.Y; while (dstCol < dstColEnd) { // Blend it over the checkerboard background if (checker) { int b = srcRowPtr->B; int g = srcRowPtr->G; int r = srcRowPtr->R; int a = srcRowPtr->A; int v = (((dstCol ^ checkerY) & 8) << 3) + 191; a = a + (a >> 7); int vmia = v * (256 - a); r = ((r * a) + vmia) >> 8; g = ((g * a) + vmia) >> 8; b = ((b * a) + vmia) >> 8; dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24); } else { *dstRowPtr = *srcRowPtr; } ++dstRowPtr; ++srcRowPtr; ++dstCol; } } }
void SetSamplePoint(Gdk.Point p) { region.X = p.X; region.Y = p.Y; region.Width = 2 * radius; region.Height = 2 * radius; if (view.Pixbuf != null) { region.Offset(-Math.Min(region.X, Math.Max(region.Right - view.Pixbuf.Width, radius)), -Math.Min(region.Y, Math.Max(region.Bottom - view.Pixbuf.Height, radius))); region.Intersect(new Gdk.Rectangle(0, 0, view.Pixbuf.Width, view.Pixbuf.Height)); } UpdateSample(); }
private void DrawSelection(Rectangle expose_area) { if ( ! isRectSelection) return; Gdk.Rectangle region; if ( ! expose_area.Intersect (rect_select, out region)) return; // draw selection using (Cairo.Context cairo_g = CairoHelper.Create (BinWindow)) { Gdk.Color color = Style.Background(StateType.Selected); cairo_g.Color = new Cairo.Color (color.Red/65535.0, color.Green/65535.0, color.Blue/65535.0, 0.5); cairo_g.Rectangle (region.X, region.Y, region.Width, region.Height); cairo_g.Fill (); } //((IDisposable) cairo_g.Target).Dispose (); //((IDisposable) cairo_g).Dispose (); }
public unsafe static void ExponentialBlur(this DockySurface self, int radius, Gdk.Rectangle area) { if (radius < 1) { return; } area.Intersect(new Gdk.Rectangle(0, 0, self.Width, self.Height)); int alpha = (int)((1 << AlphaPrecision) * (1.0 - Math.Exp(-2.3 / (radius + 1.0)))); int height = self.Height; int width = self.Width; ImageSurface original; bool owned; if (self.Internal is ImageSurface) { original = self.Internal as ImageSurface; owned = true; } else { original = new ImageSurface(Format.Argb32, width, height); owned = false; } if (!owned) { using (Cairo.Context cr = new Cairo.Context(original)) { cr.Operator = Operator.Source; cr.SetSource(self.Internal); cr.Paint(); (cr.Target as IDisposable).Dispose(); } } byte *pixels = (byte *)original.DataPtr; // Process Rows Thread th = new Thread((ThreadStart) delegate { ExponentialBlurRows(pixels, width, height, 0, height / 2, area.X, area.Right, alpha); }); th.Start(); ExponentialBlurRows(pixels, width, height, height / 2, height, area.X, area.Right, alpha); th.Join(); // Process Columns th = new Thread((ThreadStart) delegate { ExponentialBlurColumns(pixels, width, height, 0, width / 2, area.Y, area.Bottom, alpha); }); th.Start(); ExponentialBlurColumns(pixels, width, height, width / 2, width, area.Y, area.Bottom, alpha); th.Join(); original.MarkDirty(); if (!owned) { self.Context.Operator = Operator.Source; self.Context.SetSource(original); self.Context.Paint(); self.Context.Operator = Operator.Over; (original as IDisposable).Dispose(); original.Destroy(); } }
private unsafe void RenderOneToOne(List<Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset) { // The first layer should be blended with the transparent checkerboard var checker = true; CheckerBoardOperation checker_op = null; for (int i = 0; i < layers.Count; i++) { var layer = layers[i]; // If we're in LivePreview, substitute current layer with the preview layer if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled) layer = CreateLivePreviewLayer (layer); // If the layer is offset, handle it here if (!layer.Transform.IsIdentity ()) layer = CreateOffsetLayer (layer); var src = layer.Surface; // Get the blend mode for this layer and opacity var blend_op = UserBlendOps.GetBlendOp (layer.BlendMode, layer.Opacity); if (checker) checker_op = new CheckerBoardOperation (layer.Opacity); // Figure out where our source and destination intersect var srcRect = new Gdk.Rectangle (offset, dst.GetBounds ().Size); srcRect.Intersect (src.GetBounds ()); // Get pointers to our surfaces var src_ptr = (ColorBgra*)src.DataPtr; var dst_ptr = (ColorBgra*)dst.DataPtr; // Cache widths int src_width = src.Width; int dst_width = dst.Width; for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow) { ColorBgra* dstRowPtr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, dstRow); ColorBgra* srcRowPtr = src.GetPointAddressUnchecked (src_ptr, src_width, offset.X, dstRow + offset.Y); int dstCol = offset.X; int dstColEnd = offset.X + srcRect.Width; int checkerY = dstRow + offset.Y; while (dstCol < dstColEnd) { // Blend it over the checkerboard background if (checker) *dstRowPtr = checker_op.Apply (*srcRowPtr, dstCol, checkerY); else *dstRowPtr = blend_op.Apply (*dstRowPtr, *srcRowPtr); ++dstRowPtr; ++srcRowPtr; ++dstCol; } } // Only checker the first layer checker = false; } }
public static Rectangle Intersect(Rectangle r1, Rectangle r2) { Rectangle r; if (!r1.Intersect (r2, out r)) return new Rectangle (); return r; }
private unsafe void RenderOneToOne(Cairo.ImageSurface src, Cairo.ImageSurface dst, Gdk.Point offset, bool checker) { Gdk.Rectangle srcRect = new Gdk.Rectangle (offset, dst.GetBounds ().Size); srcRect.Intersect (src.GetBounds ()); ColorBgra* src_ptr = (ColorBgra*)src.DataPtr; ColorBgra* dst_ptr = (ColorBgra*)dst.DataPtr; int src_width = src.Width; int dst_width = dst.Width; int dst_height = dst.Height; for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow) { ColorBgra* dstRowPtr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, dstRow); ColorBgra* srcRowPtr = src.GetPointAddressUnchecked (src_ptr, src_width, offset.X, dstRow + offset.Y); int dstCol = offset.X; int dstColEnd = offset.X + srcRect.Width; int checkerY = dstRow + offset.Y; while (dstCol < dstColEnd) { // Blend it over the checkerboard background if (checker) { int b = srcRowPtr->B; int g = srcRowPtr->G; int r = srcRowPtr->R; int a = srcRowPtr->A; int v = (((dstCol ^ checkerY) & 8) << 3) + 191; a = a + (a >> 7); int vmia = v * (256 - a); r = ((r * a) + vmia) >> 8; g = ((g * a) + vmia) >> 8; b = ((b * a) + vmia) >> 8; dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24); } else { *dstRowPtr = *srcRowPtr; } ++dstRowPtr; ++srcRowPtr; ++dstCol; } } }
/// <summary> /// This method is used to render a sprite viewport onto a /// drawable object, such as Gdk.Pixmap. This handles the /// translation of widget space into sprite space and also the /// appropriate clipping. /// </summary> public void Render( Drawable drawable, Rectangle region) { // Create the GC GC gc = new GC(drawable); // Figure out what parts of the rectangle we care about Rectangle ourselves = new Rectangle(x, y, width, height); if (!ourselves.IntersectsWith(region)) { // No overlap, don't bother return; } // Get the intersection of ourselves and the update // region. This helps with keeping to a specific focus. ourselves.Intersect(region); // Clear everything gc.RgbFgColor = BackgroundColor; drawable.DrawRectangle(gc, true, ourselves); // Go through the sprites foreach (ISprite sprite in SpriteList) { sprite.Render(drawable, gc); } }
// FIXME Cache the GCs? protected virtual void DrawPhoto(int cell_num, Rectangle cell_area, Rectangle expose_area, bool selected, bool focussed) { if (!cell_area.Intersect (expose_area, out expose_area)) return; IPhoto photo = Collection [cell_num]; FSpot.PixbufCache.CacheEntry entry = Cache.Lookup (photo.DefaultVersion.Uri); if (entry == null) Cache.Request (photo.DefaultVersion.Uri, cell_num, ThumbnailWidth, ThumbnailHeight); else entry.Data = cell_num; StateType cell_state = selected ? (HasFocus ? StateType.Selected : StateType.Active) : State; if (cell_state != State) Style.PaintBox (Style, BinWindow, cell_state, ShadowType.Out, expose_area, this, "IconView", cell_area.X, cell_area.Y, cell_area.Width - 1, cell_area.Height - 1); Gdk.Rectangle focus = Gdk.Rectangle.Inflate (cell_area, -3, -3); if (HasFocus && focussed) { Style.PaintFocus(Style, BinWindow, cell_state, expose_area, this, null, focus.X, focus.Y, focus.Width, focus.Height); } Gdk.Rectangle region = Gdk.Rectangle.Zero; Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate (cell_area, -CELL_BORDER_WIDTH, -CELL_BORDER_WIDTH); int expansion = ThrobExpansion (cell_num, selected); Gdk.Pixbuf thumbnail = null; if (entry != null) thumbnail = entry.ShallowCopyPixbuf (); Gdk.Rectangle draw = Gdk.Rectangle.Zero; if (Gdk.Rectangle.Inflate (image_bounds, expansion + 1, expansion + 1).Intersect (expose_area, out image_bounds) && thumbnail != null) { PixbufUtils.Fit (thumbnail, ThumbnailWidth, ThumbnailHeight, true, out region.Width, out region.Height); region.X = (int) (cell_area.X + (cell_area.Width - region.Width) / 2); region.Y = (int) cell_area.Y + ThumbnailHeight - region.Height + CELL_BORDER_WIDTH; if (Math.Abs (region.Width - thumbnail.Width) > 1 && Math.Abs (region.Height - thumbnail.Height) > 1) Cache.Reload (entry, cell_num, thumbnail.Width, thumbnail.Height); region = Gdk.Rectangle.Inflate (region, expansion, expansion); Pixbuf temp_thumbnail; region.Width = System.Math.Max (1, region.Width); region.Height = System.Math.Max (1, region.Height); if (Math.Abs (region.Width - thumbnail.Width) > 1 && Math.Abs (region.Height - thumbnail.Height) > 1) { if (region.Width < thumbnail.Width && region.Height < thumbnail.Height) { /* temp_thumbnail = PixbufUtils.ScaleDown (thumbnail, region.Width, region.Height); */ temp_thumbnail = thumbnail.ScaleSimple (region.Width, region.Height, InterpType.Bilinear); lock (entry) { if (entry.Reload && expansion == 0 && !entry.IsDisposed) { entry.SetPixbufExtended (temp_thumbnail.ShallowCopy (), false); entry.Reload = true; } } } else { temp_thumbnail = thumbnail.ScaleSimple (region.Width, region.Height, InterpType.Bilinear); } } else temp_thumbnail = thumbnail; // FIXME There seems to be a rounding issue between the // scaled thumbnail sizes, we avoid this for now by using // the actual thumnail sizes here. region.Width = temp_thumbnail.Width; region.Height = temp_thumbnail.Height; draw = Gdk.Rectangle.Inflate (region, 1, 1); if (!temp_thumbnail.HasAlpha) Style.PaintShadow (Style, BinWindow, cell_state, ShadowType.Out, expose_area, this, "IconView", draw.X, draw.Y, draw.Width, draw.Height); if (region.Intersect (expose_area, out draw)) { Cms.Profile screen_profile; if (FSpot.ColorManagement.Profiles.TryGetValue (Preferences.Get<string> (Preferences.COLOR_MANAGEMENT_DISPLAY_PROFILE), out screen_profile)) { Pixbuf t = temp_thumbnail.Copy (); temp_thumbnail.Dispose (); temp_thumbnail = t; FSpot.ColorManagement.ApplyProfile (temp_thumbnail, screen_profile); } temp_thumbnail.RenderToDrawable (BinWindow, Style.WhiteGC, draw.X - region.X, draw.Y - region.Y, draw.X, draw.Y, draw.Width, draw.Height, RgbDither.None, draw.X, draw.Y); } if (temp_thumbnail != thumbnail) { temp_thumbnail.Dispose (); } } if (thumbnail != null) { thumbnail.Dispose (); } // Render Decorations if (DisplayRatings && region.X == draw.X && region.X != 0) { rating_renderer.Render (BinWindow, this, region, expose_area, cell_state, photo); } // Render Captions Rectangle caption_area = Rectangle.Zero; caption_area.Y = cell_area.Y + CELL_BORDER_WIDTH + ThumbnailHeight + CAPTION_PADDING; caption_area.X = cell_area.X + CELL_BORDER_WIDTH; caption_area.Width = cell_area.Width - 2 * CELL_BORDER_WIDTH; if (DisplayDates) { caption_area.Height = date_renderer.GetHeight (this, ThumbnailWidth); date_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } if (DisplayFilenames) { caption_area.Height = filename_renderer.GetHeight (this, ThumbnailWidth); filename_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } if (DisplayTags) { caption_area.Height = tag_renderer.GetHeight (this, ThumbnailWidth); tag_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } }
void DrawSelection(Rectangle exposeArea) { if (!isRectSelection) return; Rectangle region; if (!exposeArea.Intersect (rect_select, out region)) return; // draw selection using (Cairo.Context cairo_g = CairoHelper.Create (BinWindow)) { Color color = Style.Background (StateType.Selected); cairo_g.SetSourceColor (new Cairo.Color (color.Red / 65535.0, color.Green / 65535.0, color.Blue / 65535.0, 0.5)); cairo_g.Rectangle (region.X, region.Y, region.Width, region.Height); cairo_g.Fill (); } }
private unsafe void RenderOneToOne(List <Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset) { // The first layer should be blended with the transparent checkerboard var checker = true; CheckerBoardOperation checker_op = null; for (int i = 0; i < layers.Count; i++) { var layer = layers[i]; // If we're in LivePreview, substitute current layer with the preview layer if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled) { layer = CreateLivePreviewLayer(layer); } // If the layer is offset, handle it here if (!layer.Offset.IsEmpty()) { layer = CreateOffsetLayer(layer); } var src = layer.Surface; // Get the blend mode for this layer and opacity var blend_op = UserBlendOps.GetBlendOp(layer.BlendMode, layer.Opacity); if (checker) { checker_op = new CheckerBoardOperation(layer.Opacity); } // Figure out where our source and destination intersect var srcRect = new Gdk.Rectangle(offset, dst.GetBounds().Size); srcRect.Intersect(src.GetBounds()); // Get pointers to our surfaces var src_ptr = (ColorBgra *)src.DataPtr; var dst_ptr = (ColorBgra *)dst.DataPtr; // Cache widths int src_width = src.Width; int dst_width = dst.Width; for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow) { ColorBgra *dstRowPtr = dst.GetRowAddressUnchecked(dst_ptr, dst_width, dstRow); ColorBgra *srcRowPtr = src.GetPointAddressUnchecked(src_ptr, src_width, offset.X, dstRow + offset.Y); int dstCol = offset.X; int dstColEnd = offset.X + srcRect.Width; int checkerY = dstRow + offset.Y; while (dstCol < dstColEnd) { // Blend it over the checkerboard background if (checker) { *dstRowPtr = checker_op.Apply(*srcRowPtr, dstCol, checkerY); } else { *dstRowPtr = blend_op.Apply(*dstRowPtr, *srcRowPtr); } ++dstRowPtr; ++srcRowPtr; ++dstCol; } } // Only checker the first layer checker = false; } }
private void OnDrawingarea1ExposeEvent(object o, Gtk.ExposeEventArgs args) { double scale = PintaCore.Workspace.Scale; int x = (int)PintaCore.Workspace.Offset.X; int y = (int)PintaCore.Workspace.Offset.Y; // Translate our expose area for the whole drawingarea to just our canvas Rectangle canvas_bounds = new Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height); canvas_bounds.Intersect (args.Event.Area); if (canvas_bounds.IsEmpty) return; canvas_bounds.X -= x; canvas_bounds.Y -= y; // Resize our offscreen surface to a surface the size of our drawing area if (canvas == null || canvas.Width != canvas_bounds.Width || canvas.Height != canvas_bounds.Height) { if (canvas != null) (canvas as IDisposable).Dispose (); canvas = new Cairo.ImageSurface (Cairo.Format.Argb32, canvas_bounds.Width, canvas_bounds.Height); } cr.Initialize (PintaCore.Workspace.ImageSize, PintaCore.Workspace.CanvasSize); using (Cairo.Context g = CairoHelper.Create (drawingarea1.GdkWindow)) { // Draw our 1 px black border g.DrawRectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width + 1, PintaCore.Workspace.CanvasSize.Height + 1), new Cairo.Color (0, 0, 0), 1); // Set up our clip rectangle g.Rectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height)); g.Clip (); g.Translate (x, y); bool checker = true; // Resize each layer and paint it to the screen foreach (Layer layer in PintaCore.Layers.GetLayersToPaint ()) { cr.Render (layer.Surface, canvas, canvas_bounds.Location, checker); g.SetSourceSurface (canvas, canvas_bounds.X, canvas_bounds.Y); g.PaintWithAlpha (layer.Opacity); if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled) { cr.Render (PintaCore.LivePreview.LivePreviewSurface, canvas, canvas_bounds.Location, checker); g.Save (); g.Scale (scale, scale); g.AppendPath (PintaCore.Layers.SelectionPath); g.Clip (); g.Scale (1 / scale, 1 / scale); g.SetSourceSurface (canvas, canvas_bounds.X, canvas_bounds.Y); g.PaintWithAlpha (layer.Opacity); g.Restore (); } checker = false; } if (PintaCore.Actions.View.PixelGrid.Active) { gr.Render (canvas, canvas_bounds.Location); g.SetSourceSurface (canvas, canvas_bounds.X, canvas_bounds.Y); g.Paint (); } // Selection outline if (PintaCore.Layers.ShowSelection) { g.Save (); g.Translate (0.5, 0.5); g.Scale (scale, scale); g.AppendPath (PintaCore.Layers.SelectionPath); if (PintaCore.Tools.CurrentTool.Name.Contains ("Select") && !PintaCore.Tools.CurrentTool.Name.Contains ("Selected")) { g.Color = new Cairo.Color (0.7, 0.8, 0.9, 0.2); g.FillRule = Cairo.FillRule.EvenOdd; g.FillPreserve (); } g.SetDash (new double[] { 2 / scale, 4 / scale }, 0); g.LineWidth = 1 / scale; g.Color = new Cairo.Color (0, 0, 0); g.Stroke (); g.Restore (); } } }
protected override bool OnExposeEvent(EventExpose e) { base.OnExposeEvent (e); if (!PintaCore.Workspace.HasOpenDocuments) return true; double scale = PintaCore.Workspace.Scale; int x = (int)PintaCore.Workspace.Offset.X; int y = (int)PintaCore.Workspace.Offset.Y; // Translate our expose area for the whole drawingarea to just our canvas Rectangle canvas_bounds = new Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height); canvas_bounds.Intersect (e.Area); if (canvas_bounds.IsEmpty) return true; canvas_bounds.X -= x; canvas_bounds.Y -= y; // Resize our offscreen surface to a surface the size of our drawing area if (canvas == null || canvas.Width != canvas_bounds.Width || canvas.Height != canvas_bounds.Height) { if (canvas != null) (canvas as IDisposable).Dispose (); canvas = new Cairo.ImageSurface (Cairo.Format.Argb32, canvas_bounds.Width, canvas_bounds.Height); } cr.Initialize (PintaCore.Workspace.ImageSize, PintaCore.Workspace.CanvasSize); using (Cairo.Context g = CairoHelper.Create (GdkWindow)) { // Draw our canvas drop shadow g.DrawRectangle (new Cairo.Rectangle (x - 1, y - 1, PintaCore.Workspace.CanvasSize.Width + 2, PintaCore.Workspace.CanvasSize.Height + 2), new Cairo.Color (.5, .5, .5), 1); g.DrawRectangle (new Cairo.Rectangle (x - 2, y - 2, PintaCore.Workspace.CanvasSize.Width + 4, PintaCore.Workspace.CanvasSize.Height + 4), new Cairo.Color (.8, .8, .8), 1); g.DrawRectangle (new Cairo.Rectangle (x - 3, y - 3, PintaCore.Workspace.CanvasSize.Width + 6, PintaCore.Workspace.CanvasSize.Height + 6), new Cairo.Color (.9, .9, .9), 1); // Set up our clip rectangle g.Rectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height)); g.Clip (); g.Translate (x, y); // Render all the layers to a surface var layers = PintaCore.Layers.GetLayersToPaint (); if (layers.Count == 0) { canvas.Clear (); } cr.Render (layers, canvas, canvas_bounds.Location); // Paint the surface to our canvas g.SetSourceSurface (canvas, canvas_bounds.X + (int)(0 * scale), canvas_bounds.Y + (int)(0 * scale)); g.Paint (); // Selection outline if (PintaCore.Layers.ShowSelection) { bool fillSelection = PintaCore.Tools.CurrentTool.Name.Contains ("Select") && !PintaCore.Tools.CurrentTool.Name.Contains ("Selected"); PintaCore.Workspace.ActiveDocument.Selection.Draw (g, scale, fillSelection); } } return true; }
private Pixbuf GetScaled (Pixbuf orig) { Gdk.Rectangle pos; int width = Allocation.Width; int height = Allocation.Height; double scale = PixbufUtils.Fit (orig, width, height, false, out pos.Width, out pos.Height); pos.X = (width - pos.Width) / 2; pos.Y = (height - pos.Height) / 2; Pixbuf scaled = new Pixbuf (Colorspace.Rgb, false, 8, width, height); scaled.Fill (0x000000); Rectangle rect = new Rectangle (pos.X, pos.Y, 256, 256); Rectangle subarea; while (rect.Top < pos.Bottom) { while (rect.X < pos.Right) { if (IsRealized) GdkWindow.ProcessUpdates (false); rect.Intersect (pos, out subarea); orig.Composite (scaled, subarea.X, subarea.Y, subarea.Width, subarea.Height, pos.X, pos.Y, scale, scale, Gdk.InterpType.Bilinear, 255); rect.X += rect.Width; } rect.X = pos.X; rect.Y += rect.Height; } orig.Dispose (); return scaled; }
void PaintRectangle(Rectangle area, InterpType interpolation) { int x_offset = scaled_width < Allocation.Width ? (int)(Allocation.Width - scaled_width) / 2 : -XOffset; int y_offset = scaled_height < Allocation.Height ? (int)(Allocation.Height - scaled_height) / 2 : -YOffset; //Draw background if (y_offset > 0) //Top PaintBackground (new Rectangle (0, 0, Allocation.Width, y_offset), area); if (x_offset > 0) //Left PaintBackground (new Rectangle (0, y_offset, x_offset, (int)scaled_height), area); if (x_offset >= 0) //Right PaintBackground (new Rectangle (x_offset + (int)scaled_width, y_offset, Allocation.Width - x_offset - (int)scaled_width, (int)scaled_height), area); if (y_offset >= 0) //Bottom PaintBackground (new Rectangle (0, y_offset + (int)scaled_height, Allocation.Width, Allocation.Height - y_offset - (int)scaled_height), area); if (Pixbuf == null) return; area.Intersect (new Rectangle (x_offset, y_offset, (int)scaled_width, (int)scaled_height)); if (area.Width <= 0 || area.Height <= 0) return; //Short circuit for 1:1 zoom if (zoom == 1.0 && !Pixbuf.HasAlpha && Pixbuf.BitsPerSample == 8 && pixbuf_orientation == ImageOrientation.TopLeft) { GdkWindow.DrawPixbuf (Style.BlackGC, Pixbuf, area.X - x_offset, area.Y - y_offset, area.X, area.Y, area.Width, area.Height, RgbDither.Max, area.X - x_offset, area.Y - y_offset); return; } Rectangle pixbuf_area = PixbufUtils.TransformOrientation ((int)scaled_width, (int)scaled_height, new Rectangle ((area.X - x_offset), (area.Y - y_offset), area.Width, area.Height), PixbufUtils.ReverseTransformation (pixbuf_orientation)); using (Pixbuf temp_pixbuf = new Pixbuf (Colorspace.Rgb, false, 8, pixbuf_area.Width, pixbuf_area.Height)) { if (Pixbuf.HasAlpha) temp_pixbuf.Fill (0x00000000); Pixbuf.CompositeColor (temp_pixbuf, 0, 0, pixbuf_area.Width, pixbuf_area.Height, -pixbuf_area.X, -pixbuf_area.Y, zoom, zoom, zoom == 1.0 ? InterpType.Nearest : interpolation, 255, pixbuf_area.X, pixbuf_area.Y, CheckPattern.CheckSize, CheckPattern.Color1, CheckPattern.Color2); ApplyColorTransform (temp_pixbuf); using (var dest_pixbuf = PixbufUtils.TransformOrientation (temp_pixbuf, pixbuf_orientation)) { GdkWindow.DrawPixbuf (Style.BlackGC, dest_pixbuf, 0, 0, area.X, area.Y, area.Width, area.Height, RgbDither.Max, area.X - x_offset, area.Y - y_offset); } } }
protected override bool OnExposeEvent(EventExpose e) { base.OnExposeEvent (e); if (!PintaCore.Workspace.HasOpenDocuments) return true; double scale = PintaCore.Workspace.Scale; int x = (int)PintaCore.Workspace.Offset.X; int y = (int)PintaCore.Workspace.Offset.Y; // Translate our expose area for the whole drawingarea to just our canvas Rectangle canvas_bounds = new Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height); canvas_bounds.Intersect (e.Area); if (canvas_bounds.IsEmpty) return true; canvas_bounds.X -= x; canvas_bounds.Y -= y; // Resize our offscreen surface to a surface the size of our drawing area if (canvas == null || canvas.Width != canvas_bounds.Width || canvas.Height != canvas_bounds.Height) { if (canvas != null) (canvas as IDisposable).Dispose (); canvas = new Cairo.ImageSurface (Cairo.Format.Argb32, canvas_bounds.Width, canvas_bounds.Height); } cr.Initialize (PintaCore.Workspace.ImageSize, PintaCore.Workspace.CanvasSize); using (Cairo.Context g = CairoHelper.Create (GdkWindow)) { // Draw our canvas drop shadow g.DrawRectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width + 1, PintaCore.Workspace.CanvasSize.Height + 1), new Cairo.Color (.5, .5, .5), 1); g.DrawRectangle (new Cairo.Rectangle (x - 1, y - 1, PintaCore.Workspace.CanvasSize.Width + 3, PintaCore.Workspace.CanvasSize.Height + 3), new Cairo.Color (.8, .8, .8), 1); g.DrawRectangle (new Cairo.Rectangle (x - 2, y - 2, PintaCore.Workspace.CanvasSize.Width + 5, PintaCore.Workspace.CanvasSize.Height + 5), new Cairo.Color (.9, .9, .9), 1); // Set up our clip rectangle g.Rectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height)); g.Clip (); g.Translate (x, y); // Render all the layers to a surface var layers = PintaCore.Layers.GetLayersToPaint (); if (layers.Count == 0) { canvas.Clear (); } cr.Render (layers, canvas, canvas_bounds.Location); // Paint the surface to our canvas g.SetSourceSurface (canvas, canvas_bounds.X + (int)(0 * scale), canvas_bounds.Y + (int)(0 * scale)); g.Paint (); // Selection outline if (PintaCore.Layers.ShowSelection) { g.Save (); g.Translate (0.5, 0.5); g.Scale (scale, scale); g.AppendPath (PintaCore.Layers.SelectionPath); if (PintaCore.Tools.CurrentTool.Name.Contains ("Select") && !PintaCore.Tools.CurrentTool.Name.Contains ("Selected")) { g.Color = new Cairo.Color (0.7, 0.8, 0.9, 0.2); g.FillRule = Cairo.FillRule.EvenOdd; g.FillPreserve (); } g.LineWidth = 1 / scale; // Draw a white line first so it shows up on dark backgrounds g.Color = new Cairo.Color (1, 1, 1); g.StrokePreserve (); // Draw a black dashed line over the white line g.SetDash (new double[] { 2 / scale, 4 / scale }, 0); g.Color = new Cairo.Color (0, 0, 0); g.Stroke (); g.Restore (); } } return true; }
// FIXME Cache the GCs? protected virtual void DrawPhoto(int cell_num, Rectangle cell_area, Rectangle expose_area, bool selected, bool focussed) { if (!cell_area.Intersect(expose_area, out expose_area)) { return; } IPhoto photo = Collection [cell_num]; FSpot.PixbufCache.CacheEntry entry = Cache.Lookup(photo.DefaultVersion.Uri); if (entry == null) { Cache.Request(photo.DefaultVersion.Uri, cell_num, ThumbnailWidth, ThumbnailHeight); } else { entry.Data = cell_num; } StateType cell_state = selected ? (HasFocus ? StateType.Selected : StateType.Active) : State; if (cell_state != State) { Style.PaintBox(Style, BinWindow, cell_state, ShadowType.Out, expose_area, this, "IconView", cell_area.X, cell_area.Y, cell_area.Width - 1, cell_area.Height - 1); } Gdk.Rectangle focus = Gdk.Rectangle.Inflate(cell_area, -3, -3); if (HasFocus && focussed) { Style.PaintFocus(Style, BinWindow, cell_state, expose_area, this, null, focus.X, focus.Y, focus.Width, focus.Height); } Gdk.Rectangle region = Gdk.Rectangle.Zero; Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate(cell_area, -CELL_BORDER_WIDTH, -CELL_BORDER_WIDTH); int expansion = ThrobExpansion(cell_num, selected); Gdk.Pixbuf thumbnail = null; if (entry != null) { thumbnail = entry.ShallowCopyPixbuf(); } Gdk.Rectangle draw = Gdk.Rectangle.Zero; if (Gdk.Rectangle.Inflate(image_bounds, expansion + 1, expansion + 1).Intersect(expose_area, out image_bounds) && thumbnail != null) { PixbufUtils.Fit(thumbnail, ThumbnailWidth, ThumbnailHeight, true, out region.Width, out region.Height); region.X = (int)(cell_area.X + (cell_area.Width - region.Width) / 2); region.Y = (int)cell_area.Y + ThumbnailHeight - region.Height + CELL_BORDER_WIDTH; if (Math.Abs(region.Width - thumbnail.Width) > 1 && Math.Abs(region.Height - thumbnail.Height) > 1) { Cache.Reload(entry, cell_num, thumbnail.Width, thumbnail.Height); } region = Gdk.Rectangle.Inflate(region, expansion, expansion); Pixbuf temp_thumbnail; region.Width = System.Math.Max(1, region.Width); region.Height = System.Math.Max(1, region.Height); if (Math.Abs(region.Width - thumbnail.Width) > 1 && Math.Abs(region.Height - thumbnail.Height) > 1) { if (region.Width < thumbnail.Width && region.Height < thumbnail.Height) { /* * temp_thumbnail = PixbufUtils.ScaleDown (thumbnail, * region.Width, region.Height); */ temp_thumbnail = thumbnail.ScaleSimple(region.Width, region.Height, InterpType.Bilinear); lock (entry) { if (entry.Reload && expansion == 0 && !entry.IsDisposed) { entry.SetPixbufExtended(temp_thumbnail.ShallowCopy(), false); entry.Reload = true; } } } else { temp_thumbnail = thumbnail.ScaleSimple(region.Width, region.Height, InterpType.Bilinear); } } else { temp_thumbnail = thumbnail; } // FIXME There seems to be a rounding issue between the // scaled thumbnail sizes, we avoid this for now by using // the actual thumnail sizes here. region.Width = temp_thumbnail.Width; region.Height = temp_thumbnail.Height; draw = Gdk.Rectangle.Inflate(region, 1, 1); if (!temp_thumbnail.HasAlpha) { Style.PaintShadow(Style, BinWindow, cell_state, ShadowType.Out, expose_area, this, "IconView", draw.X, draw.Y, draw.Width, draw.Height); } if (region.Intersect(expose_area, out draw)) { Cms.Profile screen_profile; if (FSpot.ColorManagement.Profiles.TryGetValue(Preferences.Get <string> (Preferences.COLOR_MANAGEMENT_DISPLAY_PROFILE), out screen_profile)) { Pixbuf t = temp_thumbnail.Copy(); temp_thumbnail.Dispose(); temp_thumbnail = t; FSpot.ColorManagement.ApplyProfile(temp_thumbnail, screen_profile); } temp_thumbnail.RenderToDrawable(BinWindow, Style.WhiteGC, draw.X - region.X, draw.Y - region.Y, draw.X, draw.Y, draw.Width, draw.Height, RgbDither.None, draw.X, draw.Y); } if (temp_thumbnail != thumbnail) { temp_thumbnail.Dispose(); } } if (thumbnail != null) { thumbnail.Dispose(); } // Render Decorations if (DisplayRatings && region.X == draw.X && region.X != 0) { rating_renderer.Render(BinWindow, this, region, expose_area, cell_state, photo); } // Render Captions Rectangle caption_area = Rectangle.Zero; caption_area.Y = cell_area.Y + CELL_BORDER_WIDTH + ThumbnailHeight + CAPTION_PADDING; caption_area.X = cell_area.X + CELL_BORDER_WIDTH; caption_area.Width = cell_area.Width - 2 * CELL_BORDER_WIDTH; if (DisplayDates) { caption_area.Height = date_renderer.GetHeight(this, ThumbnailWidth); date_renderer.Render(BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } if (DisplayFilenames) { caption_area.Height = filename_renderer.GetHeight(this, ThumbnailWidth); filename_renderer.Render(BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } if (DisplayTags) { caption_area.Height = tag_renderer.GetHeight(this, ThumbnailWidth); tag_renderer.Render(BinWindow, this, caption_area, expose_area, cell_state, photo); caption_area.Y += caption_area.Height; } }
protected override bool OnExposeEvent(EventExpose e) { base.OnExposeEvent (e); if (!PintaCore.Workspace.HasOpenDocuments) return true; double scale = PintaCore.Workspace.Scale; int x = (int)PintaCore.Workspace.Offset.X; int y = (int)PintaCore.Workspace.Offset.Y; // Translate our expose area for the whole drawingarea to just our canvas Rectangle canvas_bounds = new Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height); canvas_bounds.Intersect (e.Area); if (canvas_bounds.IsEmpty) return true; canvas_bounds.X -= x; canvas_bounds.Y -= y; // Resize our offscreen surface to a surface the size of our drawing area if (canvas == null || canvas.Width != canvas_bounds.Width || canvas.Height != canvas_bounds.Height) { if (canvas != null) (canvas as IDisposable).Dispose (); canvas = new Cairo.ImageSurface (Cairo.Format.Argb32, canvas_bounds.Width, canvas_bounds.Height); } cr.Initialize (PintaCore.Workspace.ImageSize, PintaCore.Workspace.CanvasSize); using (Cairo.Context g = CairoHelper.Create (GdkWindow)) { // Draw our 1 px black border g.DrawRectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width + 1, PintaCore.Workspace.CanvasSize.Height + 1), new Cairo.Color (0, 0, 0), 1); // Set up our clip rectangle g.Rectangle (new Cairo.Rectangle (x, y, PintaCore.Workspace.CanvasSize.Width, PintaCore.Workspace.CanvasSize.Height)); g.Clip (); g.Translate (x, y); bool checker = true; // Resize each layer and paint it to the screen foreach (Layer layer in PintaCore.Layers.GetLayersToPaint ()) { cr.Render (layer.Surface, canvas, canvas_bounds.Location, checker); g.SetSourceSurface (canvas, canvas_bounds.X + (int)(layer.Offset.X * scale), canvas_bounds.Y + (int)(layer.Offset.Y * scale)); g.PaintWithAlpha (layer.Opacity); if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled) { cr.Render (PintaCore.LivePreview.LivePreviewSurface, canvas, canvas_bounds.Location, checker); g.Save (); g.Scale (scale, scale); g.AppendPath (PintaCore.Layers.SelectionPath); g.Clip (); g.Scale (1 / scale, 1 / scale); g.SetSourceSurface (canvas, canvas_bounds.X, canvas_bounds.Y); g.PaintWithAlpha (layer.Opacity); g.Restore (); } checker = false; } // If we are at least 200% and grid is requested, draw it if (PintaCore.Actions.View.PixelGrid.Active && cr.ScaleFactor.Ratio <= 0.5d) { gr.Render (canvas, canvas_bounds.Location); g.SetSourceSurface (canvas, canvas_bounds.X, canvas_bounds.Y); g.Paint (); } // Selection outline if (PintaCore.Layers.ShowSelection) { g.Save (); g.Translate (0.5, 0.5); g.Scale (scale, scale); g.AppendPath (PintaCore.Layers.SelectionPath); if (PintaCore.Tools.CurrentTool.Name.Contains ("Select") && !PintaCore.Tools.CurrentTool.Name.Contains ("Selected")) { g.Color = new Cairo.Color (0.7, 0.8, 0.9, 0.2); g.FillRule = Cairo.FillRule.EvenOdd; g.FillPreserve (); } g.LineWidth = 1 / scale; // Draw a white line first so it shows up on dark backgrounds g.Color = new Cairo.Color (1, 1, 1); g.StrokePreserve (); // Draw a black dashed line over the white line g.SetDash (new double[] { 2 / scale, 4 / scale }, 0); g.Color = new Cairo.Color (0, 0, 0); g.Stroke (); g.Restore (); } } return true; }
/// <summary> /// This retrieves an invalidated area (in widget space) and /// clears the current invalidation. /// </summary> public Rectangle GetInvalidatedRegion() { // Ignore blanks if (invalidated.IsEmpty) { return invalidated; } // Translate to the widget space // Get the intersection Rectangle i = new Rectangle(x, y, width, height); if (!invalidated.IntersectsWith(i)) { invalidated = Rectangle.Zero; return invalidated; } i.Intersect(invalidated); // Clear it invalidated = Rectangle.Zero; return i; }