Skip to content

Commit

Permalink
Merge pull request #1185 from mcneel/1.24
Browse files Browse the repository at this point in the history
Fix on `BuildOpacityMap.BuildOpacityMap`.
  • Loading branch information
kike-garbo authored Sep 8, 2024
2 parents 3a838a1 + 7f8bced commit 85238c6
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 51 deletions.
67 changes: 36 additions & 31 deletions src/RhinoInside.Revit.GH/ImageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,47 +143,52 @@ public static Drawing.Bitmap BuildImage(string tag, int width, int height, Drawi

public static Drawing.Bitmap BuildOpacityMap(Drawing.Bitmap bitmap)
{
var rectangle = new Drawing.Rectangle(Drawing.Point.Empty, bitmap.Size);
var opacity = new Drawing.Bitmap(bitmap.Width, bitmap.Height, Drawing.Imaging.PixelFormat.Format8bppIndexed);
var bitmapScanLine = new int[bitmap.Width];
var opacityScanLine = new byte[bitmap.Width];
if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format32bppArgb)
{
var rectangle = new Drawing.Rectangle(Drawing.Point.Empty, bitmap.Size);
var opacity = new Drawing.Bitmap(bitmap.Width, bitmap.Height, Drawing.Imaging.PixelFormat.Format8bppIndexed);
var bitmapScanLine = new int[bitmap.Width];
var opacityScanLine = new byte[bitmap.Width];

var bitmapScanData = bitmap.LockBits(rectangle, Drawing.Imaging.ImageLockMode.WriteOnly, Drawing.Imaging.PixelFormat.Format32bppArgb);
var opacityScanData = opacity?.LockBits(rectangle, Drawing.Imaging.ImageLockMode.WriteOnly, Drawing.Imaging.PixelFormat.Format8bppIndexed);
var bitmapScanData = bitmap.LockBits(rectangle, Drawing.Imaging.ImageLockMode.WriteOnly, Drawing.Imaging.PixelFormat.Format32bppArgb);
var opacityScanData = opacity?.LockBits(rectangle, Drawing.Imaging.ImageLockMode.WriteOnly, Drawing.Imaging.PixelFormat.Format8bppIndexed);

bool isOpaque = true;
for (int y = 0; y < rectangle.Height; ++y)
{
Marshal.Copy(bitmapScanData.Scan0 + (bitmapScanData.Stride * y), bitmapScanLine, 0, rectangle.Width);
for (int x = 0; x < rectangle.Width; ++x)
bool isOpaque = true;
for (int y = 0; y < rectangle.Height; ++y)
{
var color = Drawing.Color.FromArgb(bitmapScanLine[x]);
var colorA = color.A;
if (colorA != byte.MaxValue) isOpaque = false;
opacityScanLine[x] = colorA;
Marshal.Copy(bitmapScanData.Scan0 + (bitmapScanData.Stride * y), bitmapScanLine, 0, rectangle.Width);
for (int x = 0; x < rectangle.Width; ++x)
{
var color = Drawing.Color.FromArgb(bitmapScanLine[x]);
var colorA = color.A;
if (colorA != byte.MaxValue) isOpaque = false;
opacityScanLine[x] = colorA;
}

Marshal.Copy(opacityScanLine, 0, opacityScanData.Scan0 + (opacityScanData.Stride * y), rectangle.Width);
}

Marshal.Copy(opacityScanLine, 0, opacityScanData.Scan0 + (opacityScanData.Stride * y), rectangle.Width);
}
opacity.UnlockBits(opacityScanData);
bitmap.UnlockBits(bitmapScanData);

opacity.UnlockBits(opacityScanData);
bitmap.UnlockBits(bitmapScanData);
if (isOpaque)
{
opacity.Dispose();
opacity = null;
}
else
{
var palette = opacity.Palette;
for (int i = 0; i < byte.MaxValue; ++i)
palette.Entries[i] = Drawing.Color.FromArgb(i, i, i);

if (isOpaque)
{
opacity.Dispose();
opacity = null;
}
else
{
var palette = opacity.Palette;
for (int i = 0; i < byte.MaxValue; ++i)
palette.Entries[i] = Drawing.Color.FromArgb(i, i, i);
opacity.Palette = palette;
}

opacity.Palette = palette;
return opacity;
}

return opacity;
return null;
}
}
}
129 changes: 109 additions & 20 deletions src/RhinoInside.Revit.GH/Types/Instances/ImageInstance.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Collections.Generic;
using Rhino;
using Rhino.Geometry;
using Rhino.Display;
using Rhino.DocObjects;
Expand All @@ -20,7 +22,7 @@ namespace RhinoInside.Revit.GH.Types
#endif

[Kernel.Attributes.Name("Image")]
public class ImageInstance : GraphicalElement
public class ImageInstance : GraphicalElement, Bake.IGH_BakeAwareElement
{
protected override Type ValueType => typeof(ARDB_ImageInstance);
public new ARDB_ImageInstance Value => base.Value as ARDB_ImageInstance;
Expand Down Expand Up @@ -244,6 +246,65 @@ public override Mesh Mesh
}
}
#endregion

#region IGH_BakeAwareElement
bool IGH_BakeAwareData.BakeGeometry(RhinoDoc doc, ObjectAttributes att, out Guid guid) =>
BakeElement(new Dictionary<ARDB.ElementId, Guid>(), true, doc, att, out guid);

public bool BakeElement
(
IDictionary<ARDB.ElementId, Guid> idMap,
bool overwrite,
RhinoDoc doc,
ObjectAttributes att,
out Guid guid
)
{
// 1. Check if is already cloned
if (idMap.TryGetValue(Id, out guid))
return true;

if (Value is ARDB_ImageInstance)
{
att = att?.Duplicate() ?? doc.CreateDefaultAttributes();
att.Name = DisplayName;
if (Category.BakeElement(idMap, false, doc, att, out var layerGuid))
att.LayerIndex = doc.Layers.FindId(layerGuid).Index;

// 3. Update if necessary
if (overwrite)
{
var imagePath = Type.BitmapFilePath;
var plane = Location;
plane = new Plane(plane.Origin - (plane.XAxis * Width.Value * 0.5) - (plane.YAxis * Height.Value * 0.5), plane.XAxis, plane.YAxis);
guid = doc.Objects.AddPictureFrame(plane, imagePath ?? string.Empty, asMesh: false, Width.Value, Height.Value, selfIllumination: false, embedBitmap: true);

if (guid != Guid.Empty && doc.Objects.FindId(guid) is RhinoObject picture)
{
var currentAttributes = picture.Attributes;
currentAttributes.Name = att.Name;
currentAttributes.LayerIndex = att.LayerIndex;
doc.Objects.ModifyAttributes(guid, currentAttributes, quiet: true);

if (picture.RenderMaterial is Rhino.Render.RenderMaterial renderMaterial)
{
renderMaterial.BeginChange(Rhino.Render.RenderContent.ChangeContexts.Program);
renderMaterial.Name = att.Name;
renderMaterial.EndChange();
}
}
}

if (guid != Guid.Empty)
{
idMap.Add(Id, guid);
return true;
}
}

return false;
}
#endregion
}

[Kernel.Attributes.Name("Image Type")]
Expand All @@ -258,9 +319,10 @@ public ImageType(ARDB.ImageType imageType) : base(imageType)

protected override void ResetValue()
{
using (_DisplayMaterial) _DisplayMaterial = null;
using (_DiffuseTexture) _DiffuseTexture = null;
using (_OpacityTexture) _OpacityTexture = null;
using (_Bitmap) _Bitmap = null;
using (_DisplayMaterial) _DisplayMaterial = null;
using (_DiffuseTexture) _DiffuseTexture = null;
using (_OpacityTexture) _OpacityTexture = null;

base.ResetValue();
}
Expand All @@ -279,33 +341,60 @@ public override bool CastTo<Q>(out Q target)
return false;
}

#region Properties
System.Drawing.Bitmap _Bitmap;
System.Drawing.Bitmap Bitmap => _Bitmap is null ? (_Bitmap = Value?.GetImage()) : _Bitmap;

internal string BitmapFilePath
{
get
{
if (Value is ARDB.ImageType type)
{
if (Bitmap is System.Drawing.Bitmap bitmap)
{
var document = Types.Document.FromValue(type.Document);
var path = Path.Combine(document.SwapFolder.Directory.FullName, $"{document.SwapFolder.PrefixOf(this)}-Diffuse.png");

try
{
bitmap.Save(path);
var bitmapFile = new FileInfo(path);
bitmapFile.Attributes |= FileAttributes.Temporary;
return path;
}
catch { }
}
}

return null;
}
}
#endregion

#region Preview
Texture _DiffuseTexture;
Texture _OpacityTexture;
void GetDisplayTextures(out Texture diffuse, out Texture opacity)
{
if (_DiffuseTexture is null)
{
if (Value?.get_Parameter(ARDB.BuiltInParameter.RASTER_SYMBOL_FILENAME)?.AsString() is string imageFilePath)
var diffuseFile = new FileInfo(BitmapFilePath);
if (diffuseFile.Exists)
{
var imageFile = new FileInfo(imageFilePath);
if (imageFile.Exists)
_DiffuseTexture = new Texture() { FileName = diffuseFile.FullName };

var diffuseBitmap = Bitmap;
{
var document = Types.Document.FromValue(Document);
var diffuseFile = document.SwapFolder.CopyFrom(this, imageFile, "-Diffuse");
_DiffuseTexture = new Texture() { FileName = diffuseFile.FullName };

using (var diffuseBitmap = new System.Drawing.Bitmap(diffuseFile.FullName))
var opacityFile = new FileInfo(Path.Combine(document.SwapFolder.Directory.FullName, document.SwapFolder.PrefixOf(this) + "-Opacity" + ".png"));
if (ImageBuilder.BuildOpacityMap(diffuseBitmap) is System.Drawing.Bitmap opacityBitmap)
{
var opacityFile = new FileInfo(Path.Combine(document.SwapFolder.Directory.FullName, document.SwapFolder.PrefixOf(this) + "-Opacity" + ".png"));
if (ImageBuilder.BuildOpacityMap(diffuseBitmap) is System.Drawing.Bitmap opacityBitmap)
{
opacityBitmap.Save(opacityFile.FullName, System.Drawing.Imaging.ImageFormat.Png);
opacityBitmap.Dispose();

opacityFile.Attributes |= FileAttributes.Temporary;
_OpacityTexture = new Texture() { FileName = opacityFile.FullName };
}
opacityBitmap.Save(opacityFile.FullName, System.Drawing.Imaging.ImageFormat.Png);
opacityBitmap.Dispose();

opacityFile.Attributes |= FileAttributes.Temporary;
_OpacityTexture = new Texture() { FileName = opacityFile.FullName };
}
}
}
Expand Down

0 comments on commit 85238c6

Please sign in to comment.