Sign in to follow this  
Followers 0
Brandan

Saving jpg as JFIF Specification 1.02?

1 post in this topic

I have been using GDIPlus to do a lot of image manipulation and love the flexablity it gives me when combined with autoit. I am stumped on my most recent project. That takes a single image and makes it into many that form a tiled structure that can be used in a flash program to put a person in a virtural tour.

I have a test one to compare to to make sure that I am doing everything right. My script will make all of the tiles the perfect size, and will look just like the sample. But when I load it into the flash program lines show up around the edges of the cubes and the flash program takes longer to figure out to display it. Even though the compression and file types are the same.

I have uploaded photos from both to http://www.imageforensic.org The only difference that it can see is that sample is in JFIF Specification 1.02, where as the files created by GDIPlus are JFIF standard 1.01.

Anyone have any ideas how I can save .jpg files in JFIF Standard 1.02 with Autoit? I would like to use GDIPlus as I already have it working, but if I need to I will use any library that gets the job done. Thanks,

Brandan

 

Share this post


Link to post
Share on other sites



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Similar Content

    • Blaxxun
      By Blaxxun
      #include <GDIPlus.au3> Text2PNG(@DesktopDir & "\MyPNG.png", 0x00FFFFFF) ; Transparent but bold ugly text ;Text2PNG(@DesktopDir & "\MyPNG.png", 0xFFFFFFFF) ; Nice Text but not transparent Func Text2PNG($sFile, $iColor) _GDIPlus_Startup() Local $hImage = _GDIPlus_BitmapCreateFromScan0(50, 25) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsClear($hGraphics, $iColor) _GDIPlus_GraphicsDrawString($hGraphics, "Hello", 0, 0, "Arial", 12, 0) _GDIPlus_ImageSaveToFile($hImage, $sFile) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() EndFunc ;==>Text2PNG  
      Hello ladys and gentlemen,
      I have this piece of code and it does what it's supposed to do.
      I want to use it to create an image sequence with frame/image information for compositing overlay.
      However, when i use a transparent background the text starts to look kinda bold or fat.
      I dont know what causes this ugly effect.
      Is there a way to avoid this effect somehow?
      Thanks!
       
       
    • youtuber
      By youtuber
      $hImage = _GDIPlus_ImageLoadFromFile($aImageSave) $X1 = _GDIPlus_ImageGetWidth($hImage) $Y1 = _GDIPlus_ImageGetHeight($hImage) $X2 = _GDIPlus_ImageGetWidth($hImage) $Y2 = _GDIPlus_ImageGetHeight($hImage) $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($Form1) ;$PicPreview = GUICtrlCreatePic("", 24, 152, 572, 268) _GDIPlus_GraphicsDrawImage ($hGraphic, 24, 152, 572, 268);? I have the same size and relative coords to $PicPreview in the image placement form1 I want to be 
       
      Other Responsibility Is there a problem with _GDIPlus code sorting?
      #include <GDIPlus.au3> #include <GuiConstantsEx.au3> #include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Global $Form1, $hImage, $hGraphic, $OpenPictures, $PicPreview _GDIPlus_StartUp() $Form1 = GUICreate("Form1", 615, 438, 374, 347) $PicPreview = GUICtrlCreatePic("", 24, 152, 572, 268) $ButtonPreview = GUICtrlCreateButton("Preview", 520, 112, 75, 25) $InputImageDir = GUICtrlCreateInput("", 64, 48, 177, 21) $ButtonOpen = GUICtrlCreateButton("...", 256, 48, 75, 25) $ButtonWatermark = GUICtrlCreateButton("Watermark Add", 256, 112, 80, 25) GUISetState(@SW_SHOW) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_ImageDispose($hImage) _GDIPlus_ShutDown() Exit Case $ButtonOpen $OpenPictures = FileOpenDialog("Where are the pictures?", @ScriptDir & "\", "Picture format (*.jpg;*.bmp;*.png)", $FD_FILEMUSTEXIST + $FD_MULTISELECT) If Not $OpenPictures Then MsgBox(64, "İnfo","No Files Selected!",5) Else GUICtrlSetData($InputImageDir,$OpenPictures) EndIf Case $ButtonWatermark $aImageLoad = $OpenPictures $aImageSave = @ScriptDir & "\Save.png" $aImageLogo = @ScriptDir & "\Logo.png" _Watermark($aImageSave, $aImageLoad, $aImageLogo) Case $ButtonPreview $hImage = _GDIPlus_ImageLoadFromFile($aImageSave) $X1 = _GDIPlus_ImageGetWidth($hImage) $Y1 = _GDIPlus_ImageGetHeight($hImage) $X2 = _GDIPlus_ImageGetWidth($hImage) $Y2 = _GDIPlus_ImageGetHeight($hImage) $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($Form1) ;$PicPreview = GUICtrlCreatePic("", 24, 152, 572, 268) _GDIPlus_GraphicsDrawImage ($hGraphic, 24, 152, 572, 268) EndSwitch WEnd Func _Watermark($sFile2, $sFile, $sLogo) Local $hImage1, $hImage2, $hGraphic _GDIPlus_Startup () $hImage1 = _GDIPlus_ImageLoadFromFile ($sFile) ; image $X1 = _GDIPlus_ImageGetWidth ($hImage1) $Y1 = _GDIPlus_ImageGetHeight ($hImage1) $hImage2 = _GDIPlus_ImageLoadFromFile ($sLogo) ; logo $X2 = _GDIPlus_ImageGetWidth ($hImage2) $Y2 = _GDIPlus_ImageGetHeight ($hImage2) $hGraphic = _GDIPlus_ImageGetGraphicsContext ($hImage1) _GDIPlus_GraphicsDrawImage ($hGraphic, $hImage2, 20, $Y1-$Y2-30) _GDIPlus_ImageSaveToFile ($hImage1, $sFile2) ; image watermarked _GDIPlus_ImageDispose ($hImage1) _GDIPlus_ImageDispose ($hImage2) _GDIPlus_ShutDown () EndFunc ;==>_Watermark  
    • tcurran
      By tcurran
      Here are two functions to provide pixel-accurate height and width dimensions for a given string.
      The more commonly-used _GDIPlus_GraphicsMeasureString built-in UDF is problematic because it returns the width padded by roughly one en-space (for reasons related to the various ways Windows produces anti-aliased fonts).
      These are AutoIt translations of Pierre Arnaud's C# functions, described in his CodeProject article "Bypass Graphics.MeasureString limitations"
      The first is an all-purpose version that takes a window handle, string, font family, font size (in points), style, and (optionally) width of the layout column (in pixels) as parameters.
      The second, more efficient version is intended for applications where GDI+ fonts are already in use, and takes handles to the existing graphics context, string, font, layout and format as parameters.
      Both functions return a two-row array with the exact width [0] and height [1] of the string (in pixels).
      EDIT: (Note that some of the same anti-aliasing measurement issues still apply. I did my best to work around them, but the output of the function may still be off by a pixel or two. Buyer beware.)
      #include <GDIPlus.au3> #include <GUIConstantsEx.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringInPixels ; Description ...: Returns a pixel-accurate height and width for a given string using a given font, style and size. ; Syntax ........: _StringInPixels($hGUI, $sString, $sFontFamily, $fSize, $iStyle[, $iColWidth = 0]) ; Parameters ....: $hGUI - Handle to the window. ; $sString - The string to be measured. ; $sFontFamily - Full name of the font to use. ; $fSize - Font size in points (half-point increments). ; $iStyle - Combination of 0-normal, 1-bold, 2-italic, 4-underline, 8-strikethrough ; $iColWidth - [optional] If word-wrap is desired, column width in pixels ; Return values .: 2-row array. [0] is width in pixels; [1] is height in pixels. ; Author ........: Tim Curran; adapted from Pierre Arnaud's C# function ; Modified ......: ; Remarks .......: This version is longer and less efficient but works for all purposes. ; Related .......: <https://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations> ; Link ..........: ; Example .......: Example-StringInPixels.au3 ; =============================================================================================================================== #include <GDIPlus.au3> #include <GUIConstantsEx.au3> Func _StringInPixels($hGUI, $sString, $sFontFamily, $fSize, $iStyle, $iColWidth = 0) _GDIPlus_Startup() Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;Create a graphics object from a window handle Local $aRanges[2][2] = [[1]] $aRanges[1][0] = 0 ;Measure first char (0-based) $aRanges[1][1] = StringLen($sString) ;Region = String length Local $hFormat = _GDIPlus_StringFormatCreate() Local $hFamily = _GDIPlus_FontFamilyCreate($sFontFamily) Local $hFont = _GDIPlus_FontCreate($hFamily, $fSize, $iStyle) _GDIPlus_GraphicsSetTextRenderingHint($hGraphic, $GDIP_TEXTRENDERINGHINT_ANTIALIASGRIDFIT) _GDIPlus_StringFormatSetMeasurableCharacterRanges($hFormat, $aRanges) ;Set ranges Local $aWinClient = WinGetClientSize($hGUI) If $iColWidth = 0 Then $iColWidth = $aWinClient[0] Local $tLayout = _GDIPlus_RectFCreate(10, 10, $iColWidth, $aWinClient[1]) Local $aRegions = _GDIPlus_GraphicsMeasureCharacterRanges($hGraphic, $sString, $hFont, $tLayout, $hFormat) ;get array of regions Local $aBounds = _GDIPlus_RegionGetBounds($aRegions[1], $hGraphic) Local $aWidthHeight[2] = [$aBounds[2], $aBounds[3]] ; Clean up resources _GDIPlus_FontDispose($hFont) _GDIPlus_RegionDispose($aRegions[1]) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() Return $aWidthHeight EndFunc ;==>_StringInPixels ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringInPixels_gdip ; Description ...: Returns a pixel-accurate height and width for a given string using a GDI+ font, layout and format ; Syntax ........: _StringInPixels_gdip($hGraphic, $sString, $hFont, $tLayout, $hFormat) ; Parameters ....: $hGraphic - Handle to a GDI+ graphics object. ; $sString - The string to be measured. ; $hFont - Handle to a GDI+ font. ; $tLayout - A $tagGDIPRECTF structure that bounds the string. ; $hFormat - Handle to a GDI+ string format. ; Return values .: 2-row array. [0] is width in pixels; [1] is height in pixels. ; Author ........: Tim Curran; adapted from Pierre Arnaud's C# function ; Modified ......: ; Remarks .......: This much more efficient version is for use with GDI+ fonts ; Related .......: ; Link ..........: <https://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations> ; Example .......: Example-StringInPixels.au3 ; =============================================================================================================================== #include <GDIPlus.au3> #include <GUIConstantsEx.au3> Func _StringInPixels_gdip($hGraphic, $sString, $hFont, $tLayout, $hFormat) Local $aRanges[2][2] = [[1]] $aRanges[1][0] = 0 ;Measure first char (0-based) $aRanges[1][1] = StringLen($sString) ;Region = String length _GDIPlus_GraphicsSetTextRenderingHint($hGraphic, $GDIP_TEXTRENDERINGHINT_CLEARTYPEGRIDFIT) _GDIPlus_StringFormatSetMeasurableCharacterRanges($hFormat, $aRanges) ;Set ranges Local $aRegions = _GDIPlus_GraphicsMeasureCharacterRanges($hGraphic, $sString, $hFont, $tLayout, $hFormat) ;get array of regions Local $aBounds = _GDIPlus_RegionGetBounds($aRegions[1], $hGraphic) Local $aWidthHeight[2] = [$aBounds[2], $aBounds[3]] _GDIPlus_RegionDispose($aRegions[1]) Return $aWidthHeight EndFunc ;==>_StringInPixels_gdip  
      _StringInPixels.au3
      Example-StringInPixels.au3
    • c.haslam
      By c.haslam
      In the code that follows, it appears that DllStructCreate() is not allocating memory in
      $tag = 'byte val['&$iLength&']' . . Static Local $tvalue = DllStructCreate($tag) Running the code below, the problem does not show, but it does show in a much longer script: there _GDIPlus_ImageSaveToFile only writes about 30K bytes when it should write about 1MB, which it does when the code is
      $tag = 'char val['&$iLength&']' . . Static Local $tvalue = DllStructCreate($tag) It should write about 1 MB.
      I suggest caution in running the code below. On my PC, it caused a second instance of SciTE to appear at the top left of the Desktop, showing only the title bar, with a width of only approximately 200 pixels! Then rebooting the PC showed this at login. Further, double-clicking on the SciTE shortcut on the Desktop showed SciTE in the same way! (After running Regedit, and searching for SciTE, the shortcut behaves normally.)
      I would appreciate help in determining whether or not there is a bug in DLLStructCreate, preferably a way which does not clobber Windows. Of course, It is possible that there is a bug in my code.
      I have made $tvalue Static in the hope that this might make the code run properly. Doing this did not help.
      My code is based on code written by Authenticity and ChrisL.
      #include <GDIPlus.au3> #include <Array.au3> Opt('MustDeclareVars',1) ; Property Item structure Global Const $tagGDIPPROPERTYITEM = _ "uint id;" & _ ; ID of this property "ulong length;" & _ ; Length of the property value, in bytes "word type;" & _ ; Type of the value, as one of TAG_TYPE_XXX constants "ptr pvalue;" ; pointer to property value ; Image property types constants ; Ref: https://www.media.mit.edu/pia/Research/deepview/exif.html Global Const $GDIP_PROPERTYTAGTYPEUBYTE = 1 Global Const $GDIP_PROPERTYTAGTYPEASCII = 2 Global Const $GDIP_PROPERTYTAGTYPEUSHORT = 3 Global Const $GDIP_PROPERTYTAGTYPEULONG = 4 Global Const $GDIP_PROPERTYTAGTYPEURATIONAL = 5 Global Const $GDIP_PROPERTYTAGTYPESBYTE = 6 Global Const $GDIP_PROPERTYTAGTYPEUNDEFINED = 7 Global Const $GDIP_PROPERTYTAGTYPESSHORT = 8 Global Const $GDIP_PROPERTYTAGTYPESLONG = 9 Global Const $GDIP_PROPERTYTAGTYPESRATIONAL = 10 Global Const $GDIP_PROPERTYTAGTYPESFLOAT = 11 Global Const $GDIP_PROPERTYTAGTYPEDFLOAT = 12 main() Func main() _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\DSC00824 - Copy.jpg') Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage) Local $propsAr[UBound($ar,1)-1][5],$vec,$j=-1 For $i = 1 To $ar[0][0] If $ar[$i][3]<>0 Then ; pValue -- for Sony! $j += 1 $propsAr[$j][0] = $ar[$i][0] ; id $propsAr[$j][1] = $ar[$i][1] ; length $propsAr[$j][2] =$ar[$i][2]; type $vec = _GDIPlus_ImageGetPropertyItemValue($ar[$i][1],$ar[$i][2],$ar[$i][3]) $propsAr[$j][3] = $vec[0] ; val1 Switch $ar[$i][2] Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL $propsAr[$j][4] = $vec[1] Case Else $propsAr[$j][4] = '' EndSwitch EndIf Next ReDim $propsAr[$j+1][5] For $i = 0 To UBound($propsAr,1)-1 Switch $propsAr[$i][2] ; type Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _ $propsAr[$i][2],$propsAr[$i][3],$propsAr[$i][4]) Case Else _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _ $propsAr[$i][2],$propsAr[$i][3]) EndSwitch Next _GDIPlus_ImageSaveToFile($hImage,'H:\b\1.jpg') _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc Func _GDIPlus_ImageGetAllPropertyItemsEx($hImage) Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aSize, $aPropertyItems[1][1], $aResult $aSize = _GDIPlus_ImageGetPropertySize($hImage) If @error Then Return SetError(@error, @extended, -1) $iBuffer = $aSize[0] $tBuffer = DllStructCreate("byte[" & $iBuffer & "]") $pBuffer = DllStructGetPtr($tBuffer) $iCount = $aSize[1] $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, "uint", $iBuffer, "uint", $iCount, "ptr", $pBuffer) If @error Then Return SetError(@error, @extended, -1) If $aResult[0] Then Return SetError(10, $aResult[0], False) ReDim $aPropertyItems[$iCount + 1][4] $aPropertyItems[0][0] = $iCount For $iI = 1 To $iCount $tPropertyItem = DllStructCreate($tagGDIPPROPERTYITEM, $pBuffer) $aPropertyItems[$iI][0] = DllStructGetData($tPropertyItem, "id") $aPropertyItems[$iI][1] = DllStructGetData($tPropertyItem, "length") $aPropertyItems[$iI][2] = DllStructGetData($tPropertyItem, "type") $aPropertyItems[$iI][3] = DllStructGetData($tPropertyItem, "pvalue") $pBuffer += DllStructGetSize($tPropertyItem) Next Return $aPropertyItems EndFunc Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue) Static Local $tvalue Switch $iType Case 1,6 ; $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE $tvalue = DllStructCreate('byte val',$pValue) Case 2 ; $GDIP_PROPERTYTAGTYPEASCII $tvalue = DllStructCreate('char val['&$iLength&']',$pValue) Case 3 ; $GDIP_PROPERTYTAGTYPEUSHORT $tvalue = DllStructCreate('ushort val',$pValue) Case 4 ; $GDIP_PROPERTYTAGTYPEULONG $tvalue = DllStructCreate('ulong val',$pValue) Case 5 ; $GDIP_PROPERTYTAGTYPEURATIONAL $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue) Case 7 ; $GDIP_PROPERTYTAGTYPEUNDEFINED ; undefined, per specification, but may be a long but is sometimes a string $tvalue = DllStructCreate('byte val['&$ilength&']',$pValue) ; see _GDIPlus_ImageSetPropertyItemEx ;~ $tvalue = DllStructCreate('char val['&$ilength&']',$pValue) Case 8 ; $GDIP_PROPERTYTAGTYPESSHORT $tvalue = DllStructCreate('short val',$pValue) Case 9 ; $GDIP_PROPERTYTAGTYPEULONG $tvalue = DllStructCreate('ulong val',$pValue) Case 10 ; $GDIP_PROPERTYTAGTYPESRATIONAL $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue) Case 11 ; $GDIP_PROPERTYTAGTYPESFLOAT $tvalue = DllStructCreate('float val',$pValue) Case 12 ; $GDIP_PROPERTYTAGTYPEDFLOAT $tvalue = DllStructCreate('double val',$pValue) EndSwitch If @error Then Return SetError(@error,0,-1) Switch $iType Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL Local $aRet[2] $aRet[0] = DllStructGetData($tvalue,'val1') $aRet[1] = DllStructGetData($tvalue,'val2') Case Else Local $aRet[1] $aRet[0] = DllStructGetData($tvalue,'val') EndSwitch Return $aRet EndFunc Func _GDIPlus_ImageGetPropertySize($hImage) Local $aSize[2], $aResult $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "hwnd", $hImage, "uint*", 0, "uint*", 0) If @error Then Return SetError(@error, @extended, -1) $aSize[0] = $aResult[2] $aSize[1] = $aResult[3] Return $aSize EndFunc ;==>_GDIPlus_ImageGetPropertySize Func _GDIPlus_ImageSetPropertyItemEx($hImage,$id,$iLength,$iType,$value1,$value2=-1) Local $tProp = DllStructCreate($tagGDIPPROPERTYITEM) DllStructSetData($tProp,'id',$id) DllStructSetData($tProp,'type',$itype) DllStructSetData($tProp,'length',$ilength) Local $tag Switch $iType Case $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE $tag = 'byte val' Case $GDIP_PROPERTYTAGTYPEASCII $tag = 'char val['&$iLength&']' Case $GDIP_PROPERTYTAGTYPEUSHORT $tag = 'ushort val' Case $GDIP_PROPERTYTAGTYPEULONG $tag = 'ulong val' Case $GDIP_PROPERTYTAGTYPEURATIONAL $tag = 'ulong val1;ulong val2' Case $GDIP_PROPERTYTAGTYPEUNDEFINED ; undefined, per specification, but may be a long but is sometimes a string $tag = 'byte val['&$iLength&']' ; causes saving to jpeg to write junk ;~ $tag = 'char val['&$iLength&']' Case $GDIP_PROPERTYTAGTYPESSHORT $tag = 'short val' Case $GDIP_PROPERTYTAGTYPEULONG $tag = 'ulong val' Case $GDIP_PROPERTYTAGTYPESRATIONAL $tag = 'long val1;long val2' Case $GDIP_PROPERTYTAGTYPESFLOAT $tag = 'float val' Case $GDIP_PROPERTYTAGTYPEDFLOAT $tag = 'double val' EndSwitch Static Local $tvalue = DllStructCreate($tag) Switch $iType Case $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL DllStructSetData($tvalue,'val1',$value1) DllStructSetData($tvalue,'val2',$value2) Case Else DllStructSetData($tvalue,1,$value1) EndSwitch DllStructSetData($tProp,'pvalue',DllStructGetPtr($tvalue)) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hImage, "ptr", _ DllStructGetPtr($tProp)) If @error Then Return SetError(@error, @extended, -1) If $aResult[0] Then Return SetError(10, $aResult[0], -1) Return $aResult[0] = 0 EndFunc I have seen $iLength be as much as 37 KB for $GDIP_PROPERTYTAGTYPEUNDEFINED.
      Is there is a bug, how can this be demonstrated to the developers in a few lines of code (without clobbering Windows)?
       
    • c.haslam
      By c.haslam
      UEZ has kindly provided me with code that rotates an image per a line: see here
      Because I want to trim a photograph after rotation, I need to crop the photo. I wrote code which calls _GDIPlus_GraphicsSetClipRect() to do this, but it places spurious stuff in the corners: see 2.jpg attached.
      I want only the trimmed photo to show.
      The original jpeg is also attached.
      The arguments to _GDIPlus_GraphicsSetClipRect() come from solving 2 simultaneous equations: if a and b are the width and height of the original photo, find x and y, the width and height of the rotated and cropped rectangle;
      a = x cos(ang) + y sin(ang)
      b = x sin(ang) + y cos(ang)
      My solution is:
      x = (b * sin(ang) - a*cos(ang)) / (sin(ang)^2 - (cos(ang)^2)
      y = (b * cos(ang) - a * sin(ang)) / (cos(ang)^2 - sin(ang)^2)
      To try to get a handle on the problem, I have temporarily added in several lines in Case $btn. In 2.jpg, you can see that the rectangle bounding the area to be retained is in the wrong place.
      The code is:
      #include <ButtonConstants.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Opt('MustDeclareVars',1) Global Const $MK_SHIFT = 0x4 Global Const $MK_CONTROL = 0x8 Global Const $fPi = ACos(-1), $fPi2 = $fPi / 2, $fRad = 180 / $fPi GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL") GUIRegisterMsg($WM_PAINT,'WM_PAINT') Global $gX0=10,$gX1=580,$gY0,$gY1,$gForm1,$glblPic,$iLW,$iLH,$iW,$iH Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap,$ghMatrix,$ghImageClone,$ghGfxClone Global Const $kDegToRads = 3.14159/180 main() Func main() $gForm1 = GUICreate("Form1", 623, 601, 192, 114) $iLW = 589 $iLH = 500 $glblPic = GUICtrlCreateLabel("", 8, 8, $iLW, $iLH) Local $btn = GUICtrlCreateButton("Rotate", 472, 560, 65, 25) GUISetState(@SW_SHOW) Local $oldY0,$oldY1,$fAngle _GDIPlus_Startup() $ghPen = _GDIPlus_PenCreate(0xFF999999,2) $ghImage = _GDIPlus_ImageLoadFromFile('H:\b\pergola.jpg') Local $h = GUICtrlGetHandle($glblPic) $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($h) $gY0 = 400 $gY1 = 400 $iW = _GDIPlus_ImageGetWidth($ghImage) $iH = _GDIPlus_ImageGetHeight($ghImage) $ghBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap) $ghMatrix = _GDIPlus_MatrixCreate() ; Loop until the user exits. While True If $gY0<>$oldY0 Or $gY1<>$oldY1 Then Paint() $oldY0 = $gY0 $oldY1 = $gY1 Else Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $btn $ghImageClone=_GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImageClone) _GDIPlus_MatrixTranslate($ghMatrix, $iW/2, $iH/2) $gY1 = 300 ; temp Local $ang = -Angle($gY1-$gY0, $gX1-$gX0) _GDIPlus_MatrixRotate($ghMatrix, $ang) ;~ _GDIPlus_MatrixRotate($ghMatrix, -Angle($gY1-$gY0, $gX1-$gX0)) _GDIPlus_MatrixTranslate($ghMatrix, -$iW/2, -$iH/2) _GDIPlus_GraphicsSetTransform($ghGfxClone, $ghMatrix) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImage,0,0,$iW,$iH) Local $angRads = $ang*$kDegToRads Local $sinAng = Sin($angRads) Local $cosAng = Cos($angRads) Local $wid = ($iLH*$sinAng-$iLW*$cosAng)/($sinAng^2-$cosAng^2) Local $left = ($iLW-$wid)/2 Local $ht = ($iLH*$cosAng-$iLW*$sinAng)/($cosAng^2-$sinAng^2) Local $top = ($iLH-$ht)/2 _GDIPlus_GraphicsDrawRect($ghGfxClone,$left,$top,$wid,$ht,$ghPen) ; temp _GDIPlus_GraphicsSetClipRect($ghGfxClone,$left,$top,$wid,$ht,0) _GDIPlus_GraphicsDispose($ghGfxClone) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage) _GDIPlus_GraphicsClear($ghImage) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImageClone,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) _GDIPlus_ImageDispose($ghImageClone) $gy0 = 400 $gy1 = 400 Paint() _GDIPlus_ImageSaveToFile($ghImage,'H:\b\2.jpg') ; added - is rotated, with same size as original file EndSwitch EndIf WEnd ; Clean up resources _GDIPlus_MatrixDispose($ghMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() EndFunc Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local Const $kYmax=$iLH-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $vec[4]=$glblPic Then Local $iDelta = BitShift($wParam, 16) ; positive = up Local $iKeys = _WinAPI_LoWord($wParam) If BitAND($iKeys,$MK_CONTROL)=$MK_CONTROL Then If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then ; do nothing Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta EndIf Else If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then If $iDelta > 0 And $gY1>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOUSEWHEEL Func Paint() _GDIPlus_GraphicsClear($ghCanvas,0) _GDIPlus_GraphicsDrawImageRect($ghCanvas, $ghImage, 0,0, $iLW, $iLH) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $iW, $iH) EndFunc Func WM_PAINT() _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_UPDATENOW) Paint() _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_VALIDATE) EndFunc Func Angle($y, $x) ;return value is in degree Local Const $fPi = ACos(-1), $fPi2 = ACos(-1) / 2, $fRad = 180 / $fPi Switch True Case ($x > 0) Return ATan($y / $x) * $fRad Case ($x < 0 And $y >= 0) Return ATan($y / $x + $fPi) * $fRad Case ($x < 0 And $y < 0) Return ATan($y / $x - $fPi) * $fRad Case ($x = 0 And $y > 0) Return $fPi2 * $fRad Case ($x = 0 And $y < 0) Return -$fPi2 * $fRad Case ($x = 0 And $y = 0) Return 0 EndSwitch EndFunc I also don't understand how the rotated picture gets displayed. There are graphics objects, graphics contexts and PDI+ bitmaps. How are they related?
      Help would be much appreciated.