Skip to content

Commit

Permalink
New Layer > Replace menu
Browse files Browse the repository at this point in the history
Relates to #317.  Thank you to @jpbro for this suggestion, and my apologies for taking so long to implement it.

PhotoDemon now provides a Layer > Replace menu which has three options for updating the current layer's contents in-place:

1) From the clipboard
2) From an arbitrary image file
3) From the current image (visible layers merged together)

These options provide a convenient way to update the contents of an existing layer from an outside source, without the hassle of jumping through various Copy+Paste operations.
  • Loading branch information
tannerhelland committed Aug 24, 2021
1 parent 973852b commit 24f5082
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 173 deletions.
30 changes: 16 additions & 14 deletions Classes/pdClipboardMain.cls
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ End Sub

'Paste an image (e.g. create new image data based on whatever is in the clipboard).
' The parameter "srcIsMeantAsLayer" controls whether the clipboard data is loaded as a new image, or as a new layer in an existing image.
Friend Sub ClipboardPaste(ByVal srcIsMeantAsLayer As Boolean, Optional ByRef pasteToThisDIBInstead As pdDIB = Nothing, Optional ByRef fullParamString As String)
Friend Function ClipboardPaste(ByVal srcIsMeantAsLayer As Boolean, Optional ByRef pasteToThisDIBInstead As pdDIB = Nothing, Optional ByRef fullParamString As String = vbNullString) As Boolean

Dim pasteWasSuccessful As Boolean
pasteWasSuccessful = False
Expand All @@ -431,58 +431,58 @@ Friend Sub ClipboardPaste(ByVal srcIsMeantAsLayer As Boolean, Optional ByRef pas

'If PD was used to Cut or Copy something onto the clipboard, our own private format(s) will be listed first.
If m_Clipboard.DoesClipboardHaveFormatID(CF_PD_DIB) And PD_CB_ALLOW_INTERNAL_FORMAT_PASTE Then
pasteWasSuccessful = ClipboardPaste_InternalData(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_InternalData(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'PNGs on the clipboard get preferential treatment, as they preserve transparency data - so check for them first.
If m_Clipboard.DoesClipboardHaveFormatName("PNG") And (Not pasteWasSuccessful) And PD_CB_ALLOW_PNG_PASTE Then
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("PNG", srcIsMeantAsLayer, "png")
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("PNG", srcIsMeantAsLayer, "png", pasteToThisDIBInstead)
End If

'If we couldn't find PNG data (or something went horribly wrong during that step), look for an HTML fragment next.
' Images copied from web browsers typically create an HTML fragment, which should have a direct link to the copied image.
' Downloading the image manually lets us maintain things like ICC profiles and the image's original filename.
If m_Clipboard.DoesClipboardHaveHTML() And (Not pasteWasSuccessful) And PD_CB_ALLOW_ONLINE_PASTE Then
pasteWasSuccessful = ClipboardPaste_HTML(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_HTML(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'JPEGs are another possibility. We prefer them less than PNG or direct download (because there's no guarantee that the
' damn browser didn't re-encode them, but they're better than bitmaps or DIBs because they may retain metadata and
' color profiles, so test for JPEG next. (Also, note that certain versions of Microsoft Office use "JFIF" as the identifier,
' for reasons known only to them...)
If m_Clipboard.DoesClipboardHaveFormatName("JPEG") And (Not pasteWasSuccessful) And PD_CB_ALLOW_JPEG_PASTE Then
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JPEG", srcIsMeantAsLayer, "jpg")
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JPEG", srcIsMeantAsLayer, "jpg", pasteToThisDIBInstead)
End If

If m_Clipboard.DoesClipboardHaveFormatName("JPG") And (Not pasteWasSuccessful) And PD_CB_ALLOW_JPEG_PASTE Then
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JPG", srcIsMeantAsLayer, "jpg")
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JPG", srcIsMeantAsLayer, "jpg", pasteToThisDIBInstead)
End If

If m_Clipboard.DoesClipboardHaveFormatName("JFIF") And (Not pasteWasSuccessful) And PD_CB_ALLOW_JPEG_PASTE Then
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JFIF", srcIsMeantAsLayer, "jpg")
pasteWasSuccessful = ClipboardPaste_CustomImageFormat("JFIF", srcIsMeantAsLayer, "jpg", pasteToThisDIBInstead)
End If

'Next, see if the clipboard contains a generic file list. If it does, try to load each file in turn.
If m_Clipboard.DoesClipboardHaveFiles() And (Not pasteWasSuccessful) And PD_CB_ALLOW_FILE_PASTE Then
pasteWasSuccessful = ClipboardPaste_ListOfFiles(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_ListOfFiles(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'Next, look for plaintext. This could be a URL, or maybe a text representation of a filepath.
' (Also, note that we only have to search for one text format, because the OS auto-converts between text formats for free.)
If m_Clipboard.DoesClipboardHaveText() And (Not pasteWasSuccessful) And PD_CB_ALLOW_GENERIC_TEXT_PASTE Then
pasteWasSuccessful = ClipboardPaste_TextSource(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_TextSource(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'Next, use any DIBs or bitmaps. Once again, the OS auto-converts between bitmap and DIB formats, and if it all possible,
' we prefer DIBv5 as it actually supports alpha data.
If m_Clipboard.DoesClipboardHaveBitmapImage() And (Not pasteWasSuccessful) And PD_CB_ALLOW_BMP_DIB_PASTE Then
pasteWasSuccessful = ClipboardPaste_BitmapImage(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_BitmapImage(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'As a last resort, try to grab metafiles. These are not ideal as some software (*cough* OFFICE *cough*) generates
' pretty terrible metafiles, but it's better than nothing.
If m_Clipboard.DoesClipboardHaveMetafile() And (Not pasteWasSuccessful) And PD_CB_ALLOW_METAFILE_PASTE Then
pasteWasSuccessful = ClipboardPaste_Metafile(srcIsMeantAsLayer)
pasteWasSuccessful = ClipboardPaste_Metafile(srcIsMeantAsLayer, pasteToThisDIBInstead)
End If

'Regardless of success or failure, make sure to close the clipboard now that we're done with it.
Expand All @@ -494,7 +494,9 @@ Friend Sub ClipboardPaste(ByVal srcIsMeantAsLayer As Boolean, Optional ByRef pas
Else
PDDebug.LogAction "WARNING! Couldn't open the clipboard; is it possible another program has locked it?"
End If


ClipboardPaste = pasteWasSuccessful

'If a paste operation was successful, switch the current tool to the layer move/resize tool, which is most likely needed after a
' new layer has been pasted.
If pasteWasSuccessful Then
Expand Down Expand Up @@ -575,7 +577,7 @@ Friend Sub ClipboardPaste(ByVal srcIsMeantAsLayer As Boolean, Optional ByRef pas
PDMsgBox "The clipboard is empty or it does not contain a valid picture format. Please copy a valid image onto the clipboard and try again.", vbExclamation Or vbOKOnly, "Error"
End If

End Sub
End Function

'If the clipboard contains internal PD-format data (most commonly a bare DIB), you can call this function to initiate a "paste" command
' using the internal data as a source. The parameter "srcIsMeantAsLayer" controls whether the clipboard data is loaded as a new image,
Expand Down Expand Up @@ -1634,7 +1636,7 @@ Private Function DragDrop_TextData(ByRef OLEDragDrop_DataObject As DataObject, O
If (LenB(targetFile) <> 0) Then

If PDImages.IsImageActive() And loadAsLayers Then
Layers.LoadImageAsNewLayer False, targetFile, , True, , srcX, srcY
Layers.LoadImageAsNewLayer False, targetFile, vbNullString, True, True, srcX, srcY
Else
LoadFileAsNewImage targetFile
End If
Expand Down
57 changes: 42 additions & 15 deletions Forms/MainWindow.frm
Original file line number Diff line number Diff line change
Expand Up @@ -482,20 +482,36 @@ Begin VB.Form FormMain
End
End
Begin VB.Menu MnuLayer
Caption = "-"
Caption = "Replace"
Index = 2
Begin VB.Menu MnuLayerReplace
Caption = "From clipboard"
Index = 0
End
Begin VB.Menu MnuLayerReplace
Caption = "From file..."
Index = 1
End
Begin VB.Menu MnuLayerReplace
Caption = "From visible layers"
Index = 2
End
End
Begin VB.Menu MnuLayer
Caption = "Merge up"
Caption = "-"
Index = 3
End
Begin VB.Menu MnuLayer
Caption = "Merge down"
Caption = "Merge up"
Index = 4
End
Begin VB.Menu MnuLayer
Caption = "Order"
Caption = "Merge down"
Index = 5
End
Begin VB.Menu MnuLayer
Caption = "Order"
Index = 6
Begin VB.Menu MnuLayerOrder
Caption = "Go to top layer"
Index = 0
Expand Down Expand Up @@ -543,7 +559,7 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "Visibility"
Index = 6
Index = 7
Begin VB.Menu MnuLayerVisibility
Caption = "Show this layer"
Checked = -1 'True
Expand Down Expand Up @@ -576,11 +592,11 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "-"
Index = 7
Index = 8
End
Begin VB.Menu MnuLayer
Caption = "Crop"
Index = 8
Index = 9
Begin VB.Menu MnuLayerCrop
Caption = "Crop to selection"
Index = 0
Expand All @@ -600,7 +616,7 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "Orientation"
Index = 9
Index = 10
Begin VB.Menu MnuLayerOrientation
Caption = "Straighten..."
Index = 0
Expand Down Expand Up @@ -640,7 +656,7 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "Size"
Index = 10
Index = 11
Begin VB.Menu MnuLayerSize
Caption = "Reset to actual size"
Index = 0
Expand Down Expand Up @@ -668,11 +684,11 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "-"
Index = 11
Index = 12
End
Begin VB.Menu MnuLayer
Caption = "Transparency"
Index = 12
Index = 13
Begin VB.Menu MnuLayerTransparency
Caption = "From color (chroma key)..."
Index = 0
Expand All @@ -696,11 +712,11 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "-"
Index = 13
Index = 14
End
Begin VB.Menu MnuLayer
Caption = "Rasterize"
Index = 14
Index = 15
Begin VB.Menu MnuLayerRasterize
Caption = "Current layer"
Index = 0
Expand All @@ -712,7 +728,7 @@ Begin VB.Form FormMain
End
Begin VB.Menu MnuLayer
Caption = "Split"
Index = 15
Index = 16
Begin VB.Menu MnuLayerSplit
Caption = "Current layer into standalone image"
Index = 0
Expand Down Expand Up @@ -2012,6 +2028,17 @@ Private Sub MnuLayerCrop_Click(Index As Integer)
End Select
End Sub

Private Sub MnuLayerReplace_Click(Index As Integer)
Select Case Index
Case 0
Menus.ProcessDefaultAction_ByName "layer_replacefromclipboard"
Case 1
Menus.ProcessDefaultAction_ByName "layer_replacefromfile"
Case 2
Menus.ProcessDefaultAction_ByName "layer_replacefromvisiblelayers"
End Select
End Sub

Private Sub MnuLayerSplit_Click(Index As Integer)
Select Case Index
Case 0
Expand Down Expand Up @@ -2915,7 +2942,7 @@ Private Sub Form_Load()
On Error GoTo FormMainLoadError

'*************************************************************************************************************************************
' Start by rerouting control to "LoadTheProgram", which initializes all key PD systems
' Start by rerouting control to "ContinueLoadingProgram", which initializes all key PD systems
'*************************************************************************************************************************************

'The bulk of the loading code actually takes place inside the main module's ContinueLoadingProgram() function
Expand Down
Loading

0 comments on commit 24f5082

Please sign in to comment.