Browse Source

Breakout the PngPhysicalChunkData conversion and encoding functions from the encoder

af/merge-core
Jason Nelson 8 years ago
parent
commit
96ad14fb6e
  1. 93
      src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs
  2. 42
      src/ImageSharp/Formats/Png/PngEncoderCore.cs

93
src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs

@ -0,0 +1,93 @@
using System;
using System.Buffers.Binary;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Png
{
/// <summary>
/// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image.
/// </summary>
internal readonly struct PngPhysicalChunkData
{
public const int Size = 9;
public PngPhysicalChunkData(uint x, uint y, byte unitSpecifier)
{
this.XAxisPixelsPerUnit = x;
this.YAxisPixelsPerUnit = y;
this.UnitSpecifier = unitSpecifier;
}
/// <summary>
/// Gets the number of pixels per unit on the X axis.
/// </summary>
public uint XAxisPixelsPerUnit { get; }
/// <summary>
/// Gets the number of pixels per unit on the Y axis.
/// </summary>
public uint YAxisPixelsPerUnit { get; }
/// <summary>
/// Gets the unit specifier.
/// 0: unit is unknown
/// 1: unit is the meter
/// When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified.
/// </summary>
public byte UnitSpecifier { get; }
/// <summary>
/// Constructs the PngPhysicalChunkData from the provided metadata.
/// If the resolution units are not in meters, they are automatically convereted.
/// </summary>
/// <param name="meta">The metadata.</param>
/// <returns>The constructed PngPhysicalChunkData instance.</returns>
public static PngPhysicalChunkData FromMetadata(ImageMetaData meta)
{
byte unitSpecifier = 0;
uint x;
uint y;
switch (meta.ResolutionUnits)
{
case PixelResolutionUnit.AspectRatio:
unitSpecifier = 0; // Unspecified
x = (uint)Math.Round(meta.HorizontalResolution);
y = (uint)Math.Round(meta.VerticalResolution);
break;
case PixelResolutionUnit.PixelsPerInch:
unitSpecifier = 1; // Per meter
x = (uint)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution));
y = (uint)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution));
break;
case PixelResolutionUnit.PixelsPerCentimeter:
unitSpecifier = 1; // Per meter
x = (uint)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution));
y = (uint)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution));
break;
default:
unitSpecifier = 1; // Per meter
x = (uint)Math.Round(meta.HorizontalResolution);
y = (uint)Math.Round(meta.VerticalResolution);
break;
}
return new PngPhysicalChunkData(x, y, unitSpecifier);
}
/// <summary>
/// Writes the data to the given buffer.
/// </summary>
/// <param name="buffer">The buffer.</param>
public void WriteTo(Span<byte> buffer)
{
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(0, 4), this.XAxisPixelsPerUnit);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(4, 4), this.YAxisPixelsPerUnit);
buffer[8] = this.UnitSpecifier;
}
}
}

42
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -674,47 +674,9 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="meta">The image meta data.</param>
private void WritePhysicalChunk(Stream stream, ImageMetaData meta)
{
// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. It contains:
// Pixels per unit, X axis: 4 bytes (unsigned integer)
// Pixels per unit, Y axis: 4 bytes (unsigned integer)
// Unit specifier: 1 byte
//
// The following values are legal for the unit specifier:
// 0: unit is unknown
// 1: unit is the meter
//
// When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified.
Span<byte> hResolution = this.chunkDataBuffer.AsSpan(0, 4);
Span<byte> vResolution = this.chunkDataBuffer.AsSpan(4, 4);
switch (meta.ResolutionUnits)
{
case PixelResolutionUnit.AspectRatio:
this.chunkDataBuffer[8] = 0;
BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution));
BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution));
break;
case PixelResolutionUnit.PixelsPerInch:
this.chunkDataBuffer[8] = 1; // Per meter
BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution)));
BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution)));
break;
case PixelResolutionUnit.PixelsPerCentimeter:
this.chunkDataBuffer[8] = 1; // Per meter
BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution)));
BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution)));
break;
default:
this.chunkDataBuffer[8] = 1; // Per meter
BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution));
BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution));
break;
}
PngPhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer);
this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, 9);
this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PngPhysicalChunkData.Size);
}
/// <summary>

Loading…
Cancel
Save