245 lines
9.3 KiB
C#
245 lines
9.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace AgraV2
|
|
{
|
|
internal class EffectScale : Effect
|
|
{
|
|
private readonly object balancelock = new object();
|
|
private int _radius;
|
|
private float _scale;
|
|
|
|
public int Radius { get => _radius; set => _radius = value; }
|
|
public float Scale { get => _scale; set => _scale = value; }
|
|
|
|
public EffectScale(string name, Panel toolBox) : base(name, toolBox)
|
|
{
|
|
//Default values
|
|
Radius = 1;
|
|
Scale = 1;
|
|
}
|
|
public override void populatePannel()
|
|
{
|
|
base.populatePannel();
|
|
|
|
Label label = new Label();
|
|
label.Text = "Range : ";
|
|
label.BackColor = Color.Transparent;
|
|
label.Location = new Point(0, 0);
|
|
|
|
Label label2 = new Label();
|
|
label2.Text = "Scale ratio : ";
|
|
label2.BackColor = Color.Transparent;
|
|
label2.Location = new Point(0, label.Height);
|
|
|
|
NumericUpDown nupRange = new NumericUpDown();
|
|
nupRange.Minimum = 1;
|
|
nupRange.Maximum = 100;
|
|
nupRange.Increment = 1;
|
|
nupRange.ValueChanged += nupRange_ValueChanged;
|
|
nupRange.Location = new Point(label.Location.X + label.Width, label.Location.Y);
|
|
|
|
NumericUpDown nupScale = new NumericUpDown();
|
|
nupScale.Minimum = 1;
|
|
nupScale.Maximum = 100;
|
|
nupScale.Increment = 0.1M;
|
|
nupScale.ValueChanged += nupScale_ValueChanged;
|
|
nupScale.Location = new Point(label2.Location.X + label2.Width, label2.Location.Y);
|
|
|
|
ToolBox.Controls.Add(label);
|
|
ToolBox.Controls.Add(nupRange);
|
|
ToolBox.Controls.Add(label2);
|
|
ToolBox.Controls.Add(nupScale);
|
|
}
|
|
private void nupRange_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
if (sender is NumericUpDown)
|
|
{
|
|
NumericUpDown nup = (NumericUpDown)sender;
|
|
Radius = (int)nup.Value;
|
|
}
|
|
}
|
|
private void nupScale_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
if (sender is NumericUpDown)
|
|
{
|
|
NumericUpDown nup = (NumericUpDown)sender;
|
|
Scale = (float)nup.Value;
|
|
}
|
|
}
|
|
public override Bitmap[] apply(Bitmap inputBmp)
|
|
{
|
|
if (inputBmp == null)
|
|
return null;
|
|
|
|
//This is important for when the user wants to re apply an effet
|
|
ProcessingDuration = new List<double>();
|
|
|
|
Bitmap[] result = new Bitmap[] { NearestNeighbor(inputBmp)};
|
|
return result;
|
|
}
|
|
public unsafe Bitmap NearestNeighbor(Bitmap inputBmp)
|
|
{
|
|
Chrono.Restart();
|
|
|
|
Size imgSize = new Size(inputBmp.Width, inputBmp.Height);
|
|
Size newSize = new Size((int)(imgSize.Width * Scale), (int)(imgSize.Height * Scale));
|
|
|
|
Bitmap result = new Bitmap(newSize.Width, newSize.Height);
|
|
BitmapData resultData = result.LockBits(new Rectangle(0, 0, newSize.Width, newSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat);
|
|
BitmapData inputData = inputBmp.LockBits(new Rectangle(0, 0, imgSize.Width, imgSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat);
|
|
|
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(inputBmp.PixelFormat) / 8;
|
|
int byteCount = inputData.Stride * inputBmp.Height;
|
|
int offset = inputData.Stride - bytesPerPixel * imgSize.Width;
|
|
int newOffset = resultData.Stride - bytesPerPixel * newSize.Width;
|
|
|
|
|
|
lock (balancelock)
|
|
{
|
|
byte* resultStartPx = (byte*)resultData.Scan0.ToPointer();
|
|
byte* resultCursor = resultStartPx;
|
|
byte* originalStartPx = (byte*)inputData.Scan0.ToPointer();
|
|
byte* originalCursor = originalStartPx;
|
|
|
|
for (int y = 0; y < newSize.Height; y++)
|
|
{
|
|
for (int x = 0; x < newSize.Width; x++)
|
|
{
|
|
//We want to know what the pixel on the old x and y was
|
|
|
|
int oldX = (int)Math.Floor((float)x / Scale);
|
|
int oldY = (int)Math.Floor((float)y / Scale);
|
|
|
|
if (bytesPerPixel == 3 && oldX == 2 && oldY == 2)
|
|
Console.WriteLine("coucou");
|
|
|
|
//Now we would like to know what the color on this pixel was
|
|
//transfer x,y to linear : y*(width + offset) + x
|
|
|
|
int oldPosition = oldY * imgSize.Width + oldX;
|
|
oldPosition = oldPosition * bytesPerPixel + oldY * offset;
|
|
int oldBlue = (originalStartPx + oldPosition)[0];
|
|
int oldGreen = (originalStartPx + oldPosition)[1];
|
|
int oldRed = (originalStartPx + oldPosition)[2];
|
|
|
|
resultCursor[0] = (byte)oldBlue;
|
|
resultCursor[1] = (byte)oldGreen;
|
|
resultCursor[2] = (byte)oldRed;
|
|
|
|
//originalCursor += bytesPerPixel;
|
|
resultCursor += bytesPerPixel;
|
|
}
|
|
//Taking care of the offset
|
|
//originalCursor += offset;
|
|
resultCursor += newOffset;
|
|
}
|
|
|
|
}
|
|
result.UnlockBits(resultData);
|
|
inputBmp.UnlockBits(inputData);
|
|
|
|
Chrono.Stop();
|
|
ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0);
|
|
|
|
return result;
|
|
}
|
|
public unsafe Bitmap BiLinear(Bitmap inputBmp)
|
|
{
|
|
Chrono.Restart();
|
|
|
|
Size imgSize = new Size(inputBmp.Width, inputBmp.Height);
|
|
Size newSize = new Size((int)(imgSize.Width * Scale), (int)(imgSize.Height * Scale));
|
|
|
|
Bitmap result = new Bitmap(newSize.Width, newSize.Height);
|
|
BitmapData resultData = result.LockBits(new Rectangle(0, 0, newSize.Width, newSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat);
|
|
BitmapData inputData = inputBmp.LockBits(new Rectangle(0, 0, imgSize.Width, imgSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat);
|
|
|
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(inputBmp.PixelFormat) / 8;
|
|
int byteCount = inputData.Stride * inputBmp.Height;
|
|
int offset = inputData.Stride - bytesPerPixel * imgSize.Width;
|
|
int newOffset = resultData.Stride - bytesPerPixel * newSize.Width;
|
|
|
|
|
|
lock (balancelock)
|
|
{
|
|
byte* resultStartPx = (byte*)resultData.Scan0.ToPointer();
|
|
byte* resultCursor = resultStartPx;
|
|
byte* originalStartPx = (byte*)inputData.Scan0.ToPointer();
|
|
byte* originalCursor = originalStartPx;
|
|
|
|
float tx = imgSize.Width / newSize.Width;
|
|
float ty = imgSize.Height / newSize.Height;
|
|
|
|
for (int y = 0; y < newSize.Height; y++)
|
|
{
|
|
for (int x = 0; x < newSize.Width; x++)
|
|
{
|
|
|
|
int newX = (int)(tx * x);
|
|
int newY = (int)(ty * y);
|
|
|
|
float x_diff = ((tx *x)-newX);
|
|
float y_diff = ((ty *y)-newY);
|
|
|
|
//int value =
|
|
|
|
//THIS METHOD IS NOT FINISHED
|
|
|
|
//originalCursor += bytesPerPixel;
|
|
resultCursor += bytesPerPixel;
|
|
|
|
}
|
|
//Taking care of the offset
|
|
//originalCursor += offset;
|
|
resultCursor += newOffset;
|
|
}
|
|
|
|
}
|
|
result.UnlockBits(resultData);
|
|
inputBmp.UnlockBits(inputData);
|
|
|
|
Chrono.Stop();
|
|
ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0);
|
|
|
|
return result;
|
|
}
|
|
public int ConvertPointToLinear(Point position,Size imageSize,int bytesPerPixel, int offset)
|
|
{
|
|
int linearPosition = position.Y * imageSize.Width + position.X;
|
|
linearPosition = linearPosition * bytesPerPixel + position.Y * offset;
|
|
|
|
return linearPosition;
|
|
}
|
|
public List<Point> getSurroundingPixels(Point centerPoint, int Radius, int imageWidth, int imageHeight)
|
|
{
|
|
List<Point> result = new List<Point>();
|
|
int width = (Radius * 2 + 1);
|
|
|
|
Point cursor = centerPoint;
|
|
|
|
//we place the cursor on the top left of the matrix
|
|
cursor = new Point(cursor.X - Radius, cursor.Y - Radius);
|
|
|
|
for (int y = 0; y < width; y++)
|
|
{
|
|
//This scans top to bottom
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
//This scans left to right
|
|
result.Add(cursor);
|
|
cursor = new Point(cursor.X + 1, cursor.Y);
|
|
}
|
|
cursor = new Point(cursor.X - (Radius * 2 + 1), cursor.Y + 1);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|