Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
scott-mescudi committed Dec 9, 2024
2 parents 0b20d21 + b014d98 commit 9ee11bb
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 481 deletions.
37 changes: 26 additions & 11 deletions png_core.go → image_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,29 @@ import (
"fmt"
c "github.com/scott-mescudi/stegano/compression"
u "github.com/scott-mescudi/stegano/pkg"
s "github.com/scott-mescudi/stegano/png"
"image"
)

// GetImageCapacity calculates the maximum amount of data (in bytes)
// that can be embedded in the given image, based on the specified bit depth.
// Returns 0 if the bit depth exceeds 7, as higher depths are unsupported.
func (m *PngHandler) GetImageCapacity(coverImage image.Image, bitDepth uint8) int {
func (m *ImageHandler) GetImageCapacity(coverImage image.Image, bitDepth uint8) int {
if bitDepth > 7 {
return 0
}

return ((len(s.ExtractRGBChannelsFromImage(coverImage)) * 3) / 8) * (int(bitDepth) + 1)
return ((len(u.ExtractRGBChannelsFromImage(coverImage)) * 3) / 8) * (int(bitDepth) + 1)
}

// EmbedDataIntoImage embeds the given data into the RGB channels of the specified image.
// Supports optional compression via the `defaultCompression` flag. Returns the modified
// image or an error if the data exceeds the embedding capacity of the image.
func (m *PngHandler) EmbedDataIntoImage(coverImage image.Image, data []byte, bitDepth uint8, defaultCompression bool) (image.Image, error) {
RGBchannels := s.ExtractRGBChannelsFromImage(coverImage)
func (m *ImageHandler) EmbedDataIntoImage(coverImage image.Image, data []byte, bitDepth uint8, defaultCompression bool) (image.Image, error) {
if coverImage == nil {
return nil, fmt.Errorf("coverimage is nil")
}

RGBchannels := u.ExtractRGBChannelsFromImage(coverImage)
if len(data)*8 > (((len(RGBchannels))*3)/8)*(int(bitDepth)+1) {
return nil, fmt.Errorf("error: Data too large to embed into the image")
}
Expand All @@ -48,8 +51,12 @@ func (m *PngHandler) EmbedDataIntoImage(coverImage image.Image, data []byte, bit
// ExtractDataFromImage retrieves data embedded in the RGB channels of the specified image.
// Decompresses the data if `isDefaultCompressed` is true. Returns the extracted data
// or an error if the process fails.
func (m *PngHandler) ExtractDataFromImage(coverImage image.Image, bitDepth uint8, isDefaultCompressed bool) ([]byte, error) {
RGBchannels := s.ExtractRGBChannelsFromImage(coverImage)
func (m *ImageHandler) ExtractDataFromImage(coverImage image.Image, bitDepth uint8, isDefaultCompressed bool) ([]byte, error) {
if coverImage == nil {
return nil, fmt.Errorf("coverimage is nil")
}

RGBchannels := u.ExtractRGBChannelsFromImage(coverImage)
data, err := u.ExtractDataFromRGBchannelsWithDepth(RGBchannels, bitDepth)
if err != nil {
return nil, err
Expand Down Expand Up @@ -79,8 +86,12 @@ func (m *PngHandler) ExtractDataFromImage(coverImage image.Image, bitDepth uint8

// EmbedAtDepth embeds the provided data into a specific bit depth of the RGB channels of the image.
// Unlike other embedding methods, this modifies a single bit per channel at the specified depth.
func (m *PngHandler) EmbedAtDepth(coverimage image.Image, data []byte, depth uint8) (image.Image, error) {
channels := s.ExtractRGBChannelsFromImage(coverimage)
func (m *ImageHandler) EmbedAtDepth(coverimage image.Image, data []byte, depth uint8) (image.Image, error) {
if coverimage == nil {
return nil, fmt.Errorf("coverimage is nil")
}

channels := u.ExtractRGBChannelsFromImage(coverimage)
if channels == nil {
return nil, fmt.Errorf("Failed to extract channels from image")
}
Expand All @@ -95,8 +106,12 @@ func (m *PngHandler) EmbedAtDepth(coverimage image.Image, data []byte, depth uin

// ExtractAtDepth extracts data embedded at a specific bit depth from the RGB channels of an image.
// Only retrieves data from the specified bit depth. Returns the extracted data or an error if the process fails.
func (m *PngHandler) ExtractAtDepth(coverimage image.Image, depth uint8) ([]byte, error) {
channels := s.ExtractRGBChannelsFromImage(coverimage)
func (m *ImageHandler) ExtractAtDepth(coverimage image.Image, depth uint8) ([]byte, error) {
if coverimage == nil {
return nil, fmt.Errorf("coverimage is nil")
}

channels := u.ExtractRGBChannelsFromImage(coverimage)
if channels == nil {
return nil, fmt.Errorf("Failed to extract channels from image")
}
Expand Down
9 changes: 4 additions & 5 deletions png_embedder.go → image_embedder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

c "github.com/scott-mescudi/stegano/compression"
u "github.com/scott-mescudi/stegano/pkg"
s "github.com/scott-mescudi/stegano/png"
)

// EncodeAndSave embeds the provided data into the given image and saves the modified image to a new file.
Expand All @@ -22,7 +21,7 @@ import (
// - bitDepth: The number of bits per channel used for embedding (0-7).
// - outputFilename: The name of the file where the modified image will be saved.
// - defaultCompression: A flag indicating whether the data should be compressed before embedding.
func (m *PngHandler) EncodeAndSave(coverImage image.Image, data []byte, bitDepth uint8, outputFilename string, defaultCompression bool) error {
func (m *ImageHandler) EncodeAndSave(coverImage image.Image, data []byte, bitDepth uint8, outputFilename string, defaultCompression bool) error {
// Validate coverImage dimensions
if coverImage == nil {
return errors.New("coverImage is nil")
Expand All @@ -44,7 +43,7 @@ func (m *PngHandler) EncodeAndSave(coverImage image.Image, data []byte, bitDepth
}

// Extract RGB channels
RGBchannels := s.ExtractRGBChannelsFromImage(coverImage)
RGBchannels := u.ExtractRGBChannelsFromImage(coverImage)
if RGBchannels == nil {
return errors.New("failed to extract RGB channels from the image")
}
Expand Down Expand Up @@ -105,7 +104,7 @@ func (m *PngHandler) EncodeAndSave(coverImage image.Image, data []byte, bitDepth
// - coverImage: The image containing embedded data to be extracted.
// - bitDepth: The bit depth used during the embedding process.
// - isDefaultCompressed: A flag indicating whether the embedded data was compressed.
func (m *PngHandler) Decode(coverImage image.Image, bitDepth uint8, isDefaultCompressed bool) ([]byte, error) {
func (m *ImageHandler) Decode(coverImage image.Image, bitDepth uint8, isDefaultCompressed bool) ([]byte, error) {
// Validate coverImage dimensions
if coverImage == nil {
return nil, errors.New("coverImage is nil")
Expand All @@ -115,7 +114,7 @@ func (m *PngHandler) Decode(coverImage image.Image, bitDepth uint8, isDefaultCom
}

// Extract RGB channels
RGBchannels := s.ExtractRGBChannelsFromImage(coverImage)
RGBchannels := u.ExtractRGBChannelsFromImage(coverImage)
if RGBchannels == nil {
return nil, errors.New("failed to extract RGB channels from the image")
}
Expand Down
153 changes: 153 additions & 0 deletions image_embedder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package stegano

import (
"image"
"image/color"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// Mock function to create a test image
func createTestImage() image.Image {
width, height := 100, 100
img := image.NewRGBA(image.Rect(0, 0, width, height))
// Fill with some color
for x := 0; x < width; x++ {
for y := 0; y < height; y++ {
img.Set(x, y, color.RGBA{R: 255, G: 0, B: 0, A: 255})
}
}
return img
}

func TestEncodeAndSave_Valid(t *testing.T) {
// Setup
coverImage := createTestImage()
data := []byte("some secret data")
bitDepth := uint8(3)
outputFilename := "test_output.jpg"

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if no error occurred and file was created
require.NoError(t, err)

// Check if output file exists
_, err = os.Stat(outputFilename)
require.NoError(t, err)

// Cleanup
defer os.Remove(outputFilename)
}

func TestEncodeAndSave_EmptyData(t *testing.T) {
// Setup
coverImage := createTestImage()
data := []byte{}
bitDepth := uint8(3)
outputFilename := "test_output.jpg"

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if the correct error is returned
assert.Error(t, err)
assert.Contains(t, err.Error(), "data is empty")
}

func TestEncodeAndSave_DataTooLarge(t *testing.T) {
// Setup
coverImage := createTestImage()
data := make([]byte, 10000) // This is more data than the image can hold
bitDepth := uint8(3)
outputFilename := "test_output.jpg"

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if the correct error is returned
assert.Error(t, err)
assert.Contains(t, err.Error(), "data is too large to embed")
}

func TestEncodeAndSave_CompressedData(t *testing.T) {
// Setup
coverImage := createTestImage()
data := []byte("compressed test data")
bitDepth := uint8(3)
outputFilename := "test_compressed_output.jpg"

// Execute with compression enabled
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, true)

// Test if no error occurred and file was created
require.NoError(t, err)

// Check if output file exists
_, err = os.Stat(outputFilename)
require.NoError(t, err)

// Cleanup
defer os.Remove(outputFilename)
}

func TestEncodeAndSave_InvalidFileCreation(t *testing.T) {
// Setup
coverImage := createTestImage()
data := []byte("test data")
bitDepth := uint8(3)
outputFilename := "/invalid/path/test_output.jpg" // Invalid path

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if the correct error is returned
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to create output file")
}

func TestEncodeAndSave_SuccessWithSpecificFilename(t *testing.T) {
// Setup
coverImage := createTestImage()
data := []byte("another test data")
bitDepth := uint8(3)
outputFilename := "specific_output.jpg"

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if no error occurred and file was created
require.NoError(t, err)

// Check if the output file exists
_, err = os.Stat(outputFilename)
require.NoError(t, err)

// Cleanup
defer os.Remove(outputFilename)
}

func TestEncodeAndSave_NullImage(t *testing.T) {
// Setup
var coverImage image.Image = nil
data := []byte("some data")
bitDepth := uint8(3)
outputFilename := "test_output.jpg"

// Execute
handler := &ImageHandler{}
err := handler.EncodeAndSave(coverImage, data, bitDepth, outputFilename, false)

// Test if the correct error is returned
assert.Error(t, err)
}
20 changes: 0 additions & 20 deletions jpeg/image_processing.go

This file was deleted.

Loading

0 comments on commit 9ee11bb

Please sign in to comment.