Browse Source

Better calculations for angled dimensions.

Former-commit-id: 91315fcef03905db9be26393ed0cbee1bf49af71
Former-commit-id: 0274204743bd5d8c067774203f74507c2accc57c
af/merge-core
James South 11 years ago
parent
commit
97cf335094
  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 (c) James South.
// Licensed under the Apache License, Version 2.0.
@ -11,6 +11,7 @@
namespace ImageProcessor.Imaging.Filters.Artistic
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
@ -168,14 +169,22 @@ namespace ImageProcessor.Imaging.Filters.Artistic
int width = source.Width;
int height = source.Height;
int minHeight = -height * 2;
int maxHeight = height * 2;
int minWidth = -width * 2;
int maxWidth = width * 2;
// Calculate min and max widths/heights.
Rectangle rotatedBounds = this.GetBoundingRectangle(width, height);
int minY = -(rotatedBounds.Height + height);
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)Math.Sqrt(2) / 2);
float keylineMax = this.distance + (float)Math.Sqrt(2) + ((float)Math.Sqrt(2) / 2);
float max = this.distance;
// 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.
// Keyline brush is declared separately.
@ -223,16 +232,16 @@ namespace ImageProcessor.Imaging.Filters.Artistic
// loop so we have to do it old school. :(
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;
CmykColor cmykColor;
float brushWidth;
// 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 angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
@ -244,7 +253,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
}
// Magenta
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle);
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle, center);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
@ -256,19 +265,19 @@ namespace ImageProcessor.Imaging.Filters.Artistic
}
// Yellow
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle);
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle, center);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
{
color = sourceBitmap.GetPixel(angledX, angledY);
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);
}
// Keyline
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle);
rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle, center);
angledX = rotatedPoint.X;
angledY = rotatedPoint.Y;
if (rectangle.Contains(new Point(angledX, angledY)))
@ -357,16 +366,46 @@ namespace ImageProcessor.Imaging.Filters.Artistic
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.
graphics.SmoothingMode = graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
// Set up the canvas.
graphics.Clear(Color.Transparent);
int maxWidth = 0;
int maxHeight = 0;
List<float> angles = new List<float> { this.CyanAngle, this.MagentaAngle, this.YellowAngle, this.KeylineAngle };
foreach (float angle in angles)
{
double radians = ImageMaths.DegreesToRadians(angle);
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