Browse Source

Better calculations for angled dimensions.

Former-commit-id: 0ef846d654e7234df7766997999fbfa3708e9df9
Former-commit-id: 3921e31a73bb85eab9bfbd8a2a74482af6676fa2
af/merge-core
James South 11 years ago
parent
commit
3be411be6c
  1. 87
      src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs

87
src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs

@ -1,4 +1,4 @@
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// <copyright file="HalftoneFilter.cs" company="James South"> // <copyright file="HalftoneFilter.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
@ -11,6 +11,7 @@
namespace ImageProcessor.Imaging.Filters.Artistic namespace ImageProcessor.Imaging.Filters.Artistic
{ {
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -168,14 +169,22 @@ namespace ImageProcessor.Imaging.Filters.Artistic
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
int minHeight = -height * 2; // Calculate min and max widths/heights.
int maxHeight = height * 2; Rectangle rotatedBounds = this.GetBoundingRectangle(width, height);
int minWidth = -width * 2; int minY = -(rotatedBounds.Height + height);
int maxWidth = width * 2; int maxY = rotatedBounds.Height + height;
int minX = -(rotatedBounds.Width + width);
int maxX = rotatedBounds.Width + width;
Point center = Point.Empty;
// Yellow oversaturates the output.
const float YellowMultiplier = 4;
float multiplier = YellowMultiplier * (float)Math.Sqrt(2);
float multiplier = 4 * (float)Math.Sqrt(2); float max = this.distance;
float max = this.distance + ((float)Math.Sqrt(2) / 2);
float keylineMax = this.distance + (float)Math.Sqrt(2) + ((float)Math.Sqrt(2) / 2); // Bump up the keyline max so that black looks black.
float keylineMax = max + ((float)Math.Sqrt(2) * 1.5f);
// Color sampled process colours from Wikipedia pages. // Color sampled process colours from Wikipedia pages.
// Keyline brush is declared separately. // Keyline brush is declared separately.
@ -223,16 +232,16 @@ namespace ImageProcessor.Imaging.Filters.Artistic
// loop so we have to do it old school. :( // loop so we have to do it old school. :(
using (FastBitmap sourceBitmap = new FastBitmap(source)) using (FastBitmap sourceBitmap = new FastBitmap(source))
{ {
for (int y = minHeight; y < maxHeight; y += d) for (int y = minY; y < maxY; y += d)
{ {
for (int x = minWidth; x < maxWidth; x += d) for (int x = minX; x < maxX; x += d)
{ {
Color color; Color color;
CmykColor cmykColor; CmykColor cmykColor;
float brushWidth; float brushWidth;
// Cyan // Cyan
Point rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.cyanAngle); Point rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.cyanAngle, center);
int angledX = rotatedPoint.X; int angledX = rotatedPoint.X;
int angledY = rotatedPoint.Y; int angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY))) if (rectangle.Contains(new Point(angledX, angledY)))
@ -244,7 +253,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
} }
// Magenta // Magenta
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle); rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle, center);
angledX = rotatedPoint.X; angledX = rotatedPoint.X;
angledY = rotatedPoint.Y; angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY))) if (rectangle.Contains(new Point(angledX, angledY)))
@ -256,19 +265,19 @@ namespace ImageProcessor.Imaging.Filters.Artistic
} }
// Yellow // Yellow
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle); rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle, center);
angledX = rotatedPoint.X; angledX = rotatedPoint.X;
angledY = rotatedPoint.Y; angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY))) if (rectangle.Contains(new Point(angledX, angledY)))
{ {
color = sourceBitmap.GetPixel(angledX, angledY); color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color; cmykColor = color;
brushWidth = ImageMaths.Clamp(d * (cmykColor.Y / 255f) * multiplier, 0, max); brushWidth = ImageMaths.Clamp(d * (cmykColor.Y / 255f) * YellowMultiplier, 0, max);
graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth); graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth);
} }
// Keyline // Keyline
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle); rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle, center);
angledX = rotatedPoint.X; angledX = rotatedPoint.X;
angledY = rotatedPoint.Y; angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY))) if (rectangle.Contains(new Point(angledX, angledY)))
@ -357,16 +366,46 @@ namespace ImageProcessor.Imaging.Filters.Artistic
return source; return source;
} }
private void SetGraphicsSettings(ref Graphics graphics) /// <summary>
/// Gets the bounding rectangle of the image based on the rotating angles.
/// </summary>
/// <param name="width">
/// The width of the image.
/// </param>
/// <param name="height">
/// The height of the image.
/// </param>
/// <returns>
/// The <see cref="Rectangle"/>.
/// </returns>
private Rectangle GetBoundingRectangle(int width, int height)
{ {
// Set the quality properties. int maxWidth = 0;
graphics.SmoothingMode = graphics.SmoothingMode = SmoothingMode.AntiAlias; int maxHeight = 0;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; List<float> angles = new List<float> { this.CyanAngle, this.MagentaAngle, this.YellowAngle, this.KeylineAngle };
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality; foreach (float angle in angles)
{
// Set up the canvas. double radians = ImageMaths.DegreesToRadians(angle);
graphics.Clear(Color.Transparent); double radiansSin = Math.Sin(radians);
double radiansCos = Math.Cos(radians);
double width1 = (height * radiansSin) + (width * radiansCos);
double height1 = (width * radiansSin) + (height * radiansCos);
// Find dimensions in the other direction
radiansSin = Math.Sin(-radians);
radiansCos = Math.Cos(-radians);
double width2 = (height * radiansSin) + (width * radiansCos);
double height2 = (width * radiansSin) + (height * radiansCos);
int maxW = Math.Max(maxWidth, Convert.ToInt32(Math.Max(Math.Abs(width1), Math.Abs(width2))));
int maxH = Math.Max(maxHeight, Convert.ToInt32(Math.Max(Math.Abs(height1), Math.Abs(height2))));
maxHeight = maxH;
maxWidth = maxW;
}
return new Rectangle(0, 0, maxWidth, maxHeight);
} }
} }
} }

Loading…
Cancel
Save