0

I have a socket communication based application and the server sends a request to a client for a signature image. The signature is taken at the client and sent back to the server.

To do this I have used a picture box, who's data is converted into bytes and then into a string to send over the socket connection to the server. This all works OK.

I am having problems saving the data received in the database because I need to be able to save it as an image type but at this point the data is still a string so I am getting the error:

"Operand type clash: nvarchar is incompatible with image"

I presume it's because I am trying to send a string to a sql image type?

Code which attempts to call the procedure and errors (server end- received data as string):

try
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["GetConnector"].ConnectionString))
    {
        SqlCommand sqlComm = new SqlCommand("PL_Device_ReadData", conn);
        sqlComm.Parameters.AddWithValue("@DeviceTypeID", DeviceID);
        sqlComm.Parameters.AddWithValue("@RequestID", RequestID);
        if (DeviceID != "5")
        {
            sqlComm.Parameters.AddWithValue("@Reading", Reading);
        }
        else if (DeviceID == "5")
        {
            sqlComm.Parameters.AddWithValue("@ImageReading", Reading);
            sqlComm.Parameters.Add("@ImageReading", SqlDbType.Image);
            sqlComm.Parameters["@ImageReading"].Value = Reading;
        }
        sqlComm.CommandType = CommandType.StoredProcedure;

        SqlDataAdapter da = new SqlDataAdapter();
        da.SelectCommand = sqlComm;

        da.Fill(ds);
    }
}

catch (Exception e)
{

}

Stored Procedure:

ALTER PROCEDURE [dbo].[PL_Device_ReadData]
    @DeviceTypeID INT,
    @RequestID INT,
    @Reading NVARCHAR(100) = NULL,
    @ImageReading IMAGE = NULL  
AS
BEGIN
--Data
    IF @DeviceTypeID = 5 
    BEGIN
        UPDATE dbo.DeviceRequests 
        SET ImageData = @ImageReading
        WHERE id = @RequestID
        AND DeviceTypeID = @DeviceTypeID
    END
    ELSE
    BEGIN   
        UPDATE dbo.DeviceRequests 
        SET Value = @Reading
        WHERE id = @RequestID
        AND DeviceTypeID = @DeviceTypeID
END 
END

Converting the image into bytes:

byte[] imgData = null;
// storage for the img bytes
imgData = ImgToByteArray(picSignature.InitialImage, ImageFormat.Jpeg);

public static byte[] ImgToByteArray(Image img, ImageFormat imgFormat)
{
    byte[] tmpData = null;
    using (MemoryStream ms = new MemoryStream())
    {
        img.Save(ms, imgFormat);

        tmpData = ms.ToArray();
    }
    // dispose of memstream
    return tmpData;

}

Converting the bytes to string (to send over socket):

_Reading = System.Text.Encoding.UTF8.GetString(_imagevalues);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
connersz
  • 1,153
  • 3
  • 23
  • 64
  • So convert it back to the image on server and then store it in database – Mahesh Jan 14 '15 at 11:37
  • Firstly, please take more time to format your code when you post. Most of the first snippet was indented *way* over to the right. I've fixed it now, but please take a bit more care in future. – Jon Skeet Jan 14 '15 at 11:37
  • @CoderofCode That's part of the problem I have having, I am unsure of how to convert the string back into an image. – connersz Jan 14 '15 at 11:38
  • reverse answer needed http://stackoverflow.com/questions/34485968/view-image-from-list-view-string-unicode-to-picture-box-parameter-not-valid – office 302 Dec 28 '15 at 10:02

2 Answers2

3

To do this I have used a picture box, who's data is converted into bytes and then into a string to send over the socket connection to the server. This all works OK.

Given the code you've shown, I'd suggest it probably doesn't. In particular:

_Reading = System.Text.Encoding.UTF8.GetString(_imagevalues);

Image data is not UTF-8-encoded text, so you shouldn't be using Encoding.UTF8 or indeed any encoding. Encodings are designed to convert natural plain text into bytes and back. Instead, you have arbitrary binary data.

Ideally, you should transmit this over the socket as binary data - it's not clear why you need a string at all. If you really do need a string though, you should convert the bytes into text using base64:

string base64 = Convert.ToBase64String(bytes);

then on the other side, you can do the reverse:

byte[] bytes = Convert.FromBase64String(base64);

But as I say, if you're in control of the protocol, it would be cleaner and more efficient to just transmit the bytes in binary form without converting them to text at all. We can't tell what protocol this is, so it's hard to know whether or not that's an option.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

This:

_Reading = System.Text.Encoding.UTF8.GetString(_imagevalues);

is wrong. Is _imagevalues holding binary data of the image? Than in that line of code you are trying to interpret this as string, which is wrong. You have to just convert each individual byte of image to say its hexadecimal string representation. Then send the whole such string over network. e.g., see here How do you convert Byte Array to Hexadecimal String, and vice versa? (As noted in one of the answers this conversions is not really necessary and you could as well send plain bytes).

Then on the server side, you have to parse this hexadecimal string and convert it to byte array and probably save in the database.

Community
  • 1
  • 1
Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • This looks promising but the data I get back after every different signature is always the same and the image looks like the missing image logo. Is it because I am using PictureBox.InitialImage? I tried to use .Image but it was always NULL – connersz Jan 14 '15 at 11:54
  • @connersz: I am not sure I got what you mean. I just suggest following. Imagine you have binary data: 123 22 (2 bytes). I gave you idea how to encode it to(and back to) hex string, e.g., "7B 16". So if you follow what I tell you, on the server side you should receive string "7B 16" -> then you should convert it again to byte array (123 22). Now, how you read the image and the byte array, I am not sure it is up to you. – Giorgi Moniava Jan 14 '15 at 11:57
  • I mean when I get the bytes from the control which is a .net PictureBox, If I try to take the image from .Image it is NULL. Do I need to call a method to update the .Image beforehand? – connersz Jan 14 '15 at 11:58
  • @conners: Is this image loaded from file? Why not just do `ReadAllBytes` on that file? – Giorgi Moniava Jan 14 '15 at 12:00
  • No it is created using a signature pad, where the user writes their signature so it's like the image needs to be closed somehow first. – connersz Jan 14 '15 at 12:00
  • @connersz: Is this related? http://stackoverflow.com/questions/26405961/picture-box-to-byte-array – Giorgi Moniava Jan 14 '15 at 12:01
  • No I don't think so. I have the hex part working but because the image is generated in real-time. The Image property is always NULL. – connersz Jan 14 '15 at 12:03
  • imgData = ImgToByteArray(picSignature.Image, ImageFormat.Jpeg); The .Image is NULL – connersz Jan 14 '15 at 12:04
  • @connersz: hm... maybe ask a separate question on that; I'm myself not that experienced in this framework – Giorgi Moniava Jan 14 '15 at 12:05