public async Task <ImageInputModel> SaveImageAsync(IFormFile formFile)
        {
            var isValid = new ImageAttribute().IsValid(formFile);

            if (formFile == null || !isValid)
            {
                return(null);
            }

            var guid      = Guid.NewGuid().ToString();
            var extension = await Image.DetectFormatAsync(formFile.OpenReadStream());

            var source   = $"/img/{guid}.{extension.Name}";
            var filePath = $"{this.environment.ContentRootPath}/wwwroot{source}";

            using var stream = new FileStream(filePath, FileMode.Create);
            await formFile.CopyToAsync(stream);

            var imageInputModel = new ImageInputModel
            {
                Source = source,
            };

            return(imageInputModel);
        }
Beispiel #2
0
        public ImageVaueEditor(PropertyGridLabel label, PropertyItem property)
            : base(label, property)
        {
            property.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(property_PropertyChanged);
            property.ValueError += new EventHandler<ExceptionEventArgs>(property_ValueError);

            _attribute = property.GetAttribute<ImageAttribute>();

            if(null == _attribute)
            {
                _attribute = new ImageAttribute();
                _attribute.OnlyImage = false;
            }
            _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1d, GridUnitType.Auto) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition());
            _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1d, GridUnitType.Auto) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1d, GridUnitType.Auto) });
            _grid.Children.Add(_image);
            _grid.Children.Add(_text);
            _grid.Children.Add(_removeButton);
            _grid.Children.Add(_broswerButton);
            _image.SetValue(Grid.ColumnProperty, 0);
            _text.SetValue(Grid.ColumnProperty, 1);
            _removeButton.SetValue(Grid.ColumnProperty, 2);
            _broswerButton.SetValue(Grid.ColumnProperty, 3);
            this.Content = _grid;
            _broswerButton.Click += BroswerButton_Click;
            _removeButton.Click += RemoveButton_Click;
            UpdateLabel(property.Value);
            _text.GotFocus += Text_GotFocus;
            _text.Background = null;
            _text.BorderBrush = null;
            _text.BorderThickness = new Thickness();
        }
Beispiel #3
0
        /// <summary>
        /// 画像を反転します。
        /// </summary>
        /// <param name="bitmap">ビットマップ</param>
        /// <returns>ビットマップ</returns>
        public static BitmapSource Reverse(BitmapSource bitmap)
        {
            var            writeableBitmap = new WriteableBitmap(bitmap);
            ImageAttribute attr            = writeableBitmap.GetAttribute();

            writeableBitmap.Lock();
            unsafe {
                byte *pBackBuffer = (byte *)((void *)writeableBitmap.BackBuffer);
                for (int y = 0; y < attr.Height; ++y)
                {
                    for (int x = 0; x < attr.Width; ++x)
                    {
                        byte b = pBackBuffer[0];
                        byte g = pBackBuffer[1];
                        byte r = pBackBuffer[2];

                        pBackBuffer[0] = (byte)(byte.MaxValue - b);
                        pBackBuffer[1] = (byte)(byte.MaxValue - g);
                        pBackBuffer[2] = (byte)(byte.MaxValue - r);

                        pBackBuffer += attr.Channel;
                    }
                    pBackBuffer += attr.Residue;
                }
            }
            // 変更箇所の通知
            writeableBitmap.AddDirtyRect(
                new System.Windows.Int32Rect(0, 0, attr.Width, attr.Height));

            writeableBitmap.Unlock();

            return(writeableBitmap);
        }
Beispiel #4
0
        public async Task <ImageInputModel> SaveImageAsync(IFormFile formFile)
        {
            var isValid = new ImageAttribute().IsValid(formFile);

            if (formFile == null || !isValid)
            {
                return(null);
            }

            var guid      = Guid.NewGuid().ToString();
            var extension = await Image.DetectFormatAsync(formFile.OpenReadStream());

            var fileName   = $"{guid}.{extension.Name}";
            var cloudinary = new Cloudinary(this.account);

            var uploadParams = new ImageUploadParams()
            {
                File = new FileDescription(fileName, formFile.OpenReadStream()),
            };

            var uploadResult = await cloudinary.UploadAsync(uploadParams);

            var imageInput = new ImageInputModel()
            {
                Source = uploadResult.SecureUrl.AbsoluteUri,
            };

            return(imageInput);
        }
        static Tuple <string, string> GetImageInfo(ImageAttribute image, DXImageAttribute dxImage, string defaultImageName, Func <string, bool, string> getKnownImageUriCallback)
        {
            if (image != null)
            {
                return(Tuple.Create(image.ImageUri, (string)null));
            }
            string imageName = dxImage.With(x => x.ImageName) ?? defaultImageName;

            return(Tuple.Create(dxImage.With(x => x.SmallImageUri) ?? GetKnownImageUri(getKnownImageUriCallback, imageName, false),
                                dxImage.With(x => x.LargeImageUri) ?? GetKnownImageUri(getKnownImageUriCallback, imageName, true)));
        }
Beispiel #6
0
        public static ValueEditorBase CreateValueEdiorBase(PropertyItem item)
        {
            ImageAttribute imageAttribute = AttributeServices.GetAttribute <ImageAttribute>(item.PropertyInfo);

            if (null != imageAttribute)
            {
                return(new ImageValueEditor(item, imageAttribute));
            }
            if (typeof(Boolean).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new BooleanValueEditor(item));
            }
            if (typeof(Color).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new ColorValueEditor(item));
            }
            if (typeof(Brush).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new ColorValueEditor(item));
            }
            if (typeof(Thickness).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new ThicknessValueEditor(item));
            }
            if (typeof(CornerRadius).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new CornerRadiusValueEditor(item));
            }
            if (typeof(FontFamily).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new FontFamilyValueEditor(item));
            }
            if (typeof(FontStyle).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new FontStyleValueEditor(item));
            }
            if (typeof(FontWeight).IsAssignableFrom(item.PropertyInfo.PropertyType))
            {
                return(new FontWeightValueEditor(item));
            }


            // ------------------------------------------------------------------------
            if (typeof(Enum).IsAssignableFrom(item.PropertyInfo.PropertyType) ||
                null != item.Property.Source)
            {
                return(new EnumValueEditor(item));
            }
            return(new StringValueEditor(item));
        }
Beispiel #7
0
        /// <summary>
        /// ローパスフィルタを掛けた画像を取得します。
        /// </summary>
        /// <param name="bitmap">ビットマップ</param>
        /// <returns>ビットマップ</returns>
        public static BitmapSource LowPassFilter(BitmapSource bitmap)
        {
            var            writeableBitmap = new WriteableBitmap(bitmap);
            ImageAttribute attr            = writeableBitmap.GetAttribute();

            writeableBitmap.Lock();
            unsafe {
                byte *pBackBuffer = (byte *)((void *)writeableBitmap.BackBuffer);

                var neighborhoods = new int[] {
                    -attr.Channel - attr.Stride, 0 - attr.Stride, attr.Channel - attr.Stride,
                    -attr.Channel, 0, attr.Channel,
                    -attr.Channel + attr.Stride, 0 + attr.Stride, attr.Channel + attr.Stride
                };

                // 3 * 3 マスの平均を取る (端は省略)
                for (int y = 1; y < attr.Height - 1; ++y)
                {
                    for (int x = 1; x < attr.Width - 1; ++x)
                    {
                        byte b = pBackBuffer[0];
                        byte g = pBackBuffer[1];
                        byte r = pBackBuffer[2];

                        int baseIndex = x * attr.Channel + y * attr.Stride;

                        int sumB = 0;
                        int sumG = 0;
                        int sumR = 0;
                        for (int i = 0; i < neighborhoods.Length; ++i)
                        {
                            sumB += pBackBuffer[baseIndex + neighborhoods[i] + 0];
                            sumG += pBackBuffer[baseIndex + neighborhoods[i] + 1];
                            sumR += pBackBuffer[baseIndex + neighborhoods[i] + 2];
                        }

                        pBackBuffer[baseIndex + 0] = (byte)(sumB / neighborhoods.Length);
                        pBackBuffer[baseIndex + 1] = (byte)(sumG / neighborhoods.Length);
                        pBackBuffer[baseIndex + 2] = (byte)(sumR / neighborhoods.Length);
                    }
                }
            }
            // 変更箇所の通知
            writeableBitmap.AddDirtyRect(
                new System.Windows.Int32Rect(0, 0, attr.Width, attr.Height));

            writeableBitmap.Unlock();

            return(writeableBitmap);
        }
Beispiel #8
0
        public void TestImageAttribute()
        {
            Image a;

            var absolutePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Resources\ImageAttributeTest1.bmp");

            a = new ImageAttribute(absolutePath).Image;
            Assert.IsNotNull(a, "ImageAttribute (file): BMP Absolute File Path");

            a = new ImageAttribute(@"Resources\ImageAttributeTest5.ico").Image;
            Assert.IsNotNull(a, "ImageAttribute (file): ICO Relative File Path: Copy Local");

            a = new ImageAttribute(@"Resources\ImageAttributeTest2.tif").Image;
            Assert.IsNotNull(a, "ImageAttribute (file): TIF Relative File Path: Copy Local");

            a = new ImageAttribute(@"Resources\ImageAttributeTest3.jpg").Image;
            Assert.IsNotNull(a, "ImageAttribute (file): JPG Relative File Path: Copy Local");

            a = new ImageAttribute(@"Resources\ImageAttributeTest4.png").Image;
            Assert.IsNotNull(a, "ImageAttribute (file): PNG Relative File Path: Copy Local");

            a = new ImageAttribute(typeof(TestForm)).Image;
            Assert.IsNotNull(a, "ImageAttribute (manifest): typeof(FormMain) => FormMain.png");

            //Manually adding anything to a Form resource will will be erased by the designer.... However we can access designer-generated resources...
            a = new ImageAttribute(typeof(TestForm), "$this.BackgroundImage").Image;
            Assert.IsNotNull(a, "ImageAttribute (Form resource): typeof(FormMain) => $this.BackgroundImage");

            a = new ImageAttribute(typeof(TestForm), "$this.Icon").Image;
            Assert.IsNotNull(a, "ImageAttribute (Form resource): typeof(FormMain) => $this.Icon");

            a = new ImageAttribute(typeof(Panel)).Image;
            Assert.IsNotNull(a, "ImageAttribute (manifest): typeof(Panel) => Panel.bmp");

            a = new ImageAttribute(typeof(Panel), "CheckBox").Image;
            Assert.IsNotNull(a, "ImageAttribute (manifest): typeof(Panel),CheckBox => CheckBox.bmp");

            a = new ImageAttribute(typeof(Panel), "CheckBox.jpg").Image;
            Assert.IsNotNull(a, "ImageAttribute (manifest): typeof(Panel),CheckBox.jpg => CheckBox.bmp");

            a = new ImageAttribute(typeof(Panel), "checkbox").Image;
            Assert.IsNull(a, "ImageAttribute (manifest): typeof(Panel),checkbox => not case-sensitive");

            a = new ImageAttribute(this.GetType(), "ImageAttributeTest5").Image;
            Assert.IsNotNull(a, "ImageAttribute (manifest): typeof(this),ImageAttributeTest5 => ImageAttributeTest5.ico");
            Assert.IsTrue(a.Width == 32 && a.Height == 32, "ImageAttribute (manifest): typeof(this),ImageAttributeTest5 => ImageAttributeTest5.ico not 32x32");
        }
Beispiel #9
0
 public ImageValueEditor(PropertyItem item, ImageAttribute imageAttribute)
     : base(item)
 {
     _typeEnum       = TypeEnum.Other;
     _imageAttribute = imageAttribute;
     if (null != _imageAttribute)
     {
         if (typeof(string).IsAssignableFrom(item.PropertyInfo.PropertyType))
         {
             _typeEnum = TypeEnum.String;
         }
         else if (typeof(byte[]).IsAssignableFrom(item.PropertyInfo.PropertyType))
         {
             _typeEnum = TypeEnum.ByteArray;
         }
         Layout();
     }
     UpdateValue(item.Value);
 }
Beispiel #10
0
        /// <summary>
        /// グレースケール画像を取得します。
        /// </summary>
        /// <param name="bitmap">ビットマップ</param>
        /// <returns>ビットマップ</returns>
        public static BitmapSource GrayScale(BitmapSource bitmap)
        {
            var            writeableBitmap = new WriteableBitmap(bitmap);
            ImageAttribute attr            = writeableBitmap.GetAttribute();

            writeableBitmap.Lock();
            unsafe {
                byte *pBackBuffer = (byte *)((void *)writeableBitmap.BackBuffer);
                for (int y = 0; y < attr.Height; ++y)
                {
                    for (int x = 0; x < attr.Width; ++x)
                    {
                        byte b = pBackBuffer[0];
                        byte g = pBackBuffer[1];
                        byte r = pBackBuffer[2];

                        var gray = (byte)(0.3 * r + 0.59 * g + 0.11 * b);
                        if (gray > byte.MaxValue)
                        {
                            gray = byte.MaxValue;
                        }
                        else if (gray < 0)
                        {
                            gray = 0;
                        }

                        pBackBuffer[0] = gray;
                        pBackBuffer[1] = gray;
                        pBackBuffer[2] = gray;

                        pBackBuffer += attr.Channel;
                    }
                    pBackBuffer += attr.Residue;
                }
            }
            // 変更箇所の通知
            writeableBitmap.AddDirtyRect(
                new System.Windows.Int32Rect(0, 0, attr.Width, attr.Height));

            writeableBitmap.Unlock();

            return(writeableBitmap);
        }
Beispiel #11
0
 public ImageValueEditor(PropertyItem item, ImageAttribute imageAttribute)
     : base(item)
 {
     _typeEnum = TypeEnum.Other;
     _imageAttribute = imageAttribute;
     if (null != _imageAttribute)
     {
         if (typeof(string).IsAssignableFrom(item.PropertyInfo.PropertyType))
         {
             _typeEnum = TypeEnum.String;
         }
         else if (typeof(byte[]).IsAssignableFrom(item.PropertyInfo.PropertyType))
         {
             _typeEnum = TypeEnum.ByteArray;
         }
         Layout();
     }
     UpdateValue(item.Value);
 }
Beispiel #12
0
        public FormDefinition GetDefinition(string xml, bool freeze)
        {
            var document = XDocument.Parse(xml);

            if (document.Root == null)
            {
                throw new InvalidOperationException("Invalid XML document.");
            }

            void AddMetadata(IDictionary <string, string> dict, XElement xelement)
            {
                const int stroffset = 5; // "meta-".Length

                foreach (var attr in xelement.Attributes())
                {
                    if (attr.Name.LocalName.StartsWith("meta-", StringComparison.OrdinalIgnoreCase))
                    {
                        dict[attr.Name.LocalName.Substring(stroffset)] = attr.Value;
                    }
                }
            }

            FormElement WithMetadata(FormElement element, XElement xelement)
            {
                AddMetadata(element.Metadata, xelement);
                return(element);
            }

            ILayout Terminal(XElement element)
            {
                var         elementName = element.Name.LocalName.ToLower();
                FormElement formElement;

                switch (elementName)
                {
                case "layout":
                    return(Layout(element));

                case "input":
                case "textarea":
                case "toggle":
                case "password":
                {
                    var  typeName   = element.TryGetAttribute("type") ?? "string";
                    var  attributes = new List <Attribute>();
                    Type propertyType;
                    if (elementName == "input" && TypeConstructors.TryGetValue(typeName, out var constructor))
                    {
                        var data = constructor(new XmlConstructionContext(element));
                        propertyType = data.PropertyType;
                        attributes.AddRange(data.CustomAttributes);
                    }
                    else if (!TypeNames.TryGetValue(typeName, out propertyType))
                    {
                        throw new InvalidOperationException($"Type '{typeName}' not found.");
                    }

                    var fieldName = element.TryGetAttribute("name");
                    attributes.Add(Utilities.GetFieldAttributeFromElement(element));
                    attributes.Add(Utilities.GetBindingAttributeFromElement(element));

                    switch (elementName)
                    {
                    case "textarea":
                        attributes.Add(new MultiLineAttribute());
                        propertyType = typeof(string);
                        break;

                    case "toggle":
                        attributes.Add(new ToggleAttribute());
                        propertyType = typeof(bool);
                        break;

                    case "password":
                        attributes.Add(new PasswordAttribute());
                        propertyType = typeof(string);
                        break;
                    }

                    attributes.AddRange(Utilities.GetValidatorsFromElement(element));
                    var property     = new DynamicProperty(fieldName, propertyType, attributes.ToArray());
                    var deserializer = TryGetDeserializer(propertyType);
                    formElement = Build(property, deserializer);
                    if (formElement != null)
                    {
                        foreach (var initializer in FieldInitializers)
                        {
                            initializer.Initialize(formElement, property, deserializer);
                        }

                        formElement.LinePosition = (Position)(-1);
                    }

                    return(new FormElementLayout(WithMetadata(formElement, element)));
                }

                case "select":
                {
                    var    from = element.TryGetAttribute("from");
                    object itemsSource;
                    string typeName;
                    string displayPath;
                    string valuePath;
                    Type   propertyType = null;
                    if (!string.IsNullOrEmpty(from))
                    {
                        if (from.StartsWith("type:"))
                        {
                            var qualifiedType = from.Substring("type:".Length);
                            var nullable      = false;
                            if (qualifiedType.EndsWith("?"))
                            {
                                qualifiedType = qualifiedType.Substring(0, qualifiedType.Length - 1);
                                nullable      = true;
                            }

                            propertyType = Utilities.FindTypes(t => t.FullName == qualifiedType).FirstOrDefault();
                            itemsSource  = propertyType ?? throw new InvalidOperationException($"Could not find type '{qualifiedType}'.");

                            if (propertyType.IsValueType && nullable)
                            {
                                propertyType = typeof(Nullable <>).MakeGenericType(propertyType);
                                itemsSource  = propertyType;
                            }

                            typeName = element.TryGetAttribute("type");
                        }
                        else
                        {
                            itemsSource = from;
                            typeName    = element.TryGetAttribute("type") ?? "string";
                        }

                        displayPath = element.TryGetAttribute("displayPath");
                        valuePath   = element.TryGetAttribute("valuePath");
                    }
                    else
                    {
                        typeName    = "string";
                        displayPath = "Name";
                        valuePath   = "Value";
                        itemsSource = Utilities.GetSelectOptionsFromElement(element);
                    }

                    if (typeName != null && !TypeNames.TryGetValue(typeName, out propertyType))
                    {
                        throw new InvalidOperationException($"Type '{typeName}' not found.");
                    }

                    if (propertyType.IsValueType &&
                        element.TryGetAttribute("nullable") != null &&
                        (!propertyType.IsGenericType || propertyType.GetGenericTypeDefinition() != typeof(Nullable <>)))
                    {
                        propertyType = typeof(Nullable <>).MakeGenericType(propertyType);
                    }

                    var fieldName  = element.TryGetAttribute("name");
                    var attributes = new List <Attribute>
                    {
                        new SelectFromAttribute(itemsSource)
                        {
                            SelectionType    = Utilities.TryParse(element.TryGetAttribute("as"), SelectionType.ComboBox),
                            DisplayPath      = displayPath,
                            ValuePath        = valuePath,
                            ItemStringFormat = element.TryGetAttribute("itemStringFormat")
                        },
                        Utilities.GetFieldAttributeFromElement(element),
                        Utilities.GetBindingAttributeFromElement(element)
                    };

                    attributes.AddRange(Utilities.GetValidatorsFromElement(element));
                    var property     = new DynamicProperty(fieldName, propertyType, attributes.ToArray());
                    var deserializer = TryGetDeserializer(propertyType);
                    formElement = Build(property, deserializer);
                    if (formElement != null)
                    {
                        foreach (var initializer in FieldInitializers)
                        {
                            initializer.Initialize(formElement, property, deserializer);
                        }

                        formElement.LinePosition = (Position)(-1);
                    }

                    return(new FormElementLayout(WithMetadata(formElement, element)));
                }

                case "title":
                    formElement = new TitleAttribute(element.GetAttributeOrValue("content"))
                    {
                        Icon = element.TryGetAttribute("icon")
                    }
                    .WithBaseProperties(element)
                    .WithTextProperties(element)
                    .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "heading":
                    formElement = new HeadingAttribute(element.GetAttributeOrValue("content"))
                    {
                        Icon = element.TryGetAttribute("icon")
                    }
                    .WithBaseProperties(element)
                    .WithTextProperties(element)
                    .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "text":
                    formElement = new TextAttribute(element.GetAttributeOrValue("content"))
                                  .WithBaseProperties(element)
                                  .WithTextProperties(element)
                                  .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "error":
                    formElement = new ErrorTextAttribute(element.GetAttributeOrValue("content"))
                                  .WithBaseProperties(element)
                                  .WithTextProperties(element)
                                  .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "img":
                    formElement = new ImageAttribute(element.TryGetAttribute("src"))
                    {
                        Width  = element.TryGetAttribute("width"),
                        Height = element.TryGetAttribute("height"),
                        HorizontalAlignment = element.TryGetAttribute("align"),
                        VerticalAlignment   = element.TryGetAttribute("valign"),
                        Stretch             = element.TryGetAttribute("stretch"),
                        StretchDirection    = element.TryGetAttribute("direction")
                    }
                    .WithBaseProperties(element)
                    .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "br":
                    formElement = new BreakAttribute
                    {
                        Height = element.TryGetAttribute("height")
                    }
                    .WithBaseProperties(element)
                    .GetElement();

                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "hr":
                    var hasMargin = element.TryGetAttribute("hasMargin");
                    formElement = (hasMargin != null
                            ? new DividerAttribute(bool.Parse(hasMargin))
                            : new DividerAttribute())
                                  .WithBaseProperties(element)
                                  .GetElement();

                    return(new FormElementLayout(WithMetadata(formElement, element)));

                case "action":
                    formElement = Utilities.GetAction(element)
                                  .WithBaseProperties(element)
                                  .GetElement();
                    return(new FormElementLayout(WithMetadata(formElement, element)));

                default:
                    throw new InvalidOperationException($"Unknown element '{element.Name.LocalName}'.");
                }
            }

            GridColumnLayout Column(XElement element)
            {
                var elements = element.Elements().ToList();
                var child    = elements.Count == 1
                    ? Row(elements[0])
                    : new Layout(elements.Select(Row));

                return(new GridColumnLayout(
                           child,
                           Utilities.ParseDouble(element.TryGetAttribute("width"), 1d),
                           Utilities.ParseDouble(element.TryGetAttribute("left"), 0d),
                           Utilities.ParseDouble(element.TryGetAttribute("right"), 0d)));
            }

            GridLayout Grid(XElement element)
            {
                return(new GridLayout(
                           element.Elements().Select(Column),
                           Utilities.ParseDouble(element.TryGetAttribute("top"), 0d),
                           Utilities.ParseDouble(element.TryGetAttribute("bottom"), 0d)));
            }

            InlineLayout Inline(XElement element)
            {
                return(new InlineLayout(
                           element.Elements().Select(Terminal),
                           Utilities.ParseDouble(element.TryGetAttribute("top"), 0d),
                           Utilities.ParseDouble(element.TryGetAttribute("bottom"), 0d)));
            }

            ILayout Row(XElement element)
            {
                if (!string.Equals(element.Name.LocalName, "row", StringComparison.OrdinalIgnoreCase))
                {
                    return(Terminal(element));
                }

                if (element
                    .Elements()
                    .All(e => string.Equals(e.Name.LocalName, "col", StringComparison.OrdinalIgnoreCase)))
                {
                    return(Grid(element));
                }

                return(Inline(element));
            }

            Layout Layout(XElement element)
            {
                return(new Layout(
                           element.Elements().Select(Row),
                           Utilities.ParseThickness(element.TryGetAttribute("margin")),
                           Utilities.TryParse(element.TryGetAttribute("valign"), VerticalAlignment.Stretch),
                           Utilities.TryParse(element.TryGetAttribute("align"), HorizontalAlignment.Stretch),
                           Utilities.ParseNullableDouble(element.TryGetAttribute("minHeight")),
                           Utilities.ParseNullableDouble(element.TryGetAttribute("maxHeight"))));
            }

            var form = new FormDefinition(null); // null indicates dynamic type

            AddMetadata(form.Metadata, document.Root);
            form.FormRows.Add(new FormRow(true, 1)
            {
                Elements = { new FormElementContainer(0, 1, Layout(document.Root)) }
            });

            if (freeze)
            {
                form.FreezeAll();
            }

            return(form);
        }