Pregunta

Aquí están los detalles de lo que Picasa almacena como un hash. Los almacena así:

faces=rect64(54391dc9b6a76c2b),4cd643f64b715489
[DSC_2289.jpg]
faces=rect64(1680000a5c26c82),76bc8d8d518750bc

La información en la web dice esto:

El número encerrado en Rect64 () es un número hexadecimal de 64 bits.

  • Romper eso en cuatro números de 16 bits.
  • Divida cada uno por el número máximo de 16 bits sin firmar (65535) y tendrá cuatro números entre 0 y 1.
  • Los cuatro números restantes le dan coordenadas relativas para el rectángulo de la cara: (izquierda, arriba, derecha, abajo).
  • Si desea terminar con coordenadas absolutas, múltiple la izquierda y la derecha por el ancho de la imagen y la parte superior e inferior por la altura de la imagen.

Entonces, mi código para convertir eso en un RectangleF funciona bien (solo manteniendo coordenadas relativas):

    public static RectangleF GetRectangle(string hashstr)
    {
        UInt64 hash = UInt64.Parse(hashstr, System.Globalization.NumberStyles.HexNumber);
        byte[] bytes = BitConverter.GetBytes(hash);

        UInt16 l16 = BitConverter.ToUInt16(bytes, 6);
        UInt16 t16 = BitConverter.ToUInt16(bytes, 4);
        UInt16 r16 = BitConverter.ToUInt16(bytes, 2);
        UInt16 b16 = BitConverter.ToUInt16(bytes, 0);

        float left = l16 / 65535.0F;
        float top = t16 / 65535.0F;
        float right = r16 / 65535.0F;
        float bottom = b16 / 65535.0F;

        return new RectangleF(left, top, right - left, bottom - top);
    }

Ahora tengo un RectangleF y quiero volver a volver al hash mencionado anteriormente. Parece que no puedo resolver esto. Parece que Picasa usa 2 bytes, incluida la precisión, sin embargo, un flotador en C# es de 8 bytes e incluso BitConverter. Tossle es 4 bytes.

Cualquier ayuda apreciada.

EDITAR: Esto es lo que tengo ahora mismo

    public static string HashFromRectangle(RectangleCoordinates rect)
    {
        Console.WriteLine("{0} {1} {2} {3}", rect.Left, rect.Top, rect.Right, rect.Bottom);
        UInt16 left = Convert.ToUInt16((float)rect.Left * 65535.0F);
        UInt16 top = Convert.ToUInt16((float)rect.Top * 65535.0F);
        UInt16 right = Convert.ToUInt16((float)rect.Right * 65535.0F);
        UInt16 bottom = Convert.ToUInt16((float)rect.Bottom * 65535.0F);            

        byte[] lb = BitConverter.GetBytes(left);
        byte[] tb = BitConverter.GetBytes(top);
        byte[] rb = BitConverter.GetBytes(right);
        byte[] bb = BitConverter.GetBytes(bottom);

        byte[] barray = new byte[8];
        barray[0] = lb[0];
        barray[1] = lb[1];
        barray[2] = tb[0];
        barray[3] = tb[1];
        barray[4] = rb[0];
        barray[5] = rb[1];
        barray[6] = bb[0];
        barray[7] = bb[1];

        return BitConverter.ToString(barray).Replace("-", "").ToLower();
    }
¿Fue útil?

Solución

Su código actual está intercambiando los bytes de cada coordenada. Esto se debe a que BitConverter le da los bytes en el orden de Little Endian (es decir, el primer byte en la matriz es el byte menos significativo). El intercambio de sus tareas de la siguiente manera hace que la decodificación y la reiniciación devuelvan el hash original.

        barray[0] = lb[1];
        barray[1] = lb[0];
        barray[2] = tb[1];
        barray[3] = tb[0];
        barray[4] = rb[1];
        barray[5] = rb[0];
        barray[6] = bb[1];
        barray[7] = bb[0];

Dicho esto, creo que es más claro hacer la conversión utilizando multiplicaciones y agrega simples. Puede hacer algo similar con la decodificación de la cadena hash si la lee como un solo ulong y reste/divide. por ejemplo, para la codificación:

    public static ushort ToUShort(double coordinate)
    {
        double ratio = Math.Max(0, Math.Min(Math.Round(coordinate * 65535), 65535));
        return (ushort)ratio;
    }

    public static string HashFromRectangle(Rect rect)
    {
        ulong left = ToUShort(rect.Left);
        ulong top = ToUShort(rect.Top);
        ulong right = ToUShort(rect.Right);
        ulong bottom = ToUShort(rect.Bottom);

        ulong hash = (((left * 65536) + top) * 65536 + right) * 65536 + bottom;
        return hash.ToString("x");
    }

Otros consejos

Parece que debe eliminar los tipos de flotación de HashFromRectangle (RECT) como así:

    UInt16 left = (UInt16)( rect.Left * 65535.0F);
    UInt16 top =(UInt16) (rect.Top * 65535.0F);
    UInt16 right = (UInt16) (rect.Right * 65535.0F);
    UInt16 bottom = (UInt16) (rect.Bottom * 65535.0F);

Además, podría ser más legible usar esto para completar la matriz:

    Array.Copy(lb, 0, barray, 0, 2);
    Array.Copy(tb, 0, barray, 2, 2);
    Array.Copy(rb, 0, barray, 4, 2);
    Array.Copy(bb, 0, barray, 6, 2);

¡Hazme saber si esto funciona!

Aaron

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top