<commit_before>﻿using NtImageProcessor.MetaData.Misc;
using NtImageProcessor.MetaData.Structure;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NtImageProcessor.MetaData.Composer
{
    public static class JpegMetaDataProcessor
    {
        /// <summary>
        /// Set exif data to Jpeg file. 
        /// Mess of this library; everything are caused by crazy Exif format.
        /// Note that this function overwrites ALL Exif data in the given image.
        /// TODO: Support stream in this class.
        /// </summary>
        /// <param name="OriginalImage">Target image</param>
        /// <param name="MetaData">An Exif data which will be added to the image.</param>
        /// <returns>New image</returns>
        public static byte[] SetMetaData(byte[] OriginalImage, JpegMetaData MetaData)
        {
            var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage);
            // Debug.WriteLine("Original image size: " + OriginalImage.Length.ToString("X"));

            // It seems there's a bug handling little endian jpeg image on WP OS.
            var OutputImageMetadataEndian = Definitions.Endian.Big;

            var App0Offset = 0;

            if (Util.GetUIntValue(OriginalImage, 2, 2, Definitions.Endian.Big) == Definitions.APP0_MARKER)
            {
                App0Offset = 2 + (int)Util.GetUIntValue(OriginalImage, 4, 2, Definitions.Endian.Big);
                Debug.WriteLine("APP0 marker detected. " + App0Offset);
                Debug.WriteLine("*** this method with APP0 section is not tested. ***");
            }

            // Note: App1 size and ID are fixed to Big endian.
            UInt32 OriginalApp1DataSize = Util.GetUIntValue(OriginalImage, 4 + App0Offset, 2, Definitions.Endian.Big);
            // Debug.WriteLine("Original App1 size: " + OriginalApp1DataSize.ToString("X"));

            // 0-5 byte: Exif identify code. E, x, i, f, \0, \0
            // 6-13 byte: TIFF header. endian, 0x002A, Offset to Primary IFD in 4 bytes. generally, 8 is set as the offset.
            var OriginalApp1Data = new byte[OriginalApp1DataSize];
            Array.Copy(OriginalImage, 6 + App0Offset, OriginalApp1Data, 0, (int)OriginalApp1DataSize);

            var NewApp1Data = CreateApp1Data(OriginalMetaData, MetaData, OriginalApp1Data, OutputImageMetadataEndian);

            // Only size of App1 data is different.
            var NewImage = new byte[OriginalImage.Length - OriginalApp1DataSize + NewApp1Data.Length];
            // Debug.WriteLine("New image size: " + NewImage.Length.ToString("X"));

            // Copy SOI, App1 marker
            var newImageHeader = new byte[4] { 0xFF, 0xD8, 0xFF, 0xE1 };
            Array.Copy(newImageHeader, 0, NewImage, 0, 2 + 2);

            // Important note again: App 1 data size is stored in Big endian.
            var App1SizeData = Util.ToByte((UInt32)NewApp1Data.Length, 2, Definitions.Endian.Big);
            Array.Copy(App1SizeData, 0, NewImage, 4, 2);

            // After that, copy App1 data to new image.
            Array.Copy(NewApp1Data, 0, NewImage, 6, NewApp1Data.Length);

            // At last, copy body from original image.
            Array.Copy(OriginalImage, 2 + 2 + 2 + App0Offset + (int)OriginalApp1DataSize, NewImage, 2 + 2 + 2 + NewApp1Data.Length, OriginalImage.Length - 2 - 2 - 2 - (int)OriginalApp1DataSize);

            return NewImage;
        }

        public static Stream SetMetaData(Stream OriginalImage, JpegMetaData MetaData)
        {
            OriginalImage.Seek(0, SeekOrigin.Begin);

            var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage);
            var OutputImageMetaDataEndian = Definitions.Endian.Big;

            var endian = Definitions.Endian.Big;

            OriginalImage.Position = 2;
            var FirstMarker = new byte[2];
            OriginalImage.Read(FirstMarker, 0, 2);
            var App0Offset = 0;
            if (Util.GetUIntValue(FirstMarker, 0, 2, endian) == Definitions.APP0_MARKER)
            {
                var App0SizeData = new byte[2];
                OriginalImage.Read(App0SizeData, 0, 2);
                App0Offset = 2 + (int)Util.GetUIntValue(App0SizeData, 0, 2, endian);
                Debug.WriteLine("Detected APP0 seciton. offset " + App0Offset);
            }

            OriginalImage.Position = 4 + App0Offset;
            var app1sizeData = new byte[2];
            OriginalImage.Read(app1sizeData, 0, 2);

            var OriginalApp1Size = Util.GetUIntValue(app1sizeData, 0, 2, endian);<commit_msg>Fix image with app0 section in byte array issue<commit_after>﻿using NtImageProcessor.MetaData.Misc;
using NtImageProcessor.MetaData.Structure;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NtImageProcessor.MetaData.Composer
{
    public static class JpegMetaDataProcessor
    {
        /// <summary>
        /// Set exif data to Jpeg file. 
        /// Mess of this library; everything are caused by crazy Exif format.
        /// Note that this function overwrites ALL Exif data in the given image.
        /// TODO: Support stream in this class.
        /// </summary>
        /// <param name="OriginalImage">Target image</param>
        /// <param name="MetaData">An Exif data which will be added to the image.</param>
        /// <returns>New image</returns>
        public static byte[] SetMetaData(byte[] OriginalImage, JpegMetaData MetaData)
        {
            var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage);
            // Debug.WriteLine("Original image size: " + OriginalImage.Length.ToString("X"));

            // It seems there's a bug handling little endian jpeg image on WP OS.
            var OutputImageMetadataEndian = Definitions.Endian.Big;

            var App0Offset = 0;

            if (Util.GetUIntValue(OriginalImage, 2, 2, Definitions.Endian.Big) == Definitions.APP0_MARKER)
            {
                App0Offset = 2 + (int)Util.GetUIntValue(OriginalImage, 4, 2, Definitions.Endian.Big);
                Debug.WriteLine("APP0 marker detected. " + App0Offset);
                Debug.WriteLine("*** this method with APP0 section is not tested. ***");
            }

            // Note: App1 size and ID are fixed to Big endian.
            UInt32 OriginalApp1DataSize = Util.GetUIntValue(OriginalImage, 4 + App0Offset, 2, Definitions.Endian.Big);
            // Debug.WriteLine("Original App1 size: " + OriginalApp1DataSize.ToString("X"));

            // 0-5 byte: Exif identify code. E, x, i, f, \0, \0
            // 6-13 byte: TIFF header. endian, 0x002A, Offset to Primary IFD in 4 bytes. generally, 8 is set as the offset.
            var OriginalApp1Data = new byte[OriginalApp1DataSize];
            Array.Copy(OriginalImage, 6 + App0Offset, OriginalApp1Data, 0, (int)OriginalApp1DataSize);

            var NewApp1Data = CreateApp1Data(OriginalMetaData, MetaData, OriginalApp1Data, OutputImageMetadataEndian);

            // Only size of App1 data is different.
            var NewImage = new byte[OriginalImage.Length - OriginalApp1DataSize + NewApp1Data.Length];
            // Debug.WriteLine("New image size: " + NewImage.Length.ToString("X"));

            // Copy SOI, App1 marker
            var newImageHeader = new byte[4] { 0xFF, 0xD8, 0xFF, 0xE1 };
            Array.Copy(newImageHeader, 0, NewImage, 0, 2 + 2);

            // Important note again: App 1 data size is stored in Big endian.
            var App1SizeData = Util.ToByte((UInt32)NewApp1Data.Length, 2, Definitions.Endian.Big);
            Array.Copy(App1SizeData, 0, NewImage, 4, 2);

            // After that, copy App1 data to new image.
            Array.Copy(NewApp1Data, 0, NewImage, 6, NewApp1Data.Length);

            // At last, copy body from original image.
            Array.Copy(OriginalImage, 2 + 2 + 2 + App0Offset + (int)OriginalApp1DataSize, NewImage, 2 + 2 + 2 + NewApp1Data.Length, OriginalImage.Length - 2 - 2 - 2 - App0Offset - (int)OriginalApp1DataSize);

            return NewImage;
        }

        public static Stream SetMetaData(Stream OriginalImage, JpegMetaData MetaData)
        {
            OriginalImage.Seek(0, SeekOrigin.Begin);

            var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage);
            var OutputImageMetaDataEndian = Definitions.Endian.Big;

            var endian = Definitions.Endian.Big;

            OriginalImage.Position = 2;
            var FirstMarker = new byte[2];
            OriginalImage.Read(FirstMarker, 0, 2);
            var App0Offset = 0;
            if (Util.GetUIntValue(FirstMarker, 0, 2, endian) == Definitions.APP0_MARKER)
            {
                var App0SizeData = new byte[2];
                OriginalImage.Read(App0SizeData, 0, 2);
                App0Offset = 2 + (int)Util.GetUIntValue(App0SizeData, 0, 2, endian);
                Debug.WriteLine("Detected APP0 seciton. offset " + App0Offset);
            }

            OriginalImage.Position = 4 + App0Offset;
            var app1sizeData = new byte[2];
            OriginalImage.Read(app1sizeData, 0, 2);

            var OriginalApp1Size = Util.GetUIntValue(app1sizeData, 0, 2, endian);
{'fraction_non_alphanumeric': 0.10009593859929646, 'fraction_numerical': 0.02579682336637885, 'mean_word_length': 2.3507142857142855, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2401554', 'n_tokens_mistral': 2764, 'n_tokens_neox': 2609, 'n_words': 744}