using BitMiracle.LibTiff.Classic; using Microsoft.AspNetCore.Mvc; using SkiaSharp; using Microsoft.Data.SqlClient; namespace Library.Api; [Route( "Api/Upload/[action]/{id?}" )] public class UploadApi : APIController { private readonly string m_TempDirectory; public UploadApi( ILogger logger , IConfiguration configuration ) : base( logger , configuration ) { m_TempDirectory = configuration.GetValue( "TempDirectory" ) ?? string.Empty; } [HttpPost] public IActionResult StartUpload( ) { Trace( "/Api/Repository/StartUpload" ); string session = Guid.NewGuid( ).ToString( ).Replace( "-" , null ); using FileStream stream = new( m_TempDirectory + session! , FileMode.CreateNew , FileAccess.Write , FileShare.None ); return Success( session! ); } [HttpPost] public IActionResult UploadChunk( string? session , string? payload , long offset ) { if ( session == null ) return Error( "Invalid call. (session)" ); if ( !ValidateOffset( session , offset ) ) return Error( "Invalid call. (Bad offset)" ); byte[]? bytes = Base64DecodeSafe( payload ); if ( bytes == null ) return Error( "Invalid call. (Bad payload)" ); using FileStream stream = new( m_TempDirectory + session! , FileMode.Append , FileAccess.Write , FileShare.None ); stream.Write( bytes , 0 , bytes.Length ); return Success( "OK" ); } private static byte[]? PreprocessMP4( string form_file ) { byte[] file_bytes = System.IO.File.ReadAllBytes( form_file ); if ( file_bytes.Length < 100 ) return null; return file_bytes; } [HttpPost] public IActionResult SaveMP4Attachment( string? session , long offset , int id ) { if ( session == null ) return Error( "Invalid call. (Invalid parameters)" ); /* if ( !ValidateOffset( session , offset ) ) return Error( "Invalid call. (Bad offset)" ); */ byte [] ? pdf_data_array = PreprocessMP4( m_TempDirectory + session! ); if ( pdf_data_array == null ) return Error( "Invalid file" ); SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='mp4' OUTPUT INSERTED.uuid WHERE id = @id") .AddParameter( "@id" , id ) .ExecuteReader( ); if ( !reader.Read( ) ) return Error( "No such attachment!" ); string? new_uuid = reader.String( 0 ); if ( string.IsNullOrEmpty( new_uuid ) ) return Error( "No such attachment!" ); string original = GetDataDirectory( ) + new_uuid + ".mp4"; System.IO.File.WriteAllBytes( original , pdf_data_array ); return Success( new_uuid ); } [HttpPost] public IActionResult SaveCoverImage( string? session , long offset , int id ) { if ( session == null ) return Error( "Invalid call. (Invalid parameters)" ); if ( !ValidateOffset( session , offset ) ) return Error( "Invalid call. (Bad offset)" ); using SKBitmap? bitmap = PreprocessImage( m_TempDirectory + session! ); if ( bitmap == null ) return Error( "Invalid image" ); SqlDataReader reader = PrepareSQL(@"update gnm set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id") .AddParameter( "@id" , id ) .ExecuteReader( ); if ( !reader.Read( ) ) return Error( "No such book!" ); string? new_uuid = reader.String( 0 ); if ( string.IsNullOrEmpty( new_uuid ) ) return Error( "No such book!" ); string original = GetDataDirectory( ) + new_uuid + ".jpg"; using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 ); byte [] bitmap_data_array = bitmap_data.ToArray( ); System.IO.File.WriteAllBytes( original , bitmap_data_array ); return Success( new_uuid ); } [HttpPost] public IActionResult SavePDFAttachment( string? session , long offset , int id ) { if ( session == null ) return Error( "Invalid call. (Invalid parameters)" ); if ( !ValidateOffset( session , offset ) ) return Error( "Invalid call. (Bad offset)" ); byte [] ? pdf_data_array = PreprocessPDF( m_TempDirectory + session! ); if ( pdf_data_array == null ) return Error( "Invalid file" ); SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='pdf' OUTPUT INSERTED.uuid WHERE id = @id") .AddParameter( "@id" , id ) .ExecuteReader( ); if ( !reader.Read( ) ) return Error( "No such attachment!" ); string? new_uuid = reader.String( 0 ); if ( string.IsNullOrEmpty( new_uuid ) ) return Error( "No such attachment!" ); string original = GetDataDirectory( ) + new_uuid + ".pdf"; System.IO.File.WriteAllBytes( original , pdf_data_array ); return Success( new_uuid ); } [HttpPost] public IActionResult SaveImageAttachment( string? session , long offset , int id ) { if ( session == null ) return Error( "Invalid call. (Invalid parameters)" ); if ( !ValidateOffset( session , offset ) ) return Error( "Invalid call. (Bad offset)" ); using SKBitmap? bitmap = PreprocessImage( m_TempDirectory + session! ); if ( bitmap == null ) return Error( "Invalid image" ); SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id") .AddParameter( "@id" , id ) .ExecuteReader( ); if ( !reader.Read( ) ) return Error( "No such attachment!" ); string? new_uuid = reader.String( 0 ); if ( string.IsNullOrEmpty( new_uuid ) ) return Error( "No such attachment!" ); string original = GetDataDirectory( ) + new_uuid + ".jpg"; using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 ); byte [] bitmap_data_array = bitmap_data.ToArray( ); System.IO.File.WriteAllBytes( original , bitmap_data_array ); return Success( new_uuid ); } private static byte[]? Base64DecodeSafe( string? b ) { if ( b == null ) return null; try { return Convert.FromBase64String( b! ); } catch ( Exception ) { } return null; } private bool ValidateOffset( string session , long expected ) { try { FileInfo fi = new( m_TempDirectory + session ); return fi.Length == expected; } catch ( Exception ) { } return false; } private static SKBitmap? PreprocessImage( string local_file ) { SKBitmap? bitmap = SKBitmap.Decode( local_file ); if ( bitmap == null ) { bitmap = ConvertTiffToSKBitmap( local_file ); if ( bitmap == null ) return null; } if ( bitmap!.IsEmpty || bitmap.IsNull || bitmap.Width < 16 || bitmap.Height < 16 ) return null; return bitmap; } private static SKBitmap? ConvertTiffToSKBitmap( string local_file ) { SKColor[] pixels; int width, height; // open a Tiff stored in the memory stream, and grab its pixels using ( Tiff tifImg = Tiff.ClientOpen( local_file , "r" , null , new TiffStream( ) ) ) { FieldValue[] value = tifImg.GetField(TiffTag.IMAGEWIDTH); width = value[0].ToInt( ); value = tifImg.GetField( TiffTag.IMAGELENGTH ); height = value[0].ToInt( ); // Read the image into the memory buffer int[] raster = new int[width * height]; if ( !tifImg.ReadRGBAImageOriented( width , height , raster , Orientation.TOPLEFT ) ) { // Not a valid TIF image. } // store the pixels pixels = new SKColor[width * height]; for ( int y = 0 ; y < height ; y++ ) { for ( int x = 0 ; x < width ; x++ ) { int arrayOffset = y * width + x; int rgba = raster[arrayOffset]; pixels[arrayOffset] = new SKColor( (byte)Tiff.GetR( rgba ) , (byte)Tiff.GetG( rgba ) , (byte)Tiff.GetB( rgba ) , (byte)Tiff.GetA( rgba ) ); } } } return new SKBitmap( width , height ) { Pixels = pixels }; } private static byte[]? PreprocessPDF( string form_file ) { byte[] file_bytes = System.IO.File.ReadAllBytes( form_file ); if ( file_bytes.Length < 10 ) return null; if ( file_bytes[0] != (byte)'%' || file_bytes[1] != (byte)'P' || file_bytes[2] != 'D' || file_bytes[3] != 'F' ) return null; return file_bytes; } }