AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Hilfe zu IThumbnailProvider

Ein Thema von Benmik · begonnen am 4. Nov 2022 · letzter Beitrag vom 7. Nov 2022
Antwort Antwort
Seite 1 von 2  1 2      
Benmik

Registriert seit: 11. Apr 2009
543 Beiträge
 
Delphi 11 Alexandria
 
#1

Hilfe zu IThumbnailProvider

  Alt 4. Nov 2022, 14:03
Ich würde gern ausprobieren, über IThumbnailProvider Miniaturansichten von JPG zu erstellen. Das gestaltet sich aber schwierig, im Internet findet man für Delphi kaum etwas. Bei Stackoverflow habe ich zwei Hinweise gefunden:
Hier folgenden Code:
Delphi-Quellcode:
function LoadBitmapWithShellExtension(const ADllFileName: UnicodeString; const ACLSID: TCLSID;
  const AFileName: UnicodeString; ASize: Integer; out AAlpha: WTS_ALPHATYPE): HBITMAP;
type
  TDllGetClassObject = function(const CLSID, IID: TGUID; out Obj): HRESULT; stdcall;
var
  DllModule: HMODULE;
  DllGetClassObject: TDllGetClassObject;
  ClassFactory: IClassFactory;
  ThumbnailProvider: IThumbnailProvider;
  InitializeWithFile: IInitializeWithFile;
  PersistFile: IPersistFile;
begin
  DllModule := LoadLibraryW(PWideChar(ADllFileName));
  if DllModule = 0 then RaiseLastOSError;
  try
    @DllGetClassObject := GetProcAddress(DllModule, 'DllGetClassObject');
    if not Assigned(DllGetClassObject) then
      RaiseLastOSError;
    OleCheck(DllGetClassObject(ACLSID, IClassFactory, ClassFactory));
    try
      OleCheck(ClassFactory.CreateInstance(nil, IThumbnailProvider, ThumbnailProvider));
      try
        if Succeeded(ThumbnailProvider.QueryInterface(IInitializeWithFile, InitializeWithFile)) then
          try
            OleCheck(InitializeWithFile.Initialize(PWideChar(AFileName), STGM_READ));
          finally
            InitializeWithFile := nil;
          end
        else
          if Succeeded(ThumbnailProvider.QueryInterface(IPersistFile, PersistFile)) then
            try
              OleCheck(PersistFile.Load(PWideChar(AFileName), STGM_READ));
            finally
              PersistFile := nil;
            end
          else
            raise Exception.Create('Cannot initialize handler');

        OleCheck(ThumbnailProvider.GetThumbnail(ASize, Result, AAlpha));
      finally
        ThumbnailProvider := nil;
      end;
    finally
      ClassFactory := nil;
    end;
  finally
    FreeLibrary(DllModule);
  end;
end;
Es war mühsam, den ans Laufen zu bringen; ich habe IThumbnailProvider in Delphi nirgenwo gefunden und musste die Deklaration aus einer anderen Fundstelle einfügen. Letztlich bin ich dann bei DllGetClassObject(ACLSID, IClassFactory, ClassFactory) hängengeblieben, weil mir nicht klar ist, was für ACLSID eingesetzt werden muss. Ich habe dann auch nicht versucht, das herauszuknobeln, weil ich bei System.Win.ComServ.DllGetClassObject gelesen habe: Do not call DllGetClassObject directly. DllGetClassObject is exported by all ActiveX server DLLs, and it is called internally by the operating system. When a user calls CoGetClassObject (or CoCreateInstance, which internally calls CoGetClassObject) to obtain a class factory for an ActiveX object, the OLE engine loads the ActiveX server DLL into memory and calls its DllGetClassObject function. Die Umsetzung von CoCreateInstance ist mir leider auch nicht klar.

Die zweite Stelle ist von Remy Lebeau. Hier gefällt mir 1) mit IInitializeWithStream . Das umzusetzen habe ich aber auch keine Chance.

Hat vielleicht jemand den richtigen Code in der Schublade?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#2

AW: Hilfe zu IThumbnailProvider

  Alt 4. Nov 2022, 15:18
Ich würde es erstmal mit {B196B28F-BAB4-101A-B69C-00AA00341D07} probieren, also der GUID von IClassFactory,
oder vermutlich {50d9450f-2a80-4f08-93b9-2eb526477d1b} Recipe Thumbnail Handler, aus der Microsoft-Demo
https://github.com/microsoft/Windows...ovider/Dll.cpp
oder {cf572d73-d6e5-4d45-acad-f18f4f76656f} ... schau mal, was zu IThumbnailProvider in HKEY_CLASSES_ROOT\CLSID gefunden wird.

Du mußt einen Provider finden, welcher für deinen Dateityp eine Preview bietet.
Als Erstes hätte ich nun Hoffnung, dass Diese auch bei den jeweiligen Dateitypen eingetragen ist.
Für png, jpg und pdf hier auf die Schnelle zwar ein paar GUID darin gefunden, aber Nichts, was scheinbar mit Thumbnails zu tun hat.



Da steht doch beim Hersteller beschrieben, wie das Interface aussieht? (ok, hier mal nur implizit und nicht direkt mit einer Implementation)
https://learn.microsoft.com/en-us/wi...mbnailprovider

Der Name des Interfaces ist egal, aber der heißt ja "IThumbnailProvider"
und dann findet sich dort die nötige GUID, der Vorfahre und die Deklaration der einzigen Methode.


Alternativ lädt man sich das WinSDK/PSDK/... runter, denn unten findest du die Headerdatei, aus der du dir die C++-Deklaration kopieren und dann nach Delphi übersetzen kannst. (alternativ im Internet nach diesem Dateinamen suchen ... PS: Microsoft hat Vieles auf Github hochgeladen)



[edit]
"Vieles" ist gut ... da sind inzwischen schon 5200 Repos
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 4. Nov 2022 um 15:40 Uhr)
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
543 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Hilfe zu IThumbnailProvider

  Alt 6. Nov 2022, 13:25
Vielen Dank, Himitsu. Das Ganze ist am Rand meiner Kenntnisse, bzw. eigentlich darüber hinaus. Zudem bin ich mittlerweile im Zweifel, ob mir IThumbnailProvider eigentlich das bringt, was ich brauche, nämlich eine Miniaturansicht des JPG-Inhalts. Diese ganzen Thumbnailsachen scheinen nämlich einen quadratischen Thumbnail zurückzugeben, was etwas anderes ist.

Ich habe jetzt - nicht zuletzt aus didaktischen und auch sportlichen Gründen - intensiv weiter gesucht und ein paar Stellen gefunden, die relativ weit führen, aber eben nie einen funktionierenden Code liefern. Ich habe das Gefühl, wenn ich ein bisschen mehr in diesem Stoff stünde, dann wäre es von diesen Beispielen aus gar nicht so schwer, aber hingekriegt habe ich es einfach nicht.

Natürlich als Erstes die bereits erwähnten Vorschläge von Remy Lebeau. Nur halt: Wie umsetzen?

Hier hat Postscripter in einem russischen Forum in #9 ein Gerüst angegeben und in #10 offenbar auch fertiggestellt. Leider komme ich an test.rar nicht heran, selbst auf eine Anmeldung hin erfolgte keine Antwort.

Hier gibt es ebenfalls eine Anleitung, die ich aber auch nicht ans Laufen gebracht habe. Die dort angegebene function GetPreviewHandlerCLSID(const AFileName: string): string; funktioniert auch nicht. Ein Hinweis darauf, warum nicht, findet sich in der mit Vergnügen zu lesenden Frage von Ian Boyd, wie man den richtigen IPreviewHandler erzeugt. Der entscheidende Hinweis wird ganz am Schluss von Simon Mourier gegeben ("There are today some files that don't have a preview handler at all (.txt and all image types like .png, .jpg or the modern .heic, .webp, etc.)."). Tatsächlich habe ich einfach zu Fuß die Registry durchsucht, und in der Tat gab es unter HKEY_CLASSES_ROOT\jpegfile\ShellEx\ den genannten Schlüssel {e357fccd-a995-4576-b01f-234630154e96} mit der GUID {C7657C4A-9F68-40fa-A4DF-96BC08EB3551} als Wert. Den kannte ich schon von Microsoft, es handelt sich um CLSID_PhotoThumbnailProvider.

Ich habe mich erstmal an Postscripter gehalten und die beiden Interfaces als Klasse implementiert. Warum man die beiden Initialize umbiegen muss -> keine Ahnung, Postscriper selbst schreibt "извращенцы", was "Perverse!" heißt. Ein paar Deklarationen habe ich eingefügt, auch wenn sie in den referenzierten Units enthalten waren, da die Units nicht immer dieselbe Deklaration hatten und auch, um unabhängig zu sein. Die Prozedur läuft auch durch, jedoch hat das Bitmap eine Breite/Länge von 0, obwohl mir das Handle plausibel aussieht. Allerdings habe ich auch keine Ahnung, womit ich die Aufrufe von GetThumbnail und Initialize_WS eigentlich füllen soll, das sind doch API-Aufrufe?! Postscripter hat sie mit Beep und Showmessage('Funktioniert!' gefüllt; Endgültiges steht wohl im test.rar, das ich ja nicht habe.

Es ist ja klar, dass ich da herumdoktere, ohne mehr als eine Halbahnung zu haben, was ich da eigentlich tue. Wahrscheinlich kann jemand von den alten Hasen da Ordnung ins Chaos bringen.
(Der Versuch, FPreviewHandler := CreateComObject statt TComObjectFactory zu benutzen und damit QueryInterface durchzuführen, scheitert übrigens an "Interface not supported".)

Delphi-Quellcode:
uses
  ...
  ComServ,Winapi.ActiveX, ComObj, Winapi.ShlObj, Winapi.PropSys;

type
  {$EXTERNALSYM WTS_ALPHATYPE}
  WTS_ALPHATYPE = (
    WTSAT_UNKNOWN = 0,
    WTSAT_RGB = 1,
    WTSAT_ARGB = 2
  );

const
  {$EXTERNALSYM SID_IThumbnailProvider}
  SID_IThumbnailProvider = '{e357fccd-a995-4576-b01f-234630154e96}';
  SID_IInitializeWithStream = '{b824b49d-22ac-4161-ac8a-9916e8fa3f7f}';
  SID_IInitializeWithFile = '{b7d14566-0509-4cce-a71f-0a554233bd9b}';

  type
  IThumbnailProvider = interface(IUnknown)
    [SID_IThumbnailProvider]
    function GetThumbnail(cx: UINT; var phbmp: HBITMAP; var Flags: DWORD): HResult; stdcall;
  end;

  IInitializeWithFile = interface(IUnknown)
    [SID_IInitializeWithFile]
    function Initialize(pszFilePath: PWideChar; grfMode: DWORD): HRESULT; stdcall;
  end;

  IInitializeWithStream = interface(IUnknown)
    [SID_IInitializeWithStream]
    function Initialize(const pstream: IStream; grfMode: DWORD): HRESULT; stdcall;
  end;

  TThumbnailProvider = class(TComObject, IThumbnailProvider, IInitializeWithStream, IInitializeWithFile)
  private
  protected
    function GetThumbnail(cx: UINT; var phbmp: HBITMAP; var Flags: DWORD): HResult; stdcall;
    function IInitializeWithFile.Initialize = Initialize_WF; // извращенцы
    function IInitializeWithStream.Initialize = Initialize_WS;
    function Initialize_WF(pszFilePath: PWideChar; grfMode: DWORD): HResult; stdcall;
    function Initialize_WS(const pstream: IStream; grfMode: DWORD): HResult; stdcall;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  function LoadPreviewHandler(const FileName: string):HBitmap;
  function ErstelleMiniatur(const FileName: string; BMPHandel:HBitmap):HBitmap;
  function GetPreviewHandlerCLSID(const AFileName: string): string;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  BMP:TBitmap;
begin
  BMP := TBitmap.Create(256,256);
  Try
    BMP.Handle := ErstelleMiniatur('C:\Temp\7IV06423.JPG',BMP.Handle);
  Finally
    BMP.Free;
  end;
end;

function ErstelleMiniatur(const FileName: string; BMPHandle:HBitmap):HBitmap;
var
  LPreviewGUID : TGUID;
  LInitializeWithFile : IInitializeWithFile;
  LInitializeWithStream : IInitializeWithStream;
  LInitializeWithItem : IInitializeWithItem;
  LIStream : IStream;
  LShellItem : IShellItem;
  FPreviewHandler : IPreviewHandler;
  FFileStream:TFileStream;
  TP:IThumbnailProvider;
  Alpha:WTS_ALPHATYPE;
  Alpha2:Cardinal;
const
  CLSID_PhotoThumbnailProvider = '{C7657C4A-9F68-40fa-A4DF-96BC08EB3551}';
begin
  Result := BMPHandle;
  LPreviewGUID:= StringToGUID('{098f2470-bae0-11cd-b579-08002b30bfeb}');
  LPreviewGUID:= StringToGUID(SID_IThumbnailProvider);
  LPreviewGUID:= StringToGUID(CLSID_PhotoThumbnailProvider);
  TComObjectFactory.Create(ComServer, TThumbnailProvider, LPreviewGUID, 'Miniatur', 'Miniatur', ciSingleInstance, tmSingle);
// FPreviewHandler := CreateComObject(LPreviewGUID) As IPreviewHandler;
// if (FPreviewHandler = nil) then
// exit;
  TP := TThumbnailProvider.Create;
  If TP.QueryInterface(IInitializeWithStream, LInitializeWithStream) = S_OK then begin
    FFileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
    LIStream := TStreamAdapter.Create(FFileStream, soOwned) as IStream;
    LInitializeWithStream.Initialize(LIStream, STGM_READ);
    TP.GetThumbnail(256,Result,Alpha2);
    Alpha := WTS_ALPHATYPE(Alpha2);
    TP.Free;
  end;
end;

function TThumbnailProvider.GetThumbnail(cx: UINT; var phbmp: HBITMAP; var Flags: DWORD): HResult;
begin

end;

function TThumbnailProvider.Initialize_WF(pszFilePath: PWideChar; grfMode: DWORD): HResult;
begin

end;

function TThumbnailProvider.Initialize_WS(const pstream: IStream; grfMode: DWORD): HResult;
begin

end;
  Mit Zitat antworten Zitat
striderx

Registriert seit: 11. Feb 2007
Ort: Bergisch Gladbach
206 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Hilfe zu IThumbnailProvider

  Alt 6. Nov 2022, 19:49
Ich mache das (m. E. wesentlich einfacher) mit GDI+:

Delphi-Quellcode:
function GDIPMakeThumbnail(sSourceFile, sTargetFile: String;
                           AWidth, AHeight: Word): Boolean;

var
  BM: tBitmap;
  GR: tGPGraphics;
  GDPImage: TGPImage;
  GDPThumbnail: TGPImage;
  H: Single;
  R1: Single;
  R2: Single;
  W: Single;

begin
  Result := False;
  {............................................................................}
  if not tFile.Exists(sSourceFile) then Exit;
  {............................................................................}
  if (sTargetFile = '') or (sTargetFile = sSourceFile) then Exit;
  {............................................................................}
  if (AWidth < 10) or (AHeight < 10) then Exit;
  {............................................................................}
  BM := tBitmap.Create;
  BM.Width := AWidth;
  BM.Height := AHeight;
  GR := tGPGraphics.Create(BM.Canvas.Handle);
  GDPImage := TGPImage.Create(sSourceFile);
  {............................................................................}
  R1 := AWidth / AHeight;
  H := GDPImage.GetHeight;
  W := GDPImage.GetWidth;
  if (H = 0) or (W = 0) then Exit;
  {............................................................................}
  R2 := W / H;
  if R1 > R2 then begin
     W := AHeight * R2;
     H := AHeight;
  end
  else begin
     W := AWidth;
     H := AWidth / R2;
  end;
  {............................................................................}
  GDPThumbnail := GDPImage.GetThumbnailImage(Round(W), Round(H), nil, nil);
  GR.DrawImage(GDPThumbnail, MakeRect((AWidth - W) / 2, (AHeight - H) / 2, W, H));
  try
    BM.SaveToFile(sTargetFile);
    Result := True
  except
    ShowMsg('Fehler beim Speichern der Thumbnail-Datei', ' Fehler', mb_OK,
            mb_IconError);
  end;
  {............................................................................}
  GR.Free;
  GDPImage.Free;
  GDPThumbnail.Free;
  BM.Free;
end;

Geändert von striderx ( 6. Nov 2022 um 20:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#5

AW: Hilfe zu IThumbnailProvider

  Alt 6. Nov 2022, 21:07
"Diese" Thumbnails sind nunmal vorwiegend für die Vorschau im Explorer und dort sind die Icons/Images nunmal Quadrate.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#6

AW: Hilfe zu IThumbnailProvider

  Alt 6. Nov 2022, 21:38
Ich würde gern ausprobieren, über IThumbnailProvider Miniaturansichten von JPG zu erstellen.
Ich habe deinen Thread nur kurz überflogen. Dieser Beitrag (Beispiel ganz unten) aus dem DevExpress Support Center könnte vielleicht etwas für dich sein.

Bis bald...
Thomas
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
543 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Hilfe zu IThumbnailProvider

  Alt 6. Nov 2022, 23:32
Ich mache das (m. E. wesentlich einfacher) mit GDI+:
GDI+ hatte ich gar nicht auf dem Schirm, obwohl ich das schon für das verlustfreie Drehen einsetze.
Welche GDI+-Unit verwendest du denn? Anscheinend nicht die von Erik van Bilsen.

@Himitsu: Ja, das habe ich ein bisschen spät bemerkt. Allerdings ging es mir dann immer mehr um den "sportlichen" Aspekt, ich wollte das Ganze zumindest einmal ans Laufen bringen und dabei auch noch verstehen.

@mytbo: Vielen Dank. Eine Eigenart dieser reinen Thumbnail-Prozessoren ist, dass sie bei JPG-Dateien nachschauen, ob es ein Thumbnail gibt und dann verwenden sie das. Für größere Miniaturbilder ist das von der Qualität her nicht akzeptabel. Meine gegenwärtige Lösung arbeitet mit IExtractImage aus Winapi.ShlObj und das funktioniert gut. Ich wollte unter anderem aber auch mal sehen, ob die neueren Methoden vielleicht schneller sind.

Geändert von Benmik ( 6. Nov 2022 um 23:47 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#8

AW: Hilfe zu IThumbnailProvider

  Alt 7. Nov 2022, 02:15
Vielleicht ist es einfacher, sich über IShellFolder und IShellIcon oder IExtractIcon das Vorschau-Icon zu besorgen?
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
venice2
(Gast)

n/a Beiträge
 
#9

AW: Hilfe zu IThumbnailProvider

  Alt 7. Nov 2022, 02:34
https://rmklever.com/?p=266
  Mit Zitat antworten Zitat
striderx

Registriert seit: 11. Feb 2007
Ort: Bergisch Gladbach
206 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Hilfe zu IThumbnailProvider

  Alt 7. Nov 2022, 05:57
Welche GDI+-Unit verwendest du denn? Anscheinend nicht die von Erik van Bilsen.

Das ist die von Prodigy.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:20 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz