Skip to content

DCTHidePNGinWAV

stegobox.codec.DCTHidePNGinWAV

This module implements simple DCT steganography in WAV audios.

the code by zhudehua

Source code in stegobox/codec/dct_hide_pnginwav.py
class DCTHidePNGinWAV:
    """
    This module implements simple DCT steganography in WAV audios.

    the code by zhudehua
    """

    def __init__(self) -> None:
        pass

    def encode(
        self, carrier: wave.Wave_read, payload: np.ndarray
    ) -> tuple[bytes, wave._wave_params, tuple[int, int, int]]:
        """Encoder requires the carrier audio to be WAV and the payload to be a image.

        Args:
            carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
            payload: Payload (secret image) to be encoded. Read with
                `stegobox.io.image.read_cv2()`.

        Returns:
            Frame information in bytes of the audio with the payload embedded.
            Parameters for audio with the payload embedded.
            the size of secret image.
        """
        # make string to bit
        image_size = payload.shape
        payload = payload.reshape(-1)
        message_bits = np.unpackbits(payload)
        frame_num = carrier.getnframes()
        wave_head = carrier.getparams()
        frame_rate = carrier.getframerate()
        frame_data = carrier.readframes(frame_num)
        # calculate the length of dct data
        bin_data = bytearray(frame_data)
        block_size = len(bin_data) // 8
        zong_length = block_size * 8
        dct_data = bin_data[:zong_length]
        print("block num is ", block_size)
        print("num is ", len(message_bits))
        if len(message_bits) > block_size:
            print("the size of image is too large!")
            raise Exception("the image size is larger than the audio size")

        # deal the left data
        left_data = bin_data[zong_length:]
        left = []
        for i in range(len(left_data)):
            left.append(left_data[i])
            left.append(left_data[i])
        # make the carrier data to N*4*2 block for dct's input
        dct_data = np.array(dct_data).reshape(-1, 2)
        dct_data = dct_data.astype(np.float32)
        dct_data = np.vsplit(dct_data, block_size)
        temp_dct = np.zeros(shape=(block_size, 4, 2))
        # DCT
        for i in range(len(dct_data)):
            temp_dct[i] = cv2.dct(dct_data[i])

        out_audio_dct = []
        end = 0
        #   insert into secret info
        for i in range(len(message_bits)):
            end = end + 1
            out_audio_dct.append(temp_dct[i])
            te = temp_dct[i].copy()
            if message_bits[i] == 0:
                te[0][0] = te[0][0] - 10
            out_audio_dct.append(te)

        for j in range(end + 1, len(temp_dct)):
            out_audio_dct.append(temp_dct[j])
            out_audio_dct.append(temp_dct[j])

        outdata = np.zeros(shape=(2 * block_size, 4, 2))

        for i in range(len(out_audio_dct)):
            outdata[i] = cv2.idct(out_audio_dct[i])
        outdata = np.trunc(outdata).astype(np.uint8)
        outdata = outdata.reshape(-1)
        outdata = bytes(outdata)
        outdata = outdata + bytes(left)
        wave_head = wave_head._replace(framerate=2 * frame_rate)
        wave_head = wave_head._replace(nframes=2 * frame_num)
        return outdata, wave_head, (image_size[0], image_size[1], image_size[2])

    def decode(
        self, carrier: wave.Wave_read, image_size: tuple[int, int, int]
    ) -> np.ndarray:

        """Decode the secret payload from the carrier audio

        Args:
            carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
            image_size: the size of secret iamge.in format [width,hight,channels]

        Returns:
            The decoded payload (secret image).
        """
        image_size = image_size
        pay_length = image_size[0] * image_size[1] * image_size[2] * 8
        frame_data = carrier.readframes(carrier.getnframes())
        bin_data = bytearray(frame_data)
        # divide into  4*2 block
        block_size = len(bin_data) // 8
        zong_length = block_size * 8
        dct_data = bin_data[:zong_length]
        dct_data = np.array(dct_data).reshape(-1, 2)
        dct_data = dct_data.astype(np.float32)
        dct_data = np.vsplit(dct_data, block_size)
        # used to save data after dct
        temp_dct = np.zeros(shape=(block_size, 4, 2))
        for i in range(len(dct_data)):
            temp_dct[i] = cv2.dct(dct_data[i])

        # used to save extract data in format bit
        outdata = []
        for i in range(0, 2 * pay_length, 2):
            if temp_dct[i][0][0] == temp_dct[i + 1][0][0]:
                outdata.append(1)
            else:
                outdata.append(0)
        outdata = np.packbits(outdata)
        outdata = outdata.reshape(image_size)

        return outdata

encode(carrier, payload)

Encoder requires the carrier audio to be WAV and the payload to be a image.

Parameters:

Name Type Description Default
carrier Wave_read

Carrier audio in format WAV. Read with stegobox.io.audio.read().

required
payload ndarray

Payload (secret image) to be encoded. Read with stegobox.io.image.read_cv2().

required

Returns:

Type Description
bytes

Frame information in bytes of the audio with the payload embedded.

_wave_params

Parameters for audio with the payload embedded.

tuple[int, int, int]

the size of secret image.

Source code in stegobox/codec/dct_hide_pnginwav.py
def encode(
    self, carrier: wave.Wave_read, payload: np.ndarray
) -> tuple[bytes, wave._wave_params, tuple[int, int, int]]:
    """Encoder requires the carrier audio to be WAV and the payload to be a image.

    Args:
        carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
        payload: Payload (secret image) to be encoded. Read with
            `stegobox.io.image.read_cv2()`.

    Returns:
        Frame information in bytes of the audio with the payload embedded.
        Parameters for audio with the payload embedded.
        the size of secret image.
    """
    # make string to bit
    image_size = payload.shape
    payload = payload.reshape(-1)
    message_bits = np.unpackbits(payload)
    frame_num = carrier.getnframes()
    wave_head = carrier.getparams()
    frame_rate = carrier.getframerate()
    frame_data = carrier.readframes(frame_num)
    # calculate the length of dct data
    bin_data = bytearray(frame_data)
    block_size = len(bin_data) // 8
    zong_length = block_size * 8
    dct_data = bin_data[:zong_length]
    print("block num is ", block_size)
    print("num is ", len(message_bits))
    if len(message_bits) > block_size:
        print("the size of image is too large!")
        raise Exception("the image size is larger than the audio size")

    # deal the left data
    left_data = bin_data[zong_length:]
    left = []
    for i in range(len(left_data)):
        left.append(left_data[i])
        left.append(left_data[i])
    # make the carrier data to N*4*2 block for dct's input
    dct_data = np.array(dct_data).reshape(-1, 2)
    dct_data = dct_data.astype(np.float32)
    dct_data = np.vsplit(dct_data, block_size)
    temp_dct = np.zeros(shape=(block_size, 4, 2))
    # DCT
    for i in range(len(dct_data)):
        temp_dct[i] = cv2.dct(dct_data[i])

    out_audio_dct = []
    end = 0
    #   insert into secret info
    for i in range(len(message_bits)):
        end = end + 1
        out_audio_dct.append(temp_dct[i])
        te = temp_dct[i].copy()
        if message_bits[i] == 0:
            te[0][0] = te[0][0] - 10
        out_audio_dct.append(te)

    for j in range(end + 1, len(temp_dct)):
        out_audio_dct.append(temp_dct[j])
        out_audio_dct.append(temp_dct[j])

    outdata = np.zeros(shape=(2 * block_size, 4, 2))

    for i in range(len(out_audio_dct)):
        outdata[i] = cv2.idct(out_audio_dct[i])
    outdata = np.trunc(outdata).astype(np.uint8)
    outdata = outdata.reshape(-1)
    outdata = bytes(outdata)
    outdata = outdata + bytes(left)
    wave_head = wave_head._replace(framerate=2 * frame_rate)
    wave_head = wave_head._replace(nframes=2 * frame_num)
    return outdata, wave_head, (image_size[0], image_size[1], image_size[2])

decode(carrier, image_size)

Decode the secret payload from the carrier audio

Parameters:

Name Type Description Default
carrier Wave_read

Carrier audio in format WAV. Read with stegobox.io.audio.read().

required
image_size tuple[int, int, int]

the size of secret iamge.in format [width,hight,channels]

required

Returns:

Type Description
ndarray

The decoded payload (secret image).

Source code in stegobox/codec/dct_hide_pnginwav.py
def decode(
    self, carrier: wave.Wave_read, image_size: tuple[int, int, int]
) -> np.ndarray:

    """Decode the secret payload from the carrier audio

    Args:
        carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
        image_size: the size of secret iamge.in format [width,hight,channels]

    Returns:
        The decoded payload (secret image).
    """
    image_size = image_size
    pay_length = image_size[0] * image_size[1] * image_size[2] * 8
    frame_data = carrier.readframes(carrier.getnframes())
    bin_data = bytearray(frame_data)
    # divide into  4*2 block
    block_size = len(bin_data) // 8
    zong_length = block_size * 8
    dct_data = bin_data[:zong_length]
    dct_data = np.array(dct_data).reshape(-1, 2)
    dct_data = dct_data.astype(np.float32)
    dct_data = np.vsplit(dct_data, block_size)
    # used to save data after dct
    temp_dct = np.zeros(shape=(block_size, 4, 2))
    for i in range(len(dct_data)):
        temp_dct[i] = cv2.dct(dct_data[i])

    # used to save extract data in format bit
    outdata = []
    for i in range(0, 2 * pay_length, 2):
        if temp_dct[i][0][0] == temp_dct[i + 1][0][0]:
            outdata.append(1)
        else:
            outdata.append(0)
    outdata = np.packbits(outdata)
    outdata = outdata.reshape(image_size)

    return outdata