Canon EDSDK.EdsGetImage ошибка EDS_ERR_NOT_SUPPORTED при чтении файла CR2 - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь прочитать файл CR2, используя Canon EDSDKv0309W.Я не нашел пример для этой версии SDK, поэтому я посмотрел несколько примеров из более старых версий и создал код ниже.Но я всегда получаю EDS_ERR_NOT_SUPPORTED в строке EDSDK.EdsGetImage (..).

Используя 32-битную компиляцию в .Net4.6.1, я могу прочитать правильные значения и высоту из изображений, сделанных с помощью EOS500D и M100.Но я не понимаю изображение.Так что я предполагаю, что я получаю неправильный указатель от EdsCreateMemoryStream.Но я не вижу, что не так и как это отладить.Любая помощь будет оценена.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EDSDKLib;
using System.Drawing;
using System.Drawing.Imaging;

namespace CR2Reader
{
class Program
{

    static Bitmap GetImage(IntPtr img_stream, EDSDK.EdsImageSource imageSource)
    {
        IntPtr stream = IntPtr.Zero;
        IntPtr img_ref = IntPtr.Zero;
        IntPtr streamPointer = IntPtr.Zero;
        EDSDK.EdsImageInfo imageInfo;
        uint error = 0;

        try
        {
            //create reference and get image info
            error = EDSDK.EdsCreateImageRef(img_stream, out img_ref);
            if (error == 0)
            {
                error = EDSDK.EdsGetImageInfo(img_ref, imageSource, out imageInfo);
                if (error == 0)
                {
                    EDSDK.EdsSize outputSize = new EDSDK.EdsSize();
                    outputSize.width = imageInfo.EffectiveRect.width;
                    outputSize.height = imageInfo.EffectiveRect.height;
                    //calculate amount of data
                    int datalength = outputSize.height * outputSize.width * (int)imageInfo.NumOfComponents * (int)(imageInfo.ComponentDepth / 8);
                    //create buffer that stores the image
                    error = EDSDK.EdsCreateMemoryStream((ulong)datalength, out stream);
                    if (error == 0)
                    {
                        //load image into the buffer
                        error = EDSDK.EdsGetImage(img_ref, imageSource, EDSDK.EdsTargetImageType.RGB16, imageInfo.EffectiveRect, outputSize, stream);
                        if (error == 0)
                        {
                            //make BGR from RGB (System.Drawing (i.e. GDI+) uses BGR)
                            byte[] buffer = new byte[datalength];

                            unsafe
                            {
                                System.Runtime.InteropServices.Marshal.Copy(stream, buffer, 0, datalength);
                                byte tmp;
                                fixed (byte* pix = buffer)
                                {
                                    for (int i = 0; i < datalength; i += 3)
                                    {
                                        tmp = pix[i];        //Save B value
                                        pix[i] = pix[i + 2]; //Set B value with R value
                                        pix[i + 2] = tmp;    //Set R value with B value
                                    }
                                }
                            }

                            //Get pointer to stream
                            error = EDSDK.EdsGetPointer(stream, out streamPointer);
                            if (error == 0)
                            {
                                //Create bitmap with the data in the buffer
                                return new Bitmap(outputSize.width, outputSize.height, datalength, PixelFormat.Format24bppRgb, streamPointer);
                            }
                        }
                    }
                }
            }
            return null;
        }
        finally
        {
            //Release all data
            if (img_ref != IntPtr.Zero) error = EDSDK.EdsRelease(img_ref);
            if (stream != IntPtr.Zero) error = EDSDK.EdsRelease(stream);
        }
    }

   static Bitmap ReadCR2Image(string fileName)
    {
        IntPtr outStream = new IntPtr();

        uint error = EDSDK.EdsInitializeSDK();

        error += EDSDK.EdsCreateFileStream(fileName,
                     EDSDK.EdsFileCreateDisposition.OpenExisting,
                     EDSDK.EdsAccess.Read,
                     out outStream);
        Bitmap bmp = null;
        if (error == 0)
        {
            bmp = GetImage(outStream, EDSDK.EdsImageSource.FullView);
        }
        if (outStream != IntPtr.Zero)
        {
            error = EDSDK.EdsRelease(outStream);
        }
        EDSDK.EdsTerminateSDK();
        return bmp;
    }


    static void Main(string[] args)
    {
        Bitmap bmp = ReadCR2Image("IMG_3113.CR2");
    }
}
}

1 Ответ

0 голосов
/ 31 января 2019

Вы используете неправильный тип EdsImageSource.Так как вы загружаете изображение в формате RAW, вы также должны использовать EdsImageSource.RAWFullView.EdsImageSource.FullView подходит, например, для JPG или TIFF.

После того, как вы это измените, все должно работать просто отлично.

Редактировать: только что увидел, что вы используете RGB16 как цель, но остальная часть кода предполагает нормальный 8-битный RGB.Вам придется изменить целую кучу вещей, чтобы заставить это работать правильно.Я бы посоветовал вам использовать RGB, если вам действительно не нужен 16 бит.

Редактировать 2: Похоже, что библиотека немного не подходит в этом отношении (я должен действительно обновить ее).В любом случае вы всегда можете проверить заголовочные файлы SDK на предмет актуальных значений.Вот текущее определение для EdsImageSource:

enum EdsImageSource
{
    FullView = 0,
    Thumbnail,
    Preview,
    RAWThumbnail,
    RAWFullView,
}

Что касается изменений, необходимых для 16 бит:

  • datalength неверно
  • вы используете byte вместо ushort для установки пикселей
  • вы создаете Bitmap с PixelFormat.Format24bppRgb
  • , тогда есть еще одна вещь, где Bitmap не полностью поддерживает 16Bit.См. эту статью для получения более подробной информации.

В зависимости от того, что вам нужно сделать, вероятно, лучше использовать исходные данные пикселей непосредственно, как вы получаете их из SDKили используйте другую графическую библиотеку (например, WPF, SkiaSharp, ImageSharp и т. д.)

...