2010-06-09 22 views
9

Mam aplikację, w której użytkownicy końcowi mogą zmieniać rozmiar i umieszczać obrazy w projektancie. Ponieważ specyfikacja wymaga, aby obraz był "rozciągnięty" do kontrolki zawierającej, użytkownik końcowy może skończyć się niezręcznie rozciągniętym obrazem.Jak "inteligentnie zmienić rozmiar" wyświetlanego obrazu na oryginalny współczynnik proporcji

Aby pomóc użytkownikowi w zmianie rozmiaru obrazu, mam na myśli implementację inteligentnej funkcji resizera, która pozwoli użytkownikowi łatwo skorygować współczynnik kształtu obrazu, aby nie był już rozciągnięty.

Szybki sposób rozwiązania tego problemu polega na udostępnieniu dwóch opcji: 1) skali od szerokości 2) skali od wysokości. Użytkownik wybiera metodę, a algorytm dostosowuje rozmiar obrazu za pomocą oryginalnego współczynnika proporcji. Na przykład: obraz jest wyświetlany jako 200x200 na projektancie, ale oryginalny obraz ma 1024 x 768 pikseli. Użytkownik wybiera "Inteligentny rozmiar z szerokości", a nowy rozmiar zmienia się na ~ 200x150, ponieważ oryginalny współczynnik proporcji wynosi ~ 1.333

To jest w porządku, ale w jaki sposób mogę uczynić algorytm inteligentniejszym i nie przeszkadzać użytkownikowi, pytając, który wymiar powoduje ponowne obliczenie powinien być oparty na?

Odpowiedz

22

Jeśli mam poprawnie interpretując swoją specyfikację, chcesz wynik, który nie jest większa niż jeden użytkownik końcowy przewidzianą pierwotnie; chcesz zmniejszyć jeden z dwóch wymiarów, a drugi pozostać taki sam. Innymi słowy, nowy rozmiar powinien wypełnić przestrzeń projektanta w jednym kierunku, a skrócić rozmiar w innym kierunku, aby zachować oryginalny współczynnik proporcji.

original_ratio = original_width/original_height 
designer_ratio = designer_width/designer_height 
if original_ratio > designer_ratio 
    designer_height = designer_width/original_ratio 
else 
    designer_width = designer_height * original_ratio 

Często będziesz pracować ze współrzędnymi całkowitymi, ale podziały w celu uzyskania powyższych współczynników muszą być zmiennoprzecinkowe. Oto przegrupowanie formuły, aby była bardziej przyjazna dla liczb całkowitych. Upewnij się, że twoje liczby całkowite mają zasięg do obsługi maksymalnej szerokości * wysokości.

if original_width * designer_height > designer_width * original_height 
    designer_height = (designer_width * original_height)/original_width 
else 
    designer_width = (designer_height * original_width)/original_height 
+0

Tak, specyfikacja musi zostać rozszerzona, aby zdefiniować, co naprawdę robi inteligentne zmienianie rozmiaru. Ten algorytm brzmi rozsądnie. Spróbuję tego. –

1

Obliczyć nowe wymiary dla obu wariantów ("skalowanie według szerokości" i "skalowanie według wysokości"), a następnie użyć tego, który pasuje na wyświetlaczu.

Można również obliczyć współczynnik kształtu "ramki ograniczającej" i porównać go ze współczynnikiem kształtu oryginalnego obrazu. W zależności od tego, który współczynnik proporcji jest większy, należy skalować wysokość lub szerokość.

Można również ograniczyć proces zmiany rozmiaru, aby we wszystkich przypadkach "skalować według szerokości". Następnie, aby zmienić rozmiar obrazu, użytkownik musi zawsze zmienić jego szerokość. Wysokość będzie zawsze dostosowywana automatycznie.

+0

Myślałam wzdłuż tych linii, ale jak yhou ustalić, co jest zbyt szeroka lub zbyt wysoki, gdy użytkownik może dowolnie wielkość i umieścić obraz ? –

+0

@Paul: Czy to nie jest ograniczone do 200x200? Skąd bieżąca funkcja inteligentnego rozmiaru ma swoje ograniczenia? – sth

+0

zbliżamy się. Limity są domyślnie ustawione przez użytkownika poprzez manipulowanie wielkością obrazu. Zobacz moją odpowiedź do khnle poniżej. –

1

Ponieważ chcesz zmaksymalizować pokazywanie jak najwięcej skalowanego obrazu (oryginału) w twoim oknie, tj. Obszaru w twoim projektancie, musisz wziąć większą albo szerokość albo wysokość oryginalnego obrazu, i skalować że do 200. Pseudo-kod (szerokość, wysokość są wymiary oryginału):

if (width > height) { 
    scaledWidth = 200; 
    scaledHeight = (height * 200)/width; 
} else { 
    scaledHeight = 200; 
    scaledWidth = (width * 200)/height; 
} 
+0

Nie. Chcę, aby obraz był tak bliski jak to tylko możliwe. Ostatecznie jeden z wymiarów pozostałby niezmieniony. –

0

Trzeba tylko wypracować skalę potrzebną do obu wymiarów, a następnie podjąć mniejszy od 2.

2

Nie ma rozliczanie ilości kopii i pasters tam eh! Też chciałem wiedzieć to i wszystko, co widziałem, było nieskończonymi przykładami skalowania szerokości LUB wysokości .. któż by chciał przepełnić drugą ?!

  • Resize szerokość i wysokość bez konieczności pętli
  • nie przekracza zdjęć oryginalnych wymiarów
  • używa matematyki, który działa poprawnie tzn szerokość/aspekt wysokości, a wysokość * aspektem szerokości czym obrazy faktycznie są skalowane odpowiednio w górę iw dół:/

//////////////

private void ResizeImage(Image img, double maxWidth, double maxHeight) 
{ 
    double srcWidth = img.Source.Width; 
    double srcHeight = img.Source.Height; 

    double resizeWidth = srcWidth; 
    double resizeHeight = srcHeight; 

    double aspect = resizeWidth/resizeHeight; 

    if (resizeWidth > maxWidth) 
    { 
     resizeWidth = maxWidth; 
     resizeHeight = resizeWidth/aspect; 
    } 
    if (resizeHeight > maxHeight) 
    { 
     aspect = resizeWidth/resizeHeight; 
     resizeHeight = maxHeight; 
     resizeWidth = resizeHeight * aspect; 
    } 

    img.Width = resizeWidth; 
    img.Height = resizeHeight; 
} 
+0

całkiem niezły, z wyjątkiem sytuacji, gdy robisz ResizeImage (i 2000 000) –

6

Oto rozwiązanie, które wymyśliłem, gdy mam do czynienia z tym problemem. Okazało się dość krótkie i proste imo, po prostu chciałem się nim podzielić.

Handy "formuły": ratio = W/HW = H * ratio

  1. Oblicz stosunek.
  2. Oblicz wysokość obrazu, jeśli chcesz ustawić szerokość na nową szerokość (maksymalna dopuszczalna szerokość).
  3. Oblicz szerokość obrazu, jeśli chcesz ustawić wysokość na nową wysokość (maksymalna dozwolona wysokość).
  4. Sprawdź, który z dwóch rozmiarów nie zastępuje maksymalnego rozmiaru w żadnym wymiarze. Jeśli stosunek nie wynosi 1, jeden z nich będzie zawsze błędny i zawsze będzie poprawny.

w JavaScript

// Returns array with new width and height 
function proportionalScale(originalSize, newSize) 
{ 
    var ratio = originalSize[0]/originalSize[1]; 

    var maximizedToWidth = [newSize[0], newSize[0]/ratio]; 
    var maximizedToHeight = [newSize[1] * ratio, newSize[1]]; 

    if (maximizedToWidth[1] > newSize[1]) { return maximizedToHeight; } 
    else { return maximizedToWidth; } 
} 

originalSize i newSize jest tablicą [0] = width, [1] = height

2

Zajęło sugestię powyżej się skalować w górę/w dół w obrębie maksymalnej wysokości/szerokości. W tym przypadku kod pyton dla niego, a także dodaje się wsparcie dla obracania co przy jednoczesnym utrzymaniu limites:

def _resize (zdjęcie, wymiary obracać = nie) „”” zmienia rozmiar obrazu być tak blisko jak to możliwe, aby określić Wymiary to django image-model-field.

Will both scale up and down the image to meet this while keeping the proportions 
    in width and height 

""" 

if image and os.path.isfile(image.path): 

    im = pil.open(image.path) 
    logging.debug('resizing image from %s x %s --> %s x %s ' % (im.size[0], im.size[1], dimensions[0], dimensions[1])) 

    if rotate: 
     logging.debug('first rotating image %s' % rotate) 
     im = im.rotate(90) 

    srcWidth = Decimal(im.size[0]) 
    srcHeight = Decimal(im.size[1]) 

    resizeWidth = srcWidth 
    resizeHeight = srcHeight 

    aspect = resizeWidth/resizeHeight # Decimal 

    logging.debug('resize aspect is %s' % aspect) 

    if resizeWidth > dimensions[0] or resizeHeight > dimensions[1]: 
     # if width or height is bigger we need to shrink things 
     if resizeWidth > dimensions[0]: 
      resizeWidth = Decimal(dimensions[0]) 
      resizeHeight = resizeWidth/aspect 

     if resizeHeight > dimensions[1] : 
      aspect = resizeWidth/resizeHeight 
      resizeHeight = Decimal(dimensions[1]) 
      resizeWidth = resizeHeight * aspect 

    else: 
     # if both width and height are smaller we need to increase size 
     if resizeWidth < dimensions[0]: 
      resizeWidth = Decimal(dimensions[0]) 
      resizeHeight = resizeWidth/aspect 

     if resizeHeight > dimensions[1] : 
      aspect = resizeWidth/resizeHeight 
      resizeHeight = Decimal(dimensions[1]) 
      resizeWidth = resizeHeight * aspect 

    im = im.resize((resizeWidth, resizeHeight), pil.ANTIALIAS) 

    logging.debug('resized image to %s %s' % im.size) 
    im.save(image.path) 

else: 
    # no action, due to no image or no image in path 
    pass 

return image 
0

tutaj moja rozwiązanie

a = aspekt SW = oryginalny obraz szerokość SH = pierwotna wysokość obrazu DW = o maksymalna szerokość DH = żądana wysokość maksymalną

sw i SH będzie zawierać ostateczne wartości zmienione:

kod to PHP:

$a = $sw/$sh; 

if($a > 1){ 
    // wider image 
    if($sw != $dw){ 
     $rt = $dw/$sw; 
     $sw = $sw * $rt; 
     $sh = $sh * $rt; 
    } 

    if($sh > $dh){ 
     $rt = $dh/$sh; 
     $sw = $sw * $rt; 
     $sh = $sh * $rt; 
    } 
}else{ 
    // taller image 
    if($sh != $dh){ 
     $rt = $dh/$sh; 
     $sh = $sh * $rt; 
     $sw = $sw * $rt; 
    } 

    if($sw > $dw){ 
     $rt = $dw/$sw; 
     $sh = $sh * $rt; 
     $sw = $sw * $rt; 
    } 
} 
0

użyłem w ten sposób, aby zmienić rozmiar obrazu do FHD sposób

if (width >= height) { 
    var original_ratio = width/height 
    new_width = 1080 * original_ratio 
    console.log("new new_width = " + Math.round(new_width)); 
    console.log("new new_height = 1080"); 
} else { 
    var original_ratio = height/width 
    new_height = 1080 * original_ratio 
    console.log("new new_height = " + Math.round(new_height)); 
    console.log("new new_width = 1080"); 
} 

można zmienić 1080 do nowego rozmiaru.

Mam nadzieję, że przyda się przynajmniej komuś.

0

Moje rozwiązanie się kurczyć i rozwijać wielkości w javascript na podstawie https://stackoverflow.com/a/5654847/1055015

var scale = function (srcWidth, srcHeight, maxWidth, maxHeight) { 

     let resizeWidth = srcWidth; 
     let resizeHeight = srcHeight; 

     let aspect = resizeWidth/resizeHeight; 
     let scaleX = maxWidth/srcWidth; 
     let scaleY = maxHeight/srcHeight; 
     let scale = Math.min(scaleX, scaleY); 

     resizeWidth *= scale; 
     resizeHeight *= scale; 

     if (resizeWidth > maxWidth) { 
     resizeWidth = maxWidth; 
     resizeHeight = resizeWidth/aspect; 
     } 

     if (resizeHeight > maxHeight) { 
     aspect  = resizeWidth/resizeHeight; 
     resizeHeight = maxHeight; 
     resizeWidth = resizeHeight * aspect; 
     } 

     return { 
     width : resizeWidth, 
     height: resizeHeight, 
     }; 
    } 
Powiązane problemy