Browse Source

Perf improvements + fix memory leak

Former-commit-id: 20e073d2b951f20450b55df9d78dc6966a48f4a1
Former-commit-id: a8927a2352e8803cde9c7cf887d5c64e061f7726
Former-commit-id: 5e630441e640043b0840b486d00bc8d868838502
af/merge-core
James Jackson-South 10 years ago
parent
commit
b768b69857
  1. 17
      src/ImageProcessor/Formats/Bmp/BmpEncoder.cs
  2. 2
      src/ImageProcessor/Formats/Jpg/JpegDecoder.cs
  3. 67
      src/ImageProcessor/Formats/Jpg/JpegEncoder.cs
  4. 38
      src/ImageProcessor/Formats/Png/PngEncoder.cs

17
src/ImageProcessor/Formats/Bmp/BmpEncoder.cs

@ -100,29 +100,20 @@ namespace ImageProcessor.Formats
amount = 4 - amount;
}
float[] data = image.Pixels;
for (int y = image.Height - 1; y >= 0; y--)
{
for (int x = 0; x < image.Width; x++)
{
int offset = ((y * image.Width) + x) * 4;
// Limit the output range and multiply out from our floating point.
// Convert back to b-> g-> r-> a order.
// Convert to non-premultiplied color.
float r = data[offset];
float g = data[offset + 1];
float b = data[offset + 2];
float a = data[offset + 3];
Bgra32 color = Color.ToNonPremultiplied(new Color(r, g, b, a));
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
writer.Write(color.B);
writer.Write(color.G);
writer.Write(color.R);
// Allocate 1 array instead of allocating 3.
writer.Write(new[] { color.B, color.G, color.R });
}
// Pad
for (int i = 0; i < amount; i++)
{
writer.Write((byte)0);

2
src/ImageProcessor/Formats/Jpg/JpegDecoder.cs

@ -152,6 +152,8 @@ namespace ImageProcessor.Formats
}
image.SetPixels(pixelWidth, pixelHeight, pixels);
jpg.Dispose();
}
/// <summary>

67
src/ImageProcessor/Formats/Jpg/JpegEncoder.cs

@ -35,25 +35,10 @@ namespace ImageProcessor.Formats
/// <inheritdoc/>
public string MimeType => "image/jpeg";
/// <summary>
/// Gets the default file extension for this encoder.
/// </summary>
/// <value>The default file extension for this encoder.</value>
/// <inheritdoc/>
public string Extension => "jpg";
/// <summary>
/// Indicates if the image encoder supports the specified
/// file extension.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <returns>
/// <c>true</c>, if the encoder supports the specified
/// extensions; otherwise <c>false</c>.
/// </returns>
/// <exception cref="System.ArgumentNullException"><paramref name="extension"/>
/// is null (Nothing in Visual Basic).</exception>
/// <exception cref="System.ArgumentException"><paramref name="extension"/> is a string
/// of length zero or contains only blanks.</exception>
/// <inheritdoc/>
public bool IsSupportedFileExtension(string extension)
{
Guard.NotNullOrEmpty(extension, "extension");
@ -68,61 +53,41 @@ namespace ImageProcessor.Formats
extension.Equals("jfif", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Encodes the data of the specified image and writes the result to
/// the specified stream.
/// </summary>
/// <param name="image">The image, where the data should be get from.
/// Cannot be null (Nothing in Visual Basic).</param>
/// <param name="stream">The stream, where the image data should be written to.
/// Cannot be null (Nothing in Visual Basic).</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="image"/> is null (Nothing in Visual Basic).</para>
/// <para>- or -</para>
/// <para><paramref name="stream"/> is null (Nothing in Visual Basic).</para>
/// </exception>
/// <inheritdoc/>
public void Encode(ImageBase image, Stream stream)
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
int pixelWidth = image.Width;
int pixelHeight = image.Height;
float[] sourcePixels = image.Pixels;
int imageWidth = image.Width;
int imageHeight = image.Height;
SampleRow[] rows = new SampleRow[pixelHeight];
SampleRow[] rows = new SampleRow[imageHeight];
Parallel.For(
0,
pixelHeight,
imageHeight,
y =>
{
byte[] samples = new byte[pixelWidth * 3];
byte[] samples = new byte[imageWidth * 3];
for (int x = 0; x < pixelWidth; x++)
for (int x = 0; x < imageWidth; x++)
{
int start = x * 3;
int source = ((y * pixelWidth) + x) * 4;
// Convert to non-premultiplied color.
float r = sourcePixels[source];
float g = sourcePixels[source + 1];
float b = sourcePixels[source + 2];
float a = sourcePixels[source + 3];
Bgra32 color = Color.ToNonPremultiplied(new Color(r, g, b, a));
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
int start = x * 3;
samples[start] = color.R;
samples[start + 1] = color.G;
samples[start + 2] = color.B;
}
rows[y] = new SampleRow(samples, pixelWidth, 8, 3);
rows[y] = new SampleRow(samples, imageWidth, 8, 3);
});
JpegImage jpg = new JpegImage(rows, Colorspace.RGB);
jpg.WriteJpeg(stream, new CompressionParameters { Quality = this.Quality });
using (JpegImage jpg = new JpegImage(rows, Colorspace.RGB))
{
jpg.WriteJpeg(stream, new CompressionParameters { Quality = this.Quality });
}
}
}
}

38
src/ImageProcessor/Formats/Png/PngEncoder.cs

@ -196,16 +196,17 @@ namespace ImageProcessor.Formats
/// Writes the pixel information to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="imageBase">The image base.</param>
private void WriteDataChunks(Stream stream, ImageBase imageBase)
/// <param name="image">The image base.</param>
private void WriteDataChunks(Stream stream, ImageBase image)
{
float[] pixels = imageBase.Pixels;
int imageWidth = image.Width;
int imageHeight = image.Height;
byte[] data = new byte[(imageBase.Width * imageBase.Height * 4) + imageBase.Height];
byte[] data = new byte[(imageWidth * imageHeight * 4) + image.Height];
int rowLength = (imageBase.Width * 4) + 1;
int rowLength = (imageWidth * 4) + 1;
Parallel.For(0, imageBase.Height, y =>
Parallel.For(0, imageHeight, y =>
{
byte compression = 0;
if (y > 0)
@ -215,22 +216,12 @@ namespace ImageProcessor.Formats
data[y * rowLength] = compression;
for (int x = 0; x < imageBase.Width; x++)
for (int x = 0; x < imageWidth; x++)
{
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
// Calculate the offset for the new array.
int dataOffset = (y * rowLength) + (x * 4) + 1;
// Calculate the offset for the original pixel array.
int pixelOffset = ((y * imageBase.Width) + x) * 4;
// Convert to non-premultiplied color.
float r = pixels[pixelOffset];
float g = pixels[pixelOffset + 1];
float b = pixels[pixelOffset + 2];
float a = pixels[pixelOffset + 3];
Bgra32 color = Color.ToNonPremultiplied(new Color(r, g, b, a));
data[dataOffset] = color.R;
data[dataOffset + 1] = color.G;
data[dataOffset + 2] = color.B;
@ -238,14 +229,7 @@ namespace ImageProcessor.Formats
if (y > 0)
{
int lastOffset = (((y - 1) * imageBase.Width) + x) * 4;
r = pixels[lastOffset];
g = pixels[lastOffset + 1];
b = pixels[lastOffset + 2];
a = pixels[lastOffset + 3];
color = Color.ToNonPremultiplied(new Color(r, g, b, a));
color = Color.ToNonPremultiplied(image[x, y - 1]);
data[dataOffset] -= color.R;
data[dataOffset + 1] -= color.G;

Loading…
Cancel
Save