diff --git a/pkg/sif/create.go b/pkg/sif/create.go
index 0f41e0a9..0eb1e1d1 100644
--- a/pkg/sif/create.go
+++ b/pkg/sif/create.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
+// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
 // Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
 // Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
 // This software is licensed under a 3-clause BSD license. Please consult the
@@ -55,6 +55,20 @@ func writeDataObjectAt(ws io.WriteSeeker, offsetUnaligned int64, di DescriptorIn
 	return nil
 }
 
+// calculatedDataSize calculates the size of the data section based on the in-use descriptors.
+func (f *FileImage) calculatedDataSize() int64 {
+	dataEnd := f.DataOffset()
+
+	f.WithDescriptors(func(d Descriptor) bool {
+		if objectEnd := d.Offset() + d.Size(); dataEnd < objectEnd {
+			dataEnd = objectEnd
+		}
+		return false
+	})
+
+	return dataEnd - f.DataOffset()
+}
+
 var (
 	errInsufficientCapacity = errors.New("insufficient descriptor capacity to add data object(s) to image")
 	errPrimaryPartition     = errors.New("image already contains a primary partition")
@@ -80,6 +94,8 @@ func (f *FileImage) writeDataObject(i int, di DescriptorInput, t time.Time) erro
 	d := &f.rds[i]
 	d.ID = uint32(i) + 1
 
+	f.h.DataSize = f.calculatedDataSize()
+
 	if err := writeDataObjectAt(f.rw, f.h.DataOffset+f.h.DataSize, di, t, d); err != nil {
 		return err
 	}
diff --git a/pkg/sif/delete.go b/pkg/sif/delete.go
index c0f0aba3..41c0a726 100644
--- a/pkg/sif/delete.go
+++ b/pkg/sif/delete.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
+// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
 // Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
 // Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
 // This software is licensed under a 3-clause BSD license. Please consult the
@@ -8,32 +8,16 @@
 package sif
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"time"
 )
 
-// isLast return true if the data object associated with d is the last in f.
-func (f *FileImage) isLast(d *rawDescriptor) bool {
-	isLast := true
-
-	end := d.Offset + d.Size
-	f.WithDescriptors(func(d Descriptor) bool {
-		isLast = d.Offset()+d.Size() <= end
-		return !isLast
-	})
-
-	return isLast
-}
-
 // zeroReader is an io.Reader that returns a stream of zero-bytes.
 type zeroReader struct{}
 
 func (zeroReader) Read(b []byte) (int, error) {
-	for i := range b {
-		b[i] = 0
-	}
+	clear(b)
 	return len(b), nil
 }
 
@@ -47,13 +31,6 @@ func (f *FileImage) zero(d *rawDescriptor) error {
 	return err
 }
 
-// truncateAt truncates f at the start of the padded data object described by d.
-func (f *FileImage) truncateAt(d *rawDescriptor) error {
-	start := d.Offset + d.Size - d.SizeWithPadding
-
-	return f.rw.Truncate(start)
-}
-
 // deleteOpts accumulates object deletion options.
 type deleteOpts struct {
 	zero    bool
@@ -97,8 +74,6 @@ func OptDeleteWithTime(t time.Time) DeleteOpt {
 	}
 }
 
-var errCompactNotImplemented = errors.New("compact not implemented for non-last object")
-
 // DeleteObject deletes the data object with id, according to opts.
 //
 // To zero the data region of the deleted object, use OptDeleteZero. To compact the file following
@@ -125,24 +100,12 @@ func (f *FileImage) DeleteObject(id uint32, opts ...DeleteOpt) error {
 		return fmt.Errorf("%w", err)
 	}
 
-	if do.compact && !f.isLast(d) {
-		return fmt.Errorf("%w", errCompactNotImplemented)
-	}
-
 	if do.zero {
 		if err := f.zero(d); err != nil {
 			return fmt.Errorf("%w", err)
 		}
 	}
 
-	if do.compact {
-		if err := f.truncateAt(d); err != nil {
-			return fmt.Errorf("%w", err)
-		}
-
-		f.h.DataSize -= d.SizeWithPadding
-	}
-
 	f.h.DescriptorsFree++
 	f.h.ModifiedAt = do.t.Unix()
 
@@ -156,6 +119,14 @@ func (f *FileImage) DeleteObject(id uint32, opts ...DeleteOpt) error {
 	// Reset rawDescripter with empty struct
 	*d = rawDescriptor{}
 
+	if do.compact {
+		f.h.DataSize = f.calculatedDataSize()
+
+		if err := f.rw.Truncate(f.h.DataOffset + f.h.DataSize); err != nil {
+			return fmt.Errorf("%w", err)
+		}
+	}
+
 	if err := f.writeDescriptors(); err != nil {
 		return fmt.Errorf("%w", err)
 	}
diff --git a/pkg/sif/delete_test.go b/pkg/sif/delete_test.go
index 683e00dd..a7c2a165 100644
--- a/pkg/sif/delete_test.go
+++ b/pkg/sif/delete_test.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
+// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
 // This software is licensed under a 3-clause BSD license. Please consult the
 // LICENSE file distributed with the sources of this project regarding your
 // rights to use or distribute this software.
@@ -17,7 +17,7 @@ func TestDeleteObject(t *testing.T) {
 	tests := []struct {
 		name       string
 		createOpts []CreateOpt
-		id         uint32
+		ids        []uint32
 		opts       []DeleteOpt
 		wantErr    error
 	}{
@@ -26,44 +26,104 @@ func TestDeleteObject(t *testing.T) {
 			createOpts: []CreateOpt{
 				OptCreateDeterministic(),
 			},
-			id:      1,
+			ids:     []uint32{1},
 			wantErr: ErrObjectNotFound,
 		},
 		{
-			name: "Zero",
+			name: "Compact",
+			createOpts: []CreateOpt{
+				OptCreateDeterministic(),
+				OptCreateWithDescriptors(
+					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
+				),
+			},
+			ids: []uint32{1, 2},
+			opts: []DeleteOpt{
+				OptDeleteCompact(true),
+			},
+		},
+		{
+			name: "OneZero",
 			createOpts: []CreateOpt{
 				OptCreateDeterministic(),
 				OptCreateWithDescriptors(
 					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
 				),
 			},
-			id: 1,
+			ids: []uint32{1},
 			opts: []DeleteOpt{
 				OptDeleteZero(true),
 			},
 		},
 		{
-			name: "Compact",
+			name: "OneCompact",
 			createOpts: []CreateOpt{
 				OptCreateDeterministic(),
 				OptCreateWithDescriptors(
 					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
 				),
 			},
-			id: 1,
+			ids: []uint32{1},
 			opts: []DeleteOpt{
 				OptDeleteCompact(true),
 			},
 		},
 		{
-			name: "ZeroCompact",
+			name: "OneZeroCompact",
+			createOpts: []CreateOpt{
+				OptCreateDeterministic(),
+				OptCreateWithDescriptors(
+					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
+				),
+			},
+			ids: []uint32{1},
+			opts: []DeleteOpt{
+				OptDeleteZero(true),
+				OptDeleteCompact(true),
+			},
+		},
+		{
+			name: "TwoZero",
+			createOpts: []CreateOpt{
+				OptCreateDeterministic(),
+				OptCreateWithDescriptors(
+					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
+				),
+			},
+			ids: []uint32{2},
+			opts: []DeleteOpt{
+				OptDeleteZero(true),
+			},
+		},
+		{
+			name: "TwoCompact",
+			createOpts: []CreateOpt{
+				OptCreateDeterministic(),
+				OptCreateWithDescriptors(
+					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
+				),
+			},
+			ids: []uint32{2},
+			opts: []DeleteOpt{
+				OptDeleteCompact(true),
+			},
+		},
+		{
+			name: "TwoZeroCompact",
 			createOpts: []CreateOpt{
 				OptCreateDeterministic(),
 				OptCreateWithDescriptors(
 					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
+					getDescriptorInput(t, DataGeneric, []byte{0xfe, 0xed}),
 				),
 			},
-			id: 1,
+			ids: []uint32{2},
 			opts: []DeleteOpt{
 				OptDeleteZero(true),
 				OptDeleteCompact(true),
@@ -78,7 +138,7 @@ func TestDeleteObject(t *testing.T) {
 				),
 				OptCreateWithTime(time.Unix(946702800, 0)),
 			},
-			id: 1,
+			ids: []uint32{1},
 			opts: []DeleteOpt{
 				OptDeleteDeterministic(),
 			},
@@ -91,7 +151,7 @@ func TestDeleteObject(t *testing.T) {
 					getDescriptorInput(t, DataGeneric, []byte{0xfa, 0xce}),
 				),
 			},
-			id: 1,
+			ids: []uint32{1},
 			opts: []DeleteOpt{
 				OptDeleteWithTime(time.Unix(946702800, 0)),
 			},
@@ -106,7 +166,7 @@ func TestDeleteObject(t *testing.T) {
 					),
 				),
 			},
-			id: 1,
+			ids: []uint32{1},
 		},
 	}
 
@@ -119,8 +179,10 @@ func TestDeleteObject(t *testing.T) {
 				t.Fatal(err)
 			}
 
-			if got, want := f.DeleteObject(tt.id, tt.opts...), tt.wantErr; !errors.Is(got, want) {
-				t.Errorf("got error %v, want %v", got, want)
+			for _, id := range tt.ids {
+				if got, want := f.DeleteObject(id, tt.opts...), tt.wantErr; !errors.Is(got, want) {
+					t.Errorf("got error %v, want %v", got, want)
+				}
 			}
 
 			if err := f.UnloadContainer(); err != nil {
diff --git a/pkg/sif/testdata/TestDeleteObject/OneCompact.golden b/pkg/sif/testdata/TestDeleteObject/OneCompact.golden
new file mode 100644
index 00000000..cb86f62d
Binary files /dev/null and b/pkg/sif/testdata/TestDeleteObject/OneCompact.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObject/OneZero.golden b/pkg/sif/testdata/TestDeleteObject/OneZero.golden
new file mode 100644
index 00000000..ec7f18be
Binary files /dev/null and b/pkg/sif/testdata/TestDeleteObject/OneZero.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObject/OneZeroCompact.golden b/pkg/sif/testdata/TestDeleteObject/OneZeroCompact.golden
new file mode 100644
index 00000000..ec7f18be
Binary files /dev/null and b/pkg/sif/testdata/TestDeleteObject/OneZeroCompact.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObject/Zero.golden b/pkg/sif/testdata/TestDeleteObject/TwoCompact.golden
similarity index 99%
rename from pkg/sif/testdata/TestDeleteObject/Zero.golden
rename to pkg/sif/testdata/TestDeleteObject/TwoCompact.golden
index 036b3690..74b6489c 100644
Binary files a/pkg/sif/testdata/TestDeleteObject/Zero.golden and b/pkg/sif/testdata/TestDeleteObject/TwoCompact.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObject/TwoZero.golden b/pkg/sif/testdata/TestDeleteObject/TwoZero.golden
new file mode 100644
index 00000000..f57ae8c2
Binary files /dev/null and b/pkg/sif/testdata/TestDeleteObject/TwoZero.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObject/ZeroCompact.golden b/pkg/sif/testdata/TestDeleteObject/TwoZeroCompact.golden
similarity index 99%
rename from pkg/sif/testdata/TestDeleteObject/ZeroCompact.golden
rename to pkg/sif/testdata/TestDeleteObject/TwoZeroCompact.golden
index 01584e24..74b6489c 100644
Binary files a/pkg/sif/testdata/TestDeleteObject/ZeroCompact.golden and b/pkg/sif/testdata/TestDeleteObject/TwoZeroCompact.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObjectAndAddObject/NoCompact.golden b/pkg/sif/testdata/TestDeleteObjectAndAddObject/NoCompact.golden
index 7042b4ac..483ef82e 100644
Binary files a/pkg/sif/testdata/TestDeleteObjectAndAddObject/NoCompact.golden and b/pkg/sif/testdata/TestDeleteObjectAndAddObject/NoCompact.golden differ
diff --git a/pkg/sif/testdata/TestDeleteObjectAndAddObject/Zero.golden b/pkg/sif/testdata/TestDeleteObjectAndAddObject/Zero.golden
index bacfe7af..483ef82e 100644
Binary files a/pkg/sif/testdata/TestDeleteObjectAndAddObject/Zero.golden and b/pkg/sif/testdata/TestDeleteObjectAndAddObject/Zero.golden differ