Beispiel #1
0
        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;
                }
            }
        }
Beispiel #2
0
        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 ();
        }
Beispiel #4
0
        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();
            }
        }
Beispiel #5
0
        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;
            }
        }
Beispiel #6
0
        public static Rectangle Intersect(Rectangle r1, Rectangle r2)
        {
            Rectangle r;
            if (!r1.Intersect (r2, out r))
                return new Rectangle ();

            return r;
        }
Beispiel #7
0
        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;
                }
            }
        }
Beispiel #8
0
        /// <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 ();

            }
        }
Beispiel #11
0
        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;
            }
        }
Beispiel #12
0
        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 ();
                }
            }
        }
Beispiel #13
0
        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;
		}
Beispiel #15
0
        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);
                }
            }
        }
Beispiel #16
0
        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;
            }
        }
Beispiel #18
0
        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;
        }
Beispiel #19
0
        /// <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;
        }