internal void AddFrame(int index, string path, int delay = 66) { var reader = new PixelUtil(path.SourceFrom()); reader.LockBits(); var channelData = new ImageChannelData(reader.Depth, reader.Pixels, reader.Height, reader.Width, Compress); //TODO: Support for layers with multiple sizes. var layerData = new LayerRecord { Top = 0, Left = 0, Bottom = (uint)Height, // + top, Right = (uint)Width, // + left, Name = index.ToString() }; reader.UnlockBitsWithoutCommit(); //Add the lengths of the channels. for (var i = 0; i < channelData.ChannelList.Count; i++) { layerData.Channels.Add((short)(i - 1), (int)channelData.ChannelList[i].Length + 2); //+ 2 bytes for the compression type. } LayerAndMask.LayerInfo.ImageChannelDataList.Add(channelData); LayerAndMask.LayerInfo.LayerList.Add(layerData); //TODO: Add ImageResource info (timeline) //ImageResources.ImageResourceList.Add(new ImageResourceBlock(2, "shmd", null)); }
internal GifskiError AddFrame(IntPtr handle, uint index, string path, int delay, double lastTimestamp = 0, bool isLast = false) { if (Version.Major == 0 && Version.Minor < 9) { return(_addPngFrame(handle, index, path, (ushort)(delay / 10))); } //var aa = new FormatConvertedBitmap(path.SourceFrom(), PixelFormats.Rgb24, null, 0); var util = new PixelUtil(new FormatConvertedBitmap(path.SourceFrom(), PixelFormats.Rgb24, null, 0)); util.LockBitsAndUnpad(); var bytesPerRow = util.Width * 3; //Was ((util.Width * 24 + 31) / 32) * 3 //if (bytesPerRow % 4 != 0) // bytesPerRow += (4 - (bytesPerRow % 4)); //Pin the buffer in order to pass the address as parameter later. var pinnedBuffer = GCHandle.Alloc(util.Pixels, GCHandleType.Pinned); var address = pinnedBuffer.AddrOfPinnedObject(); GifskiError result; if (Version > new Version(0, 10, 4)) { //First frame receives the delay set of the last frame. result = AddFrame2Pixels(handle, index, (uint)util.Width, (uint)bytesPerRow, (uint)util.Height, address, index == 0 ? lastTimestamp : _timeStamp); _timeStamp += (delay / 1000d); } else if (Version.Major == 0 && Version.Minor >= 10) { result = AddFrame2Pixels(handle, index, (uint)util.Width, (uint)bytesPerRow, (uint)util.Height, address, _timeStamp); //As a dirty fix for Gifski 0.10.2, the last frame must be duplicated to preserve the timings. if (isLast) { _timeStamp += ((delay / 1000d) / 2d); result = AddFrame2Pixels(handle, index + 1, (uint)util.Width, (uint)bytesPerRow, (uint)util.Height, address, _timeStamp); } //Frames can't be more than 1 second apart. TODO: Add support for dealing with this issue. _timeStamp += (delay / 1000d); } else { //Normal delay. result = AddFramePixels(handle, index, (uint)util.Width, (uint)bytesPerRow, (uint)util.Height, address, (ushort)delay); } //The buffer must be unpinned, to free resources. pinnedBuffer.Free(); util.UnlockBitsWithoutCommit(); return(result); }
internal GifskiError AddFrame(IntPtr handle, uint index, string path, int delay) { if (Version.Major == 0 && Version.Minor < 9) { return(_addPngFrame(handle, index, path, (ushort)(delay / 10))); } var util = new PixelUtil(new FormatConvertedBitmap(path.SourceFrom(), PixelFormats.Rgb24, null, 0)); util.LockBits(); var result = AddFramePixels(handle, index, (uint)util.Width, (uint)((util.Width * 24 + 31) / 32) * 4, (uint)util.Height, util.BackBuffer, (ushort)delay); util.UnlockBitsWithoutCommit(); return(result); }
/// <summary> /// Copy all necessary files to a new encode folder. /// </summary> /// <param name="usePadding">True if the file names should have a left pad, to preserve the file ordering.</param> /// <param name="copyJson">True if the Project.json file should be copied too.</param> /// <param name="useBytes">True if the images should be converted to byte array.</param> /// <returns>A list of frames with the new path.</returns> internal ExportProject CopyToExport(bool usePadding = false, bool copyJson = false, bool useBytes = false) { #region Output folder var folder = Path.Combine(FullPath, "Encode " + DateTime.Now.ToString("yyyy-MM-dd hh-mm-ss-ff")); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } #endregion var export = new ExportProject(); if (useBytes) { export.Frames = new List <ExportFrame>(); export.ChunkPath = Path.Combine(folder, "Chunk"); export.NewChunkPath = Path.Combine(folder, "NewChunk"); try { //Create chunk file. using (var fileStream = new FileStream(export.ChunkPath, FileMode.Create, FileAccess.Write, FileShare.None)) { var pos = 0L; foreach (var info in Frames) { var image = new PixelUtil(info.Path.SourceFrom()); image.LockBits(); fileStream.WriteBytes(image.Pixels); export.Frames.Add(new ExportFrame { DataPosition = pos, DataLength = image.Pixels.LongLength, Delay = info.Delay, Rect = new Int32Rect(0, 0, image.Width, image.Height), ImageDepth = image.Depth }); //Advances in the position. pos += image.Pixels.LongLength; image.UnlockBitsWithoutCommit(); } } } catch (Exception e) { LogWriter.Log(e, "It was impossible to get the image bytes to encode."); throw; } return(export); } export.UsesFiles = true; export.FramesFiles = new List <FrameInfo>(); try { #region If it's being exported as project, maintain file naming if (copyJson) { foreach (var info in Frames) { var filename = Path.Combine(folder, Path.GetFileName(info.Path)); //Copy the image to the folder. File.Copy(info.Path, filename, true); //Create the new object and add to the list. export.FramesFiles.Add(new FrameInfo(filename, info.Delay)); } File.Copy(ProjectPath, Path.Combine(folder, "Project.json"), true); return(export); } #endregion //Detect pad size. var pad = usePadding ? (Frames.Count - 1).ToString().Length : 0; foreach (var info in Frames) { //Changes the path of the image. Writes as an ordered list of files, replacing the old filenames. var filename = Path.Combine(folder, export.FramesFiles.Count.ToString().PadLeft(pad, '0') + ".png"); //Copy the image to the folder. File.Copy(info.Path, filename, true); //Create the new object and add to the list. export.FramesFiles.Add(new FrameInfo(filename, info.Delay)); } } catch (Exception ex) { LogWriter.Log(ex, "It was impossible to copy the files to encode."); throw; } return(export); }