Delphi graphics32将图层保存为透明PNG出错
我有一个奇怪的问题,我想我解决不了。 我有一个包含层(透明png图像)的ImgView,我打算将所有层保存为png文件(就像“保存项目”一样),以便以后我可以重新打开它们并将它们放在我留下的地方。(就像“开放项目”一样) 这是我的问题,以下步骤效果很好:Delphi graphics32将图层保存为透明PNG出错,delphi,graphics32,Delphi,Graphics32,我有一个奇怪的问题,我想我解决不了。 我有一个包含层(透明png图像)的ImgView,我打算将所有层保存为png文件(就像“保存项目”一样),以便以后我可以重新打开它们并将它们放在我留下的地方。(就像“开放项目”一样) 这是我的问题,以下步骤效果很好: 我添加图层(透明PNG文件) 我把它们四处移动,放在我想要的地方 我按save project(因此这里我将所有图层保存为png图像文件) 它起作用了 如果我执行以下步骤,则会出现问题: 我添加图层(透明PNG文件) 我把它们四处移动,放在我想
procedure TCustomBitmap32.ResetAlpha(const AlphaValue: Byte);
var
I: Integer;
P: PByteArray;
begin
if not FMeasuringMode then <<<<<------ this line
。。。及
procedure SaveBmpAsPng(bmp:TBitmap32;dest:string);
var
Y: Integer;
X: Integer;
Png: TPortableNetworkGraphic32;
function IsWhite(Color32: TColor32): Boolean;
begin
Result:= (TColor32Entry(Color32).B = 255) and
(TColor32Entry(Color32).G = 255) and
(TColor32Entry(Color32).R = 255);
end;
begin
bmp.ResetAlpha;
for Y := 0 to bmp.Height-1 do
for X := 0 to bmp.Width-1 do
begin
if IsWhite(bmp.Pixel[X, Y]) then
bmp.Pixel[X,Y]:=Color32(255,255,255,0);
end;
Png:= TPortableNetworkGraphic32.Create;
Png.Assign(bmp);
Png.SaveToFile(dest);
Png.Free;
end;
有什么不对劲吗?
请帮忙
编辑
我想我发现了我的问题。。。
当我移动图层时,唯一的方法(据我所知)是将所有图层加载到imagelist(TBitmap32List是我当时的选择)中,然后清理图层,并按所需顺序将其从imagelist重新添加到ImageView中。
我只能假设这是出问题的地方。
这一定是因为在层中我有透明的PNG,当我将它们加载到Bitmap32List中时,我将它们作为BMP加载。
在继续之前,我必须寻找另一种方法来重新组织我的层。我将用我的解决方案更新您。如果你们中有人知道在ImageView32中重新排列图层的更好方法,请告诉我
编辑
因此,请在下图中观察GUI已完成,并且正在工作。我有代表层的面板,我可以移动它们(正如您在图片中看到的,我正在拖动层'Elementul 0'并在链中向上移动)。
我重复一遍,当我使用临时文件按顺序上下移动图层时,我的逻辑也起作用。其中一个答案建议我应该只使用Index属性来更改层层次结构中的层位置,我的意思是,如果不至少向图像添加新层,就无法完成此操作。所以这不是一个双重问题。这只是对我收到的一个答案的回应
谢谢通过您对如何更改图层顺序的描述,这很可能是您出现问题的原因。由于您没有发布该部分代码,因此无法确定对其进行评估
无论如何,要重新排列层,您可以使用
TCustomLayer
的Index
属性(其中TBitmapLayer
是其后代)因此,在重新排列层时,问题的解决方案是不使用位图32列表作为png层的临时容器,因为在这个过程中会丢失一些内容。
因此,尝试其他重新排序的解决方案。我目前的解决方案是将层作为PNG文件放到磁盘上,然后按所需顺序从磁盘重新加载它们。
另一个解决方案(尚未测试)是创建与现有层数量相等的新层,将实际层移到那里,然后按所需顺序逐个取回,然后移除额外的层
无论如何。这就是问题所在,这是迄今为止的答案。你的问题比你想象的要简单得多。使用图层很自然: 发送回 将层的索引设置为0或只需调用
SendToBack
。在此之前的所有层的索引都将增加1。之前在它之后的所有层都保持在相同的位置
向后发送
将层的索引减少1。之前的图层现在位于它之后,因此其索引增加了一
向前发送
将层的索引增加1。之前位于它后面的图层现在位于它前面,因此其索引减少了一
发送到前端
将层的索引设置为层数减1。之前在它之后的图层增加了一层,减少了一层
因此,绝对不需要触摸位图、将其保存到磁盘或使用任何类型的临时层来更改顺序。实际上,在任何情况下,只要将层的索引设置为您希望它出现的位置(从0开始,从后到前计数),就会发生正确的事情。移动列表中的面板后,可以将相应图层的索引设置为列表中面板的新索引。但是,由于面板是前后顺序排列的,GR32是前后顺序排列的,因此需要将面板的索引转换为所需的层索引
下面是一个使用t列表框
和t按钮
执行此操作的示例:
procedure TForm1.SendBackwardButtonClick(Sender: TObject);
var
LNewListBoxItemIndex: Integer;
begin
// Calculate the new list index and make sure it's valid
LNewListBoxItemIndex := Max(0, Min(ListBox1.ItemIndex + 1, ListBox1.Items.Count - 1));
// Transform the current and new list indices and use them to move the layer
ImgView321.Layers[ListBox1.Items.Count - 1 - ListBox1.ItemIndex].Index :=
ListBox1.Items.Count - 1 - LNewListBoxItemIndex;
// Move the list item
ListBox1.Items.Move(ListBox1.ItemIndex, LNewListBoxItemIndex);
// Preserve the selection (if applicable)
ListBox1.ItemIndex := LNewListBoxItemIndex;
end;
您还可以决定将列表与图层完全同步。在这种情况下,您应该将每个项目(可能是TPanel
)与一个图层相关联
// Create layers from front to back
LLayer := TBitmapLayer.Create(ImgView321.Layers);
ListBox1.Items.AddObject('First layer', LLayer);
// Could use LPanel := TPanel.Create(...); LPanel.Tag := Integer(Pointer(LLayer)) instead
LLayer := TBitmapLayer.Create(ImgView321.Layers);
ListBox1.Items.AddObject('Second layer', LLayer);
// Now the list is correct but the layers are not in the right order.
// Use the code listed below whenever you need to synchronize the layers
// with the list. In theory it may be slow (O(n^2)) but practically it
// won't matter much assuming you won't have hundreds of layers.
// Don't update the screen every time we move a layer to get closer to the final result
ImgView321.BeginUpdate;
try
for LIndex := 0 to ListBox1.Items.Count - 1 do
// Get the associated layer and make it the least visible of all processed so far
TCustomLayer(ListBox1.Items.Objects[LIndex]).SendToBack;
// Could use TCustomLayer(Pointer(SomePanel.Tag)).SendToBack instead
finally
// Always do this not to have strange behavior after an error
ImgView321.EndUpdate;
end;
// When it's done, update the screen
ImgView321.Changed;
我猜其中一个图层没有位图。但是就像我说的,如果我不改变图层索引的顺序,保存就可以了。当我把图层发送到后面的那一刻。。。出现错误。所以层是相同的,只是当崩溃发生时它们的顺序会改变哦,不要相信我,我可能错了,但是相信调试器。只需逐步完成保存过程并保存bmpaspng,然后自己检查。作为对编辑的响应。可以通过设置图层的
索引属性来更改图层顺序。哇,如果这么简单。。。这样想:我有一个面板显示
// Create layers from front to back
LLayer := TBitmapLayer.Create(ImgView321.Layers);
ListBox1.Items.AddObject('First layer', LLayer);
// Could use LPanel := TPanel.Create(...); LPanel.Tag := Integer(Pointer(LLayer)) instead
LLayer := TBitmapLayer.Create(ImgView321.Layers);
ListBox1.Items.AddObject('Second layer', LLayer);
// Now the list is correct but the layers are not in the right order.
// Use the code listed below whenever you need to synchronize the layers
// with the list. In theory it may be slow (O(n^2)) but practically it
// won't matter much assuming you won't have hundreds of layers.
// Don't update the screen every time we move a layer to get closer to the final result
ImgView321.BeginUpdate;
try
for LIndex := 0 to ListBox1.Items.Count - 1 do
// Get the associated layer and make it the least visible of all processed so far
TCustomLayer(ListBox1.Items.Objects[LIndex]).SendToBack;
// Could use TCustomLayer(Pointer(SomePanel.Tag)).SendToBack instead
finally
// Always do this not to have strange behavior after an error
ImgView321.EndUpdate;
end;
// When it's done, update the screen
ImgView321.Changed;