Skip to content

Commit

Permalink
Move around Png to correct location to be consistent.
Browse files Browse the repository at this point in the history
Work on correcting sub sampling values in Jpeg.Component.

Add some numerics method to Binary.
  • Loading branch information
juliusfriedman committed Nov 1, 2024
1 parent dc7b707 commit 514b74a
Show file tree
Hide file tree
Showing 19 changed files with 210 additions and 37 deletions.
42 changes: 39 additions & 3 deletions Codecs/Image/Jpeg/Classes/Component.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Media.Codec.Jpeg.Classes;
using Codecs.Image;

namespace Media.Codec.Jpeg.Classes;

public class Component : MediaComponent
{
Expand All @@ -21,16 +23,50 @@ public class Component : MediaComponent
/// </summary>
public int DcPredictor;

/// <summary>
/// Gets the horizontal sampling factor.
/// </summary>
public byte HorizontalSamplingFactor;

/// <summary>
/// Gets the vertical sampling factor.
/// </summary>
public byte VerticalSamplingFactor;

/// <summary>
/// Gets the number of blocks per line.
/// </summary>
public int WidthInBlocks;

/// <summary>
/// Gets the number of blocks per column.
/// </summary>
public int HeightInBlocks;

/// <summary>
///
/// </summary>
public Size? SizeInBlocks;

/// <summary>
///
/// </summary>
public Size? SubSamplingDivisors;

/// <summary>
/// </summary>
public Size? SamplingFactors;

/// <summary>
/// Constructs a <see cref="Component"> with the given quantization table number, id and size.
/// </summary>
/// <param name="quantizationTableNumber"></param>
/// <param name="id"></param>
/// <param name="size"></param>
public Component(byte quantizationTableNumber, byte id, int size)
: base(id, size)
=> Tqi = quantizationTableNumber;

=> Tqi = quantizationTableNumber;
/// <summary>
///
/// </summary>
Expand Down
20 changes: 17 additions & 3 deletions Codecs/Image/Jpeg/Classes/JpegState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ internal sealed class JpegState : IEquatable<JpegState>
/// </summary>
public byte Precision;

/// <summary>
/// </summary>
public byte MaximumHorizontalSamplingFactor;

/// <summary>
/// </summary>
public byte MaximumVerticalSamplingFactor;

public int McusPerLine;

public int McusPerColumn;

/// <summary>
/// Any <see cref="Segments.QuantizationTables"/> which are contained in the image.
/// </summary>
Expand Down Expand Up @@ -217,10 +229,12 @@ public void InitializeScan(JpegImage jpegImage)

if(mediaComponent is not Component jpegComponent)
{
jpegComponent = new Component((byte)i, (byte)i, mediaComponent.Size);
jpegComponent = new Component((byte)i, (byte)i, mediaComponent.Size)
{
HorizontalSamplingFactor = (byte)(jpegImage.ImageFormat.VerticalSamplingFactors[i] + 1),
VerticalSamplingFactor = (byte)(jpegImage.ImageFormat.HorizontalSamplingFactors[i] + 1)
};
jpegImage.ImageFormat.Components[i] = jpegComponent;
jpegImage.ImageFormat.VerticalSamplingFactors[i] = 0;
jpegImage.ImageFormat.HorizontalSamplingFactors[i] = 0;
}
}

Expand Down
4 changes: 2 additions & 2 deletions Codecs/Image/Jpeg/JpegCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,12 @@ internal static void WriteStartOfFrame(JpegImage jpegImage, Stream stream)

if (imageComponent is Component jpegComponent)
{
var frameComponent = new FrameComponent(jpegComponent.Id, jpegImage.ImageFormat.HorizontalSamplingFactors[i], jpegImage.ImageFormat.VerticalSamplingFactors[i], jpegComponent.Tqi);
var frameComponent = new FrameComponent(jpegComponent.Id, jpegComponent.HorizontalSamplingFactor, jpegComponent.VerticalSamplingFactor, jpegComponent.Tqi);
sof[i] = frameComponent;
}
else
{
var frameComponent = new FrameComponent(imageComponent.Id, jpegImage.ImageFormat.HorizontalSamplingFactors[i], jpegImage.ImageFormat.VerticalSamplingFactors[i], i);
var frameComponent = new FrameComponent(imageComponent.Id, jpegImage.ImageFormat.HorizontalSamplingFactors[i] + 1, jpegImage.ImageFormat.VerticalSamplingFactors[i] + 1, i);
sof[i] = frameComponent;
}
}
Expand Down
49 changes: 47 additions & 2 deletions Codecs/Image/Jpeg/JpegImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using Media.Common.Collections.Generic;
using Media.Codec.Jpeg.Classes;
using Media.Codec.Jpeg.Segments;
using Codecs.Image;
using System.Linq;

namespace Media.Codec.Jpeg;

Expand Down Expand Up @@ -104,18 +106,61 @@ public static JpegImage FromStream(Stream stream)
{
var frameComponent = tag[componentIndex];
var componentId = frameComponent.ComponentIdentifier;

// Store the sampling factors
// Todo determine if the shifts need to be adjusted by - 1
widths[componentIndex] = frameComponent.HorizontalSamplingFactor;
heights[componentIndex] = frameComponent.VerticalSamplingFactor;

var quantizationTableNumber = frameComponent.QuantizationTableDestinationSelector;
if (frameComponent.HorizontalSamplingFactor > jpegState.MaximumHorizontalSamplingFactor)
jpegState.MaximumHorizontalSamplingFactor = (byte)frameComponent.HorizontalSamplingFactor;

var mediaComponent = new Component((byte)quantizationTableNumber, (byte)componentId, bitsPerComponent);
if (frameComponent.VerticalSamplingFactor > jpegState.MaximumVerticalSamplingFactor)
jpegState.MaximumVerticalSamplingFactor = (byte)frameComponent.VerticalSamplingFactor;

var quantizationTableNumber = frameComponent.QuantizationTableDestinationSelector;

var mediaComponent = new Component((byte)quantizationTableNumber, (byte)componentId, bitsPerComponent)
{
HorizontalSamplingFactor = (byte)frameComponent.HorizontalSamplingFactor,
VerticalSamplingFactor = (byte)frameComponent.VerticalSamplingFactor
};

mediaComponents[componentIndex] = mediaComponent;

remains -= frameComponent.Count;
}

//Initialize the components
for (int i = 0, e = mediaComponents.Length; i < e; ++i)
{
var jpegComponent = mediaComponents[i];

jpegState.McusPerLine = (int)Binary.DivideCeil((uint)width, (uint)jpegState.MaximumHorizontalSamplingFactor * JpegCodec.BlockSize);
jpegState.McusPerColumn = (int)Binary.DivideCeil((uint)height, (uint)jpegState.MaximumVerticalSamplingFactor * JpegCodec.BlockSize);

uint widthInBlocks = ((uint)width + 7) / JpegCodec.BlockSize;
uint heightInBlocks = ((uint)height + 7) / JpegCodec.BlockSize;

jpegComponent.WidthInBlocks = (int)MathF.Ceiling(
(float)widthInBlocks * jpegComponent.HorizontalSamplingFactor / jpegState.MaximumHorizontalSamplingFactor);

jpegComponent.HeightInBlocks = (int)MathF.Ceiling(
(float)heightInBlocks * jpegComponent.VerticalSamplingFactor / jpegState.MaximumVerticalSamplingFactor);

int blocksPerLineForMcu = jpegState.McusPerLine * jpegComponent.HorizontalSamplingFactor;
int blocksPerColumnForMcu = jpegState.McusPerColumn * jpegComponent.VerticalSamplingFactor;
jpegComponent.SizeInBlocks = new Size(blocksPerLineForMcu, blocksPerColumnForMcu);
jpegComponent.SamplingFactors = new Size(jpegComponent.HorizontalSamplingFactor, jpegComponent.VerticalSamplingFactor);

jpegComponent.SubSamplingDivisors = new Size(jpegState.MaximumHorizontalSamplingFactor, jpegState.MaximumVerticalSamplingFactor) / jpegComponent.SamplingFactors;

if (jpegComponent.SubSamplingDivisors.Width == 0 || jpegComponent.SubSamplingDivisors.Height == 0)
{
throw new InvalidDataException("Bad Subsampling.");
}
}

// Create the image format based on the SOF0 data
imageFormat = new ImageFormat(Binary.ByteOrder.Big, DataLayout.Planar, mediaComponents);
imageFormat.HorizontalSamplingFactors = widths;
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\Common\Common.csproj" />
<ProjectReference Include="..\..\..\Codecs.csproj" />
<ProjectReference Include="..\..\Codecs.Image.csproj" />
<ProjectReference Include="..\..\..\Common\Common.csproj" />
<ProjectReference Include="..\..\Codecs.csproj" />
<ProjectReference Include="..\Codecs.Image.csproj" />
</ItemGroup>

</Project>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
42 changes: 42 additions & 0 deletions Codecs/Image/Size.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Media.Common;
using System;
using System.Drawing;
using System.Numerics;
using System.Runtime.CompilerServices;

Expand Down Expand Up @@ -358,6 +359,16 @@ public void Deconstruct(out float width, out float height)
public static Size operator /(Size left, float right)
=> new(left.WidthF / right, left.HeightF / right);

/// <summary>
/// Multiplies 'a.Width' with 'b.Width' and 'a.Height' with 'b.Height'.
/// </summary>
public static Size operator *(Size a, Size b) => new Size(a.Width * b.Width, a.Height * b.Height);

/// <summary>
/// Divides 'a.Width' with 'b.Width' and 'a.Height' with 'b.Height'.
/// </summary>
public static Size operator /(Size a, Size b) => new Size(a.Width / b.Width, a.Height / b.Height);

/// <summary>
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="PointF"/>.
/// </summary>
Expand All @@ -369,4 +380,35 @@ public void Deconstruct(out float width, out float height)
public static implicit operator Vector2(Size point) => new(point.WidthF, point.HeightF);

#endregion
}

/// <summary>
/// Extension methods for <see cref="Size"/>
/// </summary>
internal static class SizeExtensions
{
/// <summary>
/// Divide Width and Height as real numbers and return the Ceiling.
/// </summary>
public static Size DivideRoundUp(this Size originalSize, int divX, int divY)
{
var sizeVect = (Vector2)originalSize;
sizeVect /= new Vector2(divX, divY);
sizeVect.X = MathF.Ceiling(sizeVect.X);
sizeVect.Y = MathF.Ceiling(sizeVect.Y);

return new Size((int)sizeVect.X, (int)sizeVect.Y);
}

/// <summary>
/// Divide Width and Height as real numbers and return the Ceiling.
/// </summary>
public static Size DivideRoundUp(this Size originalSize, int divisor) =>
DivideRoundUp(originalSize, divisor, divisor);

/// <summary>
/// Divide Width and Height as real numbers and return the Ceiling.
/// </summary>
public static Size DivideRoundUp(this Size originalSize, Size divisor) =>
DivideRoundUp(originalSize, divisor.Width, divisor.Height);
}
80 changes: 58 additions & 22 deletions Common/Classes/Binary/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The above copyright notice and this permission notice shall be included in all c
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;

#endregion

Expand Down Expand Up @@ -2800,25 +2801,25 @@ public static long Roll64(long source, int amount)
/// Used for <see cref="Log2i"/> calls
/// </summary>
/// <remarks><see cref="https://github.com/xVir/FLACTools/blob/master/FLACCodecWin8/BitReader.cs">See Also</see></remarks>
internal static readonly byte[] ByteLog2Table = new byte[]
{
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
internal static readonly byte[] ByteLog2Table =
[
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
];

/// <summary>
/// Integer space based implementation of <see cref="System.Math.Log(double, double)"/> or <see cref="System.Math.Log2(double)"/>
Expand Down Expand Up @@ -2860,10 +2861,45 @@ public static int Log2i(uint v)
}

#endregion
}

//MemSet, Copy
//https://github.com/filoe/cscore/blob/af1792ea680743c5172ece4727e2b331012e99de/CSCore/Utils/ILUtils.cs
#region Numerics

/// <summary>
/// Fast division with ceiling for <see cref="uint"/> numbers.
/// </summary>
/// <param name="value">Divident value.</param>
/// <param name="divisor">Divisor value.</param>
/// <returns>Ceiled division result.</returns>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;

/// <summary>
/// Determine the Greatest CommonDivisor (GCD) of two numbers.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GreatestCommonDivisor(int a, int b)
{
while (b != 0)
{
int temp = b;
b = a % b;
a = temp;
}

return a;
}

/// <summary>
/// Determine the Least Common Multiple (LCM) of two numbers.
/// See https://en.wikipedia.org/wiki/Least_common_multiple#Reduction_by_the_greatest_common_divisor.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LeastCommonMultiple(int a, int b)
=> a / GreatestCommonDivisor(a, b) * b;

#endregion
}
}

//Move to seperate assembly
Expand Down
2 changes: 1 addition & 1 deletion UnitTests/UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<ProjectReference Include="..\Codecs\Image\Bmp\Codec.Bmp\Codec.Bmp.csproj" />
<ProjectReference Include="..\Codecs\Image\Codecs.Image.csproj" />
<ProjectReference Include="..\Codecs\Image\Jpeg\Codec.Jpeg.csproj" />
<ProjectReference Include="..\Codecs\Image\Png\Codec.Png\Codec.Png.csproj" />
<ProjectReference Include="..\Codecs\Image\Png\Codec.Png.csproj" />
<ProjectReference Include="..\Codecs\Mpeg\Mpeg.csproj" />
<ProjectReference Include="..\Codecs\Video\Codecs.Video.csproj" />
<ProjectReference Include="..\Codecs\Video\H264\Codec.H264.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion net7mma_core.sln
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rtcp.Feedback", "RtcpFeedba
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codec.Bmp", "Codecs\Image\Bmp\Codec.Bmp\Codec.Bmp.csproj", "{839F7784-2C36-40D7-909F-873FE8D897D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codec.Png", "Codecs\Image\Png\Codec.Png\Codec.Png.csproj", "{A897B44B-7C49-48A7-A2C9-8F726BF8BE3D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codec.Png", "Codecs\Image\Png\Codec.Png.csproj", "{A897B44B-7C49-48A7-A2C9-8F726BF8BE3D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down

0 comments on commit 514b74a

Please sign in to comment.