Exemplo n.º 1
0
 /// <summary>
 /// Set the type and value of an item of metadata.
 /// </summary>
 /// <remarks>
 /// Sets the type and value of an item of metadata. Any old item of the
 /// same name is removed. See <see cref="GValue"/> for types.
 /// </remarks>
 /// <param name="gtype">The GType of the metadata item to create.</param>
 /// <param name="name">The name of the piece of metadata to create.</param>
 /// <param name="value">The value to set as a C# value. It is
 /// converted to the GType, if possible.</param>
 public new void Set(IntPtr gtype, string name, object value)
 {
     using var gv = new GValue();
     gv.SetType(gtype);
     gv.Set(value);
     VipsImage.Set(this, name, in gv.Struct);
 }
Exemplo n.º 2
0
        /// <summary>
        /// Set a GObject property. The value is converted to the property type, if possible.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual void Set(string name, object value)
        {
            // logger.Debug($"Set: name = {name}, value = {value}");
            var gtype = GetTypeOf(name);
            var gv    = new GValue();

            gv.SetType(gtype);
            gv.Set(value);
            Internal.GObject.GObjectSetProperty(this, name, ref gv.Struct);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Set a GObject property. The value is converted to the property type, if possible.
        /// </summary>
        /// <param name="name">The name of the property to set.</param>
        /// <param name="value">The value.</param>
        /// <param name="gtype">The GType of the property.</param>
        public virtual void Set(IntPtr gtype, string name, object value)
        {
            // logger.Debug($"Set: gtype = {gtype}, name = {name}, value = {value}");
            using (var gv = new GValue())
            {
                gv.SetType(gtype);
                gv.Set(value);

                Internal.GObject.SetProperty(this, name, in gv.Struct);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Get a GObject property.
        /// </summary>
        /// <remarks>
        /// The value of the property is converted to a C# value.
        /// </remarks>
        /// <param name="name"></param>
        /// <returns></returns>
        public virtual object Get(string name)
        {
            // logger.Debug($"Get: name = {name}");
            var pspec = GetPspec(name);

            if (!pspec.HasValue)
            {
                throw new VipsException("Property not found.");
            }

            var gtype = pspec.Value.ValueType;
            var gv    = new GValue();

            gv.SetType(gtype);

            // this will add a ref for GObject properties, that ref will be
            // unreffed when the gvalue is finalized
            Internal.GObject.GObjectGetProperty(this, name, ref gv.Struct);

            return(gv.Get());
        }
Exemplo n.º 5
0
        /// <summary>
        /// Generate the `Image.Generated.cs` file.
        /// </summary>
        /// <remarks>
        /// This is used to generate the `Image.Generated.cs` file (<see cref="Image"/>).
        /// Use it with something like:
        /// <code language="lang-csharp">
        /// File.WriteAllText("Image.Generated.cs", Operation.GenerateImageClass());
        /// </code>
        /// </remarks>
        /// <returns></returns>
        public static string GenerateImageClass(string indent = "        ")
        {
            // generate list of all nicknames we can generate docstrings for
            var allNickNames = new List <string>();

            IntPtr TypeMap(ulong type, IntPtr a, IntPtr b)
            {
                AddNickname(type, allNickNames);

                return(IntPtr.Zero);
            }

            Base.TypeMap(Base.TypeFromName("VipsOperation"), TypeMap);

            // Sort
            allNickNames.Sort();

            // Filter duplicates
            allNickNames = allNickNames.Distinct().ToList();

            // remove operations we have to wrap by hand
            var exclude = new[]
            {
                "scale",
                "ifthenelse",
                "bandjoin",
                "bandrank",
                "composite"
            };

            allNickNames = allNickNames.Where(x => !exclude.Contains(x)).ToList();

            const string preamble = @"//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     libvips version: {0}
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------";

            var stringBuilder =
                new StringBuilder(string.Format(preamble, $"{Base.Version(0)}.{Base.Version(1)}.{Base.Version(2)}"));

            stringBuilder.AppendLine()
            .AppendLine()
            .AppendLine("namespace NetVips")
            .AppendLine("{")
            .AppendLine("    public sealed partial class Image")
            .AppendLine("    {")
            .AppendLine($"{indent}#region auto-generated functions")
            .AppendLine();
            foreach (var nickname in allNickNames)
            {
                try
                {
                    stringBuilder.AppendLine(GenerateFunction(nickname, indent));
                }
                catch (Exception)
                {
                    // ignore
                }
            }

            stringBuilder.AppendLine($"{indent}#endregion")
            .AppendLine()
            .AppendLine($"{indent}#region auto-generated properties")
            .AppendLine();

            var tmpFile       = Image.NewTempFile("%s.v");
            var allProperties = tmpFile.GetFields();

            foreach (var property in allProperties)
            {
                var type = GValue.GTypeToCSharp(tmpFile.GetTypeOf(property));
                stringBuilder.AppendLine($"{indent}/// <summary>")
                .AppendLine($"{indent}/// {tmpFile.GetBlurb(property)}")
                .AppendLine($"{indent}/// </summary>")
                .AppendLine($"{indent}public {type} {property.ToPascalCase()} => ({type})Get(\"{property}\");")
                .AppendLine();
            }

            stringBuilder.AppendLine($"{indent}#endregion")
            .AppendLine("    }")
            .AppendLine("}");

            return(stringBuilder.ToString());
        }
Exemplo n.º 6
0
        /// <summary>
        /// Make a C#-style docstring + function.
        /// </summary>
        /// <remarks>
        /// This is used to generate the functions in <see cref="Image"/>.
        /// </remarks>
        /// <param name="operationName"></param>
        /// <param name="indent"></param>
        /// <param name="outParameters"></param>
        /// <returns></returns>
        private static string GenerateFunction(string operationName, string indent = "        ",
                                               string[] outParameters = null)
        {
            var op = NewFromName(operationName);

            if ((op.GetFlags() & Internal.Enums.VipsOperationFlags.VIPS_OPERATION_DEPRECATED) != 0)
            {
                throw new Exception($"No such operator. Operator \"{operationName}\" is deprecated");
            }

            // we are only interested in non-deprecated args
            var arguments = op.GetArgs()
                            .Where(x => (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_DEPRECATED) == 0)
                            .ToList();

            // find the first required input image arg, if any ... that will be self
            string memberX = null;

            foreach (var entry in arguments)
            {
                var name = entry.Key;
                var flag = entry.Value;

                if ((flag & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_INPUT) != 0 &&
                    (flag & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) != 0 &&
                    op.GetTypeOf(name) == GValue.ImageType)
                {
                    memberX = name;
                    break;
                }
            }

            string[] reservedKeywords =
            {
                "in", "ref", "out", "ushort"
            };

            var requiredInput = arguments.Where(x =>
                                                (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_INPUT) != 0 &&
                                                (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) != 0 &&
                                                x.Key != memberX)
                                .Select(x => x.Key)
                                .ToArray();
            var optionalInput = arguments.Where(x =>
                                                (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_INPUT) != 0 &&
                                                (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) == 0)
                                .Select(x => x.Key)
                                .ToArray();
            var requiredOutput = arguments.Where(x =>
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_OUTPUT) != 0 &&
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) != 0 ||
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_INPUT) != 0 &&
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) != 0 &&
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_MODIFY) != 0)
                                 .Select(x => x.Key)
                                 .ToArray();

            string SafeIdentifier(string name) =>
            reservedKeywords.Contains(name)
                    ? "@" + name
                    : name;

            string SafeCast(string type, string name = "result")
            {
                switch (type)
                {
                case "GObject":
                case "Image":
                case "int[]":
                case "double[]":
                case "byte[]":
                case "Image[]":
                case "object[]":
                    return($" as {type};");

                case "int":
                case "double":
                    return($" is {type} {name} ? {name} : 0;");

                case "bool":
                    return($" is {type} {name} && {name};");

                case "string":
                    return($" is {type} {name} ? {name} : null;");

                default:
                    return(";");
                }
            }

            string ToNullable(string type, string name)
            {
                switch (type)
                {
                case "Image[]":
                case "object[]":
                case "int[]":
                case "double[]":
                case "byte[]":
                case "GObject":
                case "Image":
                case "string":
                    return($"{type} {name} = null");

                case "int":
                case "double":
                case "bool":
                    return($"{type}? {name} = null");

                default:
                    throw new Exception("Unsupported type: " + type);
                }
            }

            string CheckNullable(string type, string name)
            {
                switch (type)
                {
                case "Image[]":
                case "object[]":
                case "int[]":
                case "double[]":
                case "byte[]":
                    return($"{name} != null && {name}.Length > 0");

                case "GObject":
                case "string":
                    return($"{name} != null");

                case "int":
                case "double":
                case "bool":
                    return($"{name}.HasValue");

                case "Image":
                    return($"!({name} is null)");

                default:
                    throw new Exception("Unsupported type: " + type);
                }
            }

            var result = new StringBuilder($"{indent}/// <summary>\n");

            var newOperationName = operationName.ToPascalCase();

            var description = op.GetDescription();

            result.AppendLine($"{indent}/// {description.FirstLetterToUpper()}")
            .AppendLine($"{indent}/// </summary>")
            .AppendLine($"{indent}/// <example>")
            .AppendLine($"{indent}/// <code language=\"lang-csharp\">")
            .Append($"{indent}/// ");

            if (requiredOutput.Length == 1)
            {
                var name = requiredOutput[0];
                result.Append(
                    $"{GValue.GTypeToCSharp(op.GetTypeOf(name))} {SafeIdentifier(name).ToPascalCase().FirstLetterToLower()} = ");
            }
            else if (requiredOutput.Length > 1)
            {
                result.Append("var output = ");
            }

            result.Append(memberX ?? "NetVips.Image")
            .Append(
                $".{newOperationName}({string.Join(", ", requiredInput.Select(x => SafeIdentifier(x).ToPascalCase().FirstLetterToLower()).ToArray())}");

            if (outParameters != null)
            {
                if (requiredInput.Length > 0)
                {
                    result.Append(", ");
                }

                result.Append(
                    $"{string.Join(", ", outParameters.Select(name => $"out var {SafeIdentifier(name).ToPascalCase().FirstLetterToLower()}").ToArray())}");
            }

            if (optionalInput.Length > 0)
            {
                if (requiredInput.Length > 0 || outParameters != null)
                {
                    result.Append(", ");
                }

                for (var i = 0; i < optionalInput.Length; i++)
                {
                    var optionalName = optionalInput[i];
                    result.Append(
                        $"{SafeIdentifier(optionalName).ToPascalCase().FirstLetterToLower()}: {GValue.GTypeToCSharp(op.GetTypeOf(optionalName))}")
                    .Append(i != optionalInput.Length - 1 ? ", " : "");
                }
            }

            result.AppendLine(");");

            result.AppendLine($"{indent}/// </code>")
            .AppendLine($"{indent}/// </example>");

            foreach (var requiredName in requiredInput)
            {
                result.AppendLine(
                    $"{indent}/// <param name=\"{requiredName.ToPascalCase().FirstLetterToLower()}\">{op.GetBlurb(requiredName)}</param>");
            }

            if (outParameters != null)
            {
                foreach (var outParameter in outParameters)
                {
                    result.AppendLine(
                        $"{indent}/// <param name=\"{outParameter.ToPascalCase().FirstLetterToLower()}\">{op.GetBlurb(outParameter)}</param>");
                }
            }

            foreach (var optionalName in optionalInput)
            {
                result.AppendLine(
                    $"{indent}/// <param name=\"{optionalName.ToPascalCase().FirstLetterToLower()}\">{op.GetBlurb(optionalName)}</param>");
            }

            string outputType;

            var outputTypes = requiredOutput.Select(name => GValue.GTypeToCSharp(op.GetTypeOf(name))).ToArray();

            if (outputTypes.Length == 1)
            {
                outputType = outputTypes[0];
            }
            else if (outputTypes.Length == 0)
            {
                outputType = "void";
            }
            else if (outputTypes.Any(o => o != outputTypes[0]))
            {
                outputType = $"{outputTypes[0]}[]";
            }
            else
            {
                outputType = "object[]";
            }

            string ToCref(string name) =>
            name.Equals("Image") || name.Equals("GObject") ? $"new <see cref=\"{name}\"/>" : name;

            if (outputType.EndsWith("[]"))
            {
                result.AppendLine(
                    $"{indent}/// <returns>An array of {ToCref(outputType.Remove(outputType.Length - 2))}s</returns>");
            }
            else if (!outputType.Equals("void"))
            {
                result.AppendLine($"{indent}/// <returns>A {ToCref(outputType)}</returns>");
            }

            result.Append($"{indent}public ")
            .Append(memberX == null ? "static " : "")
            .Append(outputType)
            .Append(
                $" {newOperationName}({string.Join(", ", requiredInput.Select(name => $"{GValue.GTypeToCSharp(op.GetTypeOf(name))} {SafeIdentifier(name).ToPascalCase().FirstLetterToLower()}").ToArray())}");

            if (outParameters != null)
            {
                if (requiredInput.Length > 0)
                {
                    result.Append(", ");
                }

                result.Append(string.Join(", ",
                                          outParameters.Select(name =>
                                                               $"out {GValue.GTypeToCSharp(op.GetTypeOf(name))} {SafeIdentifier(name).ToPascalCase().FirstLetterToLower()}")
                                          .ToArray()));
            }

            if (optionalInput.Length > 0)
            {
                if (requiredInput.Length > 0 || outParameters != null)
                {
                    result.Append(", ");
                }

                result.Append(string.Join(", ",
                                          optionalInput.Select(name =>
                                                               $"{ToNullable(GValue.GTypeToCSharp(op.GetTypeOf(name)), SafeIdentifier(name).ToPascalCase().FirstLetterToLower())}")
                                          .ToArray()));
            }

            result.AppendLine(")")
            .AppendLine($"{indent}{{");

            if (optionalInput.Length > 0)
            {
                result.AppendLine($"{indent}    var options = new VOption();").AppendLine();

                foreach (var optionalName in optionalInput)
                {
                    var safeIdentifier = SafeIdentifier(optionalName).ToPascalCase().FirstLetterToLower();

                    result.Append($"{indent}    if (")
                    .Append(CheckNullable(GValue.GTypeToCSharp(op.GetTypeOf(optionalName)), safeIdentifier))
                    .AppendLine(")")
                    .AppendLine($"{indent}    {{")
                    .AppendLine($"{indent}        options.Add(\"{optionalName}\", {safeIdentifier});")
                    .AppendLine($"{indent}    }}")
                    .AppendLine();
                }
            }

            if (outParameters != null)
            {
                if (optionalInput.Length > 0)
                {
                    foreach (var outParameterName in outParameters)
                    {
                        result.AppendLine($"{indent}    options.Add(\"{outParameterName}\", true);");
                    }
                }
                else
                {
                    result.AppendLine($"{indent}    var optionalOutput = new VOption")
                    .AppendLine($"{indent}    {{");
                    for (var i = 0; i < outParameters.Length; i++)
                    {
                        var outParameterName = outParameters[i];
                        result.Append($"{indent}        {{\"{outParameterName}\", true}}")
                        .AppendLine(i != outParameters.Length - 1 ? "," : "");
                    }

                    result.AppendLine($"{indent}    }};");
                }

                result.AppendLine()
                .Append($"{indent}    var results = ")
                .Append(memberX == null ? "Operation" : "this")
                .Append($".Call(\"{operationName}\"")
                .Append(optionalInput.Length > 0 ? ", options" : ", optionalOutput");
            }
            else
            {
                result.Append($"{indent}    ");
                if (outputType != "void")
                {
                    result.Append("return ");
                }

                result.Append(memberX == null ? "Operation" : "this")
                .Append($".Call(\"{operationName}\"");
                if (optionalInput.Length > 0)
                {
                    result.Append(", options");
                }
            }

            if (requiredInput.Length > 0)
            {
                result.Append(", ");

                // Co-variant array conversion from Image[] to object[] can cause run-time exception on write operation.
                // So we need to wrap the image array into a object array.
                var needToWrap = requiredInput.Length == 1 &&
                                 GValue.GTypeToCSharp(op.GetTypeOf(requiredInput[0])).Equals("Image[]");
                if (needToWrap)
                {
                    result.Append("new object[] {");
                }

                result.Append(string.Join(", ",
                                          requiredInput.Select(x => SafeIdentifier(x).ToPascalCase().FirstLetterToLower()).ToArray()));

                if (needToWrap)
                {
                    result.Append("}");
                }
            }

            result.Append(")");

            if (outParameters != null)
            {
                result.AppendLine(" as object[];");
                if (outputType != "void")
                {
                    result.Append($"{indent}    var finalResult = results?[0]")
                    .Append(SafeCast(outputType));
                }
            }
            else
            {
                result.Append(SafeCast(outputType))
                .AppendLine();
            }

            if (outParameters != null)
            {
                result.AppendLine()
                .AppendLine($"{indent}    var opts = results?[1] as VOption;");
                for (var i = 0; i < outParameters.Length; i++)
                {
                    var outParameter = outParameters[i];
                    result.Append(
                        $"{indent}    {SafeIdentifier(outParameter).ToPascalCase().FirstLetterToLower()} = opts?[\"{outParameter}\"]")
                    .AppendLine(SafeCast(GValue.GTypeToCSharp(op.GetTypeOf(outParameter)), $"out{i + 1}"));
                }

                if (outputType != "void")
                {
                    result.AppendLine()
                    .Append($"{indent}    return finalResult;")
                    .AppendLine();
                }
            }

            result.Append($"{indent}}}")
            .AppendLine();

            var optionalOutput = arguments.Where(x =>
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_OUTPUT) != 0 &&
                                                 (x.Value & Internal.Enums.VipsArgumentFlags.VIPS_ARGUMENT_REQUIRED) == 0)
                                 .Select(x => x.Key)
                                 .ToArray();

            // Create method overloading if necessary
            if (optionalOutput.Length > 0 && outParameters == null)
            {
                result.AppendLine()
                .Append(GenerateFunction(operationName, indent, new[] { optionalOutput[0] }));
            }
            else if (outParameters != null && outParameters.Length != optionalOutput.Length)
            {
                result.AppendLine()
                .Append(GenerateFunction(operationName, indent,
                                         optionalOutput.Take(outParameters.Length + 1).ToArray()));
            }

            return(result.ToString());
        }