Re: AHK: Объединить кусочки картинок в одно целое
А вы пока найдите другие книги с такой же структурой и проверьте, все ли они не хотят загружаться.
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
А вы пока найдите другие книги с такой же структурой и проверьте, все ли они не хотят загружаться.
Не захотят, так как там через другой вьюер загружается - openseadragon.
У него данные в dzi прописываются.
for (var file in seadragon.files) {
tileSources.push(seadragon.iipsrvURL + '/fcgi-bin/iipsrv.fcgi?DeepZoom=' + seadragon.filesPath + '/' + seadragon.files[file] + '.dzi');
Я не понимаю одного, почему эти библиотеки не дают скачать?
Ведь всё-равно кому надо выкачает.
Если знаешь, как с ними обходиться, напиши, мне пока лень разбираться.
Не, не знаю, я просто посмотрел что подгружается.
Мне тоже лень.
Собственно, скачиваются все нужные файлы, просто количество неправильно определяется. Если поделить указанные в json ширину и высоту на два, все собирается правильно. Теперь если кто-то точно мне скажет, как наверняка отличить первый вариант от второго по исходному коду, внесу поправки.
Нет, не так всё просто оказалось. Здесь тоже есть этот самый seadragon-viewer, однако обычным способом размер определяется и скачивается правильно. Значит, неважно, какой там вьювер, tiff-файлы с одинаковой нумерацией есть в любом случае. Вопрос, как правильно определить их количество в ряду и соответственно общее количество.
Вроде понял:
#NoEnv
SetBatchLines, -1
CoordMode, ToolTip
PrLibDownload(362052, 11) ; 377452
MsgBox, Completed!
PrLibDownload(item, page, zoom := "max") {
if !GetItemInfo(item, page, zoom, width, height, file, id1, id2)
Return
if !GetChunkDimension(id1, id2, file, zoom, chunkWidth, chunkHeight)
Return
BuildImg(id1, id2, file, zoom, width, height, chunkWidth, chunkHeight, item . "-" . page . ".tif")
}
GetItemInfo(item, page, ByRef zoom, ByRef width, ByRef height, ByRef file, ByRef id1, ByRef id2) {
ToolTip, Getting item info ..., 2, 2, 1
Loop 1 {
if !html := GetHtml("https://www.prlib.ru/item/" . item) {
error := "Failed to load html"
break
}
if !RegExMatch(html, "i)public\\/([a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12})\\/(\d+)", id) {
error := "Failed to get IDs"
break
}
if !metadataJson := GetHtml("https://content.prlib.ru/metadata/public/" . id1 . "/" . id2 . "/" . id1 . ".json") {
error := "Failed to get metadata"
break
}
try Json := GetJS().eval("(" . metadataJson . ")")
catch {
error := "Bad Json data"
break
}
maxPage := Json["pgs"].length
if (page > maxPage) {
MsgBox, There is no page %page%, max page number is %maxPage%
Return
}
try maxZoom := Json.max_zoom
catch {
error := "Failed to get max_zoom value: unknown json format"
break
}
(zoom = "max" && zoom := maxZoom)
if (maxZoom < zoom) {
error := "Zoom " . zoom . " is not supported. Max zoom is " . maxZoom
break
}
Page := Json["pgs"][page - 1]
Dim := Page["d"][zoom]
try width := Dim.w
catch {
error := "Failed to get image width: unknown json format"
break
}
try height := Dim.h
catch {
error := "Failed to get image height: unknown json format"
break
}
try file := Page.f
catch {
error := "Failed to get image fileName: unknown json format"
break
}
try m := Page.m
catch {
error := "Failed to get m-value: unknown json format"
break
}
zoom += m - maxZoom
}
ToolTip,,,, 1
if !error
Return true
else
MsgBox, % error
}
GetChunkDimension(id1, id2, file, zoom, ByRef chunkWidth, ByRef chunkHeight) {
static preUrl := "https://content.prlib.ru/fcgi-bin/iipsrv.fcgi?FIF=/var/data/scans/public/"
if !hBitmap := GetHBitmapFromImageURL(preUrl . id1 . "/" . id2 . "/" . file . "&JTL=" . zoom . ",0") {
MsgBox, Failed to get bitmap from url
Return
}
VarSetCapacity(BITMAP, sz := 4*4 + A_PtrSize*2, 0)
DllCall("GetObject", "Ptr", hBitmap, "Int", sz, "Ptr", &BITMAP)
DllCall("DeleteObject", "Ptr", hBitmap)
chunkWidth := NumGet(BITMAP, 4, "UInt")
chunkHeight := NumGet(BITMAP, 8, "UInt")
Return true
}
BuildImg(id1, id2, file, zoom, width, height, chunkWidth, chunkHeight, outputTif) {
static preUrl := "https://content.prlib.ru/fcgi-bin/iipsrv.fcgi?FIF=/var/data/scans/public/"
countWidth := Ceil(width/chunkWidth)
countHeight := Ceil(height/chunkHeight)
chunkCount := countWidth*countHeight
GdipInst := new GDIp
pBitmap := GdipInst.CreateBitmap(width, height)
G := GdipInst.GraphicsFromImage(pBitmap)
Loop % chunkCount {
ToolTip % A_Index . " of " . chunkCount . " is downloading ...", 2, 2, 1
if !pIUnknown := GetImgResponseStream(preUrl . id1 . "/" . id2 . "/" . file . "&JTL=" . zoom . "," . A_Index - 1) {
MsgBox, 4,, Failed to load a chunk. Continue?
IfMsgBox, No
break
else
continue
}
pBitmapChunk := GdipInst.BitmapFromIStream(pIUnknown)
DllCall("OleAut32\VariantClear", "PtrP", pIUnknown)
GdipInst.DrawImage(G, pBitmapChunk, chunkWidth*mod((A_Index - 1), countWidth)
, chunkHeight*(A_Index//(countWidth + 0.01))
, chunkWidth, chunkHeight, 0, 0, chunkWidth, chunkHeight)
GdipInst.DisposeImage(pBitmapChunk)
}
ToolTip,,,, 1
GdipInst.SaveBitmap(pBitmap, outputTif)
GdipInst.DeleteGraphics(G)
GdipInst.DisposeImage(pBitmap)
}
GetHtml(url) {
whr := ComObjCreate("Msxml2.XMLHTTP.6.0")
whr.Open("GET", url, false)
whr.SetRequestHeader("Pragma", "no-cache")
whr.SetRequestHeader("Cache-Control", "no-cache, no-store")
whr.Send()
Return html := whr.ResponseText
}
GetJS() {
static doc, JS
if !doc {
doc := ComObjCreate("htmlfile")
doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
JS := doc.parentWindow
}
Return JS
}
GetHBitmapFromImageURL(url) {
if !pIUnknown := GetImgResponseStream(url)
Return
GdipInst := new GDIp
pBitmap := GdipInst.BitmapFromIStream(pIUnknown)
DllCall("OleAut32\VariantClear", "PtrP", pIUnknown)
hBitmap := GdipInst.CreateHBitmapFromBitmap(pBitmap)
GdipInst.DisposeImage(pBitmap)
Return hBitmap
}
GetImgResponseStream(url) {
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("GET", url, false)
whr.Send()
if (whr.Status != 200) {
MsgBox, Failed to load the image!
Return
}
contentType := whr.GetResponseHeader("Content-Type")
if !InStr(contentType, "image") {
MsgBox, URL doesn't link to an image!
Return
}
Return whr.ResponseStream
}
class GDIp {
__New() {
if !DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("LoadLibrary", "Str", "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "UPtrP", pToken, "Ptr", &si, "Ptr", 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", "Ptr", this.token)
if hModule := DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("FreeLibrary", "Ptr", hModule)
}
BitmapFromIStream(pIUnknown) {
static IID_IStream := "{0000000C-0000-0000-C000-000000000046}"
pIStream := ComObjQuery(pIUnknown, IID_IStream)
DllCall("gdiplus\GdipCreateBitmapFromStream", "Ptr", pIStream, "PtrP", pBitmap)
ObjRelease(pIStream)
Return pBitmap
}
CreateHBitmapFromBitmap(pBitmap) {
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hBitmap, "UInt", 0xFFFFFFFF)
Return hBitmap
}
CreateBitmap(Width, Height, Format=0x26200A) {
DllCall("gdiplus\GdipCreateBitmapFromScan0", "Int", Width, "Int", Height, "Int", 0, "Int", Format, "Ptr", 0, "PtrP", pBitmap)
Return pBitmap
}
GraphicsFromImage(pBitmap) {
DllCall("gdiplus\GdipGetImageGraphicsContext", "Ptr", pBitmap, "PtrP", pGraphics)
return pGraphics
}
DrawImage(pGraphics, pBitmap, dx, dy, dw, dh, sx, sy, sw, sh) {
Return DllCall("gdiplus\GdipDrawImageRectRect", "Ptr", pGraphics, "Ptr", pBitmap
, "Float", dx, "Float", dy, "Float", dw, "Float", dh
, "Float", sx, "Float", sy, "Float", sw, "Float", sh
, "Int", 2, "Ptr", 0, "Ptr", 0, "Ptr", 0)
}
SaveBitmap(pBitmap, ByRef info, Quality := 75, tobuff := "")
{
; info — если копируем в буфер, тогда расширение файла, если в файл, тогда путь к файлу
if tobuff
Extension := info
else
SplitPath, info,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", "UintP", nCount, "UintP", nSize)
VarSetCapacity(ci, nSize)
DllCall("gdiplus\GdipGetImageEncoders", "UInt", nCount, "UInt", nSize, "Ptr", &ci)
if !(nCount && nSize)
return -2
Loop, % nCount {
sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
if !InStr(sString, "*." Extension)
continue
pCodec := &ci+idx
break
}
if !pCodec
return -3
if RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", "Ptr", pBitmap, "Ptr", pCodec, "UintP", nSize)
VarSetCapacity(EncoderParameters, nSize, 0)
DllCall("gdiplus\GdipGetEncoderParameterList", "Ptr", pBitmap, "Ptr", pCodec, "UInt", nSize, "Ptr", &EncoderParameters)
Loop, % NumGet(EncoderParameters, "UInt")
{
elem := (24+A_PtrSize)*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
{
p := elem+&EncoderParameters-pad-4
NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
break
}
}
}
if !tobuff
E := DllCall("gdiplus\GdipSaveImageToFile", "Ptr", pBitmap, "WStr", info, "Ptr", pCodec, "UInt", p ? p : 0)
else {
DllCall( "ole32\CreateStreamOnHGlobal", "UInt", 0, "Int", 1, "PtrP", pStream )
if !E := DllCall( "gdiplus\GdipSaveImageToStream", "Ptr", pBitmap, "Ptr", pStream, "Ptr", pCodec, "UInt", p ? p : 0 ) {
DllCall( "ole32\GetHGlobalFromStream", "Ptr", pStream, "PtrP", hData )
pData := DllCall( "GlobalLock", "Ptr", hData, "Ptr" )
nSize := DllCall( "GlobalSize", "Ptr", hData, "Ptr" )
VarSetCapacity( info, 0), VarSetCapacity( info, nSize, 0 )
DllCall( "RtlMoveMemory", "Ptr", &info, "Ptr", pData, "Ptr", nSize )
DllCall( "GlobalUnlock", "Ptr", hData )
DllCall( "GlobalFree", "Ptr", hData )
}
ObjRelease(pStream)
}
return E ? -4 : tobuff ? nSize : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
}
DeleteGraphics(pGraphics) {
return DllCall("gdiplus\GdipDeleteGraphics", "Ptr", pGraphics)
}
}
Я не понимаю одного, почему эти библиотеки не дают скачать?
Ведь всё-равно кому надо выкачает.
А если бы к примеру фрагменты изображений накладывались бы случайным образом, а json их структурой не выдавался, шифровался и тп — тоже выкачали бы?
Хотя в этом случае уже с экрана можно было бы скринить).
А если бы к примеру фрагменты изображений накладывались бы случайным образом, а json их структурой не выдавался, шифровался и тп — тоже выкачали бы?
Вы ссылку приведите, а там посмотрим.
Думаю, что всё, что мы получаем на монитор, можно перехватить.
Да я просто спросил, теоретически).
Единственный способ защитить контент - это накладывать вотермарки.
Но всё-равно, если ваш товар будет пользоваться спросом, то найдутся умельцы, которые взломают сервер и будут продавать раз в 10 дешевле.
Если это канвас, то можно так:
oIE := ComObjCreate("InternetExplorer.Application") oIE.visible := True oIE.Navigate("https://www.w3schools.com/html/html5_canvas.asp") While oIE.readyState != 4 || oIE.document.readyState != "complete" || oIE.busy Sleep, 10 canvas := oIE.document.getElementById("myCanvas") oIE.document.parentwindow.navigator.msSaveBlob(canvas.msToBlob(), "canvas.png") msgbox done
Нашлась такая штука, которой можно скармливать ссылки с нарезанными изображениями, преобразуемые затем вроде бы в канвас. Как получить потом это собранное изображение?
Сайт http://ophir.alwaysdata.net/ в IE не полнофункционально работает, видимо поэтому не срабатывает.
Тут выше в коде есть фрагмент, объединяющий кусочки картинок в памяти, по ходу скачивания. Как совместить эту возможность с кодом из 30-го сообщения, объединяющим кусочки с диска?
#NoEnv
SetBatchLines, -1
pToken := Gdip_Startup()
offset := -1
ext = jpg
OutputFile := A_ScriptDir "\__merged.png"
arr := []
off := []
off.X[1] := off.Y[1] := aw := ah := 0
Loop, %A_ScriptDir%\*.%ext%
{
If !RegExMatch(A_LoopFileName, "S)^(\d+)_(\d+)\." ext "$", F)
Continue
col := F1 + 1, row := F2 + 1
If !arr[col]
arr[col] := []
arr[col][row] := A_LoopFileFullPath
}
If !arr[1][1]
ExitApp
for col, rows in arr
for row, path in rows
{
pBitmap := Gdip_CreateBitmapFromFile(path)
Gdip_GetImageDimensions(pBitmap, w, h)
If (row = 1)
aw := off.X[col + 1] := aw + w + offset
If (col = 1)
ah := off.Y[row + 1] := ah + h + offset
arr[col][row] := {pBitmap: pBitmap, w: w, h: h}
}
pBitmapNew := Gdip_CreateBitmap(aw, ah)
G := Gdip_GraphicsFromImage(pBitmapNew)
Gdip_SetSmoothingMode(G, 4)
Gdip_SetInterpolationMode(G, 7)
for col, rows in arr
for row, obj in rows
Gdip_DrawImage(G, obj.pBitmap, off.X[col], off.Y[row], obj.w, obj.h, 0, 0, obj.w, obj.h)
, Gdip_DisposeImage(obj.pBitmap)
Gdip_SaveBitmapToFile(pBitmapNew, OutputFile)
Gdip_DisposeImage(pBitmapNew)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
run %OutputFile%
ExitApp
Так тот что выше тоже в файл сохраняет, зачем объединять.
serzh82saratov
Имелось в виду, что скрипт teadrinker`a скачивает кусочки и тут же собирает из них изображение в памяти, а Ваш — собирает изображение из уже скачанных кусков картинок, находящихся на диске. То есть, для практического использования хотелось бы избежать необходимости сохранять все фрагменты картинок на диск, чтобы скачивание и объединение из кусков происходило в памяти.
скрипт teadrinker`a скачивает кусочки и тут же собирает из них изображение в памяти
Ну, и сохраняет на диск склееное изображение, что не так?
Он конечно сохранит склеенное изображение, но перед этим для каждой страницы придется скачивать на диск почти 700 фрагментов этого изображения, отчего хотелось бы, чтобы подготовительный сбор кусков производился в памяти.
Оба моих сообщения про код teadrinker.
То есть, с этим кодом по такому же принципу можно собирать изображения?
Насколько помню, там координаты отдельных кусков брались из файла, а тут алгоритм исходит из наибольшего числа в именах кусочков -- плюс смещение на 2 пикселя.
По какому алгоритму, я не помню ни про свой, ни конечно про чужой.
То есть, с этим кодом по такому же принципу можно собирать изображения?
Ну вы код от teadrinker запускали? После всех скачиваний, в папке скрипта появляется картинка. Потому я совсем не понимаю о чём вы ведёте речь.
DD пишет:а как скрипт узнаёт, где край изображения — где надо остановиться и снизу начать новый сбор?
w := w > ++F1 ? w : F1 h := h > ++F2 ? h : F2
Он сначала перебирает все файлы, и узнаёт максимальные числа в их названиях. Первое число - колонки, второе - строки.
Код от teadrinker запускал и картинка собирается, но это происходит в отношении другого принципа сбора и к тому же — сразу в памяти, потому использовать как дополнение к Вашему коду не представляется возможным. Ваш код собирает фрагменты с диска, а другой — в памяти.
Ваш код собирает фрагменты с диска, а другой — в памяти.
Мой с диска, а его из интернета, а картинку собирают оба одинаково в памяти.
Код от teadrinker запускал и картинка собирается, но это происходит в отношении другого принципа сбора
Так вы опишите чем он не устраивает, или приведите пример с которым он не работает.
Ходите вокруг да около.
Действительно, оба в памяти собирают). Тогда хотелось бы понять, как подавать Вашему коду фрагменты для сбора (вместо «Loop, %A_ScriptDir%\*.%ext%»)? Ведь, как Вы писали, «он сначала перебирает все файлы, и узнаёт максимальные числа в их названиях». То есть, они должны быть уже скачаны?
Сайт http://ophir.alwaysdata.net/ в IE не полнофункционально работает, видимо поэтому не срабатывает.
С IE всё меньше и меньше сайтов работает, переходите на хром.
Да я IE никогда не пользовался для интернета — просто Fiddler (анализатор сетевого трафика) перехватывает запросы из IE, а из Хрома — нет.
Вроде бы, код от teadrinker анализирует координаты каждого фрагмента из json-файла для каждой страницы, а у Вас по-другому работает.
Всё он (Fiddler) прекрасно работает.
Но для сохранения канваса с http://ophir.alwaysdata.net/dezoomify/dezoomify.html вам не нужен перехватчик траффика.
Достаточно этот код переделать под хром.
oIE := ComObjCreate("InternetExplorer.Application")
oIE.visible := True
oIE.Navigate("https://www.w3schools.com/html/html5_canvas.asp")
While oIE.readyState != 4 || oIE.document.readyState != "complete" || oIE.busy
Sleep, 10
canvas := oIE.document.getElementById("myCanvas")
oIE.document.parentwindow.navigator.msSaveBlob(canvas.msToBlob(), "canvas.png")
msgbox done
Malcev
Забыл) Я упомянул IE, потому что Ваш скрипт, который я там же приводил — он вроде работает с окном из IE.
Всё он (Fiddler) прекрасно работает.
Он у Вас и из Хрома перехватывает запросы?
Когда был установлен - перехватывал.
вам не нужен перехватчик траффика
Мне хотелось попробовать через этот сервис наладить скачивание — давать ему ссылки, чтобы он собирал, а потом брать результат. Но там это непонятно происходит.
Но самое главное: то, как они собирают — это не точно. В скрипте serzh82saratov это точнее сделано. Ниже по ссылке можно посмотреть разницу. Видно, что где на сайте алгоритм обработал первые строки по горизонтали и вертикали (обведены красным) — там стебли смещаются, блики и линии раздваиваются и т.п. — https://yadi.sk/d/Jd8Sj-ohOxq_yQ.
Сайт создает канвас с полученными изображениями.
Который вам необходимо скачать.
Этим кодом
oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
oHTTP.Open("GET", "https://www.w3schools.com/html/html5_canvas.asp")
oHTTP.Send()
oHTTP.WaitForResponse()
oHTML := ComObjCreate("HTMLFile")
oHTML.open()
oHTML.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=edge"">")
oHTML.write(oHTTP.ResponseText)
oHTML.close()
loop
{
if (oHTML.readyState = "complete")
break
sleep 10
}
canvas := oHTML.getElementById("myCanvas")
nBytes := Base64Dec(SubStr(canvas.toDataURL(), 23), Bin)
File := FileOpen("canvas.png", "w")
File.RawWrite(Bin, nBytes)
File.Close()
msgbox done
Base64Dec( ByRef B64, ByRef Bin ) { ; By SKAN / 18-Aug-2017
Local Rqd := 0, BLen := StrLen(B64) ; CRYPT_STRING_BASE64 := 0x1
DllCall( "Crypt32.dll\CryptStringToBinary", "Str",B64, "UInt",BLen, "UInt",0x1
, "UInt",0, "UIntP",Rqd, "Int",0, "Int",0 )
VarSetCapacity( Bin, 128 ), VarSetCapacity( Bin, 0 ), VarSetCapacity( Bin, Rqd, 0 )
DllCall( "Crypt32.dll\CryptStringToBinary", "Str",B64, "UInt",BLen, "UInt",0x1
, "Ptr",&Bin, "UIntP",Rqd, "Int",0, "Int",0 )
Return Rqd
}
и этим
oIE := ComObjCreate("InternetExplorer.Application")
oIE.visible := True
oIE.Navigate("https://www.w3schools.com/html/html5_canvas.asp")
While oIE.readyState != 4 || oIE.document.readyState != "complete" || oIE.busy
Sleep, 10
canvas := oIE.document.getElementById("myCanvas")
oIE.document.parentwindow.navigator.msSaveBlob(canvas.msToBlob(), "canvas.png")
msgbox done
не получится, так-как сайт с IE не работает.
Поэтому либо самому собирать через тот же gdi+, либо автоматизировать через хром.
то, как они собирают — это не точно
Кто они?
Авторы сервиса с их алгоритмами).
Значит используйте код teadrinker.
serzh82saratov
Сергей, с чем может быть связано, что когда использую ваш код в цикле, где он должен раз за разом собирать изображение из фрагментов — он отрабатывает только в первом цикле, а на втором и последующих сборка не происходит? Может, надо какие-то данные очищать?
Вы же ранее писали что он работает хорошо.
А вы имеете в виду что зацикливаете весь мой код.
Тогда вы уже ответили на свой вопрос: надо какие-то данные очищать.
Я и не говорю, что плохо работает — просто видимо при работе в цикле, надо какие-то данные очищать.
А вы имеете в виду что зацикливаете весь мой код.
Тогда вы уже ответили на свой вопрос: надо какие-то данные очищать.
Вот эти чищу, но без результата:
pToken := ""
pBitmapNew := ""
pBitmap := ""
aw := ""
ah := ""
rows := ""
col := ""
path := ""
G := ""
arr := ""
off := ""
А весь код выложить вы конечно с первой попытки не можете, и предлагаете мне угадывать как он у вас может выглядеть (
serzh82saratov
Оказалось, что строку из начала скрипта (pToken := Gdip_Startup()), надо было в метку перенести, перед основным кодом сбора.
+1 к умению всё сделать через *опу
Я конечно так делать умею, но не всё — не надо преувеличивать). Что не так с переносом переменной pToken в метку?
То что каждый раз грузит Gdip.
Наверняка так тоже будет работать.
#NoEnv
SetBatchLines, -1
pToken := Gdip_Startup()
offset := -1
ext = jpg
Loop, Parse, список итоговых файлов
{
OutputFile := A_LoopField
Folder = папка с фрагментами
arr := []
off := []
off.X[1] := off.Y[1] := aw := ah := 0
Loop, %A_ScriptDir%\%Folder%\*.%ext%
{
If !RegExMatch(A_LoopFileName, "S)^(\d+)_(\d+)\." ext "$", F)
Continue
col := F1 + 1, row := F2 + 1
If !arr[col]
arr[col] := []
arr[col][row] := A_LoopFileFullPath
}
If !arr[1][1]
ExitApp
for col, rows in arr
for row, path in rows
{
pBitmap := Gdip_CreateBitmapFromFile(path)
Gdip_GetImageDimensions(pBitmap, w, h)
If (row = 1)
aw := off.X[col + 1] := aw + w + offset
If (col = 1)
ah := off.Y[row + 1] := ah + h + offset
arr[col][row] := {pBitmap: pBitmap, w: w, h: h}
}
pBitmapNew := Gdip_CreateBitmap(aw, ah)
G := Gdip_GraphicsFromImage(pBitmapNew)
Gdip_SetSmoothingMode(G, 4)
Gdip_SetInterpolationMode(G, 7)
for col, rows in arr
for row, obj in rows
Gdip_DrawImage(G, obj.pBitmap, off.X[col], off.Y[row], obj.w, obj.h, 0, 0, obj.w, obj.h)
, Gdip_DisposeImage(obj.pBitmap)
Gdip_SaveBitmapToFile(pBitmapNew, OutputFile)
Gdip_DisposeImage(pBitmapNew)
Gdip_DeleteGraphics(G)
}
Gdip_Shutdown(pToken)
ExitApp
Сергей, как вы писали — перед сборкой изображения, ваш скрипт перебирает все файлы и узнаёт максимальные числа в их названиях. Вот используя следующий код, который надёжно скачивает фрагменты — нельзя ли запоминать эти максимальные числа из названий и отрабатывать основную часть кода по сбору? То есть, правильно понимаю, что основная задача — это скачивать эти фрагменты в память, тогда как получить инфу для сбора код ниже позволяет? А числа код получает всегда одинаковые — то есть, если один раз по вертикали или горизонтали было получено 20 фрагментов, то и дальше это число не будет меняться по тем же сторонам:
OutputFolder := A_ScriptDir "\_Tmp"
FileGetAttrib, attrib, %OutputFolder%\
IfNotInString, attrib, D
FileCreateDir, %OutputFolder%\
num1 := num2 := 0
Loop
{
sleep 111
loop ;CONNECT_LOOP
{ ;CONNECT_LOOP
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("GET", "http://www.bl.uk/manuscripts/Proxy.ashx?view=yates_thompson_ms_36_f001r_files/13/" num1 "_" num2 ".jpg", true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
try {
HTTP.Send()
HTTP.WaitForResponse()
Body := HTTP.ResponseBody
RTxt := HTTP.ResponseText
If InStr(RTxt, "ÿØÿà")
{
pData := NumGet(ComObjValue(Body), A_PtrSize = 8? 16:12, "ptr")
File := FileOpen(OutputFolder "\" num1 "_" num2 ".jpg", "w")
File.RawWrite(pData + 0, Body.MaxIndex() + 1)
File.Close()
break
}
If (num2 = 0) AND InStr(RTxt, "/NoImage.jpg") {
EndMode := 1
break
}
If InStr(RTxt, "/NoImage.jpg") {
num1++
num2 := 0
}
}
catch {
Sleep, 5000
}
} ;CONNECT_LOOP
If (EndMode == 1)
break
RTxt := EndMode := ""
num2++
}
#NoEnv
SetBatchLines, -1
pages =
(
http://www.bl.uk/manuscripts/Proxy.ashx?view=yates_thompson_ms_36_f001r_files/10
http://www.bl.uk/manuscripts/Proxy.ashx?view=yates_thompson_ms_36_f001r_files/11
)
offset := -1
OutputFileName := A_Desktop "\merged_"
OutputExt = png
OutputFolder := A_ScriptDir "\_Tmp"
FileGetAttrib, attrib, %OutputFolder%\
IfNotInString, attrib, D
FileCreateDir, %OutputFolder%\
pToken := Gdip_Startup()
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
Loop, Parse, pages, `n, `r
{
num1 := num2 := 0, arrB := {}
page := RegExReplace(A_LoopField, ".*?(\d+)$", "$1")
loop
{
HTTP.Open("GET", A_LoopField "/" num1 "_" num2 ".jpg", true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
try {
HTTP.Send()
HTTP.WaitForResponse()
RTxt := HTTP.ResponseText
If InStr(RTxt, "ÿØÿà") {
ToolTip % "page: " page " picture: " num1 "_" num2 ".jpg" " is downloading ...", 2, 2, 1
arrB.Push([num1, num2++, BitmapFromIStream(HTTP.ResponseStream)])
Continue
}
If (num2 = 0) AND InStr(RTxt, "/NoImage.jpg") {
break
}
If InStr(RTxt, "/NoImage.jpg") {
num1++, num2 := 0
}
}
catch {
Throw Exception(num1 "_" num2, -1)
}
}
merged(arrB, OutputFileName, OutputExt, page, offset)
}
HTTP := ""
Gdip_Shutdown(pToken)
ExitApp
merged(arrB, OutputFileName, OutputExt, page, offset) {
OutputFile := OutputFileName page "." OutputExt
arr := []
off := []
off.X[1] := off.Y[1] := aw := ah := 0
for key, obj in arrB
{
col := obj[1] + 1, row := obj[2] + 1
If !arr[col]
arr[col] := []
arr[col][row] := obj[3]
}
If !arr[1][1]
ExitApp
for col, rows in arr
for row, pBitmap in rows
{
Gdip_GetImageDimensions(pBitmap, w, h)
If (row = 1)
aw := off.X[col + 1] := aw + w + offset
If (col = 1)
ah := off.Y[row + 1] := ah + h + offset
arr[col][row] := {pBitmap: pBitmap, w: w, h: h}
}
pBitmapNew := Gdip_CreateBitmap(aw, ah)
G := Gdip_GraphicsFromImage(pBitmapNew)
Gdip_SetSmoothingMode(G, 4)
Gdip_SetInterpolationMode(G, 7)
for col, rows in arr
for row, obj in rows
Gdip_DrawImage(G, obj.pBitmap, off.X[col], off.Y[row], obj.w, obj.h, 0, 0, obj.w, obj.h)
, Gdip_DisposeImage(obj.pBitmap)
Gdip_SaveBitmapToFile(pBitmapNew, OutputFile)
Gdip_DisposeImage(pBitmapNew)
Gdip_DeleteGraphics(G)
run %OutputFile%
}
BitmapFromIStream(pIUnknown) {
static IID_IStream := "{0000000C-0000-0000-C000-000000000046}"
pIStream := ComObjQuery(pIUnknown, IID_IStream)
DllCall("gdiplus\GdipCreateBitmapFromStream", "Ptr", pIStream, "PtrP", pBitmap)
ObjRelease(pIStream)
DllCall("OleAut32\VariantClear", "PtrP", pIUnknown)
Return pBitmap
}
Можно ускорить отсекая заведомо неправильные запросы, и сократить merged.
#NoEnv
SetBatchLines, -1
pages =
(
yates_thompson_ms_36_f001r_files/10
yates_thompson_ms_36_f001r_files/11
yates_thompson_ms_36_f001r_files/13
)
offset := -1
OutputFile := A_Desktop "\"
OutputExt = png
OutputFolder := A_ScriptDir "\_Tmp"
FileGetAttrib, attrib, %OutputFolder%\
IfNotInString, attrib, D
FileCreateDir, %OutputFolder%\
pToken := Gdip_Startup()
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
Loop, Parse, pages, `n, `r
{
row := col := 0, arr := [], off := {aw:0, ah:0}, colmax := -1
loop
{
HTTP.Open("GET", "http://www.bl.uk/manuscripts/Proxy.ashx?view=" A_LoopField "/" row "_" col ".jpg", true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
try {
HTTP.Send()
HTTP.WaitForResponse()
RTxt := HTTP.ResponseText
If InStr(RTxt, "ÿØÿà") {
ToolTip % A_LoopField " picture: " row "_" col ".jpg" " is downloading ...", 2, 2, 1
pBitmap := BitmapFromIStream(HTTP.ResponseStream)
Gdip_GetImageDimensions(pBitmap, w, h)
If (row = 1)
off.ah := off.Y[col + 1] := off.ah + h + offset
If (col = 1)
off.aw := off.X[row + 1] := off.aw + w + offset
(!arr[row]) && (arr[row] := [])
arr[row][col] := {pBitmap: pBitmap, w: w, h: h}
col := col = colmax ? (0, row++) : col + 1
}
Else If InStr(RTxt, "/NoImage.jpg") {
If (col = 0)
break
row++, colmax := col - 1, col := 0
}
}
catch {
Throw Exception(A_LoopField "`n" row "_" col, -1)
}
}
If colmax < 0
Throw Exception(A_LoopField "`n" row "_" col, -1)
merged(arr, off, OutputFile StrReplace(A_LoopField, "/", "_") "." OutputExt)
}
HTTP := ""
Gdip_Shutdown(pToken)
ExitApp
merged(arr, off, OutputFile) {
pBitmapFile := Gdip_CreateBitmap(off.aw, off.ah)
G := Gdip_GraphicsFromImage(pBitmapFile)
Gdip_SetSmoothingMode(G, 4)
Gdip_SetInterpolationMode(G, 7)
for row, obj1 in arr
for col, obj2 in obj1
Gdip_DrawImage(G, obj2.pBitmap, off.X[row], off.Y[col], obj2.w, obj2.h, 0, 0, obj2.w, obj2.h)
, Gdip_DisposeImage(obj2.pBitmap)
Gdip_SaveBitmapToFile(pBitmapFile, OutputFile)
Gdip_DisposeImage(pBitmapFile)
Gdip_DeleteGraphics(G)
run %OutputFile%
}
BitmapFromIStream(pIUnknown) {
static IID_IStream := "{0000000C-0000-0000-C000-000000000046}"
pIStream := ComObjQuery(pIUnknown, IID_IStream)
DllCall("gdiplus\GdipCreateBitmapFromStream", "Ptr", pIStream, "PtrP", pBitmap)
ObjRelease(pIStream)
DllCall("OleAut32\VariantClear", "PtrP", pIUnknown)
Return pBitmap
}
Вот спасибо, уважаемый!
Пытаюсь собрать скриптом картину Босха из частей. Формат имен частей соответствует тому, с которым работает скрипт. Сами эти 18 частей весят почти 2 ГБ, каждая — примерно 130 МБ и разрешением 30000х30000. По какой причине скрипт не обрабатывает эти части? Памяти не хватает? (Стоит 16 ГБ оперативной, в начале скрипта указывал #MaxMem 16000).
UPD: Даже два изображения (по 130 МБ) не собирает.
Память не при чем. Лимит GDI+.
Либо уменьшайте формат картинки - сейчас у вас 32bpp:
Gdip_CreateBitmap(Width, Height, Format=0x26200A)
Либо переходите на WIC.
А что значит уменьшить формат картинки? В итоге сшитый вариант будет отличаться по глубине цвета от исходных частей?
Гуглю про WIC — инфа не по теме. Что имелось в виду?
А что значит уменьшить формат картинки?
https://docs.microsoft.com/en-us/dotnet … at-ext-5.0
В итоге сшитый вариант будет отличаться по глубине цвета от исходных частей?
Не знаю. Нужно пробовать.
Гуглю про WIC — инфа не по теме. Что имелось в виду?
https://docs.microsoft.com/en-us/window … ic/-wic-lh
Ну и на нашем форуме пара примеров есть.
С кондачка там не освоить.
В библиотеке упоминание "Format=0x26200A" дважды встречается. При тестах оба значения надо заменять?
Кстати, там на вики с краю видны узкие изображения. Попробовал скриптом объединить два из них — получилось, но изображение чёрное.
Тоже не могу сказать.
Библиотека плоха тем, что нет проверок на ошибки.
Поэтому придется проверять каждую функцию самому.
Вот возвращаемые значения, начиная с 0.
https://docs.microsoft.com/en-us/window … pes-status
А как правильно записывать эти значения форматов? К примеру, в библиотеке — "Format=0x26200A", а на сайте в первой строке значение "262144". Его надо вот так записывать? —
Format=0x262144A
Вам не в самих функциях надо менять, а в их вызовах.
RTFM о функциях.
А это в каком месте? Там встречается "bpp=32". Вместо 32 подставлять?
Сами разбирайтесь, либо нанимайте репетитора.
Посмотрю, может Gdip_All.ahk обновили.
Gdip_All тут не при чем.
Вам рано браться за такие сложные вещи.
Начните с прочтения справки.
Либо уменьшайте формат картинки - сейчас у вас 32bpp
Не понял насчет форматов. Что же — у этих картинок какая-то особая глубина цвета? Почему, когда я открываю эту пару узких частей в фотошопе и делаю их меньше — они нормально объединяются?
А что там понимать - чем меньше формат весит, тем большую длину-ширину вы можете использовать.
Все равно не понятно. Выше вы написали: "уменьшайте формат картинки - сейчас у вас 32bpp". Значит ли это, что дело в разрешении — чем разрешение больше, тем больше глубина цвета?
DD,
1) Вы не понимаете как работает данный скрипт
2) Вы не понимаете как работают функции
Не вижу смысла вам что-то разжевывать.
Я не о скрипте спрашиваю, а условии по изображениям, с которыми он работает. Выходит, это из-за большого разрешения он не срабатывает в том виде, в каком он есть, или это изображение с особой глубиной цвета?
А самому проверить религия не позволяет?
Дак не работает же с большим разрешением, собственно почему я сюда и обратился. Вот и спрашиваю: это разрешение сказывается или что-то другое?
Дак не работает же с большим разрешением
Вот и спрашиваю: это разрешение сказывается или что-то другое?
Наверное что-то другое. ))))
О том и спрашиваю — что же это?
Подумайте логически.
Вам же не 3 года.
Оттого что мне не 3 года и возникают вопросы. Вы сказали, что надо в Gdip_All уменьшить формат картинки, который сейчас 32bpp. Так же вы сказали, что память не при чём — а значит, разрешение и вес картинки может быть любым.
Так же вы сказали, что память не при чём
Я ответил на ваш вопрос про оперативную память.
DD, забейте.
Вам это самому, с текущими знаниями, не осуществить.
Я-то забил, мне бы хотелось чтобы вы причину внятно сформулировали.
Понятно, что про оперативную память косвенно было о том, что разрешение и вес большие.
Скачайте половинки, объедините в фотошопе.
Я уже скачанные объединял ранней версией вашего скрипта. Просили автоматизировать, да и в фотошопе с этим количеством файлов и разрешением может быть проблемно работать.
А WIC нельзя подключить как библиотеку?
Можно. В коммерческом разделе.
Сам я такими разрешениями не интересуюсь, думал, она уже написана.
Друг попросил.
Мсдн библиотека написана.
Враппер на ахк тоже.
Если сами не интересуетесь, то чего тогда просите подключить?
А если для друга стараетесь, то объясните другу, что бесплатно код тут не пишут и халявщиков не любят.
Это с другого форума знакомый) Просто вы писали, что WIC уже в ходу, вот и подумал что подключаем вместо gdip.
А, это, наверно, тот знакомый, которому интерпретатор с кастомным паролем нужен был?
Это — уже мне, но не настолько, чтобы за него платить, ибо мне защищать нечего).
ypppu, типа, и так все всё понимают?
Ссылка неудачная попалась, исправил.
А я уже подумал, что это был такой изящный намёк на анекдот про пустой плакат.
Это на что намёки?
анекдот про пустой плакат
Разве это анекдот.